Skip to content

Commit 2a7effb

Browse files
committed
trie/bintrie: test DeleteAccount preserves header storage
Header-range storage slots (key[31] < 64) live at the same stem as BasicData and CodeHash, at offsets 64-127. The existing TestDeleteAccountDoesNotAffectMainStorage uses a main-storage slot (key[31] = 0x80) which lives at a different stem, giving zero coverage of the same-stem case. DeleteAccount's safety against header storage relies on StemNode.InsertValuesAtStem treating nil entries as "do not overwrite". Pin that invariant so a future change filling the values slice with zeroBlob[:] instead of leaving nils cannot silently corrupt slots 0-63 of any contract.
1 parent c1c65b9 commit 2a7effb

File tree

1 file changed

+69
-0
lines changed

1 file changed

+69
-0
lines changed

trie/bintrie/trie_test.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,75 @@ func TestDeleteAccountDoesNotAffectMainStorage(t *testing.T) {
486486
}
487487
}
488488

489+
// TestDeleteAccountPreservesHeaderStorage verifies that DeleteAccount does
490+
// not clobber header-range storage slots (key[31] < 64), which live at the
491+
// SAME stem as BasicData/CodeHash but at offsets 64-127. The safety here
492+
// relies on StemNode.InsertValuesAtStem treating nil entries in the values
493+
// slice as "do not overwrite"; this test pins that invariant so a future
494+
// change cannot silently corrupt slots 0-63 of any contract.
495+
func TestDeleteAccountPreservesHeaderStorage(t *testing.T) {
496+
tr := newTestTrie(t)
497+
addr := common.HexToAddress("0x1234567890abcdef1234567890abcdef12345678")
498+
codeHash := common.HexToHash("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470")
499+
500+
// Create account.
501+
if err := tr.UpdateAccount(addr, makeAccount(1, 100, codeHash), 0); err != nil {
502+
t.Fatalf("UpdateAccount: %v", err)
503+
}
504+
505+
// Create a second, unrelated account so the root promotes from StemNode
506+
// to InternalNode. BinaryTrie.GetStorage walks via root.Get, which is
507+
// only implemented on InternalNode/Empty — calling it with a StemNode
508+
// root panics. The existing main-storage test gets away with this because
509+
// the main-storage slot lands on a separate stem and forces the same
510+
// promotion implicitly; here we want a same-stem header slot, so the
511+
// promotion has to come from a second account.
512+
other := common.HexToAddress("0xabcdef1234567890abcdef1234567890abcdef12")
513+
if err := tr.UpdateAccount(other, makeAccount(0, 0, common.Hash{}), 0); err != nil {
514+
t.Fatalf("UpdateAccount(other): %v", err)
515+
}
516+
517+
// Write a header-range storage slot — key[:31] == 0 and key[31] < 64
518+
// — which routes through the header branch in GetBinaryTreeKeyStorageSlot
519+
// and lands on the same stem as BasicData/CodeHash.
520+
var slot [HashSize]byte
521+
slot[31] = 5
522+
value := []byte{0xde, 0xad, 0xbe, 0xef}
523+
if err := tr.UpdateStorage(addr, slot[:], value); err != nil {
524+
t.Fatalf("UpdateStorage: %v", err)
525+
}
526+
527+
// Delete the account.
528+
if err := tr.DeleteAccount(addr); err != nil {
529+
t.Fatalf("DeleteAccount: %v", err)
530+
}
531+
532+
// Account metadata should be gone.
533+
got, err := tr.GetAccount(addr)
534+
if err != nil {
535+
t.Fatalf("GetAccount after delete: %v", err)
536+
}
537+
if got != nil {
538+
t.Fatalf("GetAccount after delete: got %+v, want nil", got)
539+
}
540+
541+
// Header storage slot must survive — DeleteAccount only writes offsets
542+
// BasicDataLeafKey, CodeHashLeafKey, and accountDeletedMarkerKey, leaving
543+
// the header-storage offsets (64-127) untouched.
544+
stored, err := tr.GetStorage(addr, slot[:])
545+
if err != nil {
546+
t.Fatalf("GetStorage after DeleteAccount: %v", err)
547+
}
548+
if len(stored) == 0 {
549+
t.Fatal("header storage slot was wiped by DeleteAccount, expected it to survive")
550+
}
551+
var expected [HashSize]byte
552+
copy(expected[HashSize-len(value):], value)
553+
if !bytes.Equal(stored, expected[:]) {
554+
t.Fatalf("header storage slot: got %x, want %x", stored, expected)
555+
}
556+
}
557+
489558
func TestBinaryTrieWitness(t *testing.T) {
490559
tracer := trie.NewPrevalueTracer()
491560

0 commit comments

Comments
 (0)