From 7df4ebd5eceae62004b86c8ea68734a5cceff7bf Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Fri, 10 Nov 2023 08:54:01 +0100 Subject: [PATCH 01/11] 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 ff6557458628..72d7f0eef63f 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 9ce6cd394b88..bb069165222c 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 e913ecbc9093..aa6f27b8f378 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 ad1d34fb2bc7..65dd6d43675e 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) From bebe04b56b08945a324d2d87084a80356597678b Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Fri, 10 Nov 2023 09:37:38 +0100 Subject: [PATCH 02/11] core/state: enable lookup of preimages from disk during dump operation --- core/state/dump.go | 24 ++++++++++++++---------- tests/block_test_util.go | 4 +++- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/core/state/dump.go b/core/state/dump.go index bb069165222c..b29f3b072e48 100644 --- a/core/state/dump.go +++ b/core/state/dump.go @@ -23,6 +23,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rlp" @@ -153,25 +154,28 @@ func (s *StateDB) DumpToCollector(c DumpCollector, conf *DumpConfig) (nextKey [] if err := rlp.DecodeBytes(it.Value, &data); err != nil { panic(err) } - account := DumpAccount{ - Balance: data.Balance.String(), - Nonce: data.Nonce, - Root: data.Root[:], - CodeHash: data.CodeHash, - SecureKey: it.Key, - } var ( - addrBytes = s.trie.GetKey(it.Key) - addr = common.BytesToAddress(addrBytes) + account = DumpAccount{ + Balance: data.Balance.String(), + Nonce: data.Nonce, + Root: data.Root[:], + CodeHash: data.CodeHash, + SecureKey: it.Key, + } address *common.Address + addr common.Address + addrBytes = s.trie.GetKey(it.Key) ) + if addrBytes == nil { // Preimage not present in memory. Check database. + addrBytes = rawdb.ReadPreimage(s.Database().DiskDB(), common.BytesToHash(it.Key)) + } if addrBytes == nil { - // Preimage missing missingPreimages++ if conf.OnlyWithAddresses { continue } } else { + addr = common.BytesToAddress(addrBytes) address = &addr } obj := newObject(s, addr, &data) diff --git a/tests/block_test_util.go b/tests/block_test_util.go index 65dd6d43675e..526f0b7c71c0 100644 --- a/tests/block_test_util.go +++ b/tests/block_test_util.go @@ -116,7 +116,9 @@ func (t *BlockTest) Run(snapshotter bool, scheme string, tracer vm.EVMLogger, po // import pre accounts & construct test genesis block & state root var ( db = rawdb.NewMemoryDatabase() - tconf = &trie.Config{} + tconf = &trie.Config{ + Preimages: true, + } ) if scheme == rawdb.PathScheme { tconf.PathDB = pathdb.Defaults From 9191e97ca345dff5e433f7e2cdb2ffda13f04d75 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Fri, 10 Nov 2023 10:49:25 +0100 Subject: [PATCH 03/11] tests: fix nil deref --- tests/block_test_util.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/block_test_util.go b/tests/block_test_util.go index 526f0b7c71c0..6d9e8c808cf8 100644 --- a/tests/block_test_util.go +++ b/tests/block_test_util.go @@ -162,9 +162,9 @@ func (t *BlockTest) Run(snapshotter bool, scheme string, tracer vm.EVMLogger, po } // Import succeeded: regardless of whether the _test_ succeeds or not, schedule // the post-check to run - defer func() { - postCheck(result, chain) - }() + if postCheck != nil { + defer 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) From 1a35e349c2b4dddf6e266c0b9766b526b5bd5c51 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Fri, 10 Nov 2023 12:50:37 +0100 Subject: [PATCH 04/11] core/state: simplify/unify dump implementation(s) --- core/state/dump.go | 38 +++++++------------------------------- eth/api_debug.go | 18 +++++++++--------- 2 files changed, 16 insertions(+), 40 deletions(-) diff --git a/core/state/dump.go b/core/state/dump.go index b29f3b072e48..ef8da8d4d994 100644 --- a/core/state/dump.go +++ b/core/state/dump.go @@ -65,6 +65,9 @@ type DumpAccount struct { type Dump struct { Root string `json:"root"` Accounts map[string]DumpAccount `json:"accounts"` + // Next can be set to represent that this dump is only partial, and Next + // is where an iterator should be positioned in order to continue the dump. + Next []byte `json:"next,omitempty"` // nil if no more accounts } // OnRoot implements DumpCollector interface @@ -82,25 +85,6 @@ func (d *Dump) OnAccount(addr *common.Address, account DumpAccount) { } } -// IteratorDump is an implementation for iterating over data. -type IteratorDump struct { - Root string `json:"root"` - Accounts map[common.Address]DumpAccount `json:"accounts"` - Next []byte `json:"next,omitempty"` // nil if no more accounts -} - -// OnRoot implements DumpCollector interface -func (d *IteratorDump) OnRoot(root common.Hash) { - d.Root = fmt.Sprintf("%x", root) -} - -// OnAccount implements DumpCollector interface -func (d *IteratorDump) OnAccount(addr *common.Address, account DumpAccount) { - if addr != nil { - d.Accounts[*addr] = account - } -} - // iterativeDump is a DumpCollector-implementation which dumps output line-by-line iteratively. type iterativeDump struct { *json.Encoder @@ -227,12 +211,13 @@ func (s *StateDB) DumpToCollector(c DumpCollector, conf *DumpConfig) (nextKey [] return nextKey } -// RawDump returns the entire state an a single large object +// RawDump returns the state. If the processing is aborted e.g. due to options +// reaching Max, the `Next` key is set on the returned Dump. func (s *StateDB) RawDump(opts *DumpConfig) Dump { dump := &Dump{ Accounts: make(map[string]DumpAccount), } - s.DumpToCollector(dump, opts) + dump.Next = s.DumpToCollector(dump, opts) return *dump } @@ -241,7 +226,7 @@ func (s *StateDB) Dump(opts *DumpConfig) []byte { dump := s.RawDump(opts) json, err := json.MarshalIndent(dump, "", " ") if err != nil { - fmt.Println("Dump err", err) + log.Error("Error dumping state", "err", err) } return json } @@ -250,12 +235,3 @@ func (s *StateDB) Dump(opts *DumpConfig) []byte { func (s *StateDB) IterativeDump(opts *DumpConfig, output *json.Encoder) { s.DumpToCollector(iterativeDump{output}, opts) } - -// IteratorDump dumps out a batch of accounts starts with the given start key -func (s *StateDB) IteratorDump(opts *DumpConfig) IteratorDump { - iterator := &IteratorDump{ - Accounts: make(map[common.Address]DumpAccount), - } - iterator.Next = s.DumpToCollector(iterator, opts) - return *iterator -} diff --git a/eth/api_debug.go b/eth/api_debug.go index dc9f56814699..05010a3969c6 100644 --- a/eth/api_debug.go +++ b/eth/api_debug.go @@ -133,7 +133,7 @@ func (api *DebugAPI) GetBadBlocks(ctx context.Context) ([]*BadBlockArgs, error) const AccountRangeMaxResults = 256 // AccountRange enumerates all accounts in the given block and start point in paging request -func (api *DebugAPI) AccountRange(blockNrOrHash rpc.BlockNumberOrHash, start hexutil.Bytes, maxResults int, nocode, nostorage, incompletes bool) (state.IteratorDump, error) { +func (api *DebugAPI) AccountRange(blockNrOrHash rpc.BlockNumberOrHash, start hexutil.Bytes, maxResults int, nocode, nostorage, incompletes bool) (state.Dump, error) { var stateDb *state.StateDB var err error @@ -144,7 +144,7 @@ func (api *DebugAPI) AccountRange(blockNrOrHash rpc.BlockNumberOrHash, start hex // the miner and operate on those _, stateDb = api.eth.miner.Pending() if stateDb == nil { - return state.IteratorDump{}, errors.New("pending state is not available") + return state.Dump{}, errors.New("pending state is not available") } } else { var header *types.Header @@ -158,29 +158,29 @@ func (api *DebugAPI) AccountRange(blockNrOrHash rpc.BlockNumberOrHash, start hex default: block := api.eth.blockchain.GetBlockByNumber(uint64(number)) if block == nil { - return state.IteratorDump{}, fmt.Errorf("block #%d not found", number) + return state.Dump{}, fmt.Errorf("block #%d not found", number) } header = block.Header() } if header == nil { - return state.IteratorDump{}, fmt.Errorf("block #%d not found", number) + return state.Dump{}, fmt.Errorf("block #%d not found", number) } stateDb, err = api.eth.BlockChain().StateAt(header.Root) if err != nil { - return state.IteratorDump{}, err + return state.Dump{}, err } } } else if hash, ok := blockNrOrHash.Hash(); ok { block := api.eth.blockchain.GetBlockByHash(hash) if block == nil { - return state.IteratorDump{}, fmt.Errorf("block %s not found", hash.Hex()) + return state.Dump{}, fmt.Errorf("block %s not found", hash.Hex()) } stateDb, err = api.eth.BlockChain().StateAt(block.Root()) if err != nil { - return state.IteratorDump{}, err + return state.Dump{}, err } } else { - return state.IteratorDump{}, errors.New("either block number or block hash must be specified") + return state.Dump{}, errors.New("either block number or block hash must be specified") } opts := &state.DumpConfig{ @@ -193,7 +193,7 @@ func (api *DebugAPI) AccountRange(blockNrOrHash rpc.BlockNumberOrHash, start hex if maxResults > AccountRangeMaxResults || maxResults <= 0 { opts.Max = AccountRangeMaxResults } - return stateDb.IteratorDump(opts), nil + return stateDb.RawDump(opts), nil } // StorageRangeResult is the result of a debug_storageRangeAt API call. From 87aa2e5aef08536302f33ac483ea70e41df2e8fb Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Wed, 15 Nov 2023 13:25:50 +0100 Subject: [PATCH 05/11] core/state, eth: fix dump-flaw --- core/state/dump.go | 1 + eth/api_debug_test.go | 25 +++++++++++++------------ 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/core/state/dump.go b/core/state/dump.go index ef8da8d4d994..15d266df4694 100644 --- a/core/state/dump.go +++ b/core/state/dump.go @@ -161,6 +161,7 @@ func (s *StateDB) DumpToCollector(c DumpCollector, conf *DumpConfig) (nextKey [] } else { addr = common.BytesToAddress(addrBytes) address = &addr + account.Address = address } obj := newObject(s, addr, &data) if !conf.SkipCode { diff --git a/eth/api_debug_test.go b/eth/api_debug_test.go index 3d3444a87163..cc70ae9df21b 100644 --- a/eth/api_debug_test.go +++ b/eth/api_debug_test.go @@ -31,12 +31,13 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/trie" "golang.org/x/exp/slices" + "strings" ) var dumper = spew.ConfigState{Indent: " "} -func accountRangeTest(t *testing.T, trie *state.Trie, statedb *state.StateDB, start common.Hash, requestedNum int, expectedNum int) state.IteratorDump { - result := statedb.IteratorDump(&state.DumpConfig{ +func accountRangeTest(t *testing.T, trie *state.Trie, statedb *state.StateDB, start common.Hash, requestedNum int, expectedNum int) state.Dump { + result := statedb.RawDump(&state.DumpConfig{ SkipCode: true, SkipStorage: true, OnlyWithAddresses: false, @@ -47,12 +48,12 @@ func accountRangeTest(t *testing.T, trie *state.Trie, statedb *state.StateDB, st if len(result.Accounts) != expectedNum { t.Fatalf("expected %d results, got %d", expectedNum, len(result.Accounts)) } - for address := range result.Accounts { - if address == (common.Address{}) { - t.Fatalf("empty address returned") + for addr, acc := range result.Accounts { + if strings.HasSuffix(addr, "pre") || acc.Address == nil { + t.Fatalf("account without prestate (address) returned: %v", addr) } - if !statedb.Exist(address) { - t.Fatalf("account not found in state %s", address.Hex()) + if !statedb.Exist(*acc.Address) { + t.Fatalf("account not found in state %s", acc.Address.Hex()) } } return result @@ -92,16 +93,16 @@ func TestAccountRange(t *testing.T) { secondResult := accountRangeTest(t, &trie, sdb, common.BytesToHash(firstResult.Next), AccountRangeMaxResults, AccountRangeMaxResults) hList := make([]common.Hash, 0) - for addr1 := range firstResult.Accounts { - // If address is empty, then it makes no sense to compare + for addr1, acc := range firstResult.Accounts { + // If address is non-available, then it makes no sense to compare // them as they might be two different accounts. - if addr1 == (common.Address{}) { + if acc.Address == nil { continue } if _, duplicate := secondResult.Accounts[addr1]; duplicate { t.Fatalf("pagination test failed: results should not overlap") } - hList = append(hList, crypto.Keccak256Hash(addr1.Bytes())) + hList = append(hList, crypto.Keccak256Hash(acc.Address.Bytes())) } // Test to see if it's possible to recover from the middle of the previous // set and get an even split between the first and second sets. @@ -140,7 +141,7 @@ func TestEmptyAccountRange(t *testing.T) { st.Commit(0, true) st, _ = state.New(types.EmptyRootHash, statedb, nil) - results := st.IteratorDump(&state.DumpConfig{ + results := st.RawDump(&state.DumpConfig{ SkipCode: true, SkipStorage: true, OnlyWithAddresses: true, From 1c4f44fcdb70c989845c808143879502ff511c93 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Mon, 20 Nov 2023 08:22:32 +0100 Subject: [PATCH 06/11] eth: goimports --- eth/api_debug_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eth/api_debug_test.go b/eth/api_debug_test.go index cc70ae9df21b..184b90dd09ad 100644 --- a/eth/api_debug_test.go +++ b/eth/api_debug_test.go @@ -21,6 +21,7 @@ import ( "fmt" "math/big" "reflect" + "strings" "testing" "github.com/davecgh/go-spew/spew" @@ -31,7 +32,6 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/trie" "golang.org/x/exp/slices" - "strings" ) var dumper = spew.ConfigState{Indent: " "} From 7331a120779b37b30b652c08b5edda8d6a45c29a Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Mon, 20 Nov 2023 08:28:02 +0100 Subject: [PATCH 07/11] core: fix test output-state --- core/state/state_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/state/state_test.go b/core/state/state_test.go index 2553133dea55..2f45ba44b4e4 100644 --- a/core/state/state_test.go +++ b/core/state/state_test.go @@ -71,6 +71,7 @@ func TestDump(t *testing.T) { "nonce": 0, "root": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "codeHash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "address": "0x0000000000000000000000000000000000000001", "key": "0x1468288056310c82aa4c01a7e12a10f8111a0560e72b700555479031b86c357d" }, "0x0000000000000000000000000000000000000002": { @@ -78,6 +79,7 @@ func TestDump(t *testing.T) { "nonce": 0, "root": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "codeHash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "address": "0x0000000000000000000000000000000000000002", "key": "0xd52688a8f926c816ca1e079067caba944f158e764817b83fc43594370ca9cf62" }, "0x0000000000000000000000000000000000000102": { @@ -86,6 +88,7 @@ func TestDump(t *testing.T) { "root": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "codeHash": "0x87874902497a5bb968da31a2998d8f22e949d1ef6214bcdedd8bae24cca4b9e3", "code": "0x03030303030303", + "address": "0x0000000000000000000000000000000000000102", "key": "0xa17eacbc25cda025e81db9c5c62868822c73ce097cee2a63e33a2e41268358a1" } } From 016678e12079b34592f54e76280660a22c98d08b Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Tue, 28 Nov 2023 09:37:42 +0100 Subject: [PATCH 08/11] core/state: address review concerns --- core/state/dump.go | 48 +++++++++++++++++++++------------------------- 1 file changed, 22 insertions(+), 26 deletions(-) diff --git a/core/state/dump.go b/core/state/dump.go index 15d266df4694..cf4662114448 100644 --- a/core/state/dump.go +++ b/core/state/dump.go @@ -23,7 +23,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rlp" @@ -50,14 +49,14 @@ type DumpCollector interface { // DumpAccount represents an account in the state. type DumpAccount struct { - Balance string `json:"balance"` - Nonce uint64 `json:"nonce"` - Root hexutil.Bytes `json:"root"` - CodeHash hexutil.Bytes `json:"codeHash"` - Code hexutil.Bytes `json:"code,omitempty"` - Storage map[common.Hash]string `json:"storage,omitempty"` - Address *common.Address `json:"address,omitempty"` // Address only present in iterative (line-by-line) mode - SecureKey hexutil.Bytes `json:"key,omitempty"` // If we don't have address, we can output the key + Balance string `json:"balance"` + Nonce uint64 `json:"nonce"` + Root hexutil.Bytes `json:"root"` + CodeHash hexutil.Bytes `json:"codeHash"` + Code hexutil.Bytes `json:"code,omitempty"` + Storage map[common.Hash]string `json:"storage,omitempty"` + Address *common.Address `json:"address,omitempty"` // Address only present in iterative (line-by-line) mode + AddressHash hexutil.Bytes `json:"key,omitempty"` // If we don't have address, we can output the key } @@ -78,7 +77,7 @@ 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 + d.Accounts[fmt.Sprintf("pre(%s)", account.AddressHash)] = account } if addr != nil { d.Accounts[(*addr).String()] = account @@ -93,14 +92,14 @@ type iterativeDump struct { // OnAccount implements DumpCollector interface func (d iterativeDump) OnAccount(addr *common.Address, account DumpAccount) { dumpAccount := &DumpAccount{ - Balance: account.Balance, - Nonce: account.Nonce, - Root: account.Root, - CodeHash: account.CodeHash, - Code: account.Code, - Storage: account.Storage, - SecureKey: account.SecureKey, - Address: addr, + Balance: account.Balance, + Nonce: account.Nonce, + Root: account.Root, + CodeHash: account.CodeHash, + Code: account.Code, + Storage: account.Storage, + AddressHash: account.AddressHash, + Address: addr, } d.Encode(dumpAccount) } @@ -140,19 +139,16 @@ func (s *StateDB) DumpToCollector(c DumpCollector, conf *DumpConfig) (nextKey [] } var ( account = DumpAccount{ - Balance: data.Balance.String(), - Nonce: data.Nonce, - Root: data.Root[:], - CodeHash: data.CodeHash, - SecureKey: it.Key, + Balance: data.Balance.String(), + Nonce: data.Nonce, + Root: data.Root[:], + CodeHash: data.CodeHash, + AddressHash: it.Key, } address *common.Address addr common.Address addrBytes = s.trie.GetKey(it.Key) ) - if addrBytes == nil { // Preimage not present in memory. Check database. - addrBytes = rawdb.ReadPreimage(s.Database().DiskDB(), common.BytesToHash(it.Key)) - } if addrBytes == nil { missingPreimages++ if conf.OnlyWithAddresses { From b77ff88ef2ea7c3b11065b1baf1952200df6f346 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Tue, 28 Nov 2023 09:59:41 +0100 Subject: [PATCH 09/11] cmd/geth: remove outdated comment --- cmd/geth/chaincmd.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go index b65827f5bc66..ceb596c04cb6 100644 --- a/cmd/geth/chaincmd.go +++ b/cmd/geth/chaincmd.go @@ -495,11 +495,6 @@ func dump(ctx *cli.Context) error { if ctx.Bool(utils.IterativeOutputFlag.Name) { state.IterativeDump(conf, json.NewEncoder(os.Stdout)) } else { - if conf.OnlyWithAddresses { - fmt.Fprintf(os.Stderr, "If you want to include accounts with missing preimages, you need iterative output, since"+ - " otherwise the accounts will overwrite each other in the resulting mapping.") - return errors.New("incompatible options") - } fmt.Println(string(state.Dump(conf))) } return nil From eb9e6d755ead42cf2b700913db23743fcaa4c69e Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Tue, 28 Nov 2023 11:10:04 +0100 Subject: [PATCH 10/11] cmd/geth: fix compilation err --- cmd/geth/snapshot.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cmd/geth/snapshot.go b/cmd/geth/snapshot.go index 82beb4f2e4c5..bbeac603c32c 100644 --- a/cmd/geth/snapshot.go +++ b/cmd/geth/snapshot.go @@ -568,11 +568,11 @@ func dumpState(ctx *cli.Context) error { return err } da := &state.DumpAccount{ - Balance: account.Balance.String(), - Nonce: account.Nonce, - Root: account.Root.Bytes(), - CodeHash: account.CodeHash, - SecureKey: accIt.Hash().Bytes(), + Balance: account.Balance.String(), + Nonce: account.Nonce, + Root: account.Root.Bytes(), + CodeHash: account.CodeHash, + AddressHash: accIt.Hash().Bytes(), } if !conf.SkipCode && !bytes.Equal(account.CodeHash, types.EmptyCodeHash.Bytes()) { da.Code = rawdb.ReadCode(db, common.BytesToHash(account.CodeHash)) From 41d5b6c79d3ee67a85204db35e461095e8e2fd7e Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Tue, 28 Nov 2023 12:59:15 +0100 Subject: [PATCH 11/11] tests: fix flaw in block-test runner to enable preimages --- tests/block_test_util.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/block_test_util.go b/tests/block_test_util.go index 6d9e8c808cf8..3ce3bb4faa61 100644 --- a/tests/block_test_util.go +++ b/tests/block_test_util.go @@ -143,7 +143,7 @@ func (t *BlockTest) Run(snapshotter bool, scheme string, tracer vm.EVMLogger, po // Wrap the original engine within the beacon-engine engine := beacon.New(ethash.NewFaker()) - cache := &core.CacheConfig{TrieCleanLimit: 0, StateScheme: scheme} + cache := &core.CacheConfig{TrieCleanLimit: 0, StateScheme: scheme, Preimages: true} if snapshotter { cache.SnapshotLimit = 1 cache.SnapshotWait = true