trie/bintrie: assign t.root only on successful DeleteAccount

DeleteAccount was assigning t.root unconditionally and then
returning the error, matching UpdateAccount but diverging from the
safer pattern in UpdateStorage/DeleteStorage (assign to a temp,
return on error, mutate t.root only on success).

This is a partial fix to a broader footgun: InternalNode.Insert-
ValuesAtStem mutates its receiver in place on error paths, so the
root pointer is already shared and the mutation has already leaked
by the time we return. The proper fix is either rewriting that
function or documenting the contract; both are out of scope here.
At minimum, stop pointing t.root at whatever InsertValuesAtStem
returned on error (which could be nil or a different node
altogether), and bring DeleteAccount in line with its DeleteStorage
sibling.
This commit is contained in:
CPerezz 2026-04-08 12:09:23 +02:00
parent e1673c1622
commit 090b757dc1
No known key found for this signature in database
GPG key ID: 62045F34B97177DD

View file

@ -317,7 +317,6 @@ func (t *BinaryTrie) UpdateStorage(address common.Address, key, value []byte) er
// enumerate every slot of a given account.
func (t *BinaryTrie) DeleteAccount(addr common.Address) error {
var (
err error
zeroBlob [HashSize]byte
values = make([][]byte, StemNodeWidth)
stem = GetBinaryTreeKey(addr, zero[:])
@ -330,10 +329,11 @@ func (t *BinaryTrie) DeleteAccount(addr common.Address) error {
// subsequent read. See GetAccount's deletion branch around trie.go:219.
values[accountDeletedMarkerKey] = zeroBlob[:]
t.root, err = t.root.InsertValuesAtStem(stem, values, t.nodeResolver, 0)
root, err := t.root.InsertValuesAtStem(stem, values, t.nodeResolver, 0)
if err != nil {
return fmt.Errorf("DeleteAccount (%x) error: %v", addr, err)
}
t.root = root
return nil
}