mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-12 01:41:36 +00:00
trie/bintrie: move dirty+mustRecompute flip into setValue
The invariant "mutating a value slot must mark the stem for re-hash and re-flush" was enforced by every caller remembering to set both flags after setValue. Moving the flip into setValue itself makes it structurally impossible to forget, and drops the duplicate flag-sets at each callsite. decodeNode's on-disk load path still writes directly to sn.values because loaded stems must retain whatever mustRecompute/dirty state the caller asked for (typically both false).
This commit is contained in:
parent
d216942b7c
commit
f676f04706
2 changed files with 11 additions and 5 deletions
|
|
@ -51,8 +51,15 @@ func (sn *StemNode) allValues() [][]byte {
|
||||||
return sn.values[:]
|
return sn.values[:]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// setValue mutates a value slot and marks the stem for re-hash and
|
||||||
|
// re-flush. This is the only API for post-load value mutation; direct
|
||||||
|
// values[...] writes are reserved for the on-disk load path in
|
||||||
|
// decodeNode, which must leave mustRecompute/dirty at their loaded
|
||||||
|
// state.
|
||||||
func (sn *StemNode) setValue(suffix byte, value []byte) {
|
func (sn *StemNode) setValue(suffix byte, value []byte) {
|
||||||
sn.values[suffix] = value
|
sn.values[suffix] = value
|
||||||
|
sn.mustRecompute = true
|
||||||
|
sn.dirty = true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sn *StemNode) Hash() common.Hash {
|
func (sn *StemNode) Hash() common.Hash {
|
||||||
|
|
|
||||||
|
|
@ -199,12 +199,10 @@ func (s *NodeStore) insertValuesAtStem(ref nodeRef, stem []byte, values [][]byte
|
||||||
case kindStem:
|
case kindStem:
|
||||||
sn := s.getStem(ref.Index())
|
sn := s.getStem(ref.Index())
|
||||||
if sn.Stem == [StemSize]byte(stem[:StemSize]) {
|
if sn.Stem == [StemSize]byte(stem[:StemSize]) {
|
||||||
// Same stem — merge values
|
// Same stem — merge values (setValue marks dirty+mustRecompute)
|
||||||
for i, v := range values {
|
for i, v := range values {
|
||||||
if v != nil {
|
if v != nil {
|
||||||
sn.setValue(byte(i), v)
|
sn.setValue(byte(i), v)
|
||||||
sn.mustRecompute = true
|
|
||||||
sn.dirty = true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ref, nil
|
return ref, nil
|
||||||
|
|
@ -233,7 +231,8 @@ func (s *NodeStore) insertValuesAtStem(ref nodeRef, stem []byte, values [][]byte
|
||||||
return s.insertValuesAtStem(resolved, stem, values, resolver, depth)
|
return s.insertValuesAtStem(resolved, stem, values, resolver, depth)
|
||||||
|
|
||||||
case kindEmpty:
|
case kindEmpty:
|
||||||
// Create new StemNode
|
// Create new StemNode. Flag flips before the value loop so an
|
||||||
|
// all-nil values input still marks the newly-created stem dirty.
|
||||||
stemIdx := s.allocStem()
|
stemIdx := s.allocStem()
|
||||||
sn := s.getStem(stemIdx)
|
sn := s.getStem(stemIdx)
|
||||||
copy(sn.Stem[:], stem[:StemSize])
|
copy(sn.Stem[:], stem[:StemSize])
|
||||||
|
|
@ -242,7 +241,7 @@ func (s *NodeStore) insertValuesAtStem(ref nodeRef, stem []byte, values [][]byte
|
||||||
sn.dirty = true
|
sn.dirty = true
|
||||||
for i, v := range values {
|
for i, v := range values {
|
||||||
if v != nil {
|
if v != nil {
|
||||||
sn.values[i] = v
|
sn.setValue(byte(i), v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return makeRef(kindStem, stemIdx), nil
|
return makeRef(kindStem, stemIdx), nil
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue