diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index 312f427d4c..fcba46a32e 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -116,8 +116,8 @@ type rejectedTx struct { // Apply applies a set of transactions to a pre-state func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, - txs types.Transactions, miningReward int64, - getTracerFn func(txIndex int, txHash common.Hash) (tracer vm.EVMLogger, err error)) (*state.StateDB, *ExecutionResult, error) { + txIt txIterator, miningReward int64, + getTracerFn func(txIndex int, txHash common.Hash) (tracer vm.EVMLogger, err error)) (*state.StateDB, *ExecutionResult, []byte, error) { // Capture errors for BLOCKHASH operation, if we haven't been supplied the // required blockhashes var hashError error @@ -190,7 +190,14 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, core.ProcessBeaconBlockRoot(*beaconRoot, evm, statedb) } var blobGasUsed uint64 - for i, tx := range txs { + + for i := 0; txIt.Next(); i++ { + tx, err := txIt.Tx() + if err != nil { + log.Warn("rejected tx", "index", i, "error", err) + rejectedTxs = append(rejectedTxs, &rejectedTx{i, err.Error()}) + continue + } if tx.Type() == types.BlobTxType && vmContext.BlobBaseFee == nil { errMsg := "blob tx used but field env.ExcessBlobGas missing" log.Warn("rejected tx", "index", i, "hash", tx.Hash(), "error", errMsg) @@ -208,7 +215,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, } tracer, err := getTracerFn(txIndex, tx.Hash()) if err != nil { - return nil, nil, err + return nil, nil, nil, err } vmConfig.Tracer = tracer statedb.SetTxContext(tx.Hash(), txIndex) @@ -231,7 +238,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, } includedTxs = append(includedTxs, tx) if hashError != nil { - return nil, nil, NewError(ErrorMissingBlockhash, hashError) + return nil, nil, nil, NewError(ErrorMissingBlockhash, hashError) } gasUsed += msgResult.UsedGas @@ -306,7 +313,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, // Commit block root, err := statedb.Commit(vmContext.BlockNumber.Uint64(), chainConfig.IsEIP158(vmContext.BlockNumber)) if err != nil { - return nil, nil, NewError(ErrorEVM, fmt.Errorf("could not commit state: %v", err)) + return nil, nil, nil, NewError(ErrorEVM, fmt.Errorf("could not commit state: %v", err)) } execRs := &ExecutionResult{ StateRoot: root, @@ -332,9 +339,10 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, // for accessing latest states. statedb, err = state.New(root, statedb.Database(), nil) if err != nil { - return nil, nil, NewError(ErrorEVM, fmt.Errorf("could not reopen state: %v", err)) + return nil, nil, nil, NewError(ErrorEVM, fmt.Errorf("could not reopen state: %v", err)) } - return statedb, execRs, nil + body, _ := rlp.EncodeToBytes(includedTxs) + return statedb, execRs, body, nil } func MakePreState(db ethdb.Database, accounts core.GenesisAlloc) *state.StateDB { diff --git a/cmd/evm/internal/t8ntool/transition.go b/cmd/evm/internal/t8ntool/transition.go index 985cb35263..d517592e5c 100644 --- a/cmd/evm/internal/t8ntool/transition.go +++ b/cmd/evm/internal/t8ntool/transition.go @@ -34,7 +34,6 @@ import ( "github.com/ethereum/go-ethereum/eth/tracers/logger" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" - "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/tests" "github.com/urfave/cli/v2" ) @@ -144,7 +143,7 @@ func Transition(ctx *cli.Context) error { // Check if anything needs to be read from stdin var ( prestate Prestate - txs types.Transactions // txs to apply + txIt txIterator // txs to apply allocStr = ctx.String(InputAllocFlag.Name) envStr = ctx.String(InputEnvFlag.Name) @@ -189,7 +188,7 @@ func Transition(ctx *cli.Context) error { // Set the chain id chainConfig.ChainID = big.NewInt(ctx.Int64(ChainIDFlag.Name)) - if txs, err = loadTransactions(txStr, inputData, prestate.Env, chainConfig); err != nil { + if txIt, err = loadTransactions(txStr, inputData, prestate.Env, chainConfig); err != nil { return err } if err := applyLondonChecks(&prestate.Env, chainConfig); err != nil { @@ -205,11 +204,10 @@ func Transition(ctx *cli.Context) error { return err } // Run the test and aggregate the result - s, result, err := prestate.Apply(vmConfig, chainConfig, txs, ctx.Int64(RewardFlag.Name), getTracer) + s, result, body, err := prestate.Apply(vmConfig, chainConfig, txIt, ctx.Int64(RewardFlag.Name), getTracer) if err != nil { return err } - body, _ := rlp.EncodeToBytes(txs) // Dump the excution result collector := make(Alloc) s.DumpToCollector(collector, nil) diff --git a/cmd/evm/internal/t8ntool/tx_iterator.go b/cmd/evm/internal/t8ntool/tx_iterator.go index b8b97ea597..1588da8f84 100644 --- a/cmd/evm/internal/t8ntool/tx_iterator.go +++ b/cmd/evm/internal/t8ntool/tx_iterator.go @@ -29,6 +29,7 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" + "io" ) // txWithKey is a helper-struct, to allow us to use the types.Transaction along with @@ -110,7 +111,7 @@ func signUnsignedTransactions(txs []*txWithKey, signer types.Signer) (types.Tran return signedTxs, nil } -func loadTransactions(txStr string, inputData *input, env stEnv, chainConfig *params.ChainConfig) (types.Transactions, error) { +func loadTransactions(txStr string, inputData *input, env stEnv, chainConfig *params.ChainConfig) (txIterator, error) { var txsWithKeys []*txWithKey var signed types.Transactions if txStr != stdinSelector { @@ -127,7 +128,7 @@ func loadTransactions(txStr string, inputData *input, env stEnv, chainConfig *pa if err := rlp.DecodeBytes(body, &signed); err != nil { return nil, err } - return signed, nil + return newArrayIterator(signed), err } if err := json.Unmarshal(data, &txsWithKeys); err != nil { return nil, NewError(ErrorJson, fmt.Errorf("failed unmarshaling txs-file: %v", err)) @@ -140,12 +141,44 @@ func loadTransactions(txStr string, inputData *input, env stEnv, chainConfig *pa if err := rlp.DecodeBytes(body, &signed); err != nil { return nil, err } - return signed, nil + return newArrayIterator(signed), nil } // JSON encoded transactions txsWithKeys = inputData.Txs } // We may have to sign the transactions. signer := types.LatestSignerForChainID(chainConfig.ChainID) - return signUnsignedTransactions(txsWithKeys, signer) + txs, err := signUnsignedTransactions(txsWithKeys, signer) + return newArrayIterator(txs), err +} + +type txIterator interface { + // Next returns true until EOF + Next() bool + // Tx returns the next transaction, OR an error. + Tx() (*types.Transaction, error) +} + +type arrayIterator struct { + idx int + txs types.Transactions +} + +func newArrayIterator(transactions types.Transactions) *arrayIterator { + return &arrayIterator{0, transactions} +} + +func (ait *arrayIterator) Next() bool { + if ait.idx < len(ait.txs) { + return true + } + return false +} + +func (ait *arrayIterator) Tx() (*types.Transaction, error) { + if ait.idx < len(ait.txs) { + ait.idx++ + return ait.txs[ait.idx-1], nil + } + return nil, io.EOF }