diff --git a/core/types/hashes.go b/core/types/hashes.go index 05cfaeed748..22f1f946dc3 100644 --- a/core/types/hashes.go +++ b/core/types/hashes.go @@ -45,4 +45,7 @@ var ( // EmptyVerkleHash is the known hash of an empty verkle trie. EmptyVerkleHash = common.Hash{} + + // EmptyBinaryHash is the known hash of an empty binary trie. + EmptyBinaryHash = common.Hash{} ) diff --git a/trie/bintrie/binary_node.go b/trie/bintrie/binary_node.go index 50d8c0b3ca1..1c003a6c8fd 100644 --- a/trie/bintrie/binary_node.go +++ b/trie/bintrie/binary_node.go @@ -43,8 +43,7 @@ const ( // BinaryNode is an interface for a binary trie node. type BinaryNode interface { Get([]byte, NodeResolverFn) ([]byte, error) - Insert([]byte, []byte, NodeResolverFn) (BinaryNode, error) - // Commit() common.Hash + Insert([]byte, []byte, NodeResolverFn, int) (BinaryNode, error) Copy() BinaryNode Hash() common.Hash GetValuesAtStem([]byte, NodeResolverFn) ([][]byte, error) @@ -65,7 +64,7 @@ func SerializeNode(node BinaryNode) []byte { copy(serialized[33:65], n.right.Hash().Bytes()) return serialized[:] case *StemNode: - var serialized [32 + 256*32]byte + var serialized [32 + 32 + 256*32]byte serialized[0] = nodeTypeStem copy(serialized[1:32], node.(*StemNode).Stem) bitmap := serialized[32:64] diff --git a/trie/bintrie/empty.go b/trie/bintrie/empty.go index 1effd7f03a0..7cfe373b35b 100644 --- a/trie/bintrie/empty.go +++ b/trie/bintrie/empty.go @@ -28,12 +28,13 @@ func (e Empty) Get(_ []byte, _ NodeResolverFn) ([]byte, error) { return nil, nil } -func (e Empty) Insert(key []byte, value []byte, _ NodeResolverFn) (BinaryNode, error) { +func (e Empty) Insert(key []byte, value []byte, _ NodeResolverFn, depth int) (BinaryNode, error) { var values [256][]byte values[key[31]] = value return &StemNode{ Stem: slices.Clone(key[:31]), Values: values[:], + depth: depth, }, nil } diff --git a/trie/bintrie/empty_test.go b/trie/bintrie/empty_test.go index a3c3681cad6..574ae1830be 100644 --- a/trie/bintrie/empty_test.go +++ b/trie/bintrie/empty_test.go @@ -47,7 +47,7 @@ func TestEmptyInsert(t *testing.T) { key[31] = 0x34 value := common.HexToHash("0xabcd").Bytes() - newNode, err := node.Insert(key, value, nil) + newNode, err := node.Insert(key, value, nil, 0) if err != nil { t.Fatalf("Failed to insert: %v", err) } diff --git a/trie/bintrie/hashed_node.go b/trie/bintrie/hashed_node.go index 05e50db9fbf..8f9fd66a59a 100644 --- a/trie/bintrie/hashed_node.go +++ b/trie/bintrie/hashed_node.go @@ -29,7 +29,7 @@ func (h HashedNode) Get(_ []byte, _ NodeResolverFn) ([]byte, error) { panic("not implemented") // TODO: Implement } -func (h HashedNode) Insert(key []byte, value []byte, resolver NodeResolverFn) (BinaryNode, error) { +func (h HashedNode) Insert(key []byte, value []byte, resolver NodeResolverFn, depth int) (BinaryNode, error) { return nil, errors.New("insert not implemented for hashed node") } diff --git a/trie/bintrie/hashed_node_test.go b/trie/bintrie/hashed_node_test.go index 78f8ad72af7..0c19ae0c57d 100644 --- a/trie/bintrie/hashed_node_test.go +++ b/trie/bintrie/hashed_node_test.go @@ -62,7 +62,7 @@ func TestHashedNodeInsert(t *testing.T) { key := make([]byte, 32) value := make([]byte, 32) - _, err := node.Insert(key, value, nil) + _, err := node.Insert(key, value, nil, 0) if err == nil { t.Fatal("Expected error for Insert on HashedNode") } diff --git a/trie/bintrie/internal_node.go b/trie/bintrie/internal_node.go index af9fce5ef95..70dc54a93b0 100644 --- a/trie/bintrie/internal_node.go +++ b/trie/bintrie/internal_node.go @@ -17,25 +17,22 @@ package bintrie import ( + "crypto/sha256" "errors" "fmt" "github.com/ethereum/go-ethereum/common" - "crypto/sha256" ) func keyToPath(depth int, key []byte) ([]byte, error) { - path := make([]byte, 0, depth+1) - if depth > 31*8 { return nil, errors.New("node too deep") } - + path := make([]byte, 0, depth+1) for i := range depth + 1 { bit := key[i/8] >> (7 - (i % 8)) & 1 path = append(path, bit) } - return path, nil } @@ -81,16 +78,16 @@ func (bt *InternalNode) GetValuesAtStem(stem []byte, resolver NodeResolverFn) ([ func (bt *InternalNode) Get(key []byte, resolver NodeResolverFn) ([]byte, error) { values, err := bt.GetValuesAtStem(key[:31], resolver) if err != nil { - return nil, fmt.Errorf("Get error: %w", err) + return nil, fmt.Errorf("get error: %w", err) } return values[key[31]], nil } // Insert inserts a new key-value pair into the trie. -func (bt *InternalNode) Insert(key []byte, value []byte, resolver NodeResolverFn) (BinaryNode, error) { +func (bt *InternalNode) Insert(key []byte, value []byte, resolver NodeResolverFn, depth int) (BinaryNode, error) { var values [256][]byte values[key[31]] = value - return bt.InsertValuesAtStem(key[:31], values[:], resolver, 0) + return bt.InsertValuesAtStem(key[:31], values[:], resolver, depth) } // Copy creates a deep copy of the node. @@ -121,11 +118,11 @@ func (bt *InternalNode) Hash() common.Hash { // InsertValuesAtStem inserts a full value group at the given stem in the internal node. // Already-existing values will be overwritten. func (bt *InternalNode) InsertValuesAtStem(stem []byte, values [][]byte, resolver NodeResolverFn, depth int) (BinaryNode, error) { - bit := stem[bt.depth/8] >> (7 - (bt.depth % 8)) & 1 var ( child *BinaryNode err error ) + bit := stem[bt.depth/8] >> (7 - (bt.depth % 8)) & 1 if bit == 0 { child = &bt.left } else { diff --git a/trie/bintrie/internal_node_test.go b/trie/bintrie/internal_node_test.go index 976e677177f..158d8b7147d 100644 --- a/trie/bintrie/internal_node_test.go +++ b/trie/bintrie/internal_node_test.go @@ -128,7 +128,7 @@ func TestInternalNodeInsert(t *testing.T) { leftKey[31] = 10 leftValue := common.HexToHash("0x0101").Bytes() - newNode, err := node.Insert(leftKey, leftValue, nil) + newNode, err := node.Insert(leftKey, leftValue, nil, 0) if err != nil { t.Fatalf("Failed to insert: %v", err) } diff --git a/trie/bintrie/iterator.go b/trie/bintrie/iterator.go index ebe0162177b..66564778125 100644 --- a/trie/bintrie/iterator.go +++ b/trie/bintrie/iterator.go @@ -114,7 +114,7 @@ func (it *binaryNodeIterator) Next(descend bool) bool { return it.Next(descend) case HashedNode: // resolve the node - data, err := it.trie.FlatdbNodeResolver(it.Path(), common.Hash(node)) + data, err := it.trie.nodeResolver(it.Path(), common.Hash(node)) if err != nil { panic(err) } diff --git a/trie/bintrie/key_encoding.go b/trie/bintrie/key_encoding.go new file mode 100644 index 00000000000..13c20573710 --- /dev/null +++ b/trie/bintrie/key_encoding.go @@ -0,0 +1,79 @@ +// Copyright 2025 go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package bintrie + +import ( + "bytes" + "crypto/sha256" + + "github.com/ethereum/go-ethereum/common" + "github.com/holiman/uint256" +) + +const ( + BasicDataLeafKey = 0 + CodeHashLeafKey = 1 + BasicDataCodeSizeOffset = 5 + BasicDataNonceOffset = 8 + BasicDataBalanceOffset = 16 +) + +var ( + zeroHash = common.Hash{} + codeOffset = uint256.NewInt(128) +) + +func GetBinaryTreeKey(addr common.Address, key []byte) []byte { + hasher := sha256.New() + hasher.Write(zeroHash[:12]) + hasher.Write(addr[:]) + hasher.Write(key[:31]) + k := hasher.Sum(nil) + k[31] = key[31] + return k +} + +func GetBinaryTreeKeyCodeHash(addr common.Address) []byte { + var k [32]byte + k[31] = CodeHashLeafKey + return GetBinaryTreeKey(addr, k[:]) +} + +func GetBinaryTreeKeyStorageSlot(address common.Address, key []byte) []byte { + var k [32]byte + + // Case when the key belongs to the account header + if bytes.Equal(key[:31], zeroHash[:31]) && key[31] < 64 { + k[31] = 64 + key[31] + return GetBinaryTreeKey(address, k[:]) + } + + // Set the main storage offset + // note that the first 64 bytes of the main offset storage + // are unreachable, which is consistent with the spec and + // what verkle does. + k[0] = 1 // 1 << 248 + copy(k[1:], key[:31]) + k[31] = key[31] + + return GetBinaryTreeKey(address, k[:]) +} + +func GetBinaryTreeKeyCodeChunk(address common.Address, chunknr *uint256.Int) []byte { + chunkOffset := new(uint256.Int).Add(codeOffset, chunknr).Bytes() + return GetBinaryTreeKey(address, chunkOffset) +} diff --git a/trie/bintrie/stem_node.go b/trie/bintrie/stem_node.go index 91f2482fdfb..7422175bd0e 100644 --- a/trie/bintrie/stem_node.go +++ b/trie/bintrie/stem_node.go @@ -18,12 +18,12 @@ package bintrie import ( "bytes" + "crypto/sha256" "errors" "fmt" "slices" "github.com/ethereum/go-ethereum/common" - "crypto/sha256" ) // StemNode represents a group of `NodeWith` values sharing the same stem. @@ -39,7 +39,7 @@ func (bt *StemNode) Get(key []byte, _ NodeResolverFn) ([]byte, error) { } // Insert inserts a new key-value pair into the node. -func (bt *StemNode) Insert(key []byte, value []byte, _ NodeResolverFn) (BinaryNode, error) { +func (bt *StemNode) Insert(key []byte, value []byte, _ NodeResolverFn, depth int) (BinaryNode, error) { if !bytes.Equal(bt.Stem, key[:31]) { bitStem := bt.Stem[bt.depth/8] >> (7 - (bt.depth % 8)) & 1 @@ -59,7 +59,7 @@ func (bt *StemNode) Insert(key []byte, value []byte, _ NodeResolverFn) (BinaryNo bitKey := key[new.depth/8] >> (7 - (new.depth % 8)) & 1 if bitKey == bitStem { var err error - *child, err = (*child).Insert(key, value, nil) + *child, err = (*child).Insert(key, value, nil, depth+1) if err != nil { return new, fmt.Errorf("insert error: %w", err) } @@ -70,16 +70,14 @@ func (bt *StemNode) Insert(key []byte, value []byte, _ NodeResolverFn) (BinaryNo *other = &StemNode{ Stem: slices.Clone(key[:31]), Values: values[:], - depth: new.depth + 1, + depth: depth + 1, } } - return new, nil } if len(value) != 32 { return bt, errors.New("invalid insertion: value length") } - bt.Values[key[31]] = value return bt, nil } @@ -181,7 +179,6 @@ func (bt *StemNode) InsertValuesAtStem(key []byte, values [][]byte, _ NodeResolv depth: new.depth + 1, } } - return new, nil } diff --git a/trie/bintrie/stem_node_test.go b/trie/bintrie/stem_node_test.go index 4eedb434925..e0ffd5c3c84 100644 --- a/trie/bintrie/stem_node_test.go +++ b/trie/bintrie/stem_node_test.go @@ -45,7 +45,7 @@ func TestStemNodeInsertSameStem(t *testing.T) { key[31] = 10 value := common.HexToHash("0x0202").Bytes() - newNode, err := node.Insert(key, value, nil) + newNode, err := node.Insert(key, value, nil, 0) if err != nil { t.Fatalf("Failed to insert: %v", err) } @@ -86,7 +86,7 @@ func TestStemNodeInsertDifferentStem(t *testing.T) { key[0] = 0x80 // First bit is 1 instead of 0 value := common.HexToHash("0x0202").Bytes() - newNode, err := node.Insert(key, value, nil) + newNode, err := node.Insert(key, value, nil, 0) if err != nil { t.Fatalf("Failed to insert: %v", err) } @@ -137,7 +137,7 @@ func TestStemNodeInsertInvalidValueLength(t *testing.T) { copy(key[:31], stem) invalidValue := []byte{1, 2, 3} // Not 32 bytes - _, err := node.Insert(key, invalidValue, nil) + _, err := node.Insert(key, invalidValue, nil, 0) if err == nil { t.Fatal("Expected error for invalid value length") } diff --git a/trie/bintrie/trie.go b/trie/bintrie/trie.go index ca4ac511f85..a309f64b66e 100644 --- a/trie/bintrie/trie.go +++ b/trie/bintrie/trie.go @@ -27,7 +27,6 @@ import ( "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/trie" "github.com/ethereum/go-ethereum/trie/trienode" - "github.com/ethereum/go-ethereum/trie/utils" "github.com/ethereum/go-ethereum/triedb/database" "github.com/holiman/uint256" ) @@ -39,11 +38,10 @@ func NewBinaryNode() BinaryNode { return Empty{} } -// BinaryTrie is a wrapper around VerkleNode that implements the trie.Trie -// interface so that Verkle trees can be reused verbatim. +// BinaryTrie is the implementation of https://eips.ethereum.org/EIPS/eip-7864. type BinaryTrie struct { root BinaryNode - reader *trie.TrieReader + reader *trie.Reader tracer *trie.PrevalueTracer } @@ -55,36 +53,43 @@ func (t *BinaryTrie) ToDot() string { // NewBinaryTrie creates a new binary trie. func NewBinaryTrie(root common.Hash, db database.NodeDatabase) (*BinaryTrie, error) { - reader, err := trie.NewTrieReader(root, common.Hash{}, db) + reader, err := trie.NewReader(root, common.Hash{}, db) if err != nil { return nil, err } - // Parse the root verkle node if it's not empty. - node := NewBinaryNode() - if root != types.EmptyVerkleHash && root != types.EmptyRootHash { - blob, err := reader.Node(nil, common.Hash{}) + t := &BinaryTrie{ + root: NewBinaryNode(), + reader: reader, + tracer: trie.NewPrevalueTracer(), + } + // Parse the root node if it's not empty + if root != types.EmptyBinaryHash && root != types.EmptyRootHash { + blob, err := t.nodeResolver(nil, root) if err != nil { return nil, err } - node, err = DeserializeNode(blob, 0) + node, err := DeserializeNode(blob, 0) if err != nil { return nil, err } + t.root = node } - return &BinaryTrie{ - root: node, - reader: reader, - }, nil + return t, nil } -// FlatdbNodeResolver is a node resolver that reads nodes from the flatdb. -func (t *BinaryTrie) FlatdbNodeResolver(path []byte, hash common.Hash) ([]byte, error) { +// nodeResolver is a node resolver that reads nodes from the flatdb. +func (t *BinaryTrie) nodeResolver(path []byte, hash common.Hash) ([]byte, error) { // empty nodes will be serialized as common.Hash{}, so capture // this special use case. if hash == (common.Hash{}) { return nil, nil // empty node } - return t.reader.Node(path, hash) + blob, err := t.reader.Node(path, hash) + if err != nil { + return nil, err + } + t.tracer.Put(path, blob) + return blob, nil } // GetKey returns the sha3 preimage of a hashed key that was previously used @@ -93,30 +98,23 @@ func (t *BinaryTrie) GetKey(key []byte) []byte { return key } -// Get returns the value for key stored in the trie. The value bytes must -// not be modified by the caller. If a node was not found in the database, a -// trie.MissingNodeError is returned. -func (t *BinaryTrie) GetStorage(addr common.Address, key []byte) ([]byte, error) { - return t.root.Get(utils.GetBinaryTreeKey(addr, key), t.FlatdbNodeResolver) -} - // GetWithHashedKey returns the value, assuming that the key has already // been hashed. func (t *BinaryTrie) GetWithHashedKey(key []byte) ([]byte, error) { - return t.root.Get(key, t.FlatdbNodeResolver) + return t.root.Get(key, t.nodeResolver) } // GetAccount returns the account information for the given address. func (t *BinaryTrie) GetAccount(addr common.Address) (*types.StateAccount, error) { - acc := &types.StateAccount{} - versionkey := utils.GetBinaryTreeKey(addr, zero[:]) var ( values [][]byte err error + acc = &types.StateAccount{} + key = GetBinaryTreeKey(addr, zero[:]) ) switch r := t.root.(type) { case *InternalNode: - values, err = r.GetValuesAtStem(versionkey[:31], t.FlatdbNodeResolver) + values, err = r.GetValuesAtStem(key[:31], t.nodeResolver) case *StemNode: values = r.Values case Empty: @@ -130,47 +128,53 @@ func (t *BinaryTrie) GetAccount(addr common.Address) (*types.StateAccount, error return nil, fmt.Errorf("GetAccount (%x) error: %v", addr, err) } - // The following code is required for the MPT->VKT conversion. - // An account can be partially migrated, where storage slots were moved to the VKT + // The following code is required for the MPT->Binary conversion. + // An account can be partially migrated, where storage slots were moved to the binary // but not yet the account. This means some account information as (header) storage slots - // are in the VKT but basic account information must be read in the base tree (MPT). + // are in the binary trie but basic account information must be read in the base tree (MPT). // TODO: we can simplify this logic depending if the conversion is in progress or finished. emptyAccount := true - - for i := 0; values != nil && i <= utils.CodeHashLeafKey && emptyAccount; i++ { + for i := 0; values != nil && i <= CodeHashLeafKey && emptyAccount; i++ { emptyAccount = emptyAccount && values[i] == nil } if emptyAccount { return nil, nil } - // if the account has been deleted, then values[10] will be 0 and not nil. If it has + // If the account has been deleted, then values[10] will be 0 and not nil. If it has // been recreated after that, then its code keccak will NOT be 0. So return `nil` if // the nonce, and values[10], and code keccak is 0. - if bytes.Equal(values[utils.BasicDataLeafKey], zero[:]) && len(values) > 10 && len(values[10]) > 0 && bytes.Equal(values[utils.CodeHashLeafKey], zero[:]) { + if bytes.Equal(values[BasicDataLeafKey], zero[:]) && len(values) > 10 && len(values[10]) > 0 && bytes.Equal(values[CodeHashLeafKey], zero[:]) { return nil, nil } - acc.Nonce = binary.BigEndian.Uint64(values[utils.BasicDataLeafKey][utils.BasicDataNonceOffset:]) + acc.Nonce = binary.BigEndian.Uint64(values[BasicDataLeafKey][BasicDataNonceOffset:]) var balance [16]byte - copy(balance[:], values[utils.BasicDataLeafKey][utils.BasicDataBalanceOffset:]) + copy(balance[:], values[BasicDataLeafKey][BasicDataBalanceOffset:]) acc.Balance = new(uint256.Int).SetBytes(balance[:]) - acc.CodeHash = values[utils.CodeHashLeafKey] + acc.CodeHash = values[CodeHashLeafKey] return acc, nil } +// GetStorage returns the value for key stored in the trie. The value bytes must +// not be modified by the caller. If a node was not found in the database, a +// trie.MissingNodeError is returned. +func (t *BinaryTrie) GetStorage(addr common.Address, key []byte) ([]byte, error) { + return t.root.Get(GetBinaryTreeKey(addr, key), t.nodeResolver) +} + // UpdateAccount updates the account information for the given address. func (t *BinaryTrie) UpdateAccount(addr common.Address, acc *types.StateAccount, codeLen int) error { var ( err error basicData [32]byte values = make([][]byte, NodeWidth) - stem = utils.GetBinaryTreeKey(addr, zero[:]) + stem = GetBinaryTreeKey(addr, zero[:]) ) + binary.BigEndian.PutUint32(basicData[BasicDataCodeSizeOffset-1:], uint32(codeLen)) + binary.BigEndian.PutUint64(basicData[BasicDataNonceOffset:], acc.Nonce) - binary.BigEndian.PutUint32(basicData[utils.BasicDataCodeSizeOffset-1:], uint32(codeLen)) - binary.BigEndian.PutUint64(basicData[utils.BasicDataNonceOffset:], acc.Nonce) // Because the balance is a max of 16 bytes, truncate // the extra values. This happens in devmode, where // 0xff**32 is allocated to the developer account. @@ -181,33 +185,33 @@ func (t *BinaryTrie) UpdateAccount(addr common.Address, acc *types.StateAccount, balanceBytes = balanceBytes[16:] } copy(basicData[32-len(balanceBytes):], balanceBytes[:]) - values[utils.BasicDataLeafKey] = basicData[:] - values[utils.CodeHashLeafKey] = acc.CodeHash[:] + values[BasicDataLeafKey] = basicData[:] + values[CodeHashLeafKey] = acc.CodeHash[:] - t.root, err = t.root.InsertValuesAtStem(stem, values, t.FlatdbNodeResolver, 0) + t.root, err = t.root.InsertValuesAtStem(stem, values, t.nodeResolver, 0) return err } // UpdateStem updates the values for the given stem key. func (t *BinaryTrie) UpdateStem(key []byte, values [][]byte) error { var err error - t.root, err = t.root.InsertValuesAtStem(key, values, t.FlatdbNodeResolver, 0) + t.root, err = t.root.InsertValuesAtStem(key, values, t.nodeResolver, 0) return err } -// Update associates key with value in the trie. If value has length zero, any +// UpdateStorage associates key with value in the trie. If value has length zero, any // existing value is deleted from the trie. The value bytes must not be modified // by the caller while they are stored in the trie. If a node was not found in the // database, a trie.MissingNodeError is returned. func (t *BinaryTrie) UpdateStorage(address common.Address, key, value []byte) error { - k := utils.GetBinaryTreeKeyStorageSlot(address, key) + k := GetBinaryTreeKeyStorageSlot(address, key) var v [32]byte if len(value) >= 32 { copy(v[:], value[:32]) } else { copy(v[32-len(value):], value[:]) } - root, err := t.root.Insert(k, v[:], t.FlatdbNodeResolver) + root, err := t.root.Insert(k, v[:], t.nodeResolver, 0) if err != nil { return fmt.Errorf("UpdateStorage (%x) error: %v", address, err) } @@ -220,12 +224,12 @@ func (t *BinaryTrie) DeleteAccount(addr common.Address) error { return nil } -// Delete removes any existing value for key from the trie. If a node was not +// DeleteStorage removes any existing value for key from the trie. If a node was not // found in the database, a trie.MissingNodeError is returned. func (t *BinaryTrie) DeleteStorage(addr common.Address, key []byte) error { - k := utils.GetBinaryTreeKey(addr, key) + k := GetBinaryTreeKey(addr, key) var zero [32]byte - root, err := t.root.Insert(k, zero[:], t.FlatdbNodeResolver) + root, err := t.root.Insert(k, zero[:], t.nodeResolver, 0) if err != nil { return fmt.Errorf("DeleteStorage (%x) error: %v", addr, err) } @@ -290,6 +294,8 @@ func (t *BinaryTrie) IsVerkle() bool { return true } +// UpdateContractCode updates the contract code into the trie. +// // Note: the basic data leaf needs to have been previously created for this to work func (t *BinaryTrie) UpdateContractCode(addr common.Address, codeHash common.Hash, code []byte) error { var ( @@ -304,7 +310,7 @@ func (t *BinaryTrie) UpdateContractCode(addr common.Address, codeHash common.Has values = make([][]byte, NodeWidth) var offset [32]byte binary.LittleEndian.PutUint64(offset[24:], chunknr+128) - key = utils.GetBinaryTreeKey(addr, offset[:]) + key = GetBinaryTreeKey(addr, offset[:]) } values[groupOffset] = chunks[i : i+32] diff --git a/trie/bintrie/trie_test.go b/trie/bintrie/trie_test.go index f0a9c8b8b01..84f76895494 100644 --- a/trie/bintrie/trie_test.go +++ b/trie/bintrie/trie_test.go @@ -35,7 +35,7 @@ var ( func TestSingleEntry(t *testing.T) { tree := NewBinaryNode() - tree, err := tree.Insert(zeroKey[:], oneKey[:], nil) + tree, err := tree.Insert(zeroKey[:], oneKey[:], nil, 0) if err != nil { t.Fatal(err) } @@ -52,11 +52,11 @@ func TestSingleEntry(t *testing.T) { func TestTwoEntriesDiffFirstBit(t *testing.T) { var err error tree := NewBinaryNode() - tree, err = tree.Insert(zeroKey[:], oneKey[:], nil) + tree, err = tree.Insert(zeroKey[:], oneKey[:], nil, 0) if err != nil { t.Fatal(err) } - tree, err = tree.Insert(common.HexToHash("8000000000000000000000000000000000000000000000000000000000000000").Bytes(), twoKey[:], nil) + tree, err = tree.Insert(common.HexToHash("8000000000000000000000000000000000000000000000000000000000000000").Bytes(), twoKey[:], nil, 0) if err != nil { t.Fatal(err) } @@ -71,19 +71,19 @@ func TestTwoEntriesDiffFirstBit(t *testing.T) { func TestOneStemColocatedValues(t *testing.T) { var err error tree := NewBinaryNode() - tree, err = tree.Insert(common.HexToHash("0000000000000000000000000000000000000000000000000000000000000003").Bytes(), oneKey[:], nil) + tree, err = tree.Insert(common.HexToHash("0000000000000000000000000000000000000000000000000000000000000003").Bytes(), oneKey[:], nil, 0) if err != nil { t.Fatal(err) } - tree, err = tree.Insert(common.HexToHash("0000000000000000000000000000000000000000000000000000000000000004").Bytes(), twoKey[:], nil) + tree, err = tree.Insert(common.HexToHash("0000000000000000000000000000000000000000000000000000000000000004").Bytes(), twoKey[:], nil, 0) if err != nil { t.Fatal(err) } - tree, err = tree.Insert(common.HexToHash("0000000000000000000000000000000000000000000000000000000000000009").Bytes(), threeKey[:], nil) + tree, err = tree.Insert(common.HexToHash("0000000000000000000000000000000000000000000000000000000000000009").Bytes(), threeKey[:], nil, 0) if err != nil { t.Fatal(err) } - tree, err = tree.Insert(common.HexToHash("00000000000000000000000000000000000000000000000000000000000000FF").Bytes(), fourKey[:], nil) + tree, err = tree.Insert(common.HexToHash("00000000000000000000000000000000000000000000000000000000000000FF").Bytes(), fourKey[:], nil, 0) if err != nil { t.Fatal(err) } @@ -96,20 +96,20 @@ func TestTwoStemColocatedValues(t *testing.T) { var err error tree := NewBinaryNode() // stem: 0...0 - tree, err = tree.Insert(common.HexToHash("0000000000000000000000000000000000000000000000000000000000000003").Bytes(), oneKey[:], nil) + tree, err = tree.Insert(common.HexToHash("0000000000000000000000000000000000000000000000000000000000000003").Bytes(), oneKey[:], nil, 0) if err != nil { t.Fatal(err) } - tree, err = tree.Insert(common.HexToHash("0000000000000000000000000000000000000000000000000000000000000004").Bytes(), twoKey[:], nil) + tree, err = tree.Insert(common.HexToHash("0000000000000000000000000000000000000000000000000000000000000004").Bytes(), twoKey[:], nil, 0) if err != nil { t.Fatal(err) } // stem: 10...0 - tree, err = tree.Insert(common.HexToHash("8000000000000000000000000000000000000000000000000000000000000003").Bytes(), oneKey[:], nil) + tree, err = tree.Insert(common.HexToHash("8000000000000000000000000000000000000000000000000000000000000003").Bytes(), oneKey[:], nil, 0) if err != nil { t.Fatal(err) } - tree, err = tree.Insert(common.HexToHash("8000000000000000000000000000000000000000000000000000000000000004").Bytes(), twoKey[:], nil) + tree, err = tree.Insert(common.HexToHash("8000000000000000000000000000000000000000000000000000000000000004").Bytes(), twoKey[:], nil, 0) if err != nil { t.Fatal(err) } @@ -124,11 +124,11 @@ func TestTwoKeysMatchFirst42Bits(t *testing.T) { // key1 and key 2 have the same prefix of 42 bits (b0*42+b1+b1) and differ after. key1 := common.HexToHash("0000000000C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0").Bytes() key2 := common.HexToHash("0000000000E00000000000000000000000000000000000000000000000000000").Bytes() - tree, err = tree.Insert(key1, oneKey[:], nil) + tree, err = tree.Insert(key1, oneKey[:], nil, 0) if err != nil { t.Fatal(err) } - tree, err = tree.Insert(key2, twoKey[:], nil) + tree, err = tree.Insert(key2, twoKey[:], nil, 0) if err != nil { t.Fatal(err) } @@ -139,11 +139,11 @@ func TestTwoKeysMatchFirst42Bits(t *testing.T) { func TestInsertDuplicateKey(t *testing.T) { var err error tree := NewBinaryNode() - tree, err = tree.Insert(oneKey[:], oneKey[:], nil) + tree, err = tree.Insert(oneKey[:], oneKey[:], nil, 0) if err != nil { t.Fatal(err) } - tree, err = tree.Insert(oneKey[:], twoKey[:], nil) + tree, err = tree.Insert(oneKey[:], twoKey[:], nil, 0) if err != nil { t.Fatal(err) } @@ -161,7 +161,7 @@ func TestLargeNumberOfEntries(t *testing.T) { for i := range 256 { var key [32]byte key[0] = byte(i) - tree, err = tree.Insert(key[:], ffKey[:], nil) + tree, err = tree.Insert(key[:], ffKey[:], nil, 0) if err != nil { t.Fatal(err) } @@ -184,7 +184,7 @@ func TestMerkleizeMultipleEntries(t *testing.T) { for i, key := range keys { var v [32]byte binary.LittleEndian.PutUint64(v[:8], uint64(i)) - tree, err = tree.Insert(key, v[:], nil) + tree, err = tree.Insert(key, v[:], nil, 0) if err != nil { t.Fatal(err) } diff --git a/trie/proof.go b/trie/proof.go index f9bc674d520..1a06ed5d5e3 100644 --- a/trie/proof.go +++ b/trie/proof.go @@ -571,7 +571,7 @@ func VerifyRangeProof(rootHash common.Hash, firstKey []byte, keys [][]byte, valu root: root, reader: newEmptyReader(), opTracer: newOpTracer(), - prevalueTracer: newPrevalueTracer(), + prevalueTracer: NewPrevalueTracer(), } if empty { tr.root = nil diff --git a/trie/tracer.go b/trie/tracer.go index 184a5133254..04122d1384f 100644 --- a/trie/tracer.go +++ b/trie/tracer.go @@ -104,17 +104,17 @@ type PrevalueTracer struct { lock sync.RWMutex } -// newPrevalueTracer initializes the tracer for capturing resolved trie nodes. -func newPrevalueTracer() *PrevalueTracer { +// NewPrevalueTracer initializes the tracer for capturing resolved trie nodes. +func NewPrevalueTracer() *PrevalueTracer { return &PrevalueTracer{ data: make(map[string][]byte), } } -// put tracks the newly loaded trie node and caches its RLP-encoded +// Put tracks the newly loaded trie node and caches its RLP-encoded // blob internally. Do not modify the value outside this function, // as it is not deep-copied. -func (t *PrevalueTracer) put(path []byte, val []byte) { +func (t *PrevalueTracer) Put(path []byte, val []byte) { t.lock.Lock() defer t.lock.Unlock() @@ -130,9 +130,9 @@ func (t *PrevalueTracer) Get(path []byte) []byte { return t.data[string(path)] } -// hasList returns a list of flags indicating whether the corresponding trie nodes +// HasList returns a list of flags indicating whether the corresponding trie nodes // specified by the path exist in the trie. -func (t *PrevalueTracer) hasList(list [][]byte) []bool { +func (t *PrevalueTracer) HasList(list [][]byte) []bool { t.lock.RLock() defer t.lock.RUnlock() @@ -144,24 +144,24 @@ func (t *PrevalueTracer) hasList(list [][]byte) []bool { return exists } -// values returns a list of values of the cached trie nodes. -func (t *PrevalueTracer) values() map[string][]byte { +// Values returns a list of values of the cached trie nodes. +func (t *PrevalueTracer) Values() map[string][]byte { t.lock.RLock() defer t.lock.RUnlock() return maps.Clone(t.data) } -// reset resets the cached content in the prevalueTracer. -func (t *PrevalueTracer) reset() { +// Reset resets the cached content in the prevalueTracer. +func (t *PrevalueTracer) Reset() { t.lock.Lock() defer t.lock.Unlock() clear(t.data) } -// copy returns a copied prevalueTracer instance. -func (t *PrevalueTracer) copy() *PrevalueTracer { +// Copy returns a copied prevalueTracer instance. +func (t *PrevalueTracer) Copy() *PrevalueTracer { t.lock.RLock() defer t.lock.RUnlock() diff --git a/trie/trie.go b/trie/trie.go index 9ff13c50c02..630462f8ca5 100644 --- a/trie/trie.go +++ b/trie/trie.go @@ -55,7 +55,7 @@ type Trie struct { uncommitted int // reader is the handler trie can retrieve nodes from. - reader *TrieReader + reader *Reader // Various tracers for capturing the modifications to trie opTracer *opTracer @@ -77,7 +77,7 @@ func (t *Trie) Copy() *Trie { uncommitted: t.uncommitted, reader: t.reader, opTracer: t.opTracer.copy(), - prevalueTracer: t.prevalueTracer.copy(), + prevalueTracer: t.prevalueTracer.Copy(), } } @@ -88,7 +88,7 @@ func (t *Trie) Copy() *Trie { // empty, otherwise, the root node must be present in database or returns // a MissingNodeError if not. func New(id *ID, db database.NodeDatabase) (*Trie, error) { - reader, err := NewTrieReader(id.StateRoot, id.Owner, db) + reader, err := NewReader(id.StateRoot, id.Owner, db) if err != nil { return nil, err } @@ -96,7 +96,7 @@ func New(id *ID, db database.NodeDatabase) (*Trie, error) { owner: id.Owner, reader: reader, opTracer: newOpTracer(), - prevalueTracer: newPrevalueTracer(), + prevalueTracer: NewPrevalueTracer(), } if id.Root != (common.Hash{}) && id.Root != types.EmptyRootHash { rootnode, err := trie.resolveAndTrack(id.Root[:], nil) @@ -659,7 +659,7 @@ func (t *Trie) resolveAndTrack(n hashNode, prefix []byte) (node, error) { if err != nil { return nil, err } - t.prevalueTracer.put(prefix, blob) + t.prevalueTracer.Put(prefix, blob) // The returned node blob won't be changed afterward. No need to // deep-copy the slice. @@ -673,7 +673,7 @@ func (t *Trie) deletedNodes() [][]byte { var ( pos int list = t.opTracer.deletedList() - flags = t.prevalueTracer.hasList(list) + flags = t.prevalueTracer.HasList(list) ) for i := 0; i < len(list); i++ { if flags[i] { @@ -753,7 +753,7 @@ func (t *Trie) hashRoot() []byte { // Witness returns a set containing all trie nodes that have been accessed. func (t *Trie) Witness() map[string][]byte { - return t.prevalueTracer.values() + return t.prevalueTracer.Values() } // Reset drops the referenced root node and cleans all internal state. @@ -763,6 +763,6 @@ func (t *Trie) Reset() { t.unhashed = 0 t.uncommitted = 0 t.opTracer.reset() - t.prevalueTracer.reset() + t.prevalueTracer.Reset() t.committed = false } diff --git a/trie/trie_reader.go b/trie/trie_reader.go index b776709d254..42fe4d72c7b 100644 --- a/trie/trie_reader.go +++ b/trie/trie_reader.go @@ -22,39 +22,39 @@ import ( "github.com/ethereum/go-ethereum/triedb/database" ) -// TrieReader is a wrapper of the underlying node reader. It's not safe +// Reader is a wrapper of the underlying database reader. It's not safe // for concurrent usage. -type TrieReader struct { +type Reader struct { owner common.Hash reader database.NodeReader banned map[string]struct{} // Marker to prevent node from being accessed, for tests } -// NewTrieReader initializes the trie reader with the given node reader. -func NewTrieReader(stateRoot, owner common.Hash, db database.NodeDatabase) (*TrieReader, error) { +// NewReader initializes the trie reader with the given database reader. +func NewReader(stateRoot, owner common.Hash, db database.NodeDatabase) (*Reader, error) { if stateRoot == (common.Hash{}) || stateRoot == types.EmptyRootHash { - return &TrieReader{owner: owner}, nil + return &Reader{owner: owner}, nil } reader, err := db.NodeReader(stateRoot) if err != nil { return nil, &MissingNodeError{Owner: owner, NodeHash: stateRoot, err: err} } - return &TrieReader{owner: owner, reader: reader}, nil + return &Reader{owner: owner, reader: reader}, nil } // newEmptyReader initializes the pure in-memory reader. All read operations // should be forbidden and returns the MissingNodeError. -func newEmptyReader() *TrieReader { - return &TrieReader{} +func newEmptyReader() *Reader { + return &Reader{} } -// node retrieves the rlp-encoded trie node with the provided trie node +// Node retrieves the rlp-encoded trie node with the provided trie node // information. An MissingNodeError will be returned in case the node is // not found or any error is encountered. // // Don't modify the returned byte slice since it's not deep-copied and // still be referenced by database. -func (r *TrieReader) Node(path []byte, hash common.Hash) ([]byte, error) { +func (r *Reader) Node(path []byte, hash common.Hash) ([]byte, error) { // Perform the logics in tests for preventing trie node access. if r.banned != nil { if _, ok := r.banned[string(path)]; ok { diff --git a/trie/verkle.go b/trie/verkle.go index 4922e957da6..d51867975c4 100644 --- a/trie/verkle.go +++ b/trie/verkle.go @@ -41,13 +41,13 @@ var ( type VerkleTrie struct { root verkle.VerkleNode cache *utils.PointCache - reader *TrieReader + reader *Reader tracer *PrevalueTracer } // NewVerkleTrie constructs a verkle tree based on the specified root hash. func NewVerkleTrie(root common.Hash, db database.NodeDatabase, cache *utils.PointCache) (*VerkleTrie, error) { - reader, err := NewTrieReader(root, common.Hash{}, db) + reader, err := NewReader(root, common.Hash{}, db) if err != nil { return nil, err } @@ -55,7 +55,7 @@ func NewVerkleTrie(root common.Hash, db database.NodeDatabase, cache *utils.Poin root: verkle.New(), cache: cache, reader: reader, - tracer: newPrevalueTracer(), + tracer: NewPrevalueTracer(), } // Parse the root verkle node if it's not empty. if root != types.EmptyVerkleHash && root != types.EmptyRootHash { @@ -326,7 +326,7 @@ func (t *VerkleTrie) Copy() *VerkleTrie { root: t.root.Copy(), cache: t.cache, reader: t.reader, - tracer: t.tracer.copy(), + tracer: t.tracer.Copy(), } } @@ -451,7 +451,7 @@ func (t *VerkleTrie) nodeResolver(path []byte) ([]byte, error) { if err != nil { return nil, err } - t.tracer.put(path, blob) + t.tracer.Put(path, blob) return blob, nil }