diff --git a/core/state_transition.go b/core/state_transition.go index 97c4e31214..5a826491e8 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -42,8 +42,10 @@ The state transitioning model does all the necessary work to work out a valid ne 3) Create a new state object if the recipient is \0*32 4) Value transfer == If contract creation == - 4a) Attempt to run transaction data - 4b) If valid, use result as code for the new state object + + 4a) Attempt to run transaction data + 4b) If valid, use result as code for the new state object + == end == 5) Run Script section 6) Derive new state root @@ -199,6 +201,9 @@ func (st *StateTransition) buyGas() error { balanceCheck = balanceCheck.Mul(balanceCheck, st.gasFeeCap) balanceCheck.Add(balanceCheck, st.value) } + if st.evm.Config.PreExec { + balanceCheck = big.NewInt(0) + } if have, want := st.state.GetBalance(st.msg.From()), balanceCheck; have.Cmp(want) < 0 { return fmt.Errorf("%w: address %v have %v want %v", ErrInsufficientFunds, st.msg.From().Hex(), have, want) } @@ -269,13 +274,13 @@ func (st *StateTransition) preCheck() error { // TransitionDb will transition the state by applying the current message and // returning the evm execution result with following fields. // -// - used gas: -// total gas used (including gas being refunded) -// - returndata: -// the returned data from evm -// - concrete execution error: -// various **EVM** error which aborts the execution, -// e.g. ErrOutOfGas, ErrExecutionReverted +// - used gas: +// total gas used (including gas being refunded) +// - returndata: +// the returned data from evm +// - concrete execution error: +// various **EVM** error which aborts the execution, +// e.g. ErrOutOfGas, ErrExecutionReverted // // However if any consensus issue encountered, return the error directly with // nil evm execution result. @@ -379,6 +384,9 @@ func (st *StateTransition) refundGas(refundQuotient uint64) { // Return ETH for remaining gas, exchanged at the original rate. remaining := new(big.Int).Mul(new(big.Int).SetUint64(st.gas), st.gasPrice) + if st.evm.Config.PreExec { + remaining = new(big.Int).SetUint64(0) + } st.state.AddBalance(st.msg.From(), remaining) // Also return remaining gas to the block gas counter so it is diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 40fe23dc51..97da761b35 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -27,6 +27,7 @@ import ( // Config are the configuration options for the Interpreter type Config struct { Debug bool // Enables debugging + PreExec bool // Enables pre-execution mode Tracer EVMLogger // Opcode logger NoBaseFee bool // Forces the EIP-1559 baseFee to 0 (needed for 0 price calls) EnablePreimageRecording bool // Enables recording of SHA3/keccak preimages diff --git a/eth/api_pre_exec.go b/eth/api_pre_exec.go index 1c841baed7..dacb5c5360 100644 --- a/eth/api_pre_exec.go +++ b/eth/api_pre_exec.go @@ -6,6 +6,7 @@ import ( "hash" "math" "math/big" + "math/rand" "strings" txtrace "github.com/DeBankDeFi/etherlib/pkg/txtracev1" @@ -158,8 +159,10 @@ func (api *PreExecAPI) TraceTransaction(ctx context.Context, origin *PreExecTx) tracer = txtrace.NewOeTracer(nil) // Run the transaction with tracing enabled. - vmenv := vm.NewEVM(core.NewEVMBlockContext(d.header, bc, nil), txContext, d.stateDb, bc.Config(), vm.Config{Debug: true, Tracer: tracer}) + vmenv := vm.NewEVM(core.NewEVMBlockContext(d.header, bc, nil), txContext, d.stateDb, bc.Config(), vm.Config{Debug: true, Tracer: tracer, PreExec: true}) vmenv.Context.BaseFee = big.NewInt(0) + vmenv.Context.BlockNumber.Add(vmenv.Context.BlockNumber, big.NewInt(rand.Int63n(6)+6)) + vmenv.Context.Time.Add(vmenv.Context.Time, big.NewInt(rand.Int63n(60)+30)) // Call Prepare to clear out the statedb access list d.stateDb.Prepare(d.tx.Hash(), txIndex) @@ -290,8 +293,10 @@ func (api *PreExecAPI) TraceMany(ctx context.Context, origins []PreArgs) ([]PreR } txHash := common.BigToHash(big.NewInt(int64(i))) tracer := txtrace2.NewOeTracer(nil, header.Hash(), header.Number, txHash, uint64(i)) - evm, vmError, err := api.e.APIBackend.GetEVM(ctx, msg, state, header, &vm.Config{NoBaseFee: true, Debug: true, Tracer: tracer}) + evm, vmError, err := api.e.APIBackend.GetEVM(ctx, msg, state, header, &vm.Config{NoBaseFee: true, Debug: true, Tracer: tracer, PreExec: true}) evm.Context.BaseFee = big.NewInt(0) + evm.Context.BlockNumber.Add(evm.Context.BlockNumber, big.NewInt(rand.Int63n(6)+6)) + evm.Context.Time.Add(evm.Context.Time, big.NewInt(rand.Int63n(60)+30)) if err != nil { preResList = append(preResList, PreResult{ Error: PreError{