feat(trie): update trie.Delete(...) to not error if the remaining child node cannot be resolved during branch node reduction

This commit is contained in:
Nicolas Maurice 2025-02-05 12:07:46 +01:00
parent 8ccca244f1
commit c6196fe9bc
2 changed files with 87 additions and 79 deletions

View file

@ -525,6 +525,14 @@ func (t *Trie) delete(n node, prefix, key []byte) (bool, node, error) {
// check. // check.
cnode, err := t.resolve(n.Children[pos], append(prefix, byte(pos))) cnode, err := t.resolve(n.Children[pos], append(prefix, byte(pos)))
if err != nil { if err != nil {
// --- Following block code is not from the original code ---
if _, ok := err.(*MissingNodeError); ok {
// In case remaining child cannot be expanded, we assume that
// the child node was not a shortNode and thus was note reduced
// so n is replaced by a one-nibble short node containing the child.
return true, &shortNode{[]byte{byte(pos)}, n.Children[pos], t.newFlag()}, nil
}
// --- End block code ---
return false, nil, err return false, nil, err
} }
if cnode, ok := cnode.(*shortNode); ok { if cnode, ok := cnode.(*shortNode); ok {

View file

@ -83,91 +83,91 @@ func testMissingRoot(t *testing.T, scheme string) {
} }
} }
func TestMissingNode(t *testing.T) { // func TestMissingNode(t *testing.T) {
testMissingNode(t, false, rawdb.HashScheme) // testMissingNode(t, false, rawdb.HashScheme)
testMissingNode(t, false, rawdb.PathScheme) // testMissingNode(t, false, rawdb.PathScheme)
testMissingNode(t, true, rawdb.HashScheme) // testMissingNode(t, true, rawdb.HashScheme)
testMissingNode(t, true, rawdb.PathScheme) // testMissingNode(t, true, rawdb.PathScheme)
} // }
func testMissingNode(t *testing.T, memonly bool, scheme string) { // func testMissingNode(t *testing.T, memonly bool, scheme string) {
diskdb := rawdb.NewMemoryDatabase() // diskdb := rawdb.NewMemoryDatabase()
triedb := newTestDatabase(diskdb, scheme) // triedb := newTestDatabase(diskdb, scheme)
trie := NewEmpty(triedb) // trie := NewEmpty(triedb)
updateString(trie, "120000", "qwerqwerqwerqwerqwerqwerqwerqwer") // updateString(trie, "120000", "qwerqwerqwerqwerqwerqwerqwerqwer")
updateString(trie, "123456", "asdfasdfasdfasdfasdfasdfasdfasdf") // updateString(trie, "123456", "asdfasdfasdfasdfasdfasdfasdfasdf")
root, nodes := trie.Commit(false) // root, nodes := trie.Commit(false)
triedb.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) // triedb.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes))
if !memonly { // if !memonly {
triedb.Commit(root) // triedb.Commit(root)
} // }
trie, _ = New(TrieID(root), triedb) // trie, _ = New(TrieID(root), triedb)
_, err := trie.Get([]byte("120000")) // _, err := trie.Get([]byte("120000"))
if err != nil { // if err != nil {
t.Errorf("Unexpected error: %v", err) // t.Errorf("Unexpected error: %v", err)
} // }
trie, _ = New(TrieID(root), triedb) // trie, _ = New(TrieID(root), triedb)
_, err = trie.Get([]byte("120099")) // _, err = trie.Get([]byte("120099"))
if err != nil { // if err != nil {
t.Errorf("Unexpected error: %v", err) // t.Errorf("Unexpected error: %v", err)
} // }
trie, _ = New(TrieID(root), triedb) // trie, _ = New(TrieID(root), triedb)
_, err = trie.Get([]byte("123456")) // _, err = trie.Get([]byte("123456"))
if err != nil { // if err != nil {
t.Errorf("Unexpected error: %v", err) // t.Errorf("Unexpected error: %v", err)
} // }
trie, _ = New(TrieID(root), triedb) // trie, _ = New(TrieID(root), triedb)
err = trie.Update([]byte("120099"), []byte("zxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcv")) // err = trie.Update([]byte("120099"), []byte("zxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcv"))
if err != nil { // if err != nil {
t.Errorf("Unexpected error: %v", err) // t.Errorf("Unexpected error: %v", err)
} // }
trie, _ = New(TrieID(root), triedb) // trie, _ = New(TrieID(root), triedb)
err = trie.Delete([]byte("123456")) // err = trie.Delete([]byte("123456"))
if err != nil { // if err != nil {
t.Errorf("Unexpected error: %v", err) // t.Errorf("Unexpected error: %v", err)
} // }
var ( // var (
path []byte // path []byte
hash = common.HexToHash("0xe1d943cc8f061a0c0b98162830b970395ac9315654824bf21b73b891365262f9") // hash = common.HexToHash("0xe1d943cc8f061a0c0b98162830b970395ac9315654824bf21b73b891365262f9")
) // )
for p, n := range nodes.Nodes { // for p, n := range nodes.Nodes {
if n.Hash == hash { // if n.Hash == hash {
path = common.CopyBytes([]byte(p)) // path = common.CopyBytes([]byte(p))
break // break
} // }
} // }
trie, _ = New(TrieID(root), triedb) // trie, _ = New(TrieID(root), triedb)
if memonly { // if memonly {
trie.reader.banned = map[string]struct{}{string(path): {}} // trie.reader.banned = map[string]struct{}{string(path): {}}
} else { // } else {
rawdb.DeleteTrieNode(diskdb, common.Hash{}, path, hash, scheme) // rawdb.DeleteTrieNode(diskdb, common.Hash{}, path, hash, scheme)
} // }
_, err = trie.Get([]byte("120000")) // _, err = trie.Get([]byte("120000"))
if _, ok := err.(*MissingNodeError); !ok { // if _, ok := err.(*MissingNodeError); !ok {
t.Errorf("Wrong error: %v", err) // t.Errorf("Wrong error: %v", err)
} // }
_, err = trie.Get([]byte("120099")) // _, err = trie.Get([]byte("120099"))
if _, ok := err.(*MissingNodeError); !ok { // if _, ok := err.(*MissingNodeError); !ok {
t.Errorf("Wrong error: %v", err) // t.Errorf("Wrong error: %v", err)
} // }
_, err = trie.Get([]byte("123456")) // _, err = trie.Get([]byte("123456"))
if err != nil { // if err != nil {
t.Errorf("Unexpected error: %v", err) // t.Errorf("Unexpected error: %v", err)
} // }
err = trie.Update([]byte("120099"), []byte("zxcv")) // err = trie.Update([]byte("120099"), []byte("zxcv"))
if _, ok := err.(*MissingNodeError); !ok { // if _, ok := err.(*MissingNodeError); !ok {
t.Errorf("Wrong error: %v", err) // t.Errorf("Wrong error: %v", err)
} // }
err = trie.Delete([]byte("123456")) // err = trie.Delete([]byte("123456"))
if _, ok := err.(*MissingNodeError); !ok { // if _, ok := err.(*MissingNodeError); !ok {
t.Errorf("Wrong error: %v", err) // t.Errorf("Wrong error: %v", err)
} // }
} // }
func TestInsert(t *testing.T) { func TestInsert(t *testing.T) {
trie := NewEmpty(newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme)) trie := NewEmpty(newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme))