trie/bintrie: unexport package-internal arena identifiers

Gballet asked on PR #34055 to unexport nodeRef, nodeKind, and makeRef
(comments 3099846639, 3099847640, 3100717855) — none are used outside
trie/bintrie. Cascade to the internal-only support symbols and methods:

  NodeKind          → nodeKind
  KindEmpty/...     → kindEmpty/...
  NodeRef           → nodeRef
  EmptyRef          → emptyRef
  MakeRef           → makeRef
  NodeStore.Root    → deleted; inlined to s.root field access (same pkg)
  NodeStore.SetRoot → deleted; inlined to s.root = ref
  NodeStore.ComputeHash/SerializeNode/DeserializeNode(WithHash)/
  CollectNodes/ToDot/GetHeight → lowercased

All 9 method signatures took or returned nodeRef so their export would
have tripped revive:unexported-return after the type rename. Zero
external callers means no API break. The private deserializeNode helper
was renamed to decodeNode to free the name for the newly-private
deserializeNode public function.

Pure rename; no behaviour change.
This commit is contained in:
CPerezz 2026-04-18 18:49:04 +02:00
parent 939b36345f
commit 2d44d8a4b6
No known key found for this signature in database
GPG key ID: 62045F34B97177DD
14 changed files with 209 additions and 213 deletions

View file

@ -39,9 +39,9 @@ const (
// the hash of a serialized node without maintaining a NodeStore.
func DeserializeAndHash(blob []byte, depth int) (common.Hash, error) {
s := NewNodeStore()
ref, err := s.DeserializeNode(blob, depth)
ref, err := s.deserializeNode(blob, depth)
if err != nil {
return common.Hash{}, err
}
return s.ComputeHash(ref), nil
return s.computeHash(ref), nil
}

View file

@ -37,10 +37,10 @@ func TestSerializeDeserializeInternalNode(t *testing.T) {
rootNode := s.getInternal(rootRef.Index())
rootNode.left = leftRef
rootNode.right = rightRef
s.SetRoot(rootRef)
s.root = rootRef
// Serialize the node — flat 65-byte format
serialized := s.SerializeNode(rootRef)
serialized := s.serializeNode(rootRef)
// Check the serialized format: [type(1)][leftHash(32)][rightHash(32)]
if serialized[0] != nodeTypeInternal {
@ -62,14 +62,14 @@ func TestSerializeDeserializeInternalNode(t *testing.T) {
// Deserialize into a new store
ds := NewNodeStore()
deserialized, err := ds.DeserializeNode(serialized, 0)
deserialized, err := ds.deserializeNode(serialized, 0)
if err != nil {
t.Fatalf("Failed to deserialize node: %v", err)
}
// Root should be an InternalNode
if deserialized.Kind() != KindInternal {
t.Fatalf("Expected KindInternal, got kind %d", deserialized.Kind())
if deserialized.Kind() != kindInternal {
t.Fatalf("Expected kindInternal, got kind %d", deserialized.Kind())
}
internalNode := ds.getInternal(deserialized.Index())
@ -78,19 +78,19 @@ func TestSerializeDeserializeInternalNode(t *testing.T) {
}
// Left child should be a HashedNode with the correct hash
if internalNode.left.Kind() != KindHashed {
t.Fatalf("Expected left child to be KindHashed, got %d", internalNode.left.Kind())
if internalNode.left.Kind() != kindHashed {
t.Fatalf("Expected left child to be kindHashed, got %d", internalNode.left.Kind())
}
if ds.ComputeHash(internalNode.left) != leftHash {
t.Errorf("Left hash mismatch: expected %x, got %x", leftHash, ds.ComputeHash(internalNode.left))
if ds.computeHash(internalNode.left) != leftHash {
t.Errorf("Left hash mismatch: expected %x, got %x", leftHash, ds.computeHash(internalNode.left))
}
// Right child should be a HashedNode with the correct hash
if internalNode.right.Kind() != KindHashed {
t.Fatalf("Expected right child to be KindHashed, got %d", internalNode.right.Kind())
if internalNode.right.Kind() != kindHashed {
t.Fatalf("Expected right child to be kindHashed, got %d", internalNode.right.Kind())
}
if ds.ComputeHash(internalNode.right) != rightHash {
t.Errorf("Right hash mismatch: expected %x, got %x", rightHash, ds.ComputeHash(internalNode.right))
if ds.computeHash(internalNode.right) != rightHash {
t.Errorf("Right hash mismatch: expected %x, got %x", rightHash, ds.computeHash(internalNode.right))
}
}
@ -116,7 +116,7 @@ func TestSerializeDeserializeStemNode(t *testing.T) {
}
// Serialize the node
serialized := s.SerializeNode(ref)
serialized := s.serializeNode(ref)
// Check the serialized format
if serialized[0] != nodeTypeStem {
@ -130,13 +130,13 @@ func TestSerializeDeserializeStemNode(t *testing.T) {
// Deserialize into a new store
ds := NewNodeStore()
deserializedRef, err := ds.DeserializeNode(serialized, 10)
deserializedRef, err := ds.deserializeNode(serialized, 10)
if err != nil {
t.Fatalf("Failed to deserialize node: %v", err)
}
if deserializedRef.Kind() != KindStem {
t.Fatalf("Expected KindStem, got kind %d", deserializedRef.Kind())
if deserializedRef.Kind() != kindStem {
t.Fatalf("Expected kindStem, got kind %d", deserializedRef.Kind())
}
stemNode := ds.getStem(deserializedRef.Index())
@ -171,13 +171,13 @@ func TestSerializeDeserializeStemNode(t *testing.T) {
// TestDeserializeEmptyNode tests deserialization of empty node.
func TestDeserializeEmptyNode(t *testing.T) {
s := NewNodeStore()
deserialized, err := s.DeserializeNode([]byte{}, 0)
deserialized, err := s.deserializeNode([]byte{}, 0)
if err != nil {
t.Fatalf("Failed to deserialize empty node: %v", err)
}
if !deserialized.IsEmpty() {
t.Fatalf("Expected EmptyRef, got kind %d", deserialized.Kind())
t.Fatalf("Expected emptyRef, got kind %d", deserialized.Kind())
}
}
@ -186,7 +186,7 @@ func TestDeserializeInvalidType(t *testing.T) {
s := NewNodeStore()
invalidData := []byte{99, 0, 0, 0} // Type byte 99 is invalid
_, err := s.DeserializeNode(invalidData, 0)
_, err := s.deserializeNode(invalidData, 0)
if err == nil {
t.Fatal("Expected error for invalid type byte, got nil")
}
@ -198,7 +198,7 @@ func TestDeserializeInvalidLength(t *testing.T) {
// InternalNode with valid type byte but wrong length (needs exactly 65 bytes)
invalidData := []byte{nodeTypeInternal, 0, 0, 0}
_, err := s.DeserializeNode(invalidData, 0)
_, err := s.deserializeNode(invalidData, 0)
if err == nil {
t.Fatal("Expected error for invalid data length, got nil")
}

View file

@ -30,8 +30,8 @@ func TestHashedNodeHash(t *testing.T) {
s := NewNodeStore()
ref := s.newHashedRef(hash)
if s.ComputeHash(ref) != hash {
t.Errorf("Hash mismatch: expected %x, got %x", hash, s.ComputeHash(ref))
if s.computeHash(ref) != hash {
t.Errorf("Hash mismatch: expected %x, got %x", hash, s.computeHash(ref))
}
}
@ -40,10 +40,10 @@ func TestHashedNodeCopy(t *testing.T) {
hash := common.HexToHash("0xabcdef")
s := NewNodeStore()
ref := s.newHashedRef(hash)
s.SetRoot(ref)
s.root = ref
ns := s.Copy()
copiedHash := ns.ComputeHash(ns.Root())
copiedHash := ns.computeHash(ns.root)
if copiedHash != hash {
t.Errorf("Hash mismatch after copy: expected %x, got %x", hash, copiedHash)
@ -55,7 +55,7 @@ func TestHashedNodeInsertValuesAtStem(t *testing.T) {
// Test 1: nil resolver should return an error
s := NewNodeStore()
hashedRef := s.newHashedRef(common.HexToHash("0x1234"))
s.SetRoot(hashedRef)
s.root = hashedRef
stem := make([]byte, StemSize)
values := make([][]byte, StemNodeWidth)
@ -72,7 +72,7 @@ func TestHashedNodeInsertValuesAtStem(t *testing.T) {
s2 := NewNodeStore()
hashedRef2 := s2.newHashedRef(common.HexToHash("0x1234"))
s2.SetRoot(hashedRef2)
s2.root = hashedRef2
err = s2.InsertValuesAtStem(stem, values, mockResolver)
if err == nil {
@ -95,7 +95,7 @@ func TestHashedNodeInsertValuesAtStem(t *testing.T) {
sn.setValue(byte(i), v)
}
}
serialized := rs.SerializeNode(ref)
serialized := rs.serializeNode(ref)
validResolver := func(path []byte, hash common.Hash) ([]byte, error) {
return serialized, nil
@ -103,7 +103,7 @@ func TestHashedNodeInsertValuesAtStem(t *testing.T) {
s3 := NewNodeStore()
hashedRef3 := s3.newHashedRef(common.HexToHash("0x1234"))
s3.SetRoot(hashedRef3)
s3.root = hashedRef3
newValues := make([][]byte, StemNodeWidth)
newValues[2] = common.HexToHash("0x3333333333333333333333333333333333333333333333333333333333333333").Bytes()
@ -137,8 +137,8 @@ func TestHashedNodeGetError(t *testing.T) {
rootNode := s.getInternal(rootRef.Index())
hashedLeft := s.newHashedRef(common.HexToHash("0x1234"))
rootNode.left = hashedLeft
rootNode.right = EmptyRef
s.SetRoot(rootRef)
rootNode.right = emptyRef
s.root = rootRef
key := make([]byte, 32) // goes left
key[31] = 5

View file

@ -37,7 +37,7 @@ func keyToPath(depth int, key []byte) ([]byte, error) {
// Invariant: dirty=false implies mustRecompute=false. Every mutation that
// invalidates the cached hash MUST also mark the blob for re-flush.
type InternalNode struct {
left, right NodeRef
left, right nodeRef
depth uint8
mustRecompute bool // hash is stale (cleared by Hash)
dirty bool // on-disk blob is stale (cleared by CollectNodes)

View file

@ -39,7 +39,7 @@ func TestInternalNodeGet(t *testing.T) {
// Build tree: root -> left stem, right stem
// Insert left stem values
s.SetRoot(EmptyRef)
s.root = emptyRef
if err := s.InsertValuesAtStem(leftStem, leftValues, nil); err != nil {
t.Fatal(err)
}
@ -79,8 +79,8 @@ func TestInternalNodeGetWithResolver(t *testing.T) {
rootRef := s.newInternalRef(0)
rootNode := s.getInternal(rootRef.Index())
rootNode.left = hashedChild
rootNode.right = EmptyRef
s.SetRoot(rootRef)
rootNode.right = emptyRef
s.root = rootRef
// Mock resolver that returns a stem node
resolver := func(path []byte, hash common.Hash) ([]byte, error) {
@ -90,7 +90,7 @@ func TestInternalNodeGetWithResolver(t *testing.T) {
ref := rs.newStemRef(stem, 1)
sn := rs.getStem(ref.Index())
sn.setValue(5, common.HexToHash("0xabcd").Bytes())
return rs.SerializeNode(ref), nil
return rs.serializeNode(ref), nil
}
return nil, errors.New("node not found")
}
@ -173,12 +173,12 @@ func TestInternalNodeHash(t *testing.T) {
rootNode := s.getInternal(rootRef.Index())
rootNode.left = leftRef
rootNode.right = rightRef
s.SetRoot(rootRef)
s.root = rootRef
hash1 := s.ComputeHash(rootRef)
hash1 := s.computeHash(rootRef)
// Hash should be deterministic
hash2 := s.ComputeHash(rootRef)
hash2 := s.computeHash(rootRef)
if hash1 != hash2 {
t.Errorf("Hash not deterministic: %x != %x", hash1, hash2)
}
@ -186,7 +186,7 @@ func TestInternalNodeHash(t *testing.T) {
// Changing a child should change the hash
rootNode.left = s.newHashedRef(common.HexToHash("0x3333"))
rootNode.mustRecompute = true
hash3 := s.ComputeHash(rootRef)
hash3 := s.computeHash(rootRef)
if hash1 == hash3 {
t.Error("Hash didn't change after modifying left child")
}
@ -290,7 +290,7 @@ func TestInternalNodeCollectNodes(t *testing.T) {
collectedPaths = append(collectedPaths, pathCopy)
}
err := s.CollectNodes(s.Root(), []byte{1}, flushFn)
err := s.collectNodes(s.root, []byte{1}, flushFn)
if err != nil {
t.Fatalf("Failed to collect nodes: %v", err)
}
@ -322,7 +322,7 @@ func TestInternalNodeGetHeight(t *testing.T) {
t.Fatal(err)
}
height := s.GetHeight(s.Root())
height := s.getHeight(s.root)
if height < 2 {
t.Errorf("Expected height >= 2, got %d", height)
}

View file

@ -26,14 +26,14 @@ import (
var errIteratorEnd = errors.New("end of iteration")
type binaryNodeIteratorState struct {
Node NodeRef
Node nodeRef
Index int
}
type binaryNodeIterator struct {
trie *BinaryTrie
store *NodeStore
current NodeRef
current nodeRef
lastErr error
stack []binaryNodeIteratorState
@ -43,7 +43,7 @@ func newBinaryNodeIterator(t *BinaryTrie, _ []byte) (trie.NodeIterator, error) {
if t.Hash() == zero {
return &binaryNodeIterator{trie: t, store: t.store, lastErr: errIteratorEnd}, nil
}
it := &binaryNodeIterator{trie: t, store: t.store, current: t.store.Root()}
it := &binaryNodeIterator{trie: t, store: t.store, current: t.store.root}
return it, nil
}
@ -55,13 +55,13 @@ func (it *binaryNodeIterator) Next(descend bool) bool {
}
if len(it.stack) == 0 {
it.stack = append(it.stack, binaryNodeIteratorState{Node: it.trie.store.Root()})
it.current = it.trie.store.Root()
it.stack = append(it.stack, binaryNodeIteratorState{Node: it.trie.store.root})
it.current = it.trie.store.root
return true
}
switch it.current.Kind() {
case KindInternal:
case kindInternal:
// index: 0 = nothing visited, 1 = left visited, 2 = right visited.
node := it.store.getInternal(it.current.Index())
context := &it.stack[len(it.stack)-1]
@ -107,7 +107,7 @@ func (it *binaryNodeIterator) Next(descend bool) bool {
it.stack[len(it.stack)-1].Index++
return it.Next(descend)
case KindStem:
case kindStem:
// Look for the next non-empty value in this stem.
sn := it.store.getStem(it.current.Index())
for i := it.stack[len(it.stack)-1].Index; i < 256; i++ {
@ -127,7 +127,7 @@ func (it *binaryNodeIterator) Next(descend bool) bool {
it.stack[len(it.stack)-1].Index++
return it.Next(descend)
case KindHashed:
case kindHashed:
// Resolve the hashed node from disk, then rewire the parent to point at the
// resolved node in place.
if len(it.stack) < 2 {
@ -140,7 +140,7 @@ func (it *binaryNodeIterator) Next(descend bool) bool {
it.lastErr = err
return false
}
resolved, err := it.store.DeserializeNodeWithHash(data, len(it.stack)-1, hn.Hash())
resolved, err := it.store.deserializeNodeWithHash(data, len(it.stack)-1, hn.Hash())
if err != nil {
it.lastErr = err
return false
@ -159,7 +159,7 @@ func (it *binaryNodeIterator) Next(descend bool) bool {
it.store.freeHashedNode(oldHashedIdx)
return it.Next(descend)
case KindEmpty:
case kindEmpty:
return false
default:
@ -175,7 +175,7 @@ func (it *binaryNodeIterator) Error() error {
}
func (it *binaryNodeIterator) Hash() common.Hash {
return it.store.ComputeHash(it.current)
return it.store.computeHash(it.current)
}
// Parent returns the hash of the current node's parent. When the immediate
@ -185,7 +185,7 @@ func (it *binaryNodeIterator) Parent() common.Hash {
if len(it.stack) < 2 {
return common.Hash{}
}
return it.store.ComputeHash(it.stack[len(it.stack)-2].Node)
return it.store.computeHash(it.stack[len(it.stack)-2].Node)
}
// Path returns the bit-path to the current node.
@ -205,7 +205,7 @@ func (it *binaryNodeIterator) Path() []byte {
}
func (it *binaryNodeIterator) NodeBlob() []byte {
return it.store.SerializeNode(it.current)
return it.store.serializeNode(it.current)
}
// Leaf reports whether the iterator is currently positioned at a leaf value.
@ -214,7 +214,7 @@ func (it *binaryNodeIterator) NodeBlob() []byte {
// StemNode itself. The stack Index points to the NEXT position after the
// current value, so Index == 0 means we haven't yielded anything yet.
func (it *binaryNodeIterator) Leaf() bool {
if it.current.Kind() != KindStem {
if it.current.Kind() != kindStem {
return false
}
@ -236,7 +236,7 @@ func (it *binaryNodeIterator) Leaf() bool {
// positioned at a leaf. Callers must not retain references to the returned
// slice after calling Next.
func (it *binaryNodeIterator) LeafKey() []byte {
if it.current.Kind() != KindStem {
if it.current.Kind() != kindStem {
panic("Leaf() called on an binary node iterator not at a leaf location")
}
sn := it.store.getStem(it.current.Index())
@ -247,7 +247,7 @@ func (it *binaryNodeIterator) LeafKey() []byte {
// at a leaf. Callers must not retain references to the returned slice after
// calling Next.
func (it *binaryNodeIterator) LeafBlob() []byte {
if it.current.Kind() != KindStem {
if it.current.Kind() != kindStem {
panic("LeafBlob() called on an binary node iterator not at a leaf location")
}
sn := it.store.getStem(it.current.Index())
@ -258,7 +258,7 @@ func (it *binaryNodeIterator) LeafBlob() []byte {
// not positioned at a leaf. Callers must not retain references to the
// returned slices after calling Next.
func (it *binaryNodeIterator) LeafProof() [][]byte {
if it.current.Kind() != KindStem {
if it.current.Kind() != kindStem {
panic("LeafProof() called on an binary node iterator not at a leaf location")
}
sn := it.store.getStem(it.current.Index())
@ -276,10 +276,10 @@ func (it *binaryNodeIterator) LeafProof() [][]byte {
internalNode := it.store.getInternal(state.Node.Index())
if state.Index == 0 {
rh := it.store.ComputeHash(internalNode.right)
rh := it.store.computeHash(internalNode.right)
proof = append(proof, rh.Bytes())
} else {
lh := it.store.ComputeHash(internalNode.left)
lh := it.store.computeHash(internalNode.left)
proof = append(proof, lh.Bytes())
}
}

View file

@ -144,8 +144,8 @@ func TestIteratorEmptyNodeBacktrack(t *testing.T) {
{common.HexToHash("8000000000000000000000000000000000000000000000000000000000000001"), oneKey},
})
if tr.store.Root().Kind() != KindInternal {
t.Fatalf("expected InternalNode root, got kind %d", tr.store.Root().Kind())
if tr.store.root.Kind() != kindInternal {
t.Fatalf("expected InternalNode root, got kind %d", tr.store.root.Kind())
}
if leaves := countLeaves(t, tr); leaves != 2 {
t.Fatalf("expected 2 leaves, got %d (Empty backtrack bug?)", leaves)
@ -161,8 +161,8 @@ func TestIteratorHashedNodeNilData(t *testing.T) {
{common.HexToHash("8000000000000000000000000000000000000000000000000000000000000001"), oneKey},
})
root := tr.store.Root()
if root.Kind() != KindInternal {
root := tr.store.root
if root.Kind() != kindInternal {
t.Fatalf("expected InternalNode root, got kind %d", root.Kind())
}
rootNode := tr.store.getInternal(root.Index())

View file

@ -16,38 +16,38 @@
package bintrie
// NodeKind identifies the type of a trie node stored in a NodeRef.
type NodeKind uint8
// nodeKind identifies the type of a trie node stored in a nodeRef.
type nodeKind uint8
const (
KindEmpty NodeKind = iota
KindInternal
KindStem // up to 256 values per stem
KindHashed
kindEmpty nodeKind = iota
kindInternal
kindStem // up to 256 values per stem
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)
// into a single uint32. Because NodeRef contains no Go pointers, slices
// of structs containing NodeRef fields are allocated in noscan spans —
// into a single uint32. Because nodeRef contains no Go pointers, slices
// of structs containing nodeRef fields are allocated in noscan spans —
// the garbage collector never examines them.
type NodeRef uint32
type nodeRef uint32
const (
kindShift uint32 = 30
indexMask uint32 = (1 << kindShift) - 1
// EmptyRef represents an empty node.
EmptyRef NodeRef = 0
// emptyRef represents an empty node.
emptyRef nodeRef = 0
)
func MakeRef(kind NodeKind, idx uint32) NodeRef {
return NodeRef(uint32(kind)<<kindShift | (idx & indexMask))
func makeRef(kind nodeKind, idx uint32) nodeRef {
return nodeRef(uint32(kind)<<kindShift | (idx & indexMask))
}
func (r NodeRef) Kind() NodeKind { return NodeKind(uint32(r) >> kindShift) }
func (r nodeRef) Kind() nodeKind { return nodeKind(uint32(r) >> kindShift) }
// Index within the typed pool.
func (r NodeRef) Index() uint32 { return uint32(r) & indexMask }
func (r nodeRef) Index() uint32 { return uint32(r) & indexMask }
func (r NodeRef) IsEmpty() bool { return r == EmptyRef }
func (r nodeRef) IsEmpty() bool { return r == emptyRef }

View file

@ -37,7 +37,7 @@ type NodeStore struct {
hashedChunks []*[storeChunkSize]HashedNode
hashedCount uint32
root NodeRef
root nodeRef
// Free lists for recycling deleted node slots.
freeInternals []uint32
@ -46,13 +46,9 @@ type NodeStore struct {
}
func NewNodeStore() *NodeStore {
return &NodeStore{root: EmptyRef}
return &NodeStore{root: emptyRef}
}
func (s *NodeStore) Root() NodeRef { return s.root }
func (s *NodeStore) SetRoot(ref NodeRef) { s.root = ref }
func (s *NodeStore) allocInternal() uint32 {
if n := len(s.freeInternals); n > 0 {
idx := s.freeInternals[n-1]
@ -76,7 +72,7 @@ func (s *NodeStore) getInternal(idx uint32) *InternalNode {
return &s.internalChunks[idx/storeChunkSize][idx%storeChunkSize]
}
func (s *NodeStore) newInternalRef(depth int) NodeRef {
func (s *NodeStore) newInternalRef(depth int) nodeRef {
if depth > 248 {
panic("node depth exceeds maximum binary trie depth")
}
@ -85,7 +81,7 @@ func (s *NodeStore) newInternalRef(depth int) NodeRef {
n.depth = uint8(depth)
n.mustRecompute = true
n.dirty = true
return MakeRef(KindInternal, idx)
return makeRef(kindInternal, idx)
}
func (s *NodeStore) allocStem() uint32 {
@ -111,7 +107,7 @@ func (s *NodeStore) getStem(idx uint32) *StemNode {
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 {
panic("node depth exceeds maximum binary trie depth")
}
@ -121,7 +117,7 @@ func (s *NodeStore) newStemRef(stem []byte, depth int) NodeRef {
sn.depth = uint8(depth)
sn.mustRecompute = true
sn.dirty = true
return MakeRef(KindStem, idx)
return makeRef(kindStem, idx)
}
func (s *NodeStore) allocHashed() uint32 {
@ -151,10 +147,10 @@ func (s *NodeStore) freeHashedNode(idx uint32) {
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()
*s.getHashed(idx) = HashedNode(hash)
return MakeRef(KindHashed, idx)
return makeRef(kindHashed, idx)
}
func (s *NodeStore) Copy() *NodeStore {

View file

@ -51,8 +51,8 @@ func TestStemNodeInsertSameStem(t *testing.T) {
}
// Root should still be a StemNode
if s.Root().Kind() != KindStem {
t.Fatalf("Expected KindStem root, got kind %d", s.Root().Kind())
if s.root.Kind() != kindStem {
t.Fatalf("Expected kindStem root, got kind %d", s.root.Kind())
}
// Check that both values are present
@ -87,12 +87,12 @@ func TestStemNodeInsertDifferentStem(t *testing.T) {
}
// Should now be an InternalNode
if s.Root().Kind() != KindInternal {
t.Fatalf("Expected KindInternal root, got kind %d", s.Root().Kind())
if s.root.Kind() != kindInternal {
t.Fatalf("Expected kindInternal root, got kind %d", s.root.Kind())
}
// Check depth
rootNode := s.getInternal(s.Root().Index())
rootNode := s.getInternal(s.root.Index())
if rootNode.depth != 0 {
t.Errorf("Expected depth 0, got %d", rootNode.depth)
}
@ -172,10 +172,10 @@ func TestStemNodeHash(t *testing.T) {
t.Fatal(err)
}
hash1 := s.ComputeHash(s.Root())
hash1 := s.computeHash(s.root)
// Hash should be deterministic
hash2 := s.ComputeHash(s.Root())
hash2 := s.computeHash(s.root)
if hash1 != hash2 {
t.Errorf("Hash not deterministic: %x != %x", hash1, hash2)
}
@ -187,7 +187,7 @@ func TestStemNodeHash(t *testing.T) {
if err := s.Insert(key2, value2, nil); err != nil {
t.Fatal(err)
}
hash3 := s.ComputeHash(s.Root())
hash3 := s.computeHash(s.root)
if hash1 == hash3 {
t.Error("Hash didn't change after modifying values")
}
@ -295,7 +295,7 @@ func TestStemNodeGetHeight(t *testing.T) {
t.Fatal(err)
}
height := s.GetHeight(s.Root())
height := s.getHeight(s.root)
if height != 1 {
t.Errorf("Expected height 1, got %d", height)
}
@ -320,7 +320,7 @@ func TestStemNodeCollectNodes(t *testing.T) {
collectedPaths = append(collectedPaths, pathCopy)
}
err := s.CollectNodes(s.Root(), []byte{0, 1, 0}, flushFn)
err := s.collectNodes(s.root, []byte{0, 1, 0}, flushFn)
if err != nil {
t.Fatalf("Failed to collect nodes: %v", err)
}

View file

@ -28,18 +28,18 @@ import (
type NodeFlushFn func(path []byte, hash common.Hash, serialized []byte)
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() {
case KindInternal:
case kindInternal:
return s.hashInternal(ref.Index())
case KindStem:
case kindStem:
return s.getStem(ref.Index()).Hash()
case KindHashed:
case kindHashed:
return s.getHashed(ref.Index()).Hash()
case KindEmpty:
case kindEmpty:
return common.Hash{}
default:
return common.Hash{}
@ -65,12 +65,12 @@ func (s *NodeStore) hashInternal(idx uint32) common.Hash {
if !node.left.IsEmpty() {
wg.Add(1)
go func() {
lh = s.ComputeHash(node.left)
lh = s.computeHash(node.left)
wg.Done()
}()
}
if !node.right.IsEmpty() {
rh := s.ComputeHash(node.right)
rh := s.computeHash(node.right)
copy(input[32:], rh[:])
}
wg.Wait()
@ -82,11 +82,11 @@ func (s *NodeStore) hashInternal(idx uint32) common.Hash {
var input [64]byte
if !node.left.IsEmpty() {
lh := s.ComputeHash(node.left)
lh := s.computeHash(node.left)
copy(input[:32], lh[:])
}
if !node.right.IsEmpty() {
rh := s.ComputeHash(node.right)
rh := s.computeHash(node.right)
copy(input[32:], rh[:])
}
node.hash = sha256Sum256(input[:])
@ -95,19 +95,19 @@ func (s *NodeStore) hashInternal(idx uint32) common.Hash {
}
// 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() {
case KindInternal:
case kindInternal:
node := s.getInternal(ref.Index())
var serialized [NodeTypeBytes + HashSize + HashSize]byte
serialized[0] = nodeTypeInternal
lh := s.ComputeHash(node.left)
rh := s.ComputeHash(node.right)
lh := s.computeHash(node.left)
rh := s.computeHash(node.right)
copy(serialized[NodeTypeBytes:NodeTypeBytes+HashSize], lh[:])
copy(serialized[NodeTypeBytes+HashSize:], rh[:])
return serialized[:]
case KindStem:
case kindStem:
sn := s.getStem(ref.Index())
serializedLen := NodeTypeBytes + StemSize + StemBitmapSize + len(sn.valueData)
serialized := make([]byte, serializedLen)
@ -126,31 +126,31 @@ var errInvalidSerializedLength = errors.New("invalid serialized node length")
// DeserializeNode deserializes a node from bytes, recomputing its hash. The
// returned node is marked dirty (provenance unknown, safe re-flush default).
func (s *NodeStore) DeserializeNode(serialized []byte, depth int) (NodeRef, error) {
return s.deserializeNode(serialized, depth, common.Hash{}, true, true)
func (s *NodeStore) deserializeNode(serialized []byte, depth int) (nodeRef, error) {
return s.decodeNode(serialized, depth, common.Hash{}, true, true)
}
// DeserializeNodeWithHash deserializes a node whose hash is already known and
// whose blob is already on disk (mustRecompute=false, dirty=false).
func (s *NodeStore) DeserializeNodeWithHash(serialized []byte, depth int, hn common.Hash) (NodeRef, error) {
return s.deserializeNode(serialized, depth, hn, false, false)
func (s *NodeStore) deserializeNodeWithHash(serialized []byte, depth int, hn common.Hash) (nodeRef, error) {
return s.decodeNode(serialized, depth, hn, false, false)
}
func (s *NodeStore) deserializeNode(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 {
return EmptyRef, nil
return emptyRef, nil
}
switch serialized[0] {
case nodeTypeInternal:
if len(serialized) != NodeTypeBytes+2*HashSize {
return EmptyRef, errInvalidSerializedLength
return emptyRef, errInvalidSerializedLength
}
var leftHash, rightHash common.Hash
copy(leftHash[:], serialized[NodeTypeBytes:NodeTypeBytes+HashSize])
copy(rightHash[:], serialized[NodeTypeBytes+HashSize:])
var leftRef, rightRef NodeRef
var leftRef, rightRef nodeRef
if leftHash != (common.Hash{}) {
leftRef = s.newHashedRef(leftHash)
}
@ -171,7 +171,7 @@ func (s *NodeStore) deserializeNode(serialized []byte, depth int, hn common.Hash
case nodeTypeStem:
if len(serialized) < 64 {
return EmptyRef, errInvalidSerializedLength
return emptyRef, errInvalidSerializedLength
}
stemIdx := s.allocStem()
sn := s.getStem(stemIdx)
@ -186,7 +186,7 @@ func (s *NodeStore) deserializeNode(serialized []byte, depth int, hn common.Hash
dataStart := NodeTypeBytes + StemSize + StemBitmapSize
dataEnd := dataStart + int(count)*HashSize
if len(serialized) < dataEnd {
return EmptyRef, errInvalidSerializedLength
return emptyRef, errInvalidSerializedLength
}
// Zero-copy: aliases the serialized buffer; ensureWritable() COWs before mutation.
sn.valueData = serialized[dataStart:dataEnd]
@ -195,21 +195,21 @@ func (s *NodeStore) deserializeNode(serialized []byte, depth int, hn common.Hash
sn.hash = hn
sn.mustRecompute = mustRecompute
sn.dirty = dirty
return MakeRef(KindStem, stemIdx), nil
return makeRef(kindStem, stemIdx), nil
default:
return EmptyRef, errors.New("invalid node type")
return emptyRef, errors.New("invalid node type")
}
}
// 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
// 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() {
case KindEmpty:
case kindEmpty:
return nil
case KindInternal:
case kindInternal:
node := s.getInternal(ref.Index())
if !node.dirty {
return nil
@ -217,50 +217,50 @@ func (s *NodeStore) CollectNodes(ref NodeRef, path []byte, flushfn NodeFlushFn)
leftPath := make([]byte, len(path)+1)
copy(leftPath, path)
leftPath[len(path)] = 0
if err := s.CollectNodes(node.left, leftPath, flushfn); err != nil {
if err := s.collectNodes(node.left, leftPath, flushfn); err != nil {
return err
}
rightPath := make([]byte, len(path)+1)
copy(rightPath, path)
rightPath[len(path)] = 1
if err := s.CollectNodes(node.right, rightPath, flushfn); err != nil {
if err := s.collectNodes(node.right, rightPath, flushfn); err != nil {
return err
}
flushfn(path, s.ComputeHash(ref), s.SerializeNode(ref))
flushfn(path, s.computeHash(ref), s.serializeNode(ref))
node.dirty = false
return nil
case KindStem:
case kindStem:
sn := s.getStem(ref.Index())
if !sn.dirty {
return nil
}
flushfn(path, s.ComputeHash(ref), s.SerializeNode(ref))
flushfn(path, s.computeHash(ref), s.serializeNode(ref))
sn.dirty = false
return nil
case KindHashed:
case kindHashed:
return nil // Already committed
default:
return fmt.Errorf("CollectNodes: unexpected kind %d", ref.Kind())
}
}
func (s *NodeStore) ToDot(ref NodeRef, parent, path string) string {
func (s *NodeStore) toDot(ref nodeRef, parent, path string) string {
switch ref.Kind() {
case KindInternal:
case kindInternal:
node := s.getInternal(ref.Index())
me := fmt.Sprintf("internal%s", path)
ret := fmt.Sprintf("%s [label=\"I: %x\"]\n", me, s.ComputeHash(ref))
ret := fmt.Sprintf("%s [label=\"I: %x\"]\n", me, s.computeHash(ref))
if len(parent) > 0 {
ret = fmt.Sprintf("%s %s -> %s\n", ret, parent, me)
}
if !node.left.IsEmpty() {
ret += s.ToDot(node.left, me, fmt.Sprintf("%s%02x", path, 0))
ret += s.toDot(node.left, me, fmt.Sprintf("%s%02x", path, 0))
}
if !node.right.IsEmpty() {
ret += s.ToDot(node.right, me, fmt.Sprintf("%s%02x", path, 1))
ret += s.toDot(node.right, me, fmt.Sprintf("%s%02x", path, 1))
}
return ret
case KindStem:
case kindStem:
sn := s.getStem(ref.Index())
me := fmt.Sprintf("stem%s", path)
ret := fmt.Sprintf("%s [label=\"stem=%x c=%x\"]\n", me, sn.Stem, sn.Hash())
@ -276,7 +276,7 @@ func (s *NodeStore) ToDot(ref NodeRef, parent, path string) string {
ret += fmt.Sprintf("%s -> %s%x\n", me, me, i)
}
return ret
case KindHashed:
case kindHashed:
hn := s.getHashed(ref.Index())
me := fmt.Sprintf("hash%s", path)
ret := fmt.Sprintf("%s [label=\"%x\"]\n", me, hn.Hash())

View file

@ -30,7 +30,7 @@ func (s *NodeStore) GetSingle(stem []byte, suffix byte, resolver NodeResolverFn)
return s.getSingle(s.root, stem, suffix, resolver)
}
func (s *NodeStore) getSingle(ref NodeRef, stem []byte, suffix byte, resolver NodeResolverFn) ([]byte, error) {
func (s *NodeStore) getSingle(ref nodeRef, stem []byte, suffix byte, resolver NodeResolverFn) ([]byte, error) {
cur := ref
// Track parent for HashedNode resolution (update parent's child ref).
var parentIdx uint32
@ -39,7 +39,7 @@ func (s *NodeStore) getSingle(ref NodeRef, stem []byte, suffix byte, resolver No
for {
switch cur.Kind() {
case KindInternal:
case kindInternal:
node := s.getInternal(cur.Index())
if node.depth >= 31*8 {
return nil, errors.New("node too deep")
@ -55,14 +55,14 @@ func (s *NodeStore) getSingle(ref NodeRef, stem []byte, suffix byte, resolver No
cur = node.right
}
case KindStem:
case kindStem:
sn := s.getStem(cur.Index())
if sn.Stem != [StemSize]byte(stem[:StemSize]) {
return nil, nil
}
return sn.getValue(suffix), nil
case KindHashed:
case kindHashed:
if !hasParent {
return nil, errors.New("getSingle: hashed node at root")
}
@ -79,7 +79,7 @@ func (s *NodeStore) getSingle(ref NodeRef, stem []byte, suffix byte, resolver No
if err != nil {
return nil, fmt.Errorf("getSingle resolve error: %w", err)
}
resolved, err := s.DeserializeNodeWithHash(data, int(parentNode.depth)+1, hn.Hash())
resolved, err := s.deserializeNodeWithHash(data, int(parentNode.depth)+1, hn.Hash())
if err != nil {
return nil, fmt.Errorf("getSingle deserialization error: %w", err)
}
@ -92,7 +92,7 @@ func (s *NodeStore) getSingle(ref NodeRef, stem []byte, suffix byte, resolver No
}
cur = resolved
case KindEmpty:
case kindEmpty:
return nil, nil
default:
@ -105,7 +105,7 @@ func (s *NodeStore) GetValuesAtStem(stem []byte, resolver NodeResolverFn) ([][]b
return s.getValuesAtStem(s.root, stem, resolver)
}
func (s *NodeStore) getValuesAtStem(ref NodeRef, stem []byte, resolver NodeResolverFn) ([][]byte, error) {
func (s *NodeStore) getValuesAtStem(ref nodeRef, stem []byte, resolver NodeResolverFn) ([][]byte, error) {
cur := ref
var parentIdx uint32
var parentIsLeft bool
@ -113,7 +113,7 @@ func (s *NodeStore) getValuesAtStem(ref NodeRef, stem []byte, resolver NodeResol
for {
switch cur.Kind() {
case KindInternal:
case kindInternal:
node := s.getInternal(cur.Index())
if node.depth >= 31*8 {
return nil, errors.New("node too deep")
@ -129,14 +129,14 @@ func (s *NodeStore) getValuesAtStem(ref NodeRef, stem []byte, resolver NodeResol
cur = node.right
}
case KindStem:
case kindStem:
sn := s.getStem(cur.Index())
if sn.Stem != [StemSize]byte(stem[:StemSize]) {
return nil, nil
}
return sn.allValues(), nil
case KindHashed:
case kindHashed:
if !hasParent {
return nil, errors.New("getValuesAtStem: hashed node at root")
}
@ -153,7 +153,7 @@ func (s *NodeStore) getValuesAtStem(ref NodeRef, stem []byte, resolver NodeResol
if err != nil {
return nil, fmt.Errorf("getValuesAtStem resolve error: %w", err)
}
resolved, err := s.DeserializeNodeWithHash(data, int(parentNode.depth)+1, hn.Hash())
resolved, err := s.deserializeNodeWithHash(data, int(parentNode.depth)+1, hn.Hash())
if err != nil {
return nil, fmt.Errorf("getValuesAtStem deserialization error: %w", err)
}
@ -165,7 +165,7 @@ func (s *NodeStore) getValuesAtStem(ref NodeRef, stem []byte, resolver NodeResol
}
cur = resolved
case KindEmpty:
case kindEmpty:
var values [StemNodeWidth][]byte
return values[:], nil
@ -188,7 +188,7 @@ func (s *NodeStore) InsertSingle(stem []byte, suffix byte, value []byte, resolve
return nil
}
if s.root.Kind() == KindStem {
if s.root.Kind() == kindStem {
sn := s.getStem(s.root.Index())
if sn.Stem == [StemSize]byte(stem[:StemSize]) {
sn.setValue(suffix, value)
@ -216,7 +216,7 @@ func (s *NodeStore) insertSingleInternal(stem []byte, suffix byte, value []byte,
for {
switch cur.Kind() {
case KindInternal:
case kindInternal:
node := s.getInternal(cur.Index())
node.mustRecompute = true
node.dirty = true
@ -229,7 +229,7 @@ func (s *NodeStore) insertSingleInternal(stem []byte, suffix byte, value []byte,
cur = node.right
}
case KindStem:
case kindStem:
sn := s.getStem(cur.Index())
if sn.Stem == [StemSize]byte(stem[:StemSize]) {
sn.setValue(suffix, value)
@ -249,7 +249,7 @@ func (s *NodeStore) insertSingleInternal(stem []byte, suffix byte, value []byte,
}
return nil
case KindHashed:
case kindHashed:
if pathLen == 0 {
return errors.New("insertSingle: hashed node at root")
}
@ -267,7 +267,7 @@ func (s *NodeStore) insertSingleInternal(stem []byte, suffix byte, value []byte,
if err != nil {
return fmt.Errorf("insertSingle resolve error: %w", err)
}
resolved, err := s.DeserializeNodeWithHash(data, int(parentNode.depth)+1, hn.Hash())
resolved, err := s.deserializeNodeWithHash(data, int(parentNode.depth)+1, hn.Hash())
if err != nil {
return fmt.Errorf("insertSingle deserialization error: %w", err)
}
@ -279,7 +279,7 @@ func (s *NodeStore) insertSingleInternal(stem []byte, suffix byte, value []byte,
}
cur = resolved
case KindEmpty:
case kindEmpty:
parentDepth := int(s.getInternal(pathStack[pathLen-1].internalIdx).depth) + 1
ref := s.newStemRef(stem, parentDepth)
sn := s.getStem(ref.Index())
@ -300,11 +300,11 @@ func (s *NodeStore) insertSingleInternal(stem []byte, suffix byte, value []byte,
}
// splitStemInsert splits a StemNode into InternalNodes for a divergent stem.
func (s *NodeStore) splitStemInsert(existingRef NodeRef, newStem []byte, suffix byte, value []byte, depth int) NodeRef {
func (s *NodeStore) splitStemInsert(existingRef nodeRef, newStem []byte, suffix byte, value []byte, depth int) nodeRef {
existing := s.getStem(existingRef.Index())
existingDepth := depth
var firstRef NodeRef
var firstRef nodeRef
var lastInternalIdx uint32
var lastIsLeft bool
first := true
@ -343,7 +343,7 @@ func (s *NodeStore) splitStemInsert(existingRef NodeRef, newStem []byte, suffix
newSn.mustRecompute = true
newSn.dirty = true
newSn.setValue(suffix, value)
newStemRef := MakeRef(KindStem, newStemIdx)
newStemRef := makeRef(kindStem, newStemIdx)
if bitExisting == 0 {
newInternal.left = existingRef
@ -371,13 +371,13 @@ func (s *NodeStore) InsertValuesAtStem(stem []byte, values [][]byte, resolver No
return nil
}
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() {
case KindInternal:
case kindInternal:
node := s.getInternal(ref.Index())
bit := stem[node.depth/8] >> (7 - (node.depth % 8)) & 1
if bit == 0 {
if node.left.Kind() == KindHashed {
if node.left.Kind() == kindHashed {
if resolver == nil {
return ref, errors.New("insertValuesAtStem: cannot resolve hashed node without resolver")
}
@ -390,7 +390,7 @@ func (s *NodeStore) insertValuesAtStem(ref NodeRef, stem []byte, values [][]byte
if err != nil {
return ref, fmt.Errorf("InsertValuesAtStem resolve error: %w", err)
}
resolved, err := s.DeserializeNodeWithHash(data, int(node.depth)+1, hn.Hash())
resolved, err := s.deserializeNodeWithHash(data, int(node.depth)+1, hn.Hash())
if err != nil {
return ref, fmt.Errorf("InsertValuesAtStem deserialization error: %w", err)
}
@ -403,7 +403,7 @@ func (s *NodeStore) insertValuesAtStem(ref NodeRef, stem []byte, values [][]byte
}
node.left = newChild
} else {
if node.right.Kind() == KindHashed {
if node.right.Kind() == kindHashed {
if resolver == nil {
return ref, errors.New("insertValuesAtStem: cannot resolve hashed node without resolver")
}
@ -416,7 +416,7 @@ func (s *NodeStore) insertValuesAtStem(ref NodeRef, stem []byte, values [][]byte
if err != nil {
return ref, fmt.Errorf("InsertValuesAtStem resolve error: %w", err)
}
resolved, err := s.DeserializeNodeWithHash(data, int(node.depth)+1, hn.Hash())
resolved, err := s.deserializeNodeWithHash(data, int(node.depth)+1, hn.Hash())
if err != nil {
return ref, fmt.Errorf("InsertValuesAtStem deserialization error: %w", err)
}
@ -433,7 +433,7 @@ func (s *NodeStore) insertValuesAtStem(ref NodeRef, stem []byte, values [][]byte
node.dirty = true
return ref, nil
case KindStem:
case kindStem:
sn := s.getStem(ref.Index())
if sn.Stem == [StemSize]byte(stem[:StemSize]) {
// Same stem — merge values
@ -449,7 +449,7 @@ func (s *NodeStore) insertValuesAtStem(ref NodeRef, stem []byte, values [][]byte
// Different stem — split
return s.splitStemValuesInsert(ref, stem, values, resolver, depth)
case KindHashed:
case kindHashed:
hn := s.getHashed(ref.Index())
path, err := keyToPath(depth, stem)
if err != nil {
@ -462,14 +462,14 @@ func (s *NodeStore) insertValuesAtStem(ref NodeRef, stem []byte, values [][]byte
if err != nil {
return ref, fmt.Errorf("InsertValuesAtStem resolve error: %w", err)
}
resolved, err := s.DeserializeNodeWithHash(data, depth, hn.Hash())
resolved, err := s.deserializeNodeWithHash(data, depth, hn.Hash())
if err != nil {
return ref, fmt.Errorf("InsertValuesAtStem deserialization error: %w", err)
}
s.freeHashedNode(ref.Index())
return s.insertValuesAtStem(resolved, stem, values, resolver, depth)
case KindEmpty:
case kindEmpty:
// Create new StemNode
stemIdx := s.allocStem()
sn := s.getStem(stemIdx)
@ -484,7 +484,7 @@ func (s *NodeStore) insertValuesAtStem(ref NodeRef, stem []byte, values [][]byte
sn.valueData = append(sn.valueData, v[:HashSize]...)
}
}
return MakeRef(KindStem, stemIdx), nil
return makeRef(kindStem, stemIdx), nil
default:
return ref, fmt.Errorf("insertValuesAtStem: unexpected kind %d", ref.Kind())
@ -492,7 +492,7 @@ func (s *NodeStore) insertValuesAtStem(ref NodeRef, stem []byte, values [][]byte
}
// 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())
if int(existing.depth) >= StemSize*8 {
@ -507,7 +507,7 @@ func (s *NodeStore) splitStemValuesInsert(existingRef NodeRef, newStem []byte, v
bitKey := newStem[nNode.depth/8] >> (7 - (nNode.depth % 8)) & 1
if bitKey == bitStem {
// Same direction — need deeper split
var child NodeRef
var child nodeRef
if bitStem == 0 {
nNode.left = existingRef
child = nNode.left
@ -521,10 +521,10 @@ func (s *NodeStore) splitStemValuesInsert(existingRef NodeRef, newStem []byte, v
}
if bitStem == 0 {
nNode.left = newChild
nNode.right = EmptyRef
nNode.right = emptyRef
} else {
nNode.right = newChild
nNode.left = EmptyRef
nNode.left = emptyRef
}
} else {
// Divergence — create new StemNode for the new values
@ -539,7 +539,7 @@ func (s *NodeStore) splitStemValuesInsert(existingRef NodeRef, newStem []byte, v
newSn.setValue(byte(i), v)
}
}
newStemRef := MakeRef(KindStem, newStemIdx)
newStemRef := makeRef(kindStem, newStemIdx)
if bitStem == 0 {
nNode.left = existingRef
@ -560,19 +560,19 @@ func (s *NodeStore) Get(key []byte, resolver NodeResolverFn) ([]byte, error) {
return s.GetSingle(key[:StemSize], key[StemSize], resolver)
}
func (s *NodeStore) GetHeight(ref NodeRef) int {
func (s *NodeStore) getHeight(ref nodeRef) int {
switch ref.Kind() {
case KindInternal:
case kindInternal:
node := s.getInternal(ref.Index())
lh := s.GetHeight(node.left)
rh := s.GetHeight(node.right)
lh := s.getHeight(node.left)
rh := s.getHeight(node.right)
if lh > rh {
return 1 + lh
}
return 1 + rh
case KindStem:
case kindStem:
return 1
case KindEmpty:
case kindEmpty:
return 0
default:
return 0

View file

@ -114,8 +114,8 @@ type BinaryTrie struct {
// ToDot converts the binary trie to a DOT language representation. Useful for debugging.
func (t *BinaryTrie) ToDot() string {
t.store.ComputeHash(t.store.Root())
return t.store.ToDot(t.store.Root(), "", "")
t.store.computeHash(t.store.root)
return t.store.toDot(t.store.root, "", "")
}
// NewBinaryTrie creates a new binary trie.
@ -135,11 +135,11 @@ func NewBinaryTrie(root common.Hash, db database.NodeDatabase) (*BinaryTrie, err
if err != nil {
return nil, err
}
ref, err := t.store.DeserializeNodeWithHash(blob, 0, root)
ref, err := t.store.deserializeNodeWithHash(blob, 0, root)
if err != nil {
return nil, err
}
t.store.SetRoot(ref)
t.store.root = ref
}
return t, nil
}
@ -301,7 +301,7 @@ func (t *BinaryTrie) DeleteStorage(addr common.Address, key []byte) error {
// Hash returns the root hash of the trie. It does not write to the database and
// can be used even if the trie doesn't have one.
func (t *BinaryTrie) Hash() common.Hash {
return t.store.ComputeHash(t.store.Root())
return t.store.computeHash(t.store.root)
}
// Commit writes all nodes to the trie's memory database, tracking the internal
@ -309,7 +309,7 @@ func (t *BinaryTrie) Hash() common.Hash {
func (t *BinaryTrie) Commit(_ bool) (common.Hash, *trienode.NodeSet) {
nodeset := trienode.NewNodeSet(common.Hash{})
err := t.store.CollectNodes(t.store.Root(), nil, func(path []byte, hash common.Hash, serialized []byte) {
err := t.store.collectNodes(t.store.root, nil, func(path []byte, hash common.Hash, serialized []byte) {
nodeset.AddNode(path, trienode.NewNodeWithPrev(hash, serialized, t.tracer.Get(path)))
})
if err != nil {

View file

@ -41,7 +41,7 @@ func TestSingleEntry(t *testing.T) {
if err := s.Insert(zeroKey[:], oneKey[:], nil); err != nil {
t.Fatal(err)
}
if s.GetHeight(s.Root()) != 1 {
if s.getHeight(s.root) != 1 {
t.Fatal("invalid depth")
}
expected := common.HexToHash("aab1060e04cb4f5dc6f697ae93156a95714debbf77d54238766adc5709282b6f")
@ -59,7 +59,7 @@ func TestTwoEntriesDiffFirstBit(t *testing.T) {
if err := s.Insert(common.HexToHash("8000000000000000000000000000000000000000000000000000000000000000").Bytes(), twoKey[:], nil); err != nil {
t.Fatal(err)
}
if s.GetHeight(s.Root()) != 2 {
if s.getHeight(s.root) != 2 {
t.Fatal("invalid height")
}
if s.Hash() != common.HexToHash("dfc69c94013a8b3c65395625a719a87534a7cfd38719251ad8c8ea7fe79f065e") {
@ -81,7 +81,7 @@ func TestOneStemColocatedValues(t *testing.T) {
if err := s.Insert(common.HexToHash("00000000000000000000000000000000000000000000000000000000000000FF").Bytes(), fourKey[:], nil); err != nil {
t.Fatal(err)
}
if s.GetHeight(s.Root()) != 1 {
if s.getHeight(s.root) != 1 {
t.Fatal("invalid height")
}
}
@ -102,7 +102,7 @@ func TestTwoStemColocatedValues(t *testing.T) {
if err := s.Insert(common.HexToHash("8000000000000000000000000000000000000000000000000000000000000004").Bytes(), twoKey[:], nil); err != nil {
t.Fatal(err)
}
if s.GetHeight(s.Root()) != 2 {
if s.getHeight(s.root) != 2 {
t.Fatal("invalid height")
}
}
@ -118,7 +118,7 @@ func TestTwoKeysMatchFirst42Bits(t *testing.T) {
if err := s.Insert(key2, twoKey[:], nil); err != nil {
t.Fatal(err)
}
if s.GetHeight(s.Root()) != 1+42+1 {
if s.getHeight(s.root) != 1+42+1 {
t.Fatal("invalid height")
}
}
@ -131,7 +131,7 @@ func TestInsertDuplicateKey(t *testing.T) {
if err := s.Insert(oneKey[:], twoKey[:], nil); err != nil {
t.Fatal(err)
}
if s.GetHeight(s.Root()) != 1 {
if s.getHeight(s.root) != 1 {
t.Fatal("invalid height")
}
// Verify that the value is updated
@ -153,7 +153,7 @@ func TestLargeNumberOfEntries(t *testing.T) {
t.Fatal(err)
}
}
height := s.GetHeight(s.Root())
height := s.getHeight(s.root)
if height != 1+8 {
t.Fatalf("invalid height, wanted %d, got %d", 1+8, height)
}
@ -631,8 +631,8 @@ func TestGetAccountNonMembershipStemRoot(t *testing.T) {
tr := testAccount(t, addr, 42, 100)
// Verify root is a StemNode (single stem inserted).
if tr.store.Root().Kind() != KindStem {
t.Fatalf("expected StemNode root, got kind %d", tr.store.Root().Kind())
if tr.store.root.Kind() != kindStem {
t.Fatalf("expected StemNode root, got kind %d", tr.store.root.Kind())
}
// Query a completely different address — must return nil.
@ -682,8 +682,8 @@ func TestGetAccountNonMembershipInternalRoot(t *testing.T) {
}
// Verify root is an InternalNode.
if tr.store.Root().Kind() != KindInternal {
t.Fatalf("expected InternalNode root, got kind %d", tr.store.Root().Kind())
if tr.store.root.Kind() != kindInternal {
t.Fatalf("expected InternalNode root, got kind %d", tr.store.root.Kind())
}
// Query a non-existent address — must return nil.
@ -705,8 +705,8 @@ func TestGetStorageNonMembershipStemRoot(t *testing.T) {
tr := testAccount(t, addr, 1, 100)
// Verify root is a StemNode.
if tr.store.Root().Kind() != KindStem {
t.Fatalf("expected StemNode root, got kind %d", tr.store.Root().Kind())
if tr.store.root.Kind() != kindStem {
t.Fatalf("expected StemNode root, got kind %d", tr.store.root.Kind())
}
// Query storage for a different address — must return nil, not panic.
@ -747,8 +747,8 @@ func TestGetStorageNonMembershipInternalRoot(t *testing.T) {
t.Fatalf("UpdateStorage error: %v", err)
}
if tr.store.Root().Kind() != KindInternal {
t.Fatalf("expected InternalNode root, got kind %d", tr.store.Root().Kind())
if tr.store.root.Kind() != kindInternal {
t.Fatalf("expected InternalNode root, got kind %d", tr.store.root.Kind())
}
// Query storage for a non-existent address — must return nil.