2020-01-24 10:58:01 +00:00
|
|
|
package trie
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"fmt"
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/ledgerwatch/turbo-geth/common"
|
|
|
|
)
|
|
|
|
|
|
|
|
type testWitnessStorage []byte
|
|
|
|
|
|
|
|
func (s *testWitnessStorage) GetWitnessesForBlock(_ uint64, _ uint32) ([]byte, error) {
|
|
|
|
return []byte(*s), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func generateKey(i int) []byte {
|
|
|
|
return []byte(fmt.Sprintf("key-number-%05d", i))
|
|
|
|
}
|
|
|
|
|
|
|
|
func generateValue(i int) []byte {
|
|
|
|
return []byte(fmt.Sprintf("value-number-%05d", i))
|
|
|
|
}
|
|
|
|
|
|
|
|
func buildTestTrie(numberOfNodes int) *Trie {
|
|
|
|
trie := New(EmptyRoot)
|
|
|
|
for i := 0; i < numberOfNodes; i++ {
|
2020-02-06 10:53:09 +00:00
|
|
|
trie.Update(generateKey(i), generateValue(i))
|
2020-01-24 10:58:01 +00:00
|
|
|
}
|
|
|
|
return trie
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestRebuildTrie(t *testing.T) {
|
|
|
|
trie1 := buildTestTrie(0)
|
|
|
|
trie2 := buildTestTrie(10)
|
|
|
|
trie3 := buildTestTrie(100)
|
|
|
|
|
|
|
|
w1, err := extractWitnessFromRootNode(trie1.root, 1, false, nil, nil)
|
|
|
|
if err != nil {
|
|
|
|
t.Error(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
w2, err := extractWitnessFromRootNode(trie2.root, 1, false, nil, nil)
|
|
|
|
if err != nil {
|
|
|
|
t.Error(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
w3, err := extractWitnessFromRootNode(trie3.root, 1, false, nil, nil)
|
|
|
|
if err != nil {
|
|
|
|
t.Error(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
var buff bytes.Buffer
|
|
|
|
_, err = w1.WriteTo(&buff)
|
|
|
|
if err != nil {
|
|
|
|
t.Error(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
err = buff.WriteByte(byte(OpNewTrie))
|
|
|
|
if err != nil {
|
|
|
|
t.Error(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err = w2.WriteTo(&buff)
|
|
|
|
if err != nil {
|
|
|
|
t.Error(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
err = buff.WriteByte(byte(OpNewTrie))
|
|
|
|
if err != nil {
|
|
|
|
t.Error(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err = w3.WriteTo(&buff)
|
|
|
|
if err != nil {
|
|
|
|
t.Error(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
storage := testWitnessStorage(buff.Bytes())
|
|
|
|
|
|
|
|
resolvedTries := make([]*Trie, 3)
|
|
|
|
|
|
|
|
currentTrie := 0
|
|
|
|
|
|
|
|
req1 := trie1.NewResolveRequest(nil, []byte{0x01}, 1, trie1.Hash().Bytes())
|
|
|
|
req2 := trie2.NewResolveRequest(nil, []byte{0x02}, 1, trie2.Hash().Bytes())
|
|
|
|
req21 := trie2.NewResolveRequest(nil, []byte{0x02}, 1, trie2.Hash().Bytes())
|
|
|
|
req3 := trie3.NewResolveRequest(nil, []byte{0x03}, 1, trie3.Hash().Bytes())
|
|
|
|
req31 := trie3.NewResolveRequest(nil, []byte{0x03}, 1, trie3.Hash().Bytes())
|
|
|
|
|
|
|
|
hookFunction := func(req *ResolveRequest, root node, rootHash common.Hash) error {
|
|
|
|
trie := New(rootHash)
|
|
|
|
trie.root = root
|
|
|
|
resolvedTries[currentTrie] = trie
|
|
|
|
currentTrie++
|
2020-02-12 11:34:44 +00:00
|
|
|
if !bytes.Equal(req.resolveHash.reference(), rootHash.Bytes()) {
|
2020-01-24 10:58:01 +00:00
|
|
|
return fmt.Errorf("root hash mismatch: expected %x got %x",
|
2020-02-12 11:34:44 +00:00
|
|
|
req.resolveHash.reference(), rootHash.Bytes())
|
2020-01-24 10:58:01 +00:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// it should ignore duplicate resolve requests
|
|
|
|
resolver := NewResolverStateless([]*ResolveRequest{req1, req2, req21}, hookFunction)
|
|
|
|
|
|
|
|
pos, err := resolver.RebuildTrie(&storage, 1, 1, 0)
|
|
|
|
if err != nil {
|
|
|
|
t.Error(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// we also support partial resolution with continuation (for storage tries)
|
|
|
|
// so basically we first resolve accounts, then storages separately
|
|
|
|
// but we still want to keep one entry in a DB per block, so we store the last read position
|
|
|
|
// and then use it as a start
|
|
|
|
resolver = NewResolverStateless([]*ResolveRequest{req3, req31}, hookFunction)
|
|
|
|
_, err = resolver.RebuildTrie(&storage, 1, 1, pos)
|
|
|
|
if err != nil {
|
|
|
|
t.Error(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if !bytes.Equal(resolvedTries[0].Hash().Bytes(), trie1.Hash().Bytes()) {
|
|
|
|
t.Errorf("tries are different")
|
|
|
|
}
|
|
|
|
|
|
|
|
if !bytes.Equal(resolvedTries[1].Hash().Bytes(), trie2.Hash().Bytes()) {
|
|
|
|
t.Errorf("tries are different")
|
|
|
|
}
|
|
|
|
|
|
|
|
if !bytes.Equal(resolvedTries[2].Hash().Bytes(), trie3.Hash().Bytes()) {
|
|
|
|
t.Errorf("tries are different")
|
|
|
|
}
|
|
|
|
}
|