mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-16 03:41:35 +00:00
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.
This commit is contained in:
parent
c1c65b9a56
commit
2a7effb6ca
1 changed files with 69 additions and 0 deletions
|
|
@ -486,6 +486,75 @@ func TestDeleteAccountDoesNotAffectMainStorage(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestDeleteAccountPreservesHeaderStorage verifies that DeleteAccount does
|
||||||
|
// not clobber header-range storage slots (key[31] < 64), which live at the
|
||||||
|
// SAME stem as BasicData/CodeHash but at offsets 64-127. The safety here
|
||||||
|
// relies on StemNode.InsertValuesAtStem treating nil entries in the values
|
||||||
|
// slice as "do not overwrite"; this test pins that invariant so a future
|
||||||
|
// change cannot silently corrupt slots 0-63 of any contract.
|
||||||
|
func TestDeleteAccountPreservesHeaderStorage(t *testing.T) {
|
||||||
|
tr := newTestTrie(t)
|
||||||
|
addr := common.HexToAddress("0x1234567890abcdef1234567890abcdef12345678")
|
||||||
|
codeHash := common.HexToHash("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470")
|
||||||
|
|
||||||
|
// Create account.
|
||||||
|
if err := tr.UpdateAccount(addr, makeAccount(1, 100, codeHash), 0); err != nil {
|
||||||
|
t.Fatalf("UpdateAccount: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a second, unrelated account so the root promotes from StemNode
|
||||||
|
// to InternalNode. BinaryTrie.GetStorage walks via root.Get, which is
|
||||||
|
// only implemented on InternalNode/Empty — calling it with a StemNode
|
||||||
|
// root panics. The existing main-storage test gets away with this because
|
||||||
|
// the main-storage slot lands on a separate stem and forces the same
|
||||||
|
// promotion implicitly; here we want a same-stem header slot, so the
|
||||||
|
// promotion has to come from a second account.
|
||||||
|
other := common.HexToAddress("0xabcdef1234567890abcdef1234567890abcdef12")
|
||||||
|
if err := tr.UpdateAccount(other, makeAccount(0, 0, common.Hash{}), 0); err != nil {
|
||||||
|
t.Fatalf("UpdateAccount(other): %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write a header-range storage slot — key[:31] == 0 and key[31] < 64
|
||||||
|
// — which routes through the header branch in GetBinaryTreeKeyStorageSlot
|
||||||
|
// and lands on the same stem as BasicData/CodeHash.
|
||||||
|
var slot [HashSize]byte
|
||||||
|
slot[31] = 5
|
||||||
|
value := []byte{0xde, 0xad, 0xbe, 0xef}
|
||||||
|
if err := tr.UpdateStorage(addr, slot[:], value); err != nil {
|
||||||
|
t.Fatalf("UpdateStorage: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the account.
|
||||||
|
if err := tr.DeleteAccount(addr); err != nil {
|
||||||
|
t.Fatalf("DeleteAccount: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Account metadata should be gone.
|
||||||
|
got, err := tr.GetAccount(addr)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("GetAccount after delete: %v", err)
|
||||||
|
}
|
||||||
|
if got != nil {
|
||||||
|
t.Fatalf("GetAccount after delete: got %+v, want nil", got)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Header storage slot must survive — DeleteAccount only writes offsets
|
||||||
|
// BasicDataLeafKey, CodeHashLeafKey, and accountDeletedMarkerKey, leaving
|
||||||
|
// the header-storage offsets (64-127) untouched.
|
||||||
|
stored, err := tr.GetStorage(addr, slot[:])
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("GetStorage after DeleteAccount: %v", err)
|
||||||
|
}
|
||||||
|
if len(stored) == 0 {
|
||||||
|
t.Fatal("header storage slot was wiped by DeleteAccount, expected it to survive")
|
||||||
|
}
|
||||||
|
var expected [HashSize]byte
|
||||||
|
copy(expected[HashSize-len(value):], value)
|
||||||
|
if !bytes.Equal(stored, expected[:]) {
|
||||||
|
t.Fatalf("header storage slot: got %x, want %x", stored, expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestBinaryTrieWitness(t *testing.T) {
|
func TestBinaryTrieWitness(t *testing.T) {
|
||||||
tracer := trie.NewPrevalueTracer()
|
tracer := trie.NewPrevalueTracer()
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue