mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-10 08:51:38 +00:00
also fix serialization
Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
parent
d72ecb31d6
commit
1a41b73fa7
1 changed files with 75 additions and 10 deletions
|
|
@ -107,18 +107,83 @@ func (s *nodeStore) hashInternal(idx uint32) common.Hash {
|
||||||
return node.hash
|
return node.hash
|
||||||
}
|
}
|
||||||
|
|
||||||
// SerializeNode serializes a node into the flat on-disk format.
|
// serializeSubtree recursively collects child hashes from a subtree of InternalNodes.
|
||||||
func (s *nodeStore) serializeNode(ref nodeRef) []byte {
|
// It traverses up to `remainingDepth` levels, storing hashes of bottom-layer children.
|
||||||
|
// position tracks the current index (0 to 2^groupDepth - 1) for bitmap placement.
|
||||||
|
// hashes collects the hashes of present children, bitmap tracks which positions are present.
|
||||||
|
func (s *nodeStore) serializeSubtree(ref nodeRef, remainingDepth int, position int, absoluteDepth int, bitmap []byte, hashes *[]common.Hash) {
|
||||||
|
if remainingDepth == 0 {
|
||||||
|
// Bottom layer: store hash if not empty
|
||||||
|
switch ref.Kind() {
|
||||||
|
case kindEmpty:
|
||||||
|
// Leave bitmap bit unset, don't add hash
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
// StemNode, HashedNode, or InternalNode at boundary: store hash
|
||||||
|
bitmap[position/8] |= 1 << (7 - (position % 8))
|
||||||
|
*hashes = append(*hashes, s.computeHash(ref))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
switch ref.Kind() {
|
switch ref.Kind() {
|
||||||
case kindInternal:
|
case kindInternal:
|
||||||
|
leftPos := position * 2
|
||||||
|
rightPos := position*2 + 1
|
||||||
|
s.serializeSubtree(s.getInternal(ref.Index()).left, remainingDepth-1, leftPos, absoluteDepth+1, bitmap, hashes)
|
||||||
|
s.serializeSubtree(s.getInternal(ref.Index()).right, remainingDepth-1, rightPos, absoluteDepth+1, bitmap, hashes)
|
||||||
|
case kindEmpty:
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
// StemNode or HashedNode encountered before reaching the group's bottom
|
||||||
|
// layer. Compute the leaf bitmap position where this node's hash will
|
||||||
|
// be stored.
|
||||||
|
leafPos := position
|
||||||
|
switch ref.Kind() {
|
||||||
|
case kindStem:
|
||||||
|
sn := s.getStem(ref.Index())
|
||||||
|
// Extend position using the stem's key bits so that
|
||||||
|
// GetValuesAtStem traversal (which follows key bits) finds the hash.
|
||||||
|
for d := 0; d < remainingDepth; d++ {
|
||||||
|
bit := sn.Stem[(absoluteDepth+d)/8] >> (7 - ((absoluteDepth + d) % 8)) & 1
|
||||||
|
leafPos = leafPos*2 + int(bit)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
// HashedNode or unknown: extend all-left (no key bits available).
|
||||||
|
// This matches the all-zero path that resolveNode would follow.
|
||||||
|
leafPos = position << remainingDepth
|
||||||
|
}
|
||||||
|
bitmap[leafPos/8] |= 1 << (7 - (leafPos % 8))
|
||||||
|
*hashes = append(*hashes, s.computeHash(ref))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SerializeNode serializes a node into the flat on-disk format.
|
||||||
|
func (s *nodeStore) serializeNode(ref nodeRef, groupDepth int) []byte {
|
||||||
|
switch ref.Kind() {
|
||||||
|
case kindInternal:
|
||||||
|
// InternalNode group: 1 byte type + 1 byte group depth + variable bitmap + N×32 byte hashes
|
||||||
|
bitmapSize := bitmapSizeForDepth(groupDepth)
|
||||||
|
bitmap := make([]byte, bitmapSize)
|
||||||
|
var hashes []common.Hash
|
||||||
|
|
||||||
node := s.getInternal(ref.Index())
|
node := s.getInternal(ref.Index())
|
||||||
var serialized [NodeTypeBytes + HashSize + HashSize]byte
|
s.serializeSubtree(ref, groupDepth, 0, int(node.depth), bitmap, &hashes)
|
||||||
|
|
||||||
|
// Build serialized output
|
||||||
|
serializedLen := NodeTypeBytes + 1 + bitmapSize + len(hashes)*HashSize
|
||||||
|
serialized := make([]byte, serializedLen)
|
||||||
serialized[0] = nodeTypeInternal
|
serialized[0] = nodeTypeInternal
|
||||||
lh := s.computeHash(node.left)
|
serialized[1] = byte(groupDepth) // group depth => bitmap size for a sparse group
|
||||||
rh := s.computeHash(node.right)
|
copy(serialized[2:2+bitmapSize], bitmap)
|
||||||
copy(serialized[NodeTypeBytes:NodeTypeBytes+HashSize], lh[:])
|
|
||||||
copy(serialized[NodeTypeBytes+HashSize:], rh[:])
|
offset := NodeTypeBytes + 1 + bitmapSize
|
||||||
return serialized[:]
|
for _, h := range hashes {
|
||||||
|
copy(serialized[offset:offset+HashSize], h.Bytes())
|
||||||
|
offset += HashSize
|
||||||
|
}
|
||||||
|
|
||||||
|
return serialized
|
||||||
|
|
||||||
case kindStem:
|
case kindStem:
|
||||||
sn := s.getStem(ref.Index())
|
sn := s.getStem(ref.Index())
|
||||||
|
|
@ -298,7 +363,7 @@ func (s *nodeStore) collectNodes(ref nodeRef, path []byte, flushfn nodeFlushFn,
|
||||||
if err := s.collectChildGroups(node, path, flushfn, groupDepth, groupDepth-1); err != nil {
|
if err := s.collectChildGroups(node, path, flushfn, groupDepth, groupDepth-1); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
flushfn(path, s.computeHash(ref), s.serializeNode(ref))
|
flushfn(path, s.computeHash(ref), s.serializeNode(ref, groupDepth))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
// Not at a group boundary - this shouldn't happen if we're called correctly from root
|
// Not at a group boundary - this shouldn't happen if we're called correctly from root
|
||||||
|
|
@ -309,7 +374,7 @@ func (s *nodeStore) collectNodes(ref nodeRef, path []byte, flushfn nodeFlushFn,
|
||||||
if !sn.dirty {
|
if !sn.dirty {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
flushfn(path, s.computeHash(ref), s.serializeNode(ref))
|
flushfn(path, s.computeHash(ref), s.serializeNode(ref, groupDepth))
|
||||||
sn.dirty = false
|
sn.dirty = false
|
||||||
return nil
|
return nil
|
||||||
case kindHashed:
|
case kindHashed:
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue