Skip to content

Commit b5c20e1

Browse files
committed
Revert "feat(dump): implement Binary Trie state dumping for t8n tool"
This reverts commit 91ba8a2.
1 parent 91ba8a2 commit b5c20e1

File tree

2 files changed

+3
-177
lines changed

2 files changed

+3
-177
lines changed

cmd/evm/internal/t8ntool/transition.go

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -197,14 +197,10 @@ func Transition(ctx *cli.Context) error {
197197
// Dump the execution result
198198
collector := make(Alloc)
199199
var btleaves map[common.Hash]hexutil.Bytes
200-
s.DumpToCollector(collector, nil)
201200
isBinary := chainConfig.IsVerkle(big.NewInt(int64(prestate.Env.Number)), prestate.Env.Timestamp)
202-
if isBinary {
203-
// For Binary Trie mode, we need to dump both:
204-
// 1. The state to collector (alloc) for multi-block tests to maintain state between blocks
205-
// 2. The Binary Trie leaves for witness data
206-
// Without the collector dump, the test framework cannot track state changes (like nonce updates)
207-
// between blocks, causing tests with multiple blocks (e.g., withdrawal tests) to fail.
201+
if !isBinary {
202+
s.DumpToCollector(collector, nil)
203+
} else {
208204
btleaves = make(map[common.Hash]hexutil.Bytes)
209205
if err := s.DumpBinTrieLeaves(btleaves); err != nil {
210206
return err

core/state/dump.go

Lines changed: 0 additions & 170 deletions
Original file line numberDiff line numberDiff line change
@@ -17,21 +17,17 @@
1717
package state
1818

1919
import (
20-
"bytes"
21-
"encoding/binary"
2220
"encoding/json"
2321
"fmt"
2422
"time"
2523

2624
"github.com/ethereum/go-ethereum/common"
2725
"github.com/ethereum/go-ethereum/common/hexutil"
2826
"github.com/ethereum/go-ethereum/core/types"
29-
"github.com/ethereum/go-ethereum/crypto"
3027
"github.com/ethereum/go-ethereum/log"
3128
"github.com/ethereum/go-ethereum/rlp"
3229
"github.com/ethereum/go-ethereum/trie"
3330
"github.com/ethereum/go-ethereum/trie/bintrie"
34-
"github.com/holiman/uint256"
3531
)
3632

3733
// DumpConfig is a set of options to control what portions of the state will be
@@ -138,12 +134,6 @@ func (s *StateDB) DumpToCollector(c DumpCollector, conf *DumpConfig) (nextKey []
138134
if err != nil {
139135
return nil
140136
}
141-
142-
// Check if this is a Binary Trie and handle it specially
143-
if btrie, ok := tr.(*bintrie.BinaryTrie); ok {
144-
return s.dumpBinaryTrieToCollector(btrie, c, conf)
145-
}
146-
147137
trieIt, err := tr.NodeIterator(conf.Start)
148138
if err != nil {
149139
log.Error("Trie dumping error", "err", err)
@@ -232,166 +222,6 @@ func (s *StateDB) DumpToCollector(c DumpCollector, conf *DumpConfig) (nextKey []
232222
return nextKey
233223
}
234224

235-
// dumpBinaryTrieToCollector handles dumping Binary Trie state to the collector.
236-
// This is necessary because Binary Trie stores account data in a completely different format
237-
// than MPT. While MPT uses RLP-encoded StateAccount structures, Binary Trie stores raw bytes
238-
// with specific offsets as defined in EIP-7864.
239-
//
240-
// Binary Trie storage layout for account data:
241-
// - BasicDataLeafKey (suffix byte 0): Contains nonce and balance
242-
// - Bytes 0-7: Code size (4 bytes) + padding
243-
// - Bytes 8-15: Nonce (8 bytes, big-endian)
244-
// - Bytes 16-31: Balance (16 bytes, big-endian)
245-
//
246-
// - CodeHashLeafKey (suffix byte 1): Contains the code hash (32 bytes)
247-
// - Storage slots (suffix bytes 64+): Contains storage values
248-
//
249-
// This function needs to:
250-
// 1. Iterate through Binary Trie nodes to find account data
251-
// 2. Extract and decode account information from raw bytes
252-
// 3. Map Binary Trie keys back to Ethereum addresses
253-
// 4. Reconstruct the full account state for the collector
254-
func (s *StateDB) dumpBinaryTrieToCollector(btrie *bintrie.BinaryTrie, c DumpCollector, conf *DumpConfig) (nextKey []byte) {
255-
var (
256-
accounts uint64
257-
// Map to track processed stems to avoid duplicate accounts
258-
// This prevents dumping the same account when iterating through
259-
// since nultiple leaves can belong to the same account (basic data, code hash, storage).
260-
processedStems = make(map[string]bool)
261-
)
262-
263-
// Step 1: Create an iterator to traverse the Binary Trie
264-
// The iterator will visit all nodes in the trie, allowing us to find leaf nodes
265-
// that contain actual account data
266-
it, err := btrie.NodeIterator(nil)
267-
if err != nil {
268-
log.Error("Failed to create Binary Trie iterator", "err", err)
269-
return nil
270-
}
271-
272-
// Step 2: Iterate through all nodes in the Binary Trie
273-
for it.Next(true) {
274-
// Skip non-leaf nodes as they don't contain account data
275-
if !it.Leaf() {
276-
continue
277-
}
278-
279-
// Step 3: Extract the leaf's key and value
280-
// The key is 32 bytes: 31-byte stem + 1-byte suffix
281-
// The stem encodes the account address, the suffix indicates the data type
282-
leafKey := it.LeafKey()
283-
leafValue := it.LeafBlob()
284-
285-
// Step 4: Parse the key structure
286-
// First 31 bytes: stem (encodes the account address)
287-
// Last byte: suffix (indicates the type of data)
288-
stem := string(leafKey[:31])
289-
suffixByte := leafKey[31]
290-
291-
// Step 5: Check if this leaf contains BasicData (nonce + balance)
292-
// BasicDataLeafKey = 0 is the suffix for account basic data
293-
if suffixByte == bintrie.BasicDataLeafKey {
294-
// Step 6: Ensure we only process each account once
295-
// Multiple leaves can belong to the same account (basic data, code hash, storage)
296-
// We only want to dump each account once
297-
if processedStems[stem] {
298-
continue
299-
}
300-
processedStems[stem] = true
301-
302-
// Step 7: Extract nonce from the Binary Trie format
303-
// Nonce is stored at offset 8 as an 8-byte big-endian integer
304-
var nonce uint64
305-
if len(leafValue) > bintrie.BasicDataNonceOffset+8 {
306-
nonce = binary.BigEndian.Uint64(leafValue[bintrie.BasicDataNonceOffset:])
307-
}
308-
309-
// Step 8: Extract balance from the Binary Trie format
310-
// Balance is stored at offset 16 as a 16-byte big-endian integer
311-
var balance = new(uint256.Int)
312-
if len(leafValue) > bintrie.BasicDataBalanceOffset+16 {
313-
balanceBytes := make([]byte, 16)
314-
copy(balanceBytes, leafValue[bintrie.BasicDataBalanceOffset:bintrie.BasicDataBalanceOffset+16])
315-
balance.SetBytes(balanceBytes)
316-
}
317-
318-
// Step 9: Map the Binary Trie key back to an Ethereum address
319-
// This is the challenging part: Binary Trie keys are hashed versions of addresses
320-
// We need to find which address maps to this particular key
321-
//
322-
// Current approach: (Made up by Claude) ->
323-
// Iterate through known addresses in stateObjects
324-
// and check if their Binary Trie key matches our leaf key
325-
var foundAddr *common.Address
326-
for addr := range s.stateObjects {
327-
// Generate the Binary Trie key for this address
328-
testKey := bintrie.GetBinaryTreeKeyBasicData(addr)
329-
if bytes.Equal(testKey, leafKey) {
330-
a := addr // Create a copy to avoid reference issues
331-
foundAddr = &a
332-
break
333-
}
334-
}
335-
336-
// Step 10: Error if we couldn't find the corresponding address
337-
// This might happen for accounts not in the current state cache
338-
if foundAddr == nil {
339-
// TODO(@CPerezz): Figure out how to proceed.
340-
panic("Binary Trie dump error: Cannot recover address from hash.")
341-
}
342-
343-
// Step 11: Create the dump account structure with basic data
344-
addr := *foundAddr
345-
dumpAccount := DumpAccount{
346-
Balance: balance.ToBig().String(),
347-
Nonce: nonce,
348-
Address: &addr,
349-
AddressHash: crypto.Keccak256(addr[:]),
350-
}
351-
352-
// Step 12: Fetch the code hash from a separate Binary Trie leaf
353-
// Code hash is stored at suffix byte 1 (CodeHashLeafKey)
354-
codeHashKey := bintrie.GetBinaryTreeKeyCodeHash(addr)
355-
if codeHashData, err := btrie.GetWithHashedKey(codeHashKey); err == nil && codeHashData != nil {
356-
dumpAccount.CodeHash = codeHashData
357-
// Step 13: Fetch the actual code if needed and not empty
358-
if !conf.SkipCode && !bytes.Equal(codeHashData, types.EmptyCodeHash.Bytes()) {
359-
dumpAccount.Code = s.GetCode(addr)
360-
}
361-
}
362-
363-
// Step 14: Fetch storage values if needed
364-
if !conf.SkipStorage {
365-
dumpAccount.Storage = make(map[common.Hash]string)
366-
// TODO(CPerezz): Properly iterate through Binary Trie storage slots
367-
// Storage slots are at suffix bytes 64+ in the Binary Trie
368-
// Idea from Claude:
369-
// Use the cached dirty storage from state objects
370-
if obj := s.getStateObject(addr); obj != nil {
371-
for key, value := range obj.dirtyStorage {
372-
dumpAccount.Storage[key] = common.Bytes2Hex(value[:])
373-
}
374-
}
375-
}
376-
377-
// Step 15: Send the account to the collector
378-
c.OnAccount(&addr, dumpAccount)
379-
accounts++
380-
381-
// Step 17: Check if we've reached the maximum number of accounts
382-
if conf.Max > 0 && accounts >= conf.Max {
383-
// Save the next key for resumption if there are more accounts
384-
if it.Next(true) {
385-
nextKey = it.LeafKey()
386-
}
387-
break
388-
}
389-
}
390-
}
391-
392-
return nextKey
393-
}
394-
395225
// DumpBinTrieLeaves collects all binary trie leaf nodes into the provided map.
396226
func (s *StateDB) DumpBinTrieLeaves(collector map[common.Hash]hexutil.Bytes) error {
397227
if s.trie == nil {

0 commit comments

Comments
 (0)