From 7df4ebd5eceae62004b86c8ea68734a5cceff7bf Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Fri, 10 Nov 2023 08:54:01 +0100 Subject: [PATCH] cmd/evm, core/state: add callback to blockrunner, fix dump with missing preimages This changes makes it so that the block test executor takes a callback, just like the state test executor already does. This callback can be used to examine the post-execution state, e.g. to aid debugging of test failures. This change also modifies the mechanics of Dump: previously, all accounts for which we did not have the preimage (address) were silently discarded. Now they are output instead like this: ``` { "root": "3ef447699d08e3160c448903e77bd092c67ce3faeba773a3f83c500ab80f2400", "accounts": { "pre(0x03601462093b5945d1676df093446790fd31b20e7b12a2e8e5e09d068109616b)": { "balance": "10780210", "nonce": 1, ``` --- cmd/evm/blockrunner.go | 9 ++++++++- core/state/dump.go | 11 +++++++---- tests/block_test.go | 8 ++++---- tests/block_test_util.go | 7 ++++++- 4 files changed, 25 insertions(+), 10 deletions(-) diff --git a/cmd/evm/blockrunner.go b/cmd/evm/blockrunner.go index ff65574586..72d7f0eef6 100644 --- a/cmd/evm/blockrunner.go +++ b/cmd/evm/blockrunner.go @@ -24,6 +24,7 @@ import ( "regexp" "sort" + "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/eth/tracers/logger" @@ -85,7 +86,13 @@ func blockTestCmd(ctx *cli.Context) error { continue } test := tests[name] - if err := test.Run(false, rawdb.HashScheme, tracer); err != nil { + if err := test.Run(false, rawdb.HashScheme, tracer, func(res error, chain *core.BlockChain) { + if ctx.Bool(DumpFlag.Name) { + if state, _ := chain.State(); state != nil { + fmt.Println(string(state.Dump(nil))) + } + } + }); err != nil { return fmt.Errorf("test %v: %w", name, err) } } diff --git a/core/state/dump.go b/core/state/dump.go index 9ce6cd394b..bb06916522 100644 --- a/core/state/dump.go +++ b/core/state/dump.go @@ -62,8 +62,8 @@ type DumpAccount struct { // Dump represents the full dump in a collected format, as one large map. type Dump struct { - Root string `json:"root"` - Accounts map[common.Address]DumpAccount `json:"accounts"` + Root string `json:"root"` + Accounts map[string]DumpAccount `json:"accounts"` } // OnRoot implements DumpCollector interface @@ -73,8 +73,11 @@ func (d *Dump) OnRoot(root common.Hash) { // OnAccount implements DumpCollector interface func (d *Dump) OnAccount(addr *common.Address, account DumpAccount) { + if addr == nil { + d.Accounts[fmt.Sprintf("pre(%s)", account.SecureKey)] = account + } if addr != nil { - d.Accounts[*addr] = account + d.Accounts[(*addr).String()] = account } } @@ -223,7 +226,7 @@ func (s *StateDB) DumpToCollector(c DumpCollector, conf *DumpConfig) (nextKey [] // RawDump returns the entire state an a single large object func (s *StateDB) RawDump(opts *DumpConfig) Dump { dump := &Dump{ - Accounts: make(map[common.Address]DumpAccount), + Accounts: make(map[string]DumpAccount), } s.DumpToCollector(dump, opts) return *dump diff --git a/tests/block_test.go b/tests/block_test.go index e913ecbc90..aa6f27b8f3 100644 --- a/tests/block_test.go +++ b/tests/block_test.go @@ -74,19 +74,19 @@ func TestExecutionSpec(t *testing.T) { } func execBlockTest(t *testing.T, bt *testMatcher, test *BlockTest) { - if err := bt.checkFailure(t, test.Run(false, rawdb.HashScheme, nil)); err != nil { + if err := bt.checkFailure(t, test.Run(false, rawdb.HashScheme, nil, nil)); err != nil { t.Errorf("test in hash mode without snapshotter failed: %v", err) return } - if err := bt.checkFailure(t, test.Run(true, rawdb.HashScheme, nil)); err != nil { + if err := bt.checkFailure(t, test.Run(true, rawdb.HashScheme, nil, nil)); err != nil { t.Errorf("test in hash mode with snapshotter failed: %v", err) return } - if err := bt.checkFailure(t, test.Run(false, rawdb.PathScheme, nil)); err != nil { + if err := bt.checkFailure(t, test.Run(false, rawdb.PathScheme, nil, nil)); err != nil { t.Errorf("test in path mode without snapshotter failed: %v", err) return } - if err := bt.checkFailure(t, test.Run(true, rawdb.PathScheme, nil)); err != nil { + if err := bt.checkFailure(t, test.Run(true, rawdb.PathScheme, nil, nil)); err != nil { t.Errorf("test in path mode with snapshotter failed: %v", err) return } diff --git a/tests/block_test_util.go b/tests/block_test_util.go index ad1d34fb2b..65dd6d4367 100644 --- a/tests/block_test_util.go +++ b/tests/block_test_util.go @@ -108,7 +108,7 @@ type btHeaderMarshaling struct { ExcessBlobGas *math.HexOrDecimal64 } -func (t *BlockTest) Run(snapshotter bool, scheme string, tracer vm.EVMLogger) error { +func (t *BlockTest) Run(snapshotter bool, scheme string, tracer vm.EVMLogger, postCheck func(error, *core.BlockChain)) (result error) { config, ok := Forks[t.json.Network] if !ok { return UnsupportedForkError{t.json.Network} @@ -158,6 +158,11 @@ func (t *BlockTest) Run(snapshotter bool, scheme string, tracer vm.EVMLogger) er if err != nil { return err } + // Import succeeded: regardless of whether the _test_ succeeds or not, schedule + // the post-check to run + defer func() { + postCheck(result, chain) + }() cmlast := chain.CurrentBlock().Hash() if common.Hash(t.json.BestBlock) != cmlast { return fmt.Errorf("last block hash validation mismatch: want: %x, have: %x", t.json.BestBlock, cmlast)