Compare commits
5 Commits
82f95931d6
...
321f832f49
Author | SHA1 | Date |
---|---|---|
|
321f832f49 | |
|
dab746b3ef | |
|
d6ffb496ec | |
|
9489a46982 | |
|
fbb8b85aee |
|
@ -128,9 +128,9 @@ func (l *fileWritingTracer) hooks() *tracing.Hooks {
|
|||
l.inner.OnExit(depth, output, gasUsed, err, reverted)
|
||||
}
|
||||
},
|
||||
OnOpcode: func(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) {
|
||||
OnOpcode: func(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, isCancun bool, err error) {
|
||||
if l.inner != nil && l.inner.OnOpcode != nil {
|
||||
l.inner.OnOpcode(pc, op, gas, cost, scope, rData, depth, err)
|
||||
l.inner.OnOpcode(pc, op, gas, cost, scope, rData, depth, isCancun, err)
|
||||
}
|
||||
},
|
||||
OnFault: func(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, depth int, err error) {
|
||||
|
|
|
@ -108,7 +108,7 @@ type (
|
|||
ExitHook = func(depth int, output []byte, gasUsed uint64, err error, reverted bool)
|
||||
|
||||
// OpcodeHook is invoked just prior to the execution of an opcode.
|
||||
OpcodeHook = func(pc uint64, op byte, gas, cost uint64, scope OpContext, rData []byte, depth int, err error)
|
||||
OpcodeHook = func(pc uint64, op byte, gas, cost uint64, scope OpContext, rData []byte, depth int, isCancun bool, err error)
|
||||
|
||||
// FaultHook is invoked when an error occurs during the execution of an opcode.
|
||||
FaultHook = func(pc uint64, op byte, gas, cost uint64, scope OpContext, depth int, err error)
|
||||
|
|
|
@ -216,7 +216,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
|
|||
return
|
||||
}
|
||||
if !logged && in.evm.Config.Tracer.OnOpcode != nil {
|
||||
in.evm.Config.Tracer.OnOpcode(pcCopy, byte(op), gasCopy, cost, callContext, in.returnData, in.evm.depth, VMErrorFromErr(err))
|
||||
in.evm.Config.Tracer.OnOpcode(pcCopy, byte(op), gasCopy, cost, callContext, in.returnData, in.evm.depth, in.evm.chainConfig.IsCancun(in.evm.Context.BlockNumber, in.evm.Context.Time), VMErrorFromErr(err))
|
||||
}
|
||||
if logged && in.evm.Config.Tracer.OnFault != nil {
|
||||
in.evm.Config.Tracer.OnFault(pcCopy, byte(op), gasCopy, cost, callContext, in.evm.depth, VMErrorFromErr(err))
|
||||
|
@ -298,7 +298,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
|
|||
in.evm.Config.Tracer.OnGasChange(gasCopy, gasCopy-cost, tracing.GasChangeCallOpCode)
|
||||
}
|
||||
if in.evm.Config.Tracer.OnOpcode != nil {
|
||||
in.evm.Config.Tracer.OnOpcode(pc, byte(op), gasCopy, cost, callContext, in.returnData, in.evm.depth, VMErrorFromErr(err))
|
||||
in.evm.Config.Tracer.OnOpcode(pc, byte(op), gasCopy, cost, callContext, in.returnData, in.evm.depth, in.evm.chainConfig.IsCancun(in.evm.Context.BlockNumber, in.evm.Context.Time), VMErrorFromErr(err))
|
||||
logged = true
|
||||
}
|
||||
}
|
||||
|
|
|
@ -634,3 +634,11 @@ var stringToOp = map[string]OpCode{
|
|||
func StringToOp(str string) OpCode {
|
||||
return stringToOp[str]
|
||||
}
|
||||
|
||||
// IsCancunOpcode specifies if an opcode is added at Cancun fork.
|
||||
func (op OpCode) IsCancunOpcode() bool {
|
||||
if op == BLOBHASH || op == BLOBBASEFEE || op == TLOAD || op == TSTORE || op == MCOPY {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -680,9 +680,14 @@ func TestColdAccountAccessCost(t *testing.T) {
|
|||
Execute(tc.code, nil, &Config{
|
||||
EVMConfig: vm.Config{
|
||||
Tracer: &tracing.Hooks{
|
||||
OnOpcode: func(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) {
|
||||
OnOpcode: func(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, isCancun bool, err error) {
|
||||
// Uncomment to investigate failures:
|
||||
//t.Logf("%d: %v %d", step, vm.OpCode(op).String(), cost)
|
||||
// opString := vm.OpCode(op).String()
|
||||
// Use hex string if Cancun is inactive but the opcode is invalid before Cancun fork
|
||||
// if !isCancun && vm.OpCode(op).IsCancunOpcode() {
|
||||
// opString = fmt.Sprintf("0x%x", byte(vm.OpCode(op)))
|
||||
// }
|
||||
//t.Logf("%d: %v %d", step, opString, cost)
|
||||
if step == tc.step {
|
||||
have = cost
|
||||
}
|
||||
|
@ -934,9 +939,14 @@ func TestDelegatedAccountAccessCost(t *testing.T) {
|
|||
State: statedb,
|
||||
EVMConfig: vm.Config{
|
||||
Tracer: &tracing.Hooks{
|
||||
OnOpcode: func(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) {
|
||||
OnOpcode: func(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, isCancun bool, err error) {
|
||||
// Uncomment to investigate failures:
|
||||
t.Logf("%d: %v %d", step, vm.OpCode(op).String(), cost)
|
||||
opString := vm.OpCode(op).String()
|
||||
// Use hex string if Cancun is inactive but the opcode is invalid before Cancun fork
|
||||
if !isCancun && vm.OpCode(op).IsCancunOpcode() {
|
||||
opString = fmt.Sprintf("0x%x", byte(vm.OpCode(op)))
|
||||
}
|
||||
t.Logf("%d: %v %d", step, opString, cost)
|
||||
if step == tc.step {
|
||||
have = cost
|
||||
}
|
||||
|
|
|
@ -33,6 +33,8 @@ import (
|
|||
"github.com/ethereum/go-ethereum/event"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/node"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/params/forks"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
)
|
||||
|
||||
|
@ -95,6 +97,16 @@ type SimulatedBeacon struct {
|
|||
lastBlockTime uint64
|
||||
}
|
||||
|
||||
func payloadVersion(config *params.ChainConfig, time uint64) engine.PayloadVersion {
|
||||
switch config.LatestFork(time) {
|
||||
case forks.Prague, forks.Cancun:
|
||||
return engine.PayloadV3
|
||||
case forks.Paris, forks.Shanghai:
|
||||
return engine.PayloadV2
|
||||
}
|
||||
panic("invalid fork, simulated beacon needs to be started post-merge")
|
||||
}
|
||||
|
||||
// NewSimulatedBeacon constructs a new simulated beacon chain.
|
||||
func NewSimulatedBeacon(period uint64, eth *eth.Ethereum) (*SimulatedBeacon, error) {
|
||||
block := eth.BlockChain().CurrentBlock()
|
||||
|
@ -107,7 +119,8 @@ func NewSimulatedBeacon(period uint64, eth *eth.Ethereum) (*SimulatedBeacon, err
|
|||
|
||||
// if genesis block, send forkchoiceUpdated to trigger transition to PoS
|
||||
if block.Number.Sign() == 0 {
|
||||
if _, err := engineAPI.ForkchoiceUpdatedV3(current, nil); err != nil {
|
||||
version := payloadVersion(eth.BlockChain().Config(), block.Time)
|
||||
if _, err := engineAPI.forkchoiceUpdated(current, nil, version, false); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
@ -171,6 +184,8 @@ func (c *SimulatedBeacon) sealBlock(withdrawals []*types.Withdrawal, timestamp u
|
|||
return fmt.Errorf("failed to sync txpool: %w", err)
|
||||
}
|
||||
|
||||
version := payloadVersion(c.eth.BlockChain().Config(), timestamp)
|
||||
|
||||
var random [32]byte
|
||||
rand.Read(random[:])
|
||||
fcResponse, err := c.engineAPI.forkchoiceUpdated(c.curForkchoiceState, &engine.PayloadAttributes{
|
||||
|
@ -179,7 +194,7 @@ func (c *SimulatedBeacon) sealBlock(withdrawals []*types.Withdrawal, timestamp u
|
|||
Withdrawals: withdrawals,
|
||||
Random: random,
|
||||
BeaconRoot: &common.Hash{},
|
||||
}, engine.PayloadV3, false)
|
||||
}, version, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -204,28 +219,39 @@ func (c *SimulatedBeacon) sealBlock(withdrawals []*types.Withdrawal, timestamp u
|
|||
}
|
||||
}
|
||||
|
||||
// Independently calculate the blob hashes from sidecars.
|
||||
blobHashes := make([]common.Hash, 0)
|
||||
if envelope.BlobsBundle != nil {
|
||||
hasher := sha256.New()
|
||||
for _, commit := range envelope.BlobsBundle.Commitments {
|
||||
var c kzg4844.Commitment
|
||||
if len(commit) != len(c) {
|
||||
return errors.New("invalid commitment length")
|
||||
var (
|
||||
blobHashes []common.Hash
|
||||
beaconRoot *common.Hash
|
||||
requests [][]byte
|
||||
)
|
||||
// Compute post-shanghai fields
|
||||
if version > engine.PayloadV2 {
|
||||
// Independently calculate the blob hashes from sidecars.
|
||||
blobHashes = make([]common.Hash, 0)
|
||||
if envelope.BlobsBundle != nil {
|
||||
hasher := sha256.New()
|
||||
for _, commit := range envelope.BlobsBundle.Commitments {
|
||||
var c kzg4844.Commitment
|
||||
if len(commit) != len(c) {
|
||||
return errors.New("invalid commitment length")
|
||||
}
|
||||
copy(c[:], commit)
|
||||
blobHashes = append(blobHashes, kzg4844.CalcBlobHashV1(hasher, &c))
|
||||
}
|
||||
copy(c[:], commit)
|
||||
blobHashes = append(blobHashes, kzg4844.CalcBlobHashV1(hasher, &c))
|
||||
}
|
||||
beaconRoot = &common.Hash{}
|
||||
requests = envelope.Requests
|
||||
}
|
||||
|
||||
// Mark the payload as canon
|
||||
_, err = c.engineAPI.newPayload(*payload, blobHashes, &common.Hash{}, envelope.Requests, false)
|
||||
_, err = c.engineAPI.newPayload(*payload, blobHashes, beaconRoot, requests, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.setCurrentState(payload.BlockHash, finalizedHash)
|
||||
|
||||
// Mark the block containing the payload as canonical
|
||||
if _, err = c.engineAPI.ForkchoiceUpdatedV3(c.curForkchoiceState, nil); err != nil {
|
||||
if _, err = c.engineAPI.forkchoiceUpdated(c.curForkchoiceState, nil, version, false); err != nil {
|
||||
return err
|
||||
}
|
||||
c.lastBlockTime = payload.Timestamp
|
||||
|
|
|
@ -329,7 +329,7 @@ func (t *jsTracer) onStart(from common.Address, to common.Address, create bool,
|
|||
}
|
||||
|
||||
// OnOpcode implements the Tracer interface to trace a single step of VM execution.
|
||||
func (t *jsTracer) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) {
|
||||
func (t *jsTracer) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, isCancun bool, err error) {
|
||||
if !t.traceStep {
|
||||
return
|
||||
}
|
||||
|
|
|
@ -183,10 +183,10 @@ func TestHaltBetweenSteps(t *testing.T) {
|
|||
evm.SetTxContext(vm.TxContext{GasPrice: big.NewInt(1)})
|
||||
tracer.OnTxStart(evm.GetVMContext(), types.NewTx(&types.LegacyTx{}), common.Address{})
|
||||
tracer.OnEnter(0, byte(vm.CALL), common.Address{}, common.Address{}, []byte{}, 0, big.NewInt(0))
|
||||
tracer.OnOpcode(0, 0, 0, 0, scope, nil, 0, nil)
|
||||
tracer.OnOpcode(0, 0, 0, 0, scope, nil, 0, true, nil)
|
||||
timeout := errors.New("stahp")
|
||||
tracer.Stop(timeout)
|
||||
tracer.OnOpcode(0, 0, 0, 0, scope, nil, 0, nil)
|
||||
tracer.OnOpcode(0, 0, 0, 0, scope, nil, 0, true, nil)
|
||||
|
||||
if _, err := tracer.GetResult(); !strings.Contains(err.Error(), timeout.Error()) {
|
||||
t.Errorf("Expected timeout error, got %v", err)
|
||||
|
|
|
@ -61,7 +61,7 @@ func newNoopTracer(_ json.RawMessage) (*tracing.Hooks, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
func (t *noop) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) {
|
||||
func (t *noop) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, isCancun bool, err error) {
|
||||
}
|
||||
|
||||
func (t *noop) OnFault(pc uint64, op byte, gas, cost uint64, _ tracing.OpContext, depth int, err error) {
|
||||
|
|
|
@ -132,7 +132,7 @@ func (a *AccessListTracer) Hooks() *tracing.Hooks {
|
|||
}
|
||||
|
||||
// OnOpcode captures all opcodes that touch storage or addresses and adds them to the accesslist.
|
||||
func (a *AccessListTracer) OnOpcode(pc uint64, opcode byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) {
|
||||
func (a *AccessListTracer) OnOpcode(pc uint64, opcode byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, isCancun bool, err error) {
|
||||
stackData := scope.StackData()
|
||||
stackLen := len(stackData)
|
||||
op := vm.OpCode(opcode)
|
||||
|
|
|
@ -157,10 +157,15 @@ type structLogLegacy struct {
|
|||
}
|
||||
|
||||
// toLegacyJSON converts the structLog to legacy json-encoded legacy form.
|
||||
func (s *StructLog) toLegacyJSON() json.RawMessage {
|
||||
func (s *StructLog) toLegacyJSON(isCancun bool) json.RawMessage {
|
||||
opString := s.OpName()
|
||||
// Use hex string if Cancun is inactive but the opcode is invalid before Cancun fork
|
||||
if !isCancun && s.Op.IsCancunOpcode() {
|
||||
opString = fmt.Sprintf("0x%x", byte(s.Op))
|
||||
}
|
||||
msg := structLogLegacy{
|
||||
Pc: s.Pc,
|
||||
Op: s.Op.String(),
|
||||
Op: opString,
|
||||
Gas: s.Gas,
|
||||
GasCost: s.GasCost,
|
||||
Depth: s.Depth,
|
||||
|
@ -254,7 +259,7 @@ func (l *StructLogger) Hooks() *tracing.Hooks {
|
|||
// OnOpcode logs a new structured log message and pushes it out to the environment
|
||||
//
|
||||
// OnOpcode also tracks SLOAD/SSTORE ops to track storage change.
|
||||
func (l *StructLogger) OnOpcode(pc uint64, opcode byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) {
|
||||
func (l *StructLogger) OnOpcode(pc uint64, opcode byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, isCancun bool, err error) {
|
||||
// If tracing was interrupted, exit
|
||||
if l.interrupt.Load() {
|
||||
return
|
||||
|
@ -315,7 +320,7 @@ func (l *StructLogger) OnOpcode(pc uint64, opcode byte, gas, cost uint64, scope
|
|||
|
||||
// create a log
|
||||
if l.writer == nil {
|
||||
entry := log.toLegacyJSON()
|
||||
entry := log.toLegacyJSON(isCancun)
|
||||
l.resultSize += len(entry)
|
||||
l.logs = append(l.logs, entry)
|
||||
return
|
||||
|
@ -491,12 +496,17 @@ func (t *mdLogger) OnExit(depth int, output []byte, gasUsed uint64, err error, r
|
|||
}
|
||||
|
||||
// OnOpcode also tracks SLOAD/SSTORE ops to track storage change.
|
||||
func (t *mdLogger) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) {
|
||||
func (t *mdLogger) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, isCancun bool, err error) {
|
||||
if t.skip {
|
||||
return
|
||||
}
|
||||
stack := scope.StackData()
|
||||
fmt.Fprintf(t.out, "| %4d | %10v | %3d |%10v |", pc, vm.OpCode(op).String(),
|
||||
opString := vm.OpCode(op).String()
|
||||
// Use hex string if Cancun is inactive but the opcode is invalid before Cancun fork
|
||||
if !isCancun && vm.OpCode(op).IsCancunOpcode() {
|
||||
opString = fmt.Sprintf("0x%x", byte(vm.OpCode(op)))
|
||||
}
|
||||
fmt.Fprintf(t.out, "| %4d | %10v | %3d |%10v |", pc, opString,
|
||||
cost, t.env.StateDB.GetRefund())
|
||||
|
||||
if !t.cfg.DisableStack {
|
||||
|
|
|
@ -97,11 +97,11 @@ func NewJSONLoggerWithCallFrames(cfg *Config, writer io.Writer) *tracing.Hooks {
|
|||
}
|
||||
|
||||
func (l *jsonLogger) OnFault(pc uint64, op byte, gas uint64, cost uint64, scope tracing.OpContext, depth int, err error) {
|
||||
// TODO: Add rData to this interface as well
|
||||
l.OnOpcode(pc, op, gas, cost, scope, nil, depth, err)
|
||||
// TODO: Add rData and Cancun status to this interface as well
|
||||
l.OnOpcode(pc, op, gas, cost, scope, nil, depth, true, err)
|
||||
}
|
||||
|
||||
func (l *jsonLogger) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) {
|
||||
func (l *jsonLogger) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, isCancun bool, err error) {
|
||||
memory := scope.MemoryData()
|
||||
stack := scope.StackData()
|
||||
|
||||
|
|
|
@ -76,10 +76,10 @@ func newMuxTracer(ctx *tracers.Context, cfg json.RawMessage, chainConfig *params
|
|||
}, nil
|
||||
}
|
||||
|
||||
func (t *muxTracer) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) {
|
||||
func (t *muxTracer) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, isCancun bool, err error) {
|
||||
for _, t := range t.tracers {
|
||||
if t.OnOpcode != nil {
|
||||
t.OnOpcode(pc, op, gas, cost, scope, rData, depth, err)
|
||||
t.OnOpcode(pc, op, gas, cost, scope, rData, depth, isCancun, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,7 +58,7 @@ func newNoopTracer(ctx *tracers.Context, cfg json.RawMessage, chainConfig *param
|
|||
}, nil
|
||||
}
|
||||
|
||||
func (t *noopTracer) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) {
|
||||
func (t *noopTracer) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, isCancun bool, err error) {
|
||||
}
|
||||
|
||||
func (t *noopTracer) OnFault(pc uint64, op byte, gas, cost uint64, _ tracing.OpContext, depth int, err error) {
|
||||
|
|
|
@ -101,7 +101,7 @@ func newPrestateTracer(ctx *tracers.Context, cfg json.RawMessage, chainConfig *p
|
|||
}
|
||||
|
||||
// OnOpcode implements the EVMLogger interface to trace a single step of VM execution.
|
||||
func (t *prestateTracer) OnOpcode(pc uint64, opcode byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) {
|
||||
func (t *prestateTracer) OnOpcode(pc uint64, opcode byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, isCancun bool, err error) {
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue