2019-05-27 13:51:49 +00:00
|
|
|
package trie
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"fmt"
|
2020-05-26 16:53:50 +00:00
|
|
|
"reflect"
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/holiman/uint256"
|
|
|
|
|
2021-05-20 18:25:53 +00:00
|
|
|
"github.com/ledgerwatch/erigon/common"
|
|
|
|
"github.com/ledgerwatch/erigon/core/types/accounts"
|
|
|
|
"github.com/ledgerwatch/erigon/crypto"
|
2019-05-27 13:51:49 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func TestTrieDeleteSubtree_ShortNode(t *testing.T) {
|
|
|
|
trie := newEmpty()
|
|
|
|
key := []byte{uint8(1)}
|
|
|
|
val := []byte("1")
|
|
|
|
|
2020-02-06 10:53:09 +00:00
|
|
|
trie.Update(key, val)
|
2019-05-27 13:51:49 +00:00
|
|
|
v, ok := trie.Get(key)
|
|
|
|
if ok == false || bytes.Equal(v, val) == false {
|
|
|
|
t.Fatal("incorrect")
|
|
|
|
}
|
|
|
|
//remove unknown
|
2020-02-06 10:53:09 +00:00
|
|
|
trie.DeleteSubtree([]byte{uint8(2)})
|
2019-05-27 13:51:49 +00:00
|
|
|
v, ok = trie.Get(key)
|
|
|
|
if ok == false || bytes.Equal(v, val) == false {
|
|
|
|
t.Fatal("incorrect")
|
|
|
|
}
|
|
|
|
|
|
|
|
//remove by key
|
2020-02-06 10:53:09 +00:00
|
|
|
trie.DeleteSubtree(key)
|
2019-05-27 13:51:49 +00:00
|
|
|
|
|
|
|
v, _ = trie.Get(key)
|
|
|
|
if v != nil {
|
|
|
|
t.Fatal("must be false")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestTrieDeleteSubtree_ShortNode_Debug(t *testing.T) {
|
|
|
|
trie := newEmpty()
|
|
|
|
addr1 := common.HexToAddress("0x6295ee1b4f6dd65047762f924ecd367c17eabf8f")
|
|
|
|
addr2 := common.HexToAddress("0xfc597da4849c0d854629216d9e297bbca7bb4616")
|
|
|
|
|
|
|
|
key := []byte{uint8(1)}
|
|
|
|
val := []byte{uint8(1)}
|
|
|
|
|
2021-07-17 02:09:56 +00:00
|
|
|
keyHash, err := common.HashData(key)
|
2019-05-27 13:51:49 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
addrHash1, err := common.HashData(addr1[:])
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
addrHash2, err := common.HashData(addr2[:])
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
key1 := GenerateCompositeTrieKey(addrHash1, keyHash)
|
|
|
|
key2 := GenerateCompositeTrieKey(addrHash2, keyHash)
|
2020-02-06 10:53:09 +00:00
|
|
|
trie.Update(key1, val)
|
|
|
|
trie.Update(key2, val)
|
2019-05-27 13:51:49 +00:00
|
|
|
|
|
|
|
trie.PrintTrie()
|
2020-02-06 10:53:09 +00:00
|
|
|
trie.DeleteSubtree(addrHash1.Bytes())
|
2019-05-27 13:51:49 +00:00
|
|
|
trie.PrintTrie()
|
|
|
|
|
|
|
|
v, ok := trie.Get(key2)
|
|
|
|
if ok == false || bytes.Equal(v, val) == false {
|
|
|
|
t.Fatal("incorrect")
|
|
|
|
}
|
|
|
|
|
|
|
|
v, _ = trie.Get(key1)
|
|
|
|
if v != nil {
|
|
|
|
t.Fatal("must be nil")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func GenerateCompositeTrieKey(addressHash common.Hash, seckey common.Hash) []byte {
|
|
|
|
compositeKey := make([]byte, 0, common.HashLength+common.HashLength)
|
|
|
|
compositeKey = append(compositeKey, addressHash[:]...)
|
|
|
|
compositeKey = append(compositeKey, seckey[:]...)
|
|
|
|
return compositeKey
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestTrieDeleteSubtree_ShortNode_LongPrefix(t *testing.T) {
|
|
|
|
trie := newEmpty()
|
|
|
|
key := []byte{uint8(1), uint8(1)}
|
|
|
|
prefix := []byte{uint8(1)}
|
|
|
|
val := []byte("1")
|
|
|
|
|
2020-02-06 10:53:09 +00:00
|
|
|
trie.Update(key, val)
|
2019-05-27 13:51:49 +00:00
|
|
|
v, ok := trie.Get(key)
|
|
|
|
if ok == false || bytes.Equal(v, val) == false {
|
|
|
|
t.Fatal("incorrect")
|
|
|
|
}
|
|
|
|
//remove unknown
|
2020-02-06 10:53:09 +00:00
|
|
|
trie.Delete([]byte{uint8(2)})
|
2019-05-27 13:51:49 +00:00
|
|
|
v, ok = trie.Get(key)
|
|
|
|
if ok == false || bytes.Equal(v, val) == false {
|
|
|
|
t.Fatal("incorrect")
|
|
|
|
}
|
|
|
|
|
|
|
|
//remove by key
|
2020-02-06 10:53:09 +00:00
|
|
|
trie.DeleteSubtree(prefix)
|
2019-05-27 13:51:49 +00:00
|
|
|
v, _ = trie.Get(key)
|
|
|
|
t.Log(v)
|
|
|
|
if v != nil {
|
|
|
|
t.Fatal("must be false")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestTrieDeleteSubtree_DuoNode(t *testing.T) {
|
|
|
|
trie := newEmpty()
|
|
|
|
key := []byte{uint8(1)}
|
|
|
|
val := []byte{uint8(1)}
|
|
|
|
keyExist := []byte{uint8(2)}
|
|
|
|
valExist := []byte{uint8(2)}
|
|
|
|
|
2020-02-06 10:53:09 +00:00
|
|
|
trie.Update(key, val)
|
|
|
|
trie.Update(keyExist, valExist)
|
2019-05-27 13:51:49 +00:00
|
|
|
v, ok := trie.Get(key)
|
|
|
|
if ok == false || bytes.Equal(v, val) == false {
|
|
|
|
t.Fatal("incorrect")
|
|
|
|
}
|
|
|
|
|
2020-02-06 10:53:09 +00:00
|
|
|
trie.DeleteSubtree(key)
|
2019-05-27 13:51:49 +00:00
|
|
|
|
|
|
|
v, _ = trie.Get(key)
|
|
|
|
if v != nil {
|
|
|
|
t.Fatal("must be nil")
|
|
|
|
}
|
|
|
|
v, _ = trie.Get(keyExist)
|
|
|
|
if bytes.Equal(v, valExist) == false {
|
|
|
|
t.Fatal("must be false")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestTrieDeleteSubtree_TwoDuoNode_FullMatch(t *testing.T) {
|
|
|
|
trie := newEmpty()
|
|
|
|
key1 := []byte{uint8(1), uint8(1), uint8(1)}
|
|
|
|
key2 := []byte{uint8(1), uint8(1), uint8(2)}
|
|
|
|
key3 := []byte{uint8(1), uint8(2), uint8(3)}
|
|
|
|
|
|
|
|
val1 := []byte{uint8(1)}
|
|
|
|
val2 := []byte{uint8(2)}
|
|
|
|
val3 := []byte{uint8(3)}
|
|
|
|
|
2020-02-06 10:53:09 +00:00
|
|
|
trie.Update(key1, val1)
|
|
|
|
trie.Update(key2, val2)
|
|
|
|
trie.Update(key3, val3)
|
2019-05-27 13:51:49 +00:00
|
|
|
|
2020-02-06 10:53:09 +00:00
|
|
|
trie.DeleteSubtree(key1)
|
|
|
|
trie.DeleteSubtree(key2)
|
2019-05-27 13:51:49 +00:00
|
|
|
|
|
|
|
v, _ := trie.Get(key1)
|
|
|
|
if v != nil {
|
|
|
|
t.Fatal("must be nil", v)
|
|
|
|
}
|
|
|
|
|
|
|
|
v, _ = trie.Get(key2)
|
|
|
|
if v != nil {
|
|
|
|
t.Fatal("must be nil", v)
|
|
|
|
}
|
|
|
|
|
|
|
|
v, _ = trie.Get(key3)
|
|
|
|
if bytes.Equal(v, val3) != true {
|
|
|
|
t.Fatal("must be equals", v)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestTrieDeleteSubtree_DuoNode_PartialMatch(t *testing.T) {
|
|
|
|
trie := newEmpty()
|
|
|
|
|
|
|
|
key1 := []byte{uint8(1), uint8(1), uint8(1)}
|
|
|
|
key2 := []byte{uint8(1), uint8(1), uint8(2)}
|
|
|
|
key3 := []byte{uint8(1), uint8(2), uint8(3)}
|
|
|
|
partialKey := []byte{uint8(1), uint8(1)}
|
|
|
|
|
|
|
|
val1 := []byte{uint8(1)}
|
|
|
|
val2 := []byte{uint8(2)}
|
|
|
|
val3 := []byte{uint8(3)}
|
|
|
|
|
2020-02-06 10:53:09 +00:00
|
|
|
trie.Update(key1, val1)
|
|
|
|
trie.Update(key2, val2)
|
|
|
|
trie.Update(key3, val3)
|
2019-05-27 13:51:49 +00:00
|
|
|
|
2020-02-06 10:53:09 +00:00
|
|
|
trie.DeleteSubtree(partialKey)
|
2019-05-27 13:51:49 +00:00
|
|
|
v, _ := trie.Get(key1)
|
|
|
|
if v != nil {
|
|
|
|
t.Fatal("must be nil", v)
|
|
|
|
}
|
|
|
|
|
|
|
|
v, _ = trie.Get(key2)
|
|
|
|
if v != nil {
|
|
|
|
t.Fatal("must be nil", v)
|
|
|
|
}
|
|
|
|
|
|
|
|
v, _ = trie.Get(key3)
|
|
|
|
if bytes.Equal(v, val3) != true {
|
|
|
|
t.Fatal("must be equals", v)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestTrieDeleteSubtree_FromFullNode_PartialMatch(t *testing.T) {
|
|
|
|
trie := newEmpty()
|
|
|
|
key1 := []byte{uint8(1), uint8(1), uint8(1)}
|
|
|
|
key2 := []byte{uint8(1), uint8(1), uint8(2)}
|
|
|
|
key3 := []byte{uint8(1), uint8(1), uint8(3)}
|
|
|
|
key4 := []byte{uint8(1), uint8(2), uint8(4)}
|
|
|
|
partialKey := []byte{uint8(1), uint8(1)}
|
|
|
|
|
|
|
|
val1 := []byte{uint8(1)}
|
|
|
|
val2 := []byte{uint8(2)}
|
|
|
|
val3 := []byte{uint8(3)}
|
|
|
|
val4 := []byte{uint8(4)}
|
|
|
|
|
2020-02-06 10:53:09 +00:00
|
|
|
trie.Update(key1, val1)
|
|
|
|
trie.Update(key2, val2)
|
|
|
|
trie.Update(key3, val3)
|
|
|
|
trie.Update(key4, val4)
|
2019-05-27 13:51:49 +00:00
|
|
|
|
2020-02-06 10:53:09 +00:00
|
|
|
trie.DeleteSubtree(partialKey)
|
2019-05-27 13:51:49 +00:00
|
|
|
|
|
|
|
v, _ := trie.Get(key1)
|
|
|
|
if v != nil {
|
|
|
|
t.Fatal("must be nil", v)
|
|
|
|
}
|
|
|
|
|
|
|
|
v, _ = trie.Get(key2)
|
|
|
|
if v != nil {
|
|
|
|
t.Fatal("must be nil", v)
|
|
|
|
}
|
|
|
|
|
|
|
|
v, _ = trie.Get(key3)
|
|
|
|
if v != nil {
|
|
|
|
t.Fatal("must be nil", v)
|
|
|
|
}
|
|
|
|
|
|
|
|
v, _ = trie.Get(key4)
|
|
|
|
if bytes.Equal(v, val4) != true {
|
|
|
|
t.Fatal("must be equals", v)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestTrieDeleteSubtree_RemoveFullNode_PartialMatch(t *testing.T) {
|
|
|
|
trie := newEmpty()
|
|
|
|
key1 := []byte{uint8(1), uint8(1), uint8(1), uint8(1)}
|
|
|
|
key2 := []byte{uint8(1), uint8(1), uint8(2), uint8(1)}
|
|
|
|
key3 := []byte{uint8(1), uint8(1), uint8(3), uint8(1)}
|
|
|
|
key4 := []byte{uint8(1), uint8(2), uint8(4)}
|
|
|
|
partialKey := []byte{uint8(1), uint8(1)}
|
|
|
|
|
|
|
|
val1 := []byte{uint8(1)}
|
|
|
|
val2 := []byte{uint8(2)}
|
|
|
|
val3 := []byte{uint8(3)}
|
|
|
|
val4 := []byte{uint8(4)}
|
|
|
|
|
2020-02-06 10:53:09 +00:00
|
|
|
trie.Update(key1, val1)
|
|
|
|
trie.Update(key2, val2)
|
|
|
|
trie.Update(key3, val3)
|
|
|
|
trie.Update(key4, val4)
|
2019-05-27 13:51:49 +00:00
|
|
|
|
2020-02-06 10:53:09 +00:00
|
|
|
trie.DeleteSubtree(partialKey)
|
2019-05-27 13:51:49 +00:00
|
|
|
|
|
|
|
v, _ := trie.Get(key1)
|
|
|
|
if v != nil {
|
|
|
|
t.Fatal("must be nil", v)
|
|
|
|
}
|
|
|
|
|
|
|
|
v, _ = trie.Get(key2)
|
|
|
|
if v != nil {
|
|
|
|
t.Fatal("must be nil", v)
|
|
|
|
}
|
|
|
|
|
|
|
|
v, _ = trie.Get(key3)
|
|
|
|
if v != nil {
|
|
|
|
t.Fatal("must be nil", v)
|
|
|
|
}
|
|
|
|
|
|
|
|
v, _ = trie.Get(key4)
|
|
|
|
if bytes.Equal(v, val4) != true {
|
|
|
|
t.Fatal("must be equals", v)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestTrieDeleteSubtree_FullNode_FullMatch(t *testing.T) {
|
|
|
|
trie := newEmpty()
|
|
|
|
key1 := []byte{uint8(1), uint8(1), uint8(1)}
|
|
|
|
key2 := []byte{uint8(1), uint8(1), uint8(2)}
|
|
|
|
key3 := []byte{uint8(1), uint8(1), uint8(3)}
|
|
|
|
key4 := []byte{uint8(1), uint8(2), uint8(4)}
|
|
|
|
|
|
|
|
val1 := []byte{uint8(1)}
|
|
|
|
val2 := []byte{uint8(2)}
|
|
|
|
val3 := []byte{uint8(3)}
|
|
|
|
val4 := []byte{uint8(4)}
|
|
|
|
|
2020-02-06 10:53:09 +00:00
|
|
|
trie.Update(key1, val1)
|
|
|
|
trie.Update(key2, val2)
|
|
|
|
trie.Update(key3, val3)
|
|
|
|
trie.Update(key4, val4)
|
2019-05-27 13:51:49 +00:00
|
|
|
|
2020-02-06 10:53:09 +00:00
|
|
|
trie.DeleteSubtree(key1)
|
|
|
|
trie.DeleteSubtree(key2)
|
2019-05-27 13:51:49 +00:00
|
|
|
|
|
|
|
v, _ := trie.Get(key1)
|
|
|
|
if v != nil {
|
|
|
|
t.Fatal("must be nil", v)
|
|
|
|
}
|
|
|
|
|
|
|
|
v, _ = trie.Get(key2)
|
|
|
|
if v != nil {
|
|
|
|
t.Fatal("must be nil", v)
|
|
|
|
}
|
|
|
|
|
|
|
|
v, _ = trie.Get(key3)
|
|
|
|
if bytes.Equal(v, val3) != true {
|
|
|
|
t.Fatal("must be equals", v)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestTrieDeleteSubtree_ValueNode_PartialMatch(t *testing.T) {
|
|
|
|
trie := newEmpty()
|
|
|
|
key := []byte{uint8(1)}
|
|
|
|
val := []byte{uint8(1)}
|
|
|
|
keyExist := []byte{uint8(2)}
|
|
|
|
valExist := []byte{uint8(2)}
|
2020-02-06 10:53:09 +00:00
|
|
|
trie.Update(key, val)
|
|
|
|
trie.Update(keyExist, valExist)
|
2019-05-27 13:51:49 +00:00
|
|
|
v, ok := trie.Get(key)
|
|
|
|
if ok == false || bytes.Equal(v, val) == false {
|
|
|
|
t.Fatal("incorrect")
|
|
|
|
}
|
2020-02-06 10:53:09 +00:00
|
|
|
trie.DeleteSubtree(key)
|
2019-05-27 13:51:49 +00:00
|
|
|
v, _ = trie.Get(key)
|
|
|
|
if v != nil {
|
|
|
|
t.Fatal("must be empty")
|
|
|
|
}
|
|
|
|
v, ok = trie.Get(keyExist)
|
|
|
|
if ok == false || bytes.Equal(v, valExist) == false {
|
|
|
|
t.Fatal("must be true")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestAccountNotRemovedAfterRemovingSubtrieAfterAccount(t *testing.T) {
|
|
|
|
acc := &accounts.Account{
|
|
|
|
Nonce: 2,
|
|
|
|
Incarnation: 2,
|
2021-06-04 16:25:28 +00:00
|
|
|
Balance: *uint256.NewInt(200),
|
2019-05-27 13:51:49 +00:00
|
|
|
Root: EmptyRoot,
|
|
|
|
CodeHash: emptyState,
|
|
|
|
}
|
|
|
|
|
|
|
|
trie := newEmpty()
|
|
|
|
key, err := crypto.GenerateKey()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
addrHash, err := common.HashData(crypto.PubkeyToAddress(key.PublicKey).Bytes())
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
trie.UpdateAccount(addrHash.Bytes(), acc)
|
|
|
|
|
|
|
|
accRes1, _ := trie.GetAccount(addrHash.Bytes())
|
|
|
|
if reflect.DeepEqual(acc, accRes1) == false {
|
|
|
|
t.Fatal("not equal", addrHash)
|
|
|
|
}
|
|
|
|
|
|
|
|
val1 := []byte("1")
|
|
|
|
dataKey1, err := common.HashData([]byte("1"))
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
val2 := []byte("2")
|
|
|
|
dataKey2, err := common.HashData([]byte("2"))
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
fmt.Println("=============================")
|
|
|
|
trie.PrintTrie()
|
|
|
|
fmt.Println("=============================")
|
|
|
|
ck1 := GenerateCompositeTrieKey(addrHash, dataKey1)
|
|
|
|
ck2 := GenerateCompositeTrieKey(addrHash, dataKey2)
|
2020-02-06 10:53:09 +00:00
|
|
|
trie.Update(ck1, val1)
|
|
|
|
trie.Update(ck2, val2)
|
2019-05-27 13:51:49 +00:00
|
|
|
|
2020-02-06 10:53:09 +00:00
|
|
|
trie.DeleteSubtree(addrHash.Bytes())
|
2019-05-27 13:51:49 +00:00
|
|
|
|
|
|
|
accRes2, _ := trie.GetAccount(addrHash.Bytes())
|
|
|
|
if reflect.DeepEqual(acc, accRes2) == false {
|
|
|
|
t.Fatal("account was deleted", addrHash)
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|