mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-15 03:11:36 +00:00
trie/bintrie: unexport NodeStore, NewNodeStore, NodeFlushFn, nodeResolverFn
grep across the repo confirms zero external callers of bintrie.NodeStore, NewNodeStore, NodeFlushFn, or NodeResolverFn. The arena is purely an implementation detail of BinaryTrie; unexport the top-level names so the package's external surface stays confined to BinaryTrie plus the EIP-7864 helpers (ChunkifyCode, GetBinaryTreeKey*). Methods on *nodeStore remain capitalized for now — with nodeStore itself unexported, external code has no way to hold a *nodeStore pointer, so the methods are effectively internal despite their case. Method case is a cosmetic follow-up.
This commit is contained in:
parent
f676f04706
commit
c24930bebf
13 changed files with 118 additions and 118 deletions
|
|
@ -36,9 +36,9 @@ const (
|
||||||
|
|
||||||
// DeserializeAndHash deserializes a node from bytes and returns its hash.
|
// DeserializeAndHash deserializes a node from bytes and returns its hash.
|
||||||
// This is a convenience function for external callers that need to compute
|
// This is a convenience function for external callers that need to compute
|
||||||
// the hash of a serialized node without maintaining a NodeStore.
|
// the hash of a serialized node without maintaining a nodeStore.
|
||||||
func DeserializeAndHash(blob []byte, depth int) (common.Hash, error) {
|
func DeserializeAndHash(blob []byte, depth int) (common.Hash, error) {
|
||||||
s := NewNodeStore()
|
s := newNodeStore()
|
||||||
ref, err := s.deserializeNode(blob, depth)
|
ref, err := s.deserializeNode(blob, depth)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return common.Hash{}, err
|
return common.Hash{}, err
|
||||||
|
|
|
||||||
|
|
@ -24,12 +24,12 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestSerializeDeserializeInternalNode tests flat 65-byte serialization and
|
// TestSerializeDeserializeInternalNode tests flat 65-byte serialization and
|
||||||
// deserialization of InternalNode through NodeStore.
|
// deserialization of InternalNode through nodeStore.
|
||||||
func TestSerializeDeserializeInternalNode(t *testing.T) {
|
func TestSerializeDeserializeInternalNode(t *testing.T) {
|
||||||
leftHash := common.HexToHash("0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef")
|
leftHash := common.HexToHash("0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef")
|
||||||
rightHash := common.HexToHash("0xfedcba0987654321fedcba0987654321fedcba0987654321fedcba0987654321")
|
rightHash := common.HexToHash("0xfedcba0987654321fedcba0987654321fedcba0987654321fedcba0987654321")
|
||||||
|
|
||||||
s := NewNodeStore()
|
s := newNodeStore()
|
||||||
leftRef := s.newHashedRef(leftHash)
|
leftRef := s.newHashedRef(leftHash)
|
||||||
rightRef := s.newHashedRef(rightHash)
|
rightRef := s.newHashedRef(rightHash)
|
||||||
|
|
||||||
|
|
@ -61,7 +61,7 @@ func TestSerializeDeserializeInternalNode(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deserialize into a new store
|
// Deserialize into a new store
|
||||||
ds := NewNodeStore()
|
ds := newNodeStore()
|
||||||
deserialized, err := ds.deserializeNode(serialized, 0)
|
deserialized, err := ds.deserializeNode(serialized, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to deserialize node: %v", err)
|
t.Fatalf("Failed to deserialize node: %v", err)
|
||||||
|
|
@ -94,7 +94,7 @@ func TestSerializeDeserializeInternalNode(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestSerializeDeserializeStemNode tests serialization and deserialization of StemNode through NodeStore.
|
// TestSerializeDeserializeStemNode tests serialization and deserialization of StemNode through nodeStore.
|
||||||
func TestSerializeDeserializeStemNode(t *testing.T) {
|
func TestSerializeDeserializeStemNode(t *testing.T) {
|
||||||
stem := make([]byte, StemSize)
|
stem := make([]byte, StemSize)
|
||||||
for i := range stem {
|
for i := range stem {
|
||||||
|
|
@ -106,7 +106,7 @@ func TestSerializeDeserializeStemNode(t *testing.T) {
|
||||||
values[10] = common.HexToHash("0x0202020202020202020202020202020202020202020202020202020202020202").Bytes()
|
values[10] = common.HexToHash("0x0202020202020202020202020202020202020202020202020202020202020202").Bytes()
|
||||||
values[255] = common.HexToHash("0x0303030303030303030303030303030303030303030303030303030303030303").Bytes()
|
values[255] = common.HexToHash("0x0303030303030303030303030303030303030303030303030303030303030303").Bytes()
|
||||||
|
|
||||||
s := NewNodeStore()
|
s := newNodeStore()
|
||||||
ref := s.newStemRef(stem, 10)
|
ref := s.newStemRef(stem, 10)
|
||||||
sn := s.getStem(ref.Index())
|
sn := s.getStem(ref.Index())
|
||||||
for i, v := range values {
|
for i, v := range values {
|
||||||
|
|
@ -129,7 +129,7 @@ func TestSerializeDeserializeStemNode(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deserialize into a new store
|
// Deserialize into a new store
|
||||||
ds := NewNodeStore()
|
ds := newNodeStore()
|
||||||
deserializedRef, err := ds.deserializeNode(serialized, 10)
|
deserializedRef, err := ds.deserializeNode(serialized, 10)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to deserialize node: %v", err)
|
t.Fatalf("Failed to deserialize node: %v", err)
|
||||||
|
|
@ -170,7 +170,7 @@ func TestSerializeDeserializeStemNode(t *testing.T) {
|
||||||
|
|
||||||
// TestDeserializeEmptyNode tests deserialization of empty node.
|
// TestDeserializeEmptyNode tests deserialization of empty node.
|
||||||
func TestDeserializeEmptyNode(t *testing.T) {
|
func TestDeserializeEmptyNode(t *testing.T) {
|
||||||
s := NewNodeStore()
|
s := newNodeStore()
|
||||||
deserialized, err := s.deserializeNode([]byte{}, 0)
|
deserialized, err := s.deserializeNode([]byte{}, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to deserialize empty node: %v", err)
|
t.Fatalf("Failed to deserialize empty node: %v", err)
|
||||||
|
|
@ -183,7 +183,7 @@ func TestDeserializeEmptyNode(t *testing.T) {
|
||||||
|
|
||||||
// TestDeserializeInvalidType tests deserialization with invalid type byte.
|
// TestDeserializeInvalidType tests deserialization with invalid type byte.
|
||||||
func TestDeserializeInvalidType(t *testing.T) {
|
func TestDeserializeInvalidType(t *testing.T) {
|
||||||
s := NewNodeStore()
|
s := newNodeStore()
|
||||||
invalidData := []byte{99, 0, 0, 0} // Type byte 99 is invalid
|
invalidData := []byte{99, 0, 0, 0} // Type byte 99 is invalid
|
||||||
|
|
||||||
_, err := s.deserializeNode(invalidData, 0)
|
_, err := s.deserializeNode(invalidData, 0)
|
||||||
|
|
@ -194,7 +194,7 @@ func TestDeserializeInvalidType(t *testing.T) {
|
||||||
|
|
||||||
// TestDeserializeInvalidLength tests deserialization with invalid data length.
|
// TestDeserializeInvalidLength tests deserialization with invalid data length.
|
||||||
func TestDeserializeInvalidLength(t *testing.T) {
|
func TestDeserializeInvalidLength(t *testing.T) {
|
||||||
s := NewNodeStore()
|
s := newNodeStore()
|
||||||
// InternalNode with valid type byte but wrong length (needs exactly 65 bytes)
|
// InternalNode with valid type byte but wrong length (needs exactly 65 bytes)
|
||||||
invalidData := []byte{nodeTypeInternal, 0, 0, 0}
|
invalidData := []byte{nodeTypeInternal, 0, 0, 0}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,10 +24,10 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestHashedNodeHash tests the Hash method via NodeStore.
|
// TestHashedNodeHash tests the Hash method via nodeStore.
|
||||||
func TestHashedNodeHash(t *testing.T) {
|
func TestHashedNodeHash(t *testing.T) {
|
||||||
hash := common.HexToHash("0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef")
|
hash := common.HexToHash("0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef")
|
||||||
s := NewNodeStore()
|
s := newNodeStore()
|
||||||
ref := s.newHashedRef(hash)
|
ref := s.newHashedRef(hash)
|
||||||
|
|
||||||
if s.computeHash(ref) != hash {
|
if s.computeHash(ref) != hash {
|
||||||
|
|
@ -35,10 +35,10 @@ func TestHashedNodeHash(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestHashedNodeCopy tests the Copy method via NodeStore.
|
// TestHashedNodeCopy tests the Copy method via nodeStore.
|
||||||
func TestHashedNodeCopy(t *testing.T) {
|
func TestHashedNodeCopy(t *testing.T) {
|
||||||
hash := common.HexToHash("0xabcdef")
|
hash := common.HexToHash("0xabcdef")
|
||||||
s := NewNodeStore()
|
s := newNodeStore()
|
||||||
ref := s.newHashedRef(hash)
|
ref := s.newHashedRef(hash)
|
||||||
s.root = ref
|
s.root = ref
|
||||||
|
|
||||||
|
|
@ -50,10 +50,10 @@ func TestHashedNodeCopy(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestHashedNodeInsertValuesAtStem tests InsertValuesAtStem resolution via NodeStore.
|
// TestHashedNodeInsertValuesAtStem tests InsertValuesAtStem resolution via nodeStore.
|
||||||
func TestHashedNodeInsertValuesAtStem(t *testing.T) {
|
func TestHashedNodeInsertValuesAtStem(t *testing.T) {
|
||||||
// Test 1: nil resolver should return an error
|
// Test 1: nil resolver should return an error
|
||||||
s := NewNodeStore()
|
s := newNodeStore()
|
||||||
hashedRef := s.newHashedRef(common.HexToHash("0x1234"))
|
hashedRef := s.newHashedRef(common.HexToHash("0x1234"))
|
||||||
s.root = hashedRef
|
s.root = hashedRef
|
||||||
|
|
||||||
|
|
@ -70,7 +70,7 @@ func TestHashedNodeInsertValuesAtStem(t *testing.T) {
|
||||||
return []byte{0xff, 0xff, 0xff}, nil
|
return []byte{0xff, 0xff, 0xff}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
s2 := NewNodeStore()
|
s2 := newNodeStore()
|
||||||
hashedRef2 := s2.newHashedRef(common.HexToHash("0x1234"))
|
hashedRef2 := s2.newHashedRef(common.HexToHash("0x1234"))
|
||||||
s2.root = hashedRef2
|
s2.root = hashedRef2
|
||||||
|
|
||||||
|
|
@ -87,7 +87,7 @@ func TestHashedNodeInsertValuesAtStem(t *testing.T) {
|
||||||
originalValues[1] = common.HexToHash("0x2222222222222222222222222222222222222222222222222222222222222222").Bytes()
|
originalValues[1] = common.HexToHash("0x2222222222222222222222222222222222222222222222222222222222222222").Bytes()
|
||||||
|
|
||||||
// Build the serialized node
|
// Build the serialized node
|
||||||
rs := NewNodeStore()
|
rs := newNodeStore()
|
||||||
ref := rs.newStemRef(stem, 0)
|
ref := rs.newStemRef(stem, 0)
|
||||||
sn := rs.getStem(ref.Index())
|
sn := rs.getStem(ref.Index())
|
||||||
for i, v := range originalValues {
|
for i, v := range originalValues {
|
||||||
|
|
@ -101,7 +101,7 @@ func TestHashedNodeInsertValuesAtStem(t *testing.T) {
|
||||||
return serialized, nil
|
return serialized, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
s3 := NewNodeStore()
|
s3 := newNodeStore()
|
||||||
hashedRef3 := s3.newHashedRef(common.HexToHash("0x1234"))
|
hashedRef3 := s3.newHashedRef(common.HexToHash("0x1234"))
|
||||||
s3.root = hashedRef3
|
s3.root = hashedRef3
|
||||||
|
|
||||||
|
|
@ -131,7 +131,7 @@ func TestHashedNodeInsertValuesAtStem(t *testing.T) {
|
||||||
|
|
||||||
// TestHashedNodeGetError tests that getting through an unresolved HashedNode root returns error.
|
// TestHashedNodeGetError tests that getting through an unresolved HashedNode root returns error.
|
||||||
func TestHashedNodeGetError(t *testing.T) {
|
func TestHashedNodeGetError(t *testing.T) {
|
||||||
s := NewNodeStore()
|
s := newNodeStore()
|
||||||
// Create root as hashed, then try to resolve through InternalNode parent
|
// Create root as hashed, then try to resolve through InternalNode parent
|
||||||
rootRef := s.newInternalRef(0)
|
rootRef := s.newInternalRef(0)
|
||||||
rootNode := s.getInternal(rootRef.Index())
|
rootNode := s.getInternal(rootRef.Index())
|
||||||
|
|
|
||||||
|
|
@ -24,9 +24,9 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestInternalNodeGet tests the Get method via NodeStore.
|
// TestInternalNodeGet tests the Get method via nodeStore.
|
||||||
func TestInternalNodeGet(t *testing.T) {
|
func TestInternalNodeGet(t *testing.T) {
|
||||||
s := NewNodeStore()
|
s := newNodeStore()
|
||||||
|
|
||||||
leftStem := make([]byte, 31)
|
leftStem := make([]byte, 31)
|
||||||
rightStem := make([]byte, 31)
|
rightStem := make([]byte, 31)
|
||||||
|
|
@ -71,10 +71,10 @@ func TestInternalNodeGet(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestInternalNodeGetWithResolver tests Get with HashedNode resolution via NodeStore.
|
// TestInternalNodeGetWithResolver tests Get with HashedNode resolution via nodeStore.
|
||||||
func TestInternalNodeGetWithResolver(t *testing.T) {
|
func TestInternalNodeGetWithResolver(t *testing.T) {
|
||||||
// Create a store with an internal node containing a hashed child
|
// Create a store with an internal node containing a hashed child
|
||||||
s := NewNodeStore()
|
s := newNodeStore()
|
||||||
hashedChild := s.newHashedRef(common.HexToHash("0x1234"))
|
hashedChild := s.newHashedRef(common.HexToHash("0x1234"))
|
||||||
rootRef := s.newInternalRef(0)
|
rootRef := s.newInternalRef(0)
|
||||||
rootNode := s.getInternal(rootRef.Index())
|
rootNode := s.getInternal(rootRef.Index())
|
||||||
|
|
@ -85,7 +85,7 @@ func TestInternalNodeGetWithResolver(t *testing.T) {
|
||||||
// Mock resolver that returns a stem node
|
// Mock resolver that returns a stem node
|
||||||
resolver := func(path []byte, hash common.Hash) ([]byte, error) {
|
resolver := func(path []byte, hash common.Hash) ([]byte, error) {
|
||||||
if hash == common.HexToHash("0x1234") {
|
if hash == common.HexToHash("0x1234") {
|
||||||
rs := NewNodeStore()
|
rs := newNodeStore()
|
||||||
stem := make([]byte, 31)
|
stem := make([]byte, 31)
|
||||||
ref := rs.newStemRef(stem, 1)
|
ref := rs.newStemRef(stem, 1)
|
||||||
sn := rs.getStem(ref.Index())
|
sn := rs.getStem(ref.Index())
|
||||||
|
|
@ -109,9 +109,9 @@ func TestInternalNodeGetWithResolver(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestInternalNodeInsert tests the Insert method via NodeStore.
|
// TestInternalNodeInsert tests the Insert method via nodeStore.
|
||||||
func TestInternalNodeInsert(t *testing.T) {
|
func TestInternalNodeInsert(t *testing.T) {
|
||||||
s := NewNodeStore()
|
s := newNodeStore()
|
||||||
|
|
||||||
leftKey := make([]byte, 32)
|
leftKey := make([]byte, 32)
|
||||||
leftKey[31] = 10
|
leftKey[31] = 10
|
||||||
|
|
@ -131,9 +131,9 @@ func TestInternalNodeInsert(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestInternalNodeCopy tests the Copy method via NodeStore.
|
// TestInternalNodeCopy tests the Copy method via nodeStore.
|
||||||
func TestInternalNodeCopy(t *testing.T) {
|
func TestInternalNodeCopy(t *testing.T) {
|
||||||
s := NewNodeStore()
|
s := newNodeStore()
|
||||||
|
|
||||||
leftKey := make([]byte, 32)
|
leftKey := make([]byte, 32)
|
||||||
leftKey[31] = 0
|
leftKey[31] = 0
|
||||||
|
|
@ -164,9 +164,9 @@ func TestInternalNodeCopy(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestInternalNodeHash tests the Hash method via NodeStore.
|
// TestInternalNodeHash tests the Hash method via nodeStore.
|
||||||
func TestInternalNodeHash(t *testing.T) {
|
func TestInternalNodeHash(t *testing.T) {
|
||||||
s := NewNodeStore()
|
s := newNodeStore()
|
||||||
leftRef := s.newHashedRef(common.HexToHash("0x1111"))
|
leftRef := s.newHashedRef(common.HexToHash("0x1111"))
|
||||||
rightRef := s.newHashedRef(common.HexToHash("0x2222"))
|
rightRef := s.newHashedRef(common.HexToHash("0x2222"))
|
||||||
rootRef := s.newInternalRef(0)
|
rootRef := s.newInternalRef(0)
|
||||||
|
|
@ -192,9 +192,9 @@ func TestInternalNodeHash(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestInternalNodeGetValuesAtStem tests GetValuesAtStem method via NodeStore.
|
// TestInternalNodeGetValuesAtStem tests GetValuesAtStem method via nodeStore.
|
||||||
func TestInternalNodeGetValuesAtStem(t *testing.T) {
|
func TestInternalNodeGetValuesAtStem(t *testing.T) {
|
||||||
s := NewNodeStore()
|
s := newNodeStore()
|
||||||
|
|
||||||
leftStem := make([]byte, 31)
|
leftStem := make([]byte, 31)
|
||||||
rightStem := make([]byte, 31)
|
rightStem := make([]byte, 31)
|
||||||
|
|
@ -239,9 +239,9 @@ func TestInternalNodeGetValuesAtStem(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestInternalNodeInsertValuesAtStem tests InsertValuesAtStem method via NodeStore.
|
// TestInternalNodeInsertValuesAtStem tests InsertValuesAtStem method via nodeStore.
|
||||||
func TestInternalNodeInsertValuesAtStem(t *testing.T) {
|
func TestInternalNodeInsertValuesAtStem(t *testing.T) {
|
||||||
s := NewNodeStore()
|
s := newNodeStore()
|
||||||
|
|
||||||
stem := make([]byte, 31)
|
stem := make([]byte, 31)
|
||||||
values := make([][]byte, 256)
|
values := make([][]byte, 256)
|
||||||
|
|
@ -265,9 +265,9 @@ func TestInternalNodeInsertValuesAtStem(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestInternalNodeCollectNodes tests CollectNodes method via NodeStore.
|
// TestInternalNodeCollectNodes tests CollectNodes method via nodeStore.
|
||||||
func TestInternalNodeCollectNodes(t *testing.T) {
|
func TestInternalNodeCollectNodes(t *testing.T) {
|
||||||
s := NewNodeStore()
|
s := newNodeStore()
|
||||||
|
|
||||||
leftStem := make([]byte, 31)
|
leftStem := make([]byte, 31)
|
||||||
rightStem := make([]byte, 31)
|
rightStem := make([]byte, 31)
|
||||||
|
|
@ -301,9 +301,9 @@ func TestInternalNodeCollectNodes(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestInternalNodeGetHeight tests GetHeight method via NodeStore.
|
// TestInternalNodeGetHeight tests GetHeight method via nodeStore.
|
||||||
func TestInternalNodeGetHeight(t *testing.T) {
|
func TestInternalNodeGetHeight(t *testing.T) {
|
||||||
s := NewNodeStore()
|
s := newNodeStore()
|
||||||
|
|
||||||
// Insert values that create a deeper tree
|
// Insert values that create a deeper tree
|
||||||
stem1 := make([]byte, 31) // left
|
stem1 := make([]byte, 31) // left
|
||||||
|
|
@ -328,9 +328,9 @@ func TestInternalNodeGetHeight(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestInternalNodeDepthTooLarge tests handling of excessive depth via NodeStore.
|
// TestInternalNodeDepthTooLarge tests handling of excessive depth via nodeStore.
|
||||||
func TestInternalNodeDepthTooLarge(t *testing.T) {
|
func TestInternalNodeDepthTooLarge(t *testing.T) {
|
||||||
s := NewNodeStore()
|
s := newNodeStore()
|
||||||
// Creating an internal node beyond max depth should panic
|
// Creating an internal node beyond max depth should panic
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r == nil {
|
if r := recover(); r == nil {
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ type binaryNodeIteratorState struct {
|
||||||
|
|
||||||
type binaryNodeIterator struct {
|
type binaryNodeIterator struct {
|
||||||
trie *BinaryTrie
|
trie *BinaryTrie
|
||||||
store *NodeStore
|
store *nodeStore
|
||||||
current nodeRef
|
current nodeRef
|
||||||
lastErr error
|
lastErr error
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ import (
|
||||||
// makeTrie creates a BinaryTrie populated with the given key-value pairs.
|
// makeTrie creates a BinaryTrie populated with the given key-value pairs.
|
||||||
func makeTrie(t *testing.T, entries [][2]common.Hash) *BinaryTrie {
|
func makeTrie(t *testing.T, entries [][2]common.Hash) *BinaryTrie {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
store := NewNodeStore()
|
store := newNodeStore()
|
||||||
tr := &BinaryTrie{
|
tr := &BinaryTrie{
|
||||||
store: store,
|
store: store,
|
||||||
tracer: trie.NewPrevalueTracer(),
|
tracer: trie.NewPrevalueTracer(),
|
||||||
|
|
@ -63,7 +63,7 @@ func countLeaves(t *testing.T, tr *BinaryTrie) int {
|
||||||
// no nodes and reports no error.
|
// no nodes and reports no error.
|
||||||
func TestIteratorEmptyTrie(t *testing.T) {
|
func TestIteratorEmptyTrie(t *testing.T) {
|
||||||
tr := &BinaryTrie{
|
tr := &BinaryTrie{
|
||||||
store: NewNodeStore(),
|
store: newNodeStore(),
|
||||||
tracer: trie.NewPrevalueTracer(),
|
tracer: trie.NewPrevalueTracer(),
|
||||||
}
|
}
|
||||||
it, err := newBinaryNodeIterator(tr, nil)
|
it, err := newBinaryNodeIterator(tr, nil)
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ const (
|
||||||
kindHashed
|
kindHashed
|
||||||
)
|
)
|
||||||
|
|
||||||
// nodeRef is a compact, GC-invisible reference to a node in a NodeStore.
|
// nodeRef is a compact, GC-invisible reference to a node in a nodeStore.
|
||||||
// It packs a 2-bit type tag (bits 31-30) and a 30-bit index (bits 29-0)
|
// It packs a 2-bit type tag (bits 31-30) and a 30-bit index (bits 29-0)
|
||||||
// into a single uint32. Because nodeRef contains no Go pointers, slices
|
// into a single uint32. Because nodeRef contains no Go pointers, slices
|
||||||
// of structs containing nodeRef fields are allocated in noscan spans —
|
// of structs containing nodeRef fields are allocated in noscan spans —
|
||||||
|
|
|
||||||
|
|
@ -21,10 +21,10 @@ import "github.com/ethereum/go-ethereum/common"
|
||||||
// storeChunkSize is the number of nodes per chunk in each typed pool.
|
// storeChunkSize is the number of nodes per chunk in each typed pool.
|
||||||
const storeChunkSize = 4096
|
const storeChunkSize = 4096
|
||||||
|
|
||||||
// NodeStore is a GC-friendly arena for binary trie nodes. Nodes are packed
|
// nodeStore is a GC-friendly arena for binary trie nodes. Nodes are packed
|
||||||
// into typed chunked pools so pointer-free types (InternalNode, HashedNode)
|
// into typed chunked pools so pointer-free types (InternalNode, HashedNode)
|
||||||
// land in noscan spans the GC skips entirely.
|
// land in noscan spans the GC skips entirely.
|
||||||
type NodeStore struct {
|
type nodeStore struct {
|
||||||
internalChunks []*[storeChunkSize]InternalNode
|
internalChunks []*[storeChunkSize]InternalNode
|
||||||
internalCount uint32
|
internalCount uint32
|
||||||
|
|
||||||
|
|
@ -43,11 +43,11 @@ type NodeStore struct {
|
||||||
freeHashed []uint32
|
freeHashed []uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewNodeStore() *NodeStore {
|
func newNodeStore() *nodeStore {
|
||||||
return &NodeStore{root: emptyRef}
|
return &nodeStore{root: emptyRef}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *NodeStore) allocInternal() uint32 {
|
func (s *nodeStore) allocInternal() uint32 {
|
||||||
idx := s.internalCount
|
idx := s.internalCount
|
||||||
chunkIdx := idx / storeChunkSize
|
chunkIdx := idx / storeChunkSize
|
||||||
if uint32(len(s.internalChunks)) <= chunkIdx {
|
if uint32(len(s.internalChunks)) <= chunkIdx {
|
||||||
|
|
@ -60,11 +60,11 @@ func (s *NodeStore) allocInternal() uint32 {
|
||||||
return idx
|
return idx
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *NodeStore) getInternal(idx uint32) *InternalNode {
|
func (s *nodeStore) getInternal(idx uint32) *InternalNode {
|
||||||
return &s.internalChunks[idx/storeChunkSize][idx%storeChunkSize]
|
return &s.internalChunks[idx/storeChunkSize][idx%storeChunkSize]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *NodeStore) newInternalRef(depth int) nodeRef {
|
func (s *nodeStore) newInternalRef(depth int) nodeRef {
|
||||||
if depth > 248 {
|
if depth > 248 {
|
||||||
panic("node depth exceeds maximum binary trie depth")
|
panic("node depth exceeds maximum binary trie depth")
|
||||||
}
|
}
|
||||||
|
|
@ -76,7 +76,7 @@ func (s *NodeStore) newInternalRef(depth int) nodeRef {
|
||||||
return makeRef(kindInternal, idx)
|
return makeRef(kindInternal, idx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *NodeStore) allocStem() uint32 {
|
func (s *nodeStore) allocStem() uint32 {
|
||||||
idx := s.stemCount
|
idx := s.stemCount
|
||||||
chunkIdx := idx / storeChunkSize
|
chunkIdx := idx / storeChunkSize
|
||||||
if uint32(len(s.stemChunks)) <= chunkIdx {
|
if uint32(len(s.stemChunks)) <= chunkIdx {
|
||||||
|
|
@ -89,11 +89,11 @@ func (s *NodeStore) allocStem() uint32 {
|
||||||
return idx
|
return idx
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *NodeStore) getStem(idx uint32) *StemNode {
|
func (s *nodeStore) getStem(idx uint32) *StemNode {
|
||||||
return &s.stemChunks[idx/storeChunkSize][idx%storeChunkSize]
|
return &s.stemChunks[idx/storeChunkSize][idx%storeChunkSize]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *NodeStore) newStemRef(stem []byte, depth int) nodeRef {
|
func (s *nodeStore) newStemRef(stem []byte, depth int) nodeRef {
|
||||||
if depth > 248 {
|
if depth > 248 {
|
||||||
panic("node depth exceeds maximum binary trie depth")
|
panic("node depth exceeds maximum binary trie depth")
|
||||||
}
|
}
|
||||||
|
|
@ -106,7 +106,7 @@ func (s *NodeStore) newStemRef(stem []byte, depth int) nodeRef {
|
||||||
return makeRef(kindStem, idx)
|
return makeRef(kindStem, idx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *NodeStore) allocHashed() uint32 {
|
func (s *nodeStore) allocHashed() uint32 {
|
||||||
if n := len(s.freeHashed); n > 0 {
|
if n := len(s.freeHashed); n > 0 {
|
||||||
idx := s.freeHashed[n-1]
|
idx := s.freeHashed[n-1]
|
||||||
s.freeHashed = s.freeHashed[:n-1]
|
s.freeHashed = s.freeHashed[:n-1]
|
||||||
|
|
@ -125,22 +125,22 @@ func (s *NodeStore) allocHashed() uint32 {
|
||||||
return idx
|
return idx
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *NodeStore) getHashed(idx uint32) *HashedNode {
|
func (s *nodeStore) getHashed(idx uint32) *HashedNode {
|
||||||
return &s.hashedChunks[idx/storeChunkSize][idx%storeChunkSize]
|
return &s.hashedChunks[idx/storeChunkSize][idx%storeChunkSize]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *NodeStore) freeHashedNode(idx uint32) {
|
func (s *nodeStore) freeHashedNode(idx uint32) {
|
||||||
s.freeHashed = append(s.freeHashed, idx)
|
s.freeHashed = append(s.freeHashed, idx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *NodeStore) newHashedRef(hash common.Hash) nodeRef {
|
func (s *nodeStore) newHashedRef(hash common.Hash) nodeRef {
|
||||||
idx := s.allocHashed()
|
idx := s.allocHashed()
|
||||||
*s.getHashed(idx) = HashedNode(hash)
|
*s.getHashed(idx) = HashedNode(hash)
|
||||||
return makeRef(kindHashed, idx)
|
return makeRef(kindHashed, idx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *NodeStore) Copy() *NodeStore {
|
func (s *nodeStore) Copy() *nodeStore {
|
||||||
ns := &NodeStore{
|
ns := &nodeStore{
|
||||||
root: s.root,
|
root: s.root,
|
||||||
internalCount: s.internalCount,
|
internalCount: s.internalCount,
|
||||||
stemCount: s.stemCount,
|
stemCount: s.stemCount,
|
||||||
|
|
|
||||||
|
|
@ -23,9 +23,9 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestStemNodeInsertSameStem tests inserting values with the same stem via NodeStore.
|
// TestStemNodeInsertSameStem tests inserting values with the same stem via nodeStore.
|
||||||
func TestStemNodeInsertSameStem(t *testing.T) {
|
func TestStemNodeInsertSameStem(t *testing.T) {
|
||||||
s := NewNodeStore()
|
s := newNodeStore()
|
||||||
|
|
||||||
stem := make([]byte, 31)
|
stem := make([]byte, 31)
|
||||||
for i := range stem {
|
for i := range stem {
|
||||||
|
|
@ -66,9 +66,9 @@ func TestStemNodeInsertSameStem(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestStemNodeInsertDifferentStem tests inserting values with different stems via NodeStore.
|
// TestStemNodeInsertDifferentStem tests inserting values with different stems via nodeStore.
|
||||||
func TestStemNodeInsertDifferentStem(t *testing.T) {
|
func TestStemNodeInsertDifferentStem(t *testing.T) {
|
||||||
s := NewNodeStore()
|
s := newNodeStore()
|
||||||
|
|
||||||
// Insert first value with stem of all zeros
|
// Insert first value with stem of all zeros
|
||||||
key1 := make([]byte, 32)
|
key1 := make([]byte, 32)
|
||||||
|
|
@ -108,9 +108,9 @@ func TestStemNodeInsertDifferentStem(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestStemNodeInsertInvalidValueLength tests inserting value with invalid length via NodeStore.
|
// TestStemNodeInsertInvalidValueLength tests inserting value with invalid length via nodeStore.
|
||||||
func TestStemNodeInsertInvalidValueLength(t *testing.T) {
|
func TestStemNodeInsertInvalidValueLength(t *testing.T) {
|
||||||
s := NewNodeStore()
|
s := newNodeStore()
|
||||||
|
|
||||||
key := make([]byte, 32)
|
key := make([]byte, 32)
|
||||||
invalidValue := []byte{1, 2, 3} // Not 32 bytes
|
invalidValue := []byte{1, 2, 3} // Not 32 bytes
|
||||||
|
|
@ -125,9 +125,9 @@ func TestStemNodeInsertInvalidValueLength(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestStemNodeCopy tests the Copy method via NodeStore.
|
// TestStemNodeCopy tests the Copy method via nodeStore.
|
||||||
func TestStemNodeCopy(t *testing.T) {
|
func TestStemNodeCopy(t *testing.T) {
|
||||||
s := NewNodeStore()
|
s := newNodeStore()
|
||||||
|
|
||||||
key1 := make([]byte, 32)
|
key1 := make([]byte, 32)
|
||||||
for i := range 31 {
|
for i := range 31 {
|
||||||
|
|
@ -163,7 +163,7 @@ func TestStemNodeCopy(t *testing.T) {
|
||||||
|
|
||||||
// TestStemNodeHash tests the Hash method.
|
// TestStemNodeHash tests the Hash method.
|
||||||
func TestStemNodeHash(t *testing.T) {
|
func TestStemNodeHash(t *testing.T) {
|
||||||
s := NewNodeStore()
|
s := newNodeStore()
|
||||||
|
|
||||||
key := make([]byte, 32)
|
key := make([]byte, 32)
|
||||||
key[31] = 0
|
key[31] = 0
|
||||||
|
|
@ -193,9 +193,9 @@ func TestStemNodeHash(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestStemNodeGetValuesAtStem tests GetValuesAtStem method via NodeStore.
|
// TestStemNodeGetValuesAtStem tests GetValuesAtStem method via nodeStore.
|
||||||
func TestStemNodeGetValuesAtStem(t *testing.T) {
|
func TestStemNodeGetValuesAtStem(t *testing.T) {
|
||||||
s := NewNodeStore()
|
s := newNodeStore()
|
||||||
|
|
||||||
stem := make([]byte, 31)
|
stem := make([]byte, 31)
|
||||||
for i := range stem {
|
for i := range stem {
|
||||||
|
|
@ -248,9 +248,9 @@ func TestStemNodeGetValuesAtStem(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestStemNodeInsertValuesAtStem tests InsertValuesAtStem method via NodeStore.
|
// TestStemNodeInsertValuesAtStem tests InsertValuesAtStem method via nodeStore.
|
||||||
func TestStemNodeInsertValuesAtStem(t *testing.T) {
|
func TestStemNodeInsertValuesAtStem(t *testing.T) {
|
||||||
s := NewNodeStore()
|
s := newNodeStore()
|
||||||
|
|
||||||
stem := make([]byte, 31)
|
stem := make([]byte, 31)
|
||||||
values := make([][]byte, 256)
|
values := make([][]byte, 256)
|
||||||
|
|
@ -285,9 +285,9 @@ func TestStemNodeInsertValuesAtStem(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestStemNodeGetHeight tests GetHeight method via NodeStore.
|
// TestStemNodeGetHeight tests GetHeight method via nodeStore.
|
||||||
func TestStemNodeGetHeight(t *testing.T) {
|
func TestStemNodeGetHeight(t *testing.T) {
|
||||||
s := NewNodeStore()
|
s := newNodeStore()
|
||||||
|
|
||||||
key := make([]byte, 32)
|
key := make([]byte, 32)
|
||||||
value := common.HexToHash("0x01").Bytes()
|
value := common.HexToHash("0x01").Bytes()
|
||||||
|
|
@ -301,9 +301,9 @@ func TestStemNodeGetHeight(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestStemNodeCollectNodes tests CollectNodes method via NodeStore.
|
// TestStemNodeCollectNodes tests CollectNodes method via nodeStore.
|
||||||
func TestStemNodeCollectNodes(t *testing.T) {
|
func TestStemNodeCollectNodes(t *testing.T) {
|
||||||
s := NewNodeStore()
|
s := newNodeStore()
|
||||||
|
|
||||||
stem := make([]byte, 31)
|
stem := make([]byte, 31)
|
||||||
values := make([][]byte, 256)
|
values := make([][]byte, 256)
|
||||||
|
|
|
||||||
|
|
@ -27,13 +27,13 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
type NodeFlushFn func(path []byte, hash common.Hash, serialized []byte)
|
type nodeFlushFn func(path []byte, hash common.Hash, serialized []byte)
|
||||||
|
|
||||||
func (s *NodeStore) Hash() common.Hash {
|
func (s *nodeStore) Hash() common.Hash {
|
||||||
return s.computeHash(s.root)
|
return s.computeHash(s.root)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *NodeStore) computeHash(ref nodeRef) common.Hash {
|
func (s *nodeStore) computeHash(ref nodeRef) common.Hash {
|
||||||
switch ref.Kind() {
|
switch ref.Kind() {
|
||||||
case kindInternal:
|
case kindInternal:
|
||||||
return s.hashInternal(ref.Index())
|
return s.hashInternal(ref.Index())
|
||||||
|
|
@ -59,7 +59,7 @@ var parallelHashDepth = min(bits.Len(uint(runtime.NumCPU())), 8)
|
||||||
// goroutine while the right subtree is hashed inline, then the two digests
|
// goroutine while the right subtree is hashed inline, then the two digests
|
||||||
// are combined. Below that threshold the goroutine spawn cost outweighs the
|
// are combined. Below that threshold the goroutine spawn cost outweighs the
|
||||||
// hashing work, so deeper nodes hash both children sequentially.
|
// hashing work, so deeper nodes hash both children sequentially.
|
||||||
func (s *NodeStore) hashInternal(idx uint32) common.Hash {
|
func (s *nodeStore) hashInternal(idx uint32) common.Hash {
|
||||||
node := s.getInternal(idx)
|
node := s.getInternal(idx)
|
||||||
if !node.mustRecompute {
|
if !node.mustRecompute {
|
||||||
return node.hash
|
return node.hash
|
||||||
|
|
@ -108,7 +108,7 @@ func (s *NodeStore) hashInternal(idx uint32) common.Hash {
|
||||||
}
|
}
|
||||||
|
|
||||||
// SerializeNode serializes a node into the flat on-disk format.
|
// SerializeNode serializes a node into the flat on-disk format.
|
||||||
func (s *NodeStore) serializeNode(ref nodeRef) []byte {
|
func (s *nodeStore) serializeNode(ref nodeRef) []byte {
|
||||||
switch ref.Kind() {
|
switch ref.Kind() {
|
||||||
case kindInternal:
|
case kindInternal:
|
||||||
node := s.getInternal(ref.Index())
|
node := s.getInternal(ref.Index())
|
||||||
|
|
@ -153,17 +153,17 @@ var errInvalidSerializedLength = errors.New("invalid serialized node length")
|
||||||
|
|
||||||
// DeserializeNode deserializes a node from bytes, recomputing its hash. The
|
// DeserializeNode deserializes a node from bytes, recomputing its hash. The
|
||||||
// returned node is marked dirty (provenance unknown, safe re-flush default).
|
// returned node is marked dirty (provenance unknown, safe re-flush default).
|
||||||
func (s *NodeStore) deserializeNode(serialized []byte, depth int) (nodeRef, error) {
|
func (s *nodeStore) deserializeNode(serialized []byte, depth int) (nodeRef, error) {
|
||||||
return s.decodeNode(serialized, depth, common.Hash{}, true, true)
|
return s.decodeNode(serialized, depth, common.Hash{}, true, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeserializeNodeWithHash deserializes a node whose hash is already known and
|
// DeserializeNodeWithHash deserializes a node whose hash is already known and
|
||||||
// whose blob is already on disk (mustRecompute=false, dirty=false).
|
// whose blob is already on disk (mustRecompute=false, dirty=false).
|
||||||
func (s *NodeStore) deserializeNodeWithHash(serialized []byte, depth int, hn common.Hash) (nodeRef, error) {
|
func (s *nodeStore) deserializeNodeWithHash(serialized []byte, depth int, hn common.Hash) (nodeRef, error) {
|
||||||
return s.decodeNode(serialized, depth, hn, false, false)
|
return s.decodeNode(serialized, depth, hn, false, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *NodeStore) decodeNode(serialized []byte, depth int, hn common.Hash, mustRecompute, dirty bool) (nodeRef, error) {
|
func (s *nodeStore) decodeNode(serialized []byte, depth int, hn common.Hash, mustRecompute, dirty bool) (nodeRef, error) {
|
||||||
if len(serialized) == 0 {
|
if len(serialized) == 0 {
|
||||||
return emptyRef, nil
|
return emptyRef, nil
|
||||||
}
|
}
|
||||||
|
|
@ -230,7 +230,7 @@ func (s *NodeStore) decodeNode(serialized []byte, depth int, hn common.Hash, mus
|
||||||
// CollectNodes flushes every node that needs flushing via flushfn in post-order.
|
// CollectNodes flushes every node that needs flushing via flushfn in post-order.
|
||||||
// Invariant: any ancestor of a node that needs flushing is itself marked, so a
|
// Invariant: any ancestor of a node that needs flushing is itself marked, so a
|
||||||
// clean root means the whole subtree is clean.
|
// clean root means the whole subtree is clean.
|
||||||
func (s *NodeStore) collectNodes(ref nodeRef, path []byte, flushfn NodeFlushFn) error {
|
func (s *nodeStore) collectNodes(ref nodeRef, path []byte, flushfn nodeFlushFn) error {
|
||||||
switch ref.Kind() {
|
switch ref.Kind() {
|
||||||
case kindEmpty:
|
case kindEmpty:
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -269,7 +269,7 @@ func (s *NodeStore) collectNodes(ref nodeRef, path []byte, flushfn NodeFlushFn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *NodeStore) toDot(ref nodeRef, parent, path string) string {
|
func (s *nodeStore) toDot(ref nodeRef, parent, path string) string {
|
||||||
switch ref.Kind() {
|
switch ref.Kind() {
|
||||||
case kindInternal:
|
case kindInternal:
|
||||||
node := s.getInternal(ref.Index())
|
node := s.getInternal(ref.Index())
|
||||||
|
|
|
||||||
|
|
@ -23,14 +23,14 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NodeResolverFn resolves a hashed node from the database.
|
// nodeResolverFn resolves a hashed node from the database.
|
||||||
type NodeResolverFn func([]byte, common.Hash) ([]byte, error)
|
type nodeResolverFn func([]byte, common.Hash) ([]byte, error)
|
||||||
|
|
||||||
// GetValue returns the value at (stem, suffix) or nil if absent. Thin
|
// GetValue returns the value at (stem, suffix) or nil if absent. Thin
|
||||||
// wrapper over GetValuesAtStem — the underlying StemNode returns its
|
// wrapper over GetValuesAtStem — the underlying StemNode returns its
|
||||||
// 256-slot array as a slice header (no allocation), so the per-call cost
|
// 256-slot array as a slice header (no allocation), so the per-call cost
|
||||||
// is the tree walk plus one index.
|
// is the tree walk plus one index.
|
||||||
func (s *NodeStore) GetValue(stem []byte, suffix byte, resolver NodeResolverFn) ([]byte, error) {
|
func (s *nodeStore) GetValue(stem []byte, suffix byte, resolver nodeResolverFn) ([]byte, error) {
|
||||||
values, err := s.GetValuesAtStem(stem, resolver)
|
values, err := s.GetValuesAtStem(stem, resolver)
|
||||||
if err != nil || values == nil {
|
if err != nil || values == nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -41,7 +41,7 @@ func (s *NodeStore) GetValue(stem []byte, suffix byte, resolver NodeResolverFn)
|
||||||
// GetValuesAtStem returns the 256 value slots at stem, or nil if the stem
|
// GetValuesAtStem returns the 256 value slots at stem, or nil if the stem
|
||||||
// is not in the trie. The returned slice is a view over the in-place
|
// is not in the trie. The returned slice is a view over the in-place
|
||||||
// StemNode values array (no allocation) and must be treated read-only.
|
// StemNode values array (no allocation) and must be treated read-only.
|
||||||
func (s *NodeStore) GetValuesAtStem(stem []byte, resolver NodeResolverFn) ([][]byte, error) {
|
func (s *nodeStore) GetValuesAtStem(stem []byte, resolver nodeResolverFn) ([][]byte, error) {
|
||||||
cur := s.root
|
cur := s.root
|
||||||
var parentIdx uint32
|
var parentIdx uint32
|
||||||
var parentIsLeft bool
|
var parentIsLeft bool
|
||||||
|
|
@ -115,7 +115,7 @@ func (s *NodeStore) GetValuesAtStem(stem []byte, resolver NodeResolverFn) ([][]b
|
||||||
// gballet referenced (comment 3101751325): one primary insert path; the
|
// gballet referenced (comment 3101751325): one primary insert path; the
|
||||||
// single-slot variant dispatches through it so the split / resolve logic
|
// single-slot variant dispatches through it so the split / resolve logic
|
||||||
// lives in one place.
|
// lives in one place.
|
||||||
func (s *NodeStore) InsertSingle(stem []byte, suffix byte, value []byte, resolver NodeResolverFn) error {
|
func (s *nodeStore) InsertSingle(stem []byte, suffix byte, value []byte, resolver nodeResolverFn) error {
|
||||||
if len(value) != HashSize {
|
if len(value) != HashSize {
|
||||||
return errors.New("invalid insertion: value length")
|
return errors.New("invalid insertion: value length")
|
||||||
}
|
}
|
||||||
|
|
@ -128,13 +128,13 @@ func (s *NodeStore) InsertSingle(stem []byte, suffix byte, value []byte, resolve
|
||||||
// sparse (nil entries are ignored). The recursive implementation dispatches
|
// sparse (nil entries are ignored). The recursive implementation dispatches
|
||||||
// through the same body, so a single code path handles internal descent,
|
// through the same body, so a single code path handles internal descent,
|
||||||
// HashedNode resolution, stem merge, and stem split.
|
// HashedNode resolution, stem merge, and stem split.
|
||||||
func (s *NodeStore) InsertValuesAtStem(stem []byte, values [][]byte, resolver NodeResolverFn) error {
|
func (s *nodeStore) InsertValuesAtStem(stem []byte, values [][]byte, resolver nodeResolverFn) error {
|
||||||
var err error
|
var err error
|
||||||
s.root, err = s.insertValuesAtStem(s.root, stem, values, resolver, 0)
|
s.root, err = s.insertValuesAtStem(s.root, stem, values, resolver, 0)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *NodeStore) insertValuesAtStem(ref nodeRef, stem []byte, values [][]byte, resolver NodeResolverFn, depth int) (nodeRef, error) {
|
func (s *nodeStore) insertValuesAtStem(ref nodeRef, stem []byte, values [][]byte, resolver nodeResolverFn, depth int) (nodeRef, error) {
|
||||||
switch ref.Kind() {
|
switch ref.Kind() {
|
||||||
case kindInternal:
|
case kindInternal:
|
||||||
node := s.getInternal(ref.Index())
|
node := s.getInternal(ref.Index())
|
||||||
|
|
@ -252,7 +252,7 @@ func (s *NodeStore) insertValuesAtStem(ref nodeRef, stem []byte, values [][]byte
|
||||||
}
|
}
|
||||||
|
|
||||||
// splitStemValuesInsert splits a StemNode when the new stem diverges.
|
// splitStemValuesInsert splits a StemNode when the new stem diverges.
|
||||||
func (s *NodeStore) splitStemValuesInsert(existingRef nodeRef, newStem []byte, values [][]byte, resolver NodeResolverFn, depth int) (nodeRef, error) {
|
func (s *nodeStore) splitStemValuesInsert(existingRef nodeRef, newStem []byte, values [][]byte, resolver nodeResolverFn, depth int) (nodeRef, error) {
|
||||||
existing := s.getStem(existingRef.Index())
|
existing := s.getStem(existingRef.Index())
|
||||||
|
|
||||||
if int(existing.depth) >= StemSize*8 {
|
if int(existing.depth) >= StemSize*8 {
|
||||||
|
|
@ -317,15 +317,15 @@ func (s *NodeStore) splitStemValuesInsert(existingRef nodeRef, newStem []byte, v
|
||||||
return nRef, nil
|
return nRef, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *NodeStore) Insert(key []byte, value []byte, resolver NodeResolverFn) error {
|
func (s *nodeStore) Insert(key []byte, value []byte, resolver nodeResolverFn) error {
|
||||||
return s.InsertSingle(key[:StemSize], key[StemSize], value, resolver)
|
return s.InsertSingle(key[:StemSize], key[StemSize], value, resolver)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *NodeStore) Get(key []byte, resolver NodeResolverFn) ([]byte, error) {
|
func (s *nodeStore) Get(key []byte, resolver nodeResolverFn) ([]byte, error) {
|
||||||
return s.GetValue(key[:StemSize], key[StemSize], resolver)
|
return s.GetValue(key[:StemSize], key[StemSize], resolver)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *NodeStore) getHeight(ref nodeRef) int {
|
func (s *nodeStore) getHeight(ref nodeRef) int {
|
||||||
switch ref.Kind() {
|
switch ref.Kind() {
|
||||||
case kindInternal:
|
case kindInternal:
|
||||||
node := s.getInternal(ref.Index())
|
node := s.getInternal(ref.Index())
|
||||||
|
|
|
||||||
|
|
@ -107,7 +107,7 @@ func ChunkifyCode(code []byte) ChunkedCode {
|
||||||
|
|
||||||
// BinaryTrie is the implementation of https://eips.ethereum.org/EIPS/eip-7864.
|
// BinaryTrie is the implementation of https://eips.ethereum.org/EIPS/eip-7864.
|
||||||
type BinaryTrie struct {
|
type BinaryTrie struct {
|
||||||
store *NodeStore
|
store *nodeStore
|
||||||
reader *trie.Reader
|
reader *trie.Reader
|
||||||
tracer *trie.PrevalueTracer
|
tracer *trie.PrevalueTracer
|
||||||
}
|
}
|
||||||
|
|
@ -125,7 +125,7 @@ func NewBinaryTrie(root common.Hash, db database.NodeDatabase) (*BinaryTrie, err
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
t := &BinaryTrie{
|
t := &BinaryTrie{
|
||||||
store: NewNodeStore(),
|
store: newNodeStore(),
|
||||||
reader: reader,
|
reader: reader,
|
||||||
tracer: trie.NewPrevalueTracer(),
|
tracer: trie.NewPrevalueTracer(),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSingleEntry(t *testing.T) {
|
func TestSingleEntry(t *testing.T) {
|
||||||
s := NewNodeStore()
|
s := newNodeStore()
|
||||||
if err := s.Insert(zeroKey[:], oneKey[:], nil); err != nil {
|
if err := s.Insert(zeroKey[:], oneKey[:], nil); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
@ -52,7 +52,7 @@ func TestSingleEntry(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTwoEntriesDiffFirstBit(t *testing.T) {
|
func TestTwoEntriesDiffFirstBit(t *testing.T) {
|
||||||
s := NewNodeStore()
|
s := newNodeStore()
|
||||||
if err := s.Insert(zeroKey[:], oneKey[:], nil); err != nil {
|
if err := s.Insert(zeroKey[:], oneKey[:], nil); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
@ -68,7 +68,7 @@ func TestTwoEntriesDiffFirstBit(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestOneStemColocatedValues(t *testing.T) {
|
func TestOneStemColocatedValues(t *testing.T) {
|
||||||
s := NewNodeStore()
|
s := newNodeStore()
|
||||||
if err := s.Insert(common.HexToHash("0000000000000000000000000000000000000000000000000000000000000003").Bytes(), oneKey[:], nil); err != nil {
|
if err := s.Insert(common.HexToHash("0000000000000000000000000000000000000000000000000000000000000003").Bytes(), oneKey[:], nil); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
@ -87,7 +87,7 @@ func TestOneStemColocatedValues(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTwoStemColocatedValues(t *testing.T) {
|
func TestTwoStemColocatedValues(t *testing.T) {
|
||||||
s := NewNodeStore()
|
s := newNodeStore()
|
||||||
// stem: 0...0
|
// stem: 0...0
|
||||||
if err := s.Insert(common.HexToHash("0000000000000000000000000000000000000000000000000000000000000003").Bytes(), oneKey[:], nil); err != nil {
|
if err := s.Insert(common.HexToHash("0000000000000000000000000000000000000000000000000000000000000003").Bytes(), oneKey[:], nil); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
|
@ -108,7 +108,7 @@ func TestTwoStemColocatedValues(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTwoKeysMatchFirst42Bits(t *testing.T) {
|
func TestTwoKeysMatchFirst42Bits(t *testing.T) {
|
||||||
s := NewNodeStore()
|
s := newNodeStore()
|
||||||
// key1 and key 2 have the same prefix of 42 bits (b0*42+b1+b1) and differ after.
|
// key1 and key 2 have the same prefix of 42 bits (b0*42+b1+b1) and differ after.
|
||||||
key1 := common.HexToHash("0000000000C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0").Bytes()
|
key1 := common.HexToHash("0000000000C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0").Bytes()
|
||||||
key2 := common.HexToHash("0000000000E00000000000000000000000000000000000000000000000000000").Bytes()
|
key2 := common.HexToHash("0000000000E00000000000000000000000000000000000000000000000000000").Bytes()
|
||||||
|
|
@ -124,7 +124,7 @@ func TestTwoKeysMatchFirst42Bits(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInsertDuplicateKey(t *testing.T) {
|
func TestInsertDuplicateKey(t *testing.T) {
|
||||||
s := NewNodeStore()
|
s := newNodeStore()
|
||||||
if err := s.Insert(oneKey[:], oneKey[:], nil); err != nil {
|
if err := s.Insert(oneKey[:], oneKey[:], nil); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
@ -145,7 +145,7 @@ func TestInsertDuplicateKey(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLargeNumberOfEntries(t *testing.T) {
|
func TestLargeNumberOfEntries(t *testing.T) {
|
||||||
s := NewNodeStore()
|
s := newNodeStore()
|
||||||
for i := range StemNodeWidth {
|
for i := range StemNodeWidth {
|
||||||
var key [HashSize]byte
|
var key [HashSize]byte
|
||||||
key[0] = byte(i)
|
key[0] = byte(i)
|
||||||
|
|
@ -160,7 +160,7 @@ func TestLargeNumberOfEntries(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMerkleizeMultipleEntries(t *testing.T) {
|
func TestMerkleizeMultipleEntries(t *testing.T) {
|
||||||
s := NewNodeStore()
|
s := newNodeStore()
|
||||||
keys := [][]byte{
|
keys := [][]byte{
|
||||||
zeroKey[:],
|
zeroKey[:],
|
||||||
common.HexToHash("8000000000000000000000000000000000000000000000000000000000000000").Bytes(),
|
common.HexToHash("8000000000000000000000000000000000000000000000000000000000000000").Bytes(),
|
||||||
|
|
@ -188,7 +188,7 @@ func TestMerkleizeMultipleEntries(t *testing.T) {
|
||||||
func TestStorageRoundTrip(t *testing.T) {
|
func TestStorageRoundTrip(t *testing.T) {
|
||||||
tracer := trie.NewPrevalueTracer()
|
tracer := trie.NewPrevalueTracer()
|
||||||
tr := &BinaryTrie{
|
tr := &BinaryTrie{
|
||||||
store: NewNodeStore(),
|
store: newNodeStore(),
|
||||||
tracer: tracer,
|
tracer: tracer,
|
||||||
}
|
}
|
||||||
addr := common.HexToAddress("0x1234567890abcdef1234567890abcdef12345678")
|
addr := common.HexToAddress("0x1234567890abcdef1234567890abcdef12345678")
|
||||||
|
|
@ -256,7 +256,7 @@ func TestStorageRoundTrip(t *testing.T) {
|
||||||
func newEmptyTestTrie(t *testing.T) *BinaryTrie {
|
func newEmptyTestTrie(t *testing.T) *BinaryTrie {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
return &BinaryTrie{
|
return &BinaryTrie{
|
||||||
store: NewNodeStore(),
|
store: newNodeStore(),
|
||||||
tracer: trie.NewPrevalueTracer(),
|
tracer: trie.NewPrevalueTracer(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -581,7 +581,7 @@ func TestBinaryTrieWitness(t *testing.T) {
|
||||||
tracer := trie.NewPrevalueTracer()
|
tracer := trie.NewPrevalueTracer()
|
||||||
|
|
||||||
tr := &BinaryTrie{
|
tr := &BinaryTrie{
|
||||||
store: NewNodeStore(),
|
store: newNodeStore(),
|
||||||
tracer: tracer,
|
tracer: tracer,
|
||||||
}
|
}
|
||||||
if w := tr.Witness(); len(w) != 0 {
|
if w := tr.Witness(); len(w) != 0 {
|
||||||
|
|
@ -608,7 +608,7 @@ func TestBinaryTrieWitness(t *testing.T) {
|
||||||
func testAccount(t *testing.T, addr common.Address, nonce uint64, balance uint64) *BinaryTrie {
|
func testAccount(t *testing.T, addr common.Address, nonce uint64, balance uint64) *BinaryTrie {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
tr := &BinaryTrie{
|
tr := &BinaryTrie{
|
||||||
store: NewNodeStore(),
|
store: newNodeStore(),
|
||||||
tracer: trie.NewPrevalueTracer(),
|
tracer: trie.NewPrevalueTracer(),
|
||||||
}
|
}
|
||||||
acc := &types.StateAccount{
|
acc := &types.StateAccount{
|
||||||
|
|
@ -662,7 +662,7 @@ func TestGetAccountNonMembershipStemRoot(t *testing.T) {
|
||||||
// address returns nil when the trie root is an InternalNode (multi-account trie).
|
// address returns nil when the trie root is an InternalNode (multi-account trie).
|
||||||
func TestGetAccountNonMembershipInternalRoot(t *testing.T) {
|
func TestGetAccountNonMembershipInternalRoot(t *testing.T) {
|
||||||
tr := &BinaryTrie{
|
tr := &BinaryTrie{
|
||||||
store: NewNodeStore(),
|
store: newNodeStore(),
|
||||||
tracer: trie.NewPrevalueTracer(),
|
tracer: trie.NewPrevalueTracer(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -725,7 +725,7 @@ func TestGetStorageNonMembershipStemRoot(t *testing.T) {
|
||||||
// non-existent address returns nil when the root is an InternalNode.
|
// non-existent address returns nil when the root is an InternalNode.
|
||||||
func TestGetStorageNonMembershipInternalRoot(t *testing.T) {
|
func TestGetStorageNonMembershipInternalRoot(t *testing.T) {
|
||||||
tr := &BinaryTrie{
|
tr := &BinaryTrie{
|
||||||
store: NewNodeStore(),
|
store: newNodeStore(),
|
||||||
tracer: trie.NewPrevalueTracer(),
|
tracer: trie.NewPrevalueTracer(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -768,7 +768,7 @@ func TestGetStorageNonMembershipInternalRoot(t *testing.T) {
|
||||||
// flushes only the root-to-leaf path.
|
// flushes only the root-to-leaf path.
|
||||||
func TestCommitSkipCleanSubtrees(t *testing.T) {
|
func TestCommitSkipCleanSubtrees(t *testing.T) {
|
||||||
tr := &BinaryTrie{
|
tr := &BinaryTrie{
|
||||||
store: NewNodeStore(),
|
store: newNodeStore(),
|
||||||
tracer: trie.NewPrevalueTracer(),
|
tracer: trie.NewPrevalueTracer(),
|
||||||
}
|
}
|
||||||
const n = 200
|
const n = 200
|
||||||
|
|
@ -826,7 +826,7 @@ func TestCommitSkipCleanSubtrees(t *testing.T) {
|
||||||
func BenchmarkCollectNodesSparseWrite(b *testing.B) {
|
func BenchmarkCollectNodesSparseWrite(b *testing.B) {
|
||||||
const n = 10_000
|
const n = 10_000
|
||||||
tr := &BinaryTrie{
|
tr := &BinaryTrie{
|
||||||
store: NewNodeStore(),
|
store: newNodeStore(),
|
||||||
tracer: trie.NewPrevalueTracer(),
|
tracer: trie.NewPrevalueTracer(),
|
||||||
}
|
}
|
||||||
keys := make([][HashSize]byte, n)
|
keys := make([][HashSize]byte, n)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue