2020-01-31 04:11:20 +00:00
|
|
|
package trie
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2020-02-12 13:52:59 +00:00
|
|
|
"math/big"
|
2020-01-31 04:11:20 +00:00
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/ledgerwatch/turbo-geth/common"
|
|
|
|
"github.com/ledgerwatch/turbo-geth/common/dbutils"
|
|
|
|
"github.com/ledgerwatch/turbo-geth/common/pool"
|
|
|
|
"github.com/ledgerwatch/turbo-geth/core/types/accounts"
|
|
|
|
"github.com/ledgerwatch/turbo-geth/crypto"
|
|
|
|
"github.com/ledgerwatch/turbo-geth/ethdb"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Put 1 embedded entry into the database and try to resolve it
|
|
|
|
func TestResolve1(t *testing.T) {
|
2020-02-12 13:52:59 +00:00
|
|
|
require, assert, db := require.New(t), assert.New(t), ethdb.NewMemDatabase()
|
2020-01-31 04:11:20 +00:00
|
|
|
tr := New(common.Hash{})
|
|
|
|
putStorage := func(k string, v string) {
|
2020-04-19 19:51:32 +00:00
|
|
|
err := db.Put(dbutils.CurrentStateBucket, common.Hex2Bytes(k), common.Hex2Bytes(v))
|
2020-02-12 13:52:59 +00:00
|
|
|
require.NoError(err)
|
2020-01-31 04:11:20 +00:00
|
|
|
}
|
|
|
|
putStorage("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "")
|
|
|
|
|
|
|
|
req := &ResolveRequest{
|
|
|
|
t: tr,
|
|
|
|
resolveHex: keybytesToHex(common.Hex2Bytes("aaaaabbbbbaaaaabbbbbaaaaabbbbbaa")),
|
|
|
|
resolvePos: 10, // 5 bytes is 10 nibbles
|
|
|
|
resolveHash: hashNode(common.HexToHash("bfb355c9a7c26a9c173a9c30e1fb2895fd9908726a8d3dd097203b207d852cf5").Bytes()),
|
|
|
|
}
|
|
|
|
r := NewResolver(0, false, 0)
|
|
|
|
r.AddRequest(req)
|
2020-04-01 16:04:41 +00:00
|
|
|
err := r.ResolveWithDb(db, 0, false)
|
2020-02-12 13:52:59 +00:00
|
|
|
require.NoError(err)
|
2020-01-31 04:11:20 +00:00
|
|
|
|
|
|
|
_, ok := tr.Get(common.Hex2Bytes("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"))
|
2020-01-31 07:31:50 +00:00
|
|
|
assert.True(ok)
|
2020-01-31 04:11:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestResolve2(t *testing.T) {
|
2020-02-12 13:52:59 +00:00
|
|
|
require, assert, db := require.New(t), assert.New(t), ethdb.NewMemDatabase()
|
2020-01-31 04:11:20 +00:00
|
|
|
tr := New(common.Hash{})
|
|
|
|
putStorage := func(k string, v string) {
|
2020-04-19 19:51:32 +00:00
|
|
|
err := db.Put(dbutils.CurrentStateBucket, common.Hex2Bytes(k), common.Hex2Bytes(v))
|
2020-02-12 13:52:59 +00:00
|
|
|
require.NoError(err)
|
2020-01-31 04:11:20 +00:00
|
|
|
}
|
|
|
|
putStorage("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "")
|
|
|
|
putStorage("aaaaaccccccccccccccccccccccccccc", "")
|
|
|
|
|
|
|
|
req := &ResolveRequest{
|
|
|
|
t: tr,
|
|
|
|
resolveHex: keybytesToHex(common.Hex2Bytes("aaaaabbbbbaaaaabbbbbaaaaabbbbbaa")),
|
|
|
|
resolvePos: 10, // 5 bytes is 10 nibbles
|
|
|
|
resolveHash: hashNode(common.HexToHash("38eb1d28b717978c8cb21b6939dc69ba445d5dea67ca0e948bbf0aef9f1bc2fb").Bytes()),
|
|
|
|
}
|
|
|
|
r := NewResolver(0, false, 0)
|
|
|
|
r.AddRequest(req)
|
2020-04-01 16:04:41 +00:00
|
|
|
err := r.ResolveWithDb(db, 0, false)
|
2020-02-12 13:52:59 +00:00
|
|
|
require.NoError(err)
|
2020-01-31 04:11:20 +00:00
|
|
|
|
|
|
|
_, ok := tr.Get(common.Hex2Bytes("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"))
|
2020-01-31 07:31:50 +00:00
|
|
|
assert.True(ok)
|
2020-01-31 04:11:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestResolve2Keep(t *testing.T) {
|
2020-02-12 13:52:59 +00:00
|
|
|
require, assert, db := require.New(t), assert.New(t), ethdb.NewMemDatabase()
|
2020-01-31 04:11:20 +00:00
|
|
|
tr := New(common.Hash{})
|
|
|
|
putStorage := func(k string, v string) {
|
2020-04-19 19:51:32 +00:00
|
|
|
err := db.Put(dbutils.CurrentStateBucket, common.Hex2Bytes(k), common.Hex2Bytes(v))
|
2020-02-12 13:52:59 +00:00
|
|
|
require.NoError(err)
|
2020-01-31 04:11:20 +00:00
|
|
|
}
|
|
|
|
putStorage("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "")
|
|
|
|
putStorage("aaaaaccccccccccccccccccccccccccc", "")
|
|
|
|
|
|
|
|
req := &ResolveRequest{
|
|
|
|
t: tr,
|
|
|
|
resolveHex: keybytesToHex(common.Hex2Bytes("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")),
|
|
|
|
resolvePos: 10, // 5 bytes is 10 nibbles
|
|
|
|
resolveHash: hashNode(common.HexToHash("38eb1d28b717978c8cb21b6939dc69ba445d5dea67ca0e948bbf0aef9f1bc2fb").Bytes()),
|
|
|
|
}
|
|
|
|
r := NewResolver(0, false, 0)
|
|
|
|
r.AddRequest(req)
|
2020-04-01 16:04:41 +00:00
|
|
|
err := r.ResolveWithDb(db, 0, false)
|
2020-02-12 13:52:59 +00:00
|
|
|
require.NoError(err)
|
2020-01-31 04:11:20 +00:00
|
|
|
|
|
|
|
_, ok := tr.Get(common.Hex2Bytes("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"))
|
2020-01-31 07:31:50 +00:00
|
|
|
assert.True(ok)
|
2020-01-31 04:11:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestResolve3Keep(t *testing.T) {
|
2020-02-12 13:52:59 +00:00
|
|
|
require, assert, db := require.New(t), assert.New(t), ethdb.NewMemDatabase()
|
2020-01-31 04:11:20 +00:00
|
|
|
tr := New(common.Hash{})
|
|
|
|
putStorage := func(k string, v string) {
|
2020-04-19 19:51:32 +00:00
|
|
|
err := db.Put(dbutils.CurrentStateBucket, common.Hex2Bytes(k), common.Hex2Bytes(v))
|
2020-02-12 13:52:59 +00:00
|
|
|
require.NoError(err)
|
2020-01-31 04:11:20 +00:00
|
|
|
}
|
|
|
|
putStorage("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "")
|
|
|
|
putStorage("aaaaabbbbbbbbbbbbbbbbbbbbbbbbbbb", "")
|
|
|
|
putStorage("aaaaaccccccccccccccccccccccccccc", "")
|
|
|
|
|
|
|
|
req := &ResolveRequest{
|
|
|
|
t: tr,
|
|
|
|
resolveHex: keybytesToHex(common.Hex2Bytes("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")),
|
|
|
|
resolvePos: 10, // 5 bytes is 10 nibbles
|
|
|
|
resolveHash: hashNode(common.HexToHash("b780e7d2bc3b7ab7f85084edb2fff42facefa0df9dd1e8190470f277d8183e7c").Bytes()),
|
|
|
|
}
|
|
|
|
r := NewResolver(0, false, 0)
|
|
|
|
r.AddRequest(req)
|
2020-04-01 16:04:41 +00:00
|
|
|
err := r.ResolveWithDb(db, 0, false)
|
2020-02-12 13:52:59 +00:00
|
|
|
require.NoError(err, "resolve error")
|
2020-01-31 04:11:20 +00:00
|
|
|
|
|
|
|
_, ok := tr.Get(common.Hex2Bytes("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"))
|
2020-01-31 07:31:50 +00:00
|
|
|
assert.True(ok)
|
2020-01-31 04:11:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestTrieResolver(t *testing.T) {
|
2020-02-12 13:52:59 +00:00
|
|
|
require, assert, db := require.New(t), assert.New(t), ethdb.NewMemDatabase()
|
2020-01-31 04:11:20 +00:00
|
|
|
tr := New(common.Hash{})
|
|
|
|
putStorage := func(k string, v string) {
|
2020-04-19 19:51:32 +00:00
|
|
|
err := db.Put(dbutils.CurrentStateBucket, common.Hex2Bytes(k), common.Hex2Bytes(v))
|
2020-02-12 13:52:59 +00:00
|
|
|
require.NoError(err)
|
2020-01-31 04:11:20 +00:00
|
|
|
}
|
|
|
|
putStorage("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "")
|
|
|
|
putStorage("aaaaaccccccccccccccccccccccccccc", "")
|
|
|
|
putStorage("baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "")
|
|
|
|
putStorage("bbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "")
|
|
|
|
putStorage("bbaaaccccccccccccccccccccccccccc", "")
|
|
|
|
putStorage("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", "")
|
|
|
|
putStorage("bccccccccccccccccccccccccccccccc", "")
|
|
|
|
|
|
|
|
req1 := &ResolveRequest{
|
|
|
|
t: tr,
|
|
|
|
resolveHex: keybytesToHex(common.Hex2Bytes("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")),
|
|
|
|
resolvePos: 10, // 5 bytes is 10 nibbles
|
|
|
|
resolveHash: hashNode(common.HexToHash("38eb1d28b717978c8cb21b6939dc69ba445d5dea67ca0e948bbf0aef9f1bc2fb").Bytes()),
|
|
|
|
}
|
|
|
|
req2 := &ResolveRequest{
|
|
|
|
t: tr,
|
|
|
|
resolveHex: keybytesToHex(common.Hex2Bytes("bbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")),
|
|
|
|
resolvePos: 2, // 1 bytes is 2 nibbles
|
|
|
|
resolveHash: hashNode(common.HexToHash("dc2332366fcf65ad75d09901e199e3dd52a5389ad85ff1d853803c5f40cbde56").Bytes()),
|
|
|
|
}
|
|
|
|
req3 := &ResolveRequest{
|
|
|
|
t: tr,
|
|
|
|
resolveHex: keybytesToHex(common.Hex2Bytes("bbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")),
|
|
|
|
resolvePos: 2, // 1 bytes is 2 nibbles
|
|
|
|
resolveHash: hashNode(common.HexToHash("df6fd126d62ec79182d9ab6f879b63dfacb9ce2e1cb765b17b9752de9c2cbaa7").Bytes()),
|
|
|
|
}
|
|
|
|
resolver := NewResolver(0, false, 0)
|
|
|
|
resolver.AddRequest(req3)
|
|
|
|
resolver.AddRequest(req2)
|
|
|
|
resolver.AddRequest(req1)
|
|
|
|
|
2020-04-01 16:04:41 +00:00
|
|
|
err := resolver.ResolveWithDb(db, 0, false)
|
2020-02-12 13:52:59 +00:00
|
|
|
require.NoError(err, "resolve error")
|
2020-01-31 04:11:20 +00:00
|
|
|
|
|
|
|
_, ok := tr.Get(common.Hex2Bytes("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"))
|
2020-01-31 07:31:50 +00:00
|
|
|
assert.True(ok)
|
2020-01-31 04:11:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestTwoStorageItems(t *testing.T) {
|
2020-02-12 13:52:59 +00:00
|
|
|
require, assert, db := require.New(t), assert.New(t), ethdb.NewMemDatabase()
|
2020-01-31 04:11:20 +00:00
|
|
|
tr := New(common.Hash{})
|
|
|
|
|
2020-04-19 19:51:32 +00:00
|
|
|
key1 := common.Hex2Bytes("d7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb5f5")
|
|
|
|
key2 := common.Hex2Bytes("df6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c7f5")
|
2020-01-31 04:11:20 +00:00
|
|
|
val1 := common.Hex2Bytes("02")
|
|
|
|
val2 := common.Hex2Bytes("03")
|
|
|
|
|
2020-04-19 19:51:32 +00:00
|
|
|
require.NoError(db.Put(dbutils.CurrentStateBucket, key1, val1))
|
|
|
|
require.NoError(db.Put(dbutils.CurrentStateBucket, key2, val2))
|
2020-01-31 04:11:20 +00:00
|
|
|
leaf1 := shortNode{Key: keybytesToHex(key1[1:]), Val: valueNode(val1)}
|
|
|
|
leaf2 := shortNode{Key: keybytesToHex(key2[1:]), Val: valueNode(val2)}
|
|
|
|
var branch fullNode
|
|
|
|
branch.Children[0x7] = &leaf1
|
|
|
|
branch.Children[0xf] = &leaf2
|
|
|
|
root := shortNode{Key: []byte{0xd}, Val: &branch}
|
|
|
|
|
|
|
|
hasher := newHasher(false)
|
|
|
|
defer returnHasherToPool(hasher)
|
|
|
|
rootRlp, err := hasher.hashChildren(&root, 0)
|
2020-01-31 07:31:50 +00:00
|
|
|
require.NoError(err, "failed ot hash children")
|
2020-01-31 04:11:20 +00:00
|
|
|
|
|
|
|
// Resolve the root node
|
|
|
|
|
2020-04-19 19:51:32 +00:00
|
|
|
rootHash := common.HexToHash("85737b049107f866fedbd6d787077fc2c245f4748e28896a3e8ee82c377ecdcf")
|
2020-01-31 07:31:50 +00:00
|
|
|
assert.Equal(rootHash, crypto.Keccak256Hash(rootRlp))
|
2020-01-31 04:11:20 +00:00
|
|
|
|
|
|
|
req := &ResolveRequest{
|
|
|
|
t: tr,
|
|
|
|
resolveHex: []byte{},
|
|
|
|
resolvePos: 0,
|
|
|
|
resolveHash: hashNode(rootHash.Bytes()),
|
|
|
|
}
|
|
|
|
resolver := NewResolver(0, false, 0)
|
|
|
|
resolver.AddRequest(req)
|
|
|
|
|
2020-04-01 16:04:41 +00:00
|
|
|
err = resolver.ResolveWithDb(db, 0, false)
|
2020-01-31 07:31:50 +00:00
|
|
|
require.NoError(err, "resolve error")
|
2020-01-31 04:11:20 +00:00
|
|
|
|
2020-01-31 07:31:50 +00:00
|
|
|
assert.Equal(rootHash.String(), tr.Hash().String())
|
2020-01-31 04:11:20 +00:00
|
|
|
|
|
|
|
// Resolve the branch node
|
|
|
|
|
|
|
|
branchRlp, err := hasher.hashChildren(&branch, 0)
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("failed ot hash children: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
req2 := &ResolveRequest{
|
|
|
|
t: tr,
|
|
|
|
resolveHex: []byte{0xd},
|
|
|
|
resolvePos: 1,
|
|
|
|
resolveHash: hashNode(crypto.Keccak256(branchRlp)),
|
|
|
|
}
|
|
|
|
resolver2 := NewResolver(0, false, 0)
|
|
|
|
resolver2.AddRequest(req2)
|
|
|
|
|
2020-04-01 16:04:41 +00:00
|
|
|
err = resolver2.ResolveWithDb(db, 0, false)
|
2020-01-31 07:31:50 +00:00
|
|
|
require.NoError(err, "resolve error")
|
2020-01-31 04:11:20 +00:00
|
|
|
|
2020-01-31 07:31:50 +00:00
|
|
|
assert.Equal(rootHash.String(), tr.Hash().String())
|
2020-01-31 04:11:20 +00:00
|
|
|
|
|
|
|
_, ok := tr.Get(key1)
|
2020-01-31 07:31:50 +00:00
|
|
|
assert.True(ok)
|
2020-01-31 04:11:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestTwoAccounts(t *testing.T) {
|
2020-02-12 13:52:59 +00:00
|
|
|
require, assert, db := require.New(t), assert.New(t), ethdb.NewMemDatabase()
|
2020-01-31 04:11:20 +00:00
|
|
|
tr := New(common.Hash{})
|
|
|
|
key1 := common.Hex2Bytes("03601462093b5945d1676df093446790fd31b20e7b12a2e8e5e09d068109616b")
|
2020-04-18 20:09:44 +00:00
|
|
|
acc := accounts.NewAccount()
|
|
|
|
acc.Initialised = true
|
|
|
|
acc.Balance.SetInt64(10000000000)
|
|
|
|
acc.CodeHash.SetBytes(common.Hex2Bytes("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"))
|
|
|
|
err := writeAccount(db, common.BytesToHash(key1), acc)
|
2020-01-31 07:31:50 +00:00
|
|
|
require.NoError(err)
|
2020-04-18 20:09:44 +00:00
|
|
|
|
|
|
|
key2 := common.Hex2Bytes("0fbc62ba90dec43ec1d6016f9dd39dc324e967f2a3459a78281d1f4b2ba962a6")
|
|
|
|
acc2 := accounts.NewAccount()
|
|
|
|
acc2.Initialised = true
|
|
|
|
acc2.Balance.SetInt64(100)
|
|
|
|
acc2.CodeHash.SetBytes(common.Hex2Bytes("4f1593970e8f030c0a2c39758181a447774eae7c65653c4e6440e8c18dad69bc"))
|
|
|
|
err = writeAccount(db, common.BytesToHash(key2), acc2)
|
2020-01-31 07:31:50 +00:00
|
|
|
require.NoError(err)
|
2020-01-31 04:11:20 +00:00
|
|
|
|
|
|
|
expect := common.HexToHash("925002c3260b44e44c3edebad1cc442142b03020209df1ab8bb86752edbd2cd7")
|
|
|
|
|
|
|
|
buf := pool.GetBuffer(64)
|
|
|
|
buf.Reset()
|
|
|
|
defer pool.PutBuffer(buf)
|
|
|
|
|
2020-02-12 13:52:59 +00:00
|
|
|
DecompressNibbles(common.Hex2Bytes("03601462093b5945d1676df093446790fd31b20e7b12a2e8e5e09d068109616b"), &buf.B)
|
2020-01-31 04:11:20 +00:00
|
|
|
|
|
|
|
req := &ResolveRequest{
|
|
|
|
t: tr,
|
|
|
|
resolveHex: buf.Bytes(),
|
|
|
|
resolvePos: 0,
|
|
|
|
resolveHash: hashNode(expect.Bytes()),
|
|
|
|
}
|
|
|
|
|
|
|
|
resolver := NewResolver(0, true, 0)
|
|
|
|
resolver.AddRequest(req)
|
2020-04-01 16:04:41 +00:00
|
|
|
err = resolver.ResolveWithDb(db, 0, false)
|
2020-01-31 07:31:50 +00:00
|
|
|
require.NoError(err, "resolve error")
|
2020-01-31 04:11:20 +00:00
|
|
|
|
2020-02-12 13:52:59 +00:00
|
|
|
assert.Equal(expect.String(), tr.Hash().String())
|
2020-01-31 04:11:20 +00:00
|
|
|
|
|
|
|
_, ok := tr.GetAccount(key1)
|
2020-02-12 13:52:59 +00:00
|
|
|
assert.True(ok)
|
2020-01-31 04:11:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestReturnErrOnWrongRootHash(t *testing.T) {
|
2020-02-12 13:52:59 +00:00
|
|
|
require, db := require.New(t), ethdb.NewMemDatabase()
|
2020-01-31 04:11:20 +00:00
|
|
|
tr := New(common.Hash{})
|
|
|
|
putAccount := func(k string) {
|
|
|
|
a := accounts.Account{}
|
2020-04-18 20:09:44 +00:00
|
|
|
err := writeAccount(db, common.BytesToHash(common.Hex2Bytes(k)), a)
|
2020-02-12 13:52:59 +00:00
|
|
|
require.NoError(err)
|
2020-01-31 04:11:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
putAccount("0000000000000000000000000000000000000000000000000000000000000000")
|
|
|
|
|
|
|
|
req := &ResolveRequest{
|
|
|
|
t: tr,
|
|
|
|
resolveHex: []byte{},
|
|
|
|
resolvePos: 0,
|
|
|
|
resolveHash: hashNode(common.HexToHash("wrong hash").Bytes()),
|
|
|
|
}
|
|
|
|
resolver := NewResolver(0, true, 0)
|
|
|
|
resolver.AddRequest(req)
|
2020-04-01 16:04:41 +00:00
|
|
|
err := resolver.ResolveWithDb(db, 0, false)
|
2020-01-31 04:11:20 +00:00
|
|
|
require.NotNil(t, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestApiDetails(t *testing.T) {
|
2020-02-12 13:52:59 +00:00
|
|
|
const Stateful = "stateful"
|
|
|
|
const StatefulCached = "stateful_cached"
|
|
|
|
|
|
|
|
require, assert, db := require.New(t), assert.New(t), ethdb.NewMemDatabase()
|
2020-01-31 07:31:50 +00:00
|
|
|
|
2020-04-05 06:32:28 +00:00
|
|
|
storageKey := func(incarnation uint64, k string) []byte {
|
|
|
|
return dbutils.GenerateCompositeStorageKey(common.HexToHash(k), incarnation, common.HexToHash(k))
|
2020-01-31 04:11:20 +00:00
|
|
|
}
|
2020-04-05 06:32:28 +00:00
|
|
|
putIH := func(k string, v string) {
|
2020-02-12 13:52:59 +00:00
|
|
|
require.NoError(db.Put(dbutils.IntermediateTrieHashBucket, common.Hex2Bytes(k), common.Hex2Bytes(v)))
|
2020-01-31 04:11:20 +00:00
|
|
|
}
|
|
|
|
|
2020-02-12 13:52:59 +00:00
|
|
|
// Test attempt handle cases when: Trie root hash is same for Cached and non-Cached Resolvers
|
|
|
|
// Test works with keys like: {base}{i}{j}{zeroes}
|
|
|
|
// base = 0 or f - it covers edge cases - first/last subtrees
|
|
|
|
//
|
2020-04-05 06:32:28 +00:00
|
|
|
// i=0 - has data, has IntermediateHash, no resolve. Tree must have Hash.
|
|
|
|
// i=1 - has values with incarnation=1. Tree must have Nil.
|
|
|
|
// i=2 - has accounts and storage, no IntermediateHash. Tree must have Account nodes.
|
|
|
|
// i>2 - no data, no IntermediateHash, no resolve.
|
|
|
|
// i=f - has data, has IntermediateHash, no resolve. Edge case - last subtree.
|
2020-02-12 13:52:59 +00:00
|
|
|
for _, base := range []string{"0", "f"} {
|
|
|
|
for _, i := range []int{0, 1, 2, 15} {
|
|
|
|
for _, j := range []int{0, 1, 2, 15} {
|
|
|
|
k := fmt.Sprintf(base+"%x%x%061x", i, j, 0)
|
2020-04-18 20:09:44 +00:00
|
|
|
//storageV := common.Hex2Bytes(fmt.Sprintf("%x%x", i, j))
|
|
|
|
storageV := []byte{0}
|
2020-04-05 06:32:28 +00:00
|
|
|
incarnation := uint64(2)
|
2020-02-12 13:52:59 +00:00
|
|
|
if i == 1 {
|
|
|
|
storageV = []byte{}
|
2020-04-05 06:32:28 +00:00
|
|
|
incarnation = 1
|
2020-02-12 13:52:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
a := accounts.Account{
|
|
|
|
// Using Nonce field as an ID of account.
|
|
|
|
// Will check later if value which we .Get() from Trie has expected ID.
|
|
|
|
Nonce: uint64(i*10 + j),
|
|
|
|
Initialised: true,
|
|
|
|
Root: EmptyRoot,
|
|
|
|
CodeHash: EmptyCodeHash,
|
|
|
|
Balance: *big.NewInt(0),
|
|
|
|
StorageSize: uint64(len(storageV)),
|
|
|
|
HasStorageSize: len(storageV) > 0,
|
|
|
|
}
|
2020-04-18 20:09:44 +00:00
|
|
|
require.NoError(writeAccount(db, common.BytesToHash(common.Hex2Bytes(k)), a))
|
2020-04-19 19:51:32 +00:00
|
|
|
require.NoError(db.Put(dbutils.CurrentStateBucket, storageKey(incarnation, k), storageV))
|
2020-01-31 04:11:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-05 06:32:28 +00:00
|
|
|
putIH("00", "06e98f77330d54fa691a724018df5b2c5689596c03413ca59717ea9bd8a98893")
|
|
|
|
putIH("ff", "ad4f92ca84a5980e14a356667eaf0db5d9ff78063630ebaa3d00a6634cd2a3fe")
|
2020-01-31 07:31:50 +00:00
|
|
|
|
2020-04-05 06:32:28 +00:00
|
|
|
// this IntermediateHash key must not be used, because such key is in ResolveRequest
|
|
|
|
putIH("01", "0000000000000000000000000000000000000000000000000000000000000000")
|
2020-01-31 04:11:20 +00:00
|
|
|
|
2020-04-18 20:09:44 +00:00
|
|
|
tries := []*Trie{New(common.Hash{}), New(common.Hash{})}
|
|
|
|
{
|
2020-02-12 13:52:59 +00:00
|
|
|
for i, resolverName := range []string{Stateful, StatefulCached} {
|
2020-04-18 20:09:44 +00:00
|
|
|
i := i
|
|
|
|
resolver := NewResolver(1, true, 0)
|
2020-02-12 13:52:59 +00:00
|
|
|
expectRootHash := common.HexToHash("1af5daf4281e4e5552e79069d0688492de8684c11b1e983f9c3bbac500ad694a")
|
2020-01-31 04:11:20 +00:00
|
|
|
|
2020-04-18 20:09:44 +00:00
|
|
|
resolver.AddRequest(tries[i].NewResolveRequest(nil, append(common.Hex2Bytes(fmt.Sprintf("000101%0122x", 0)), 16), 0, expectRootHash.Bytes()))
|
|
|
|
resolver.AddRequest(tries[i].NewResolveRequest(nil, common.Hex2Bytes("000202"), 0, expectRootHash.Bytes()))
|
|
|
|
resolver.AddRequest(tries[i].NewResolveRequest(nil, common.Hex2Bytes("0f"), 0, expectRootHash.Bytes()))
|
2020-01-31 04:11:20 +00:00
|
|
|
|
2020-02-12 13:52:59 +00:00
|
|
|
if resolverName == Stateful {
|
|
|
|
err := resolver.ResolveStateful(db, 0)
|
2020-04-18 20:09:44 +00:00
|
|
|
//fmt.Printf("%x\n", tr.root.(*fullNode).Children[0].(*fullNode).Children[0].reference())
|
|
|
|
//fmt.Printf("%x\n", tr.root.(*fullNode).Children[15].(*fullNode).Children[15].reference())
|
2020-02-12 13:52:59 +00:00
|
|
|
assert.NoError(err)
|
|
|
|
} else {
|
2020-04-01 16:04:41 +00:00
|
|
|
err := resolver.ResolveStatefulCached(db, 0, false)
|
2020-02-12 13:52:59 +00:00
|
|
|
assert.NoError(err)
|
|
|
|
}
|
|
|
|
|
2020-04-18 20:09:44 +00:00
|
|
|
assert.Equal(expectRootHash.String(), tries[i].Hash().String(), resolverName)
|
2020-02-12 13:52:59 +00:00
|
|
|
|
2020-04-18 20:09:44 +00:00
|
|
|
_, found := tries[i].GetAccount(common.Hex2Bytes(fmt.Sprintf("000%061x", 0)))
|
2020-02-12 13:52:59 +00:00
|
|
|
assert.False(found) // exists in DB but resolved, there is hashNode
|
|
|
|
|
2020-04-18 20:09:44 +00:00
|
|
|
acc, found := tries[i].GetAccount(common.Hex2Bytes(fmt.Sprintf("011%061x", 0)))
|
2020-02-12 13:52:59 +00:00
|
|
|
assert.True(found)
|
|
|
|
require.NotNil(acc) // cache bucket has empty value, but self-destructed Account still available
|
|
|
|
assert.Equal(int(acc.Nonce), 11) // i * 10 + j
|
|
|
|
|
2020-04-18 20:09:44 +00:00
|
|
|
acc, found = tries[i].GetAccount(common.Hex2Bytes(fmt.Sprintf("021%061x", 0)))
|
2020-02-12 13:52:59 +00:00
|
|
|
assert.True(found)
|
|
|
|
require.NotNil(acc) // exists in db and resolved
|
|
|
|
assert.Equal(int(acc.Nonce), 21) // i * 10 + j
|
|
|
|
|
2020-04-18 20:09:44 +00:00
|
|
|
acc, found = tries[i].GetAccount(common.Hex2Bytes(fmt.Sprintf("051%061x", 0)))
|
2020-04-05 06:32:28 +00:00
|
|
|
assert.True(found)
|
|
|
|
assert.Nil(acc) // not exists in DB
|
2020-01-31 04:11:20 +00:00
|
|
|
|
2020-04-05 06:32:28 +00:00
|
|
|
assert.Panics(func() {
|
2020-04-18 20:09:44 +00:00
|
|
|
tries[i].UpdateAccount(common.Hex2Bytes(fmt.Sprintf("001%061x", 0)), &accounts.Account{})
|
2020-04-05 06:32:28 +00:00
|
|
|
})
|
|
|
|
assert.NotPanics(func() {
|
2020-04-18 20:09:44 +00:00
|
|
|
tries[i].UpdateAccount(common.Hex2Bytes(fmt.Sprintf("011%061x", 0)), &accounts.Account{})
|
|
|
|
tries[i].UpdateAccount(common.Hex2Bytes(fmt.Sprintf("021%061x", 0)), &accounts.Account{})
|
|
|
|
tries[i].UpdateAccount(common.Hex2Bytes(fmt.Sprintf("051%061x", 0)), &accounts.Account{})
|
2020-04-05 06:32:28 +00:00
|
|
|
})
|
|
|
|
}
|
2020-04-18 20:09:44 +00:00
|
|
|
}
|
2020-02-12 13:52:59 +00:00
|
|
|
|
2020-04-18 20:09:44 +00:00
|
|
|
/*
|
|
|
|
{ // storage resolver
|
|
|
|
putIH("00", "0aca8baf23c54bda626bc3c3d1590f9cdb9deb8defaef7455f5f0b55b3d1c76e")
|
|
|
|
putIH("ff", "71c0df1d41959526a6961cca7e5831982848074c4cc556fbef4f8a1fad6621ca")
|
|
|
|
|
|
|
|
for i, resolverName := range []string{Stateful, StatefulCached} {
|
|
|
|
resolver := NewResolver(32, false, 0)
|
|
|
|
expectRootHash := common.HexToHash("494e295f60cfde19548157facc0c425d8b254f791a006b74173dc71113f56df0")
|
|
|
|
|
|
|
|
resolver.AddRequest(tries[i].NewResolveRequest(nil, append(common.Hex2Bytes(fmt.Sprintf("000101%0122x", 0)), 16), 0, expectRootHash.Bytes()))
|
|
|
|
resolver.AddRequest(tries[i].NewResolveRequest(nil, common.Hex2Bytes("00020100"), 0, expectRootHash.Bytes()))
|
|
|
|
resolver.AddRequest(tries[i].NewResolveRequest(nil, common.Hex2Bytes("0f"), 0, expectRootHash.Bytes()))
|
|
|
|
|
|
|
|
if resolverName == Stateful {
|
|
|
|
err := resolver.ResolveStateful(db, 0)
|
|
|
|
require.NoError(err)
|
|
|
|
//fmt.Printf("%x\n", tr.root.(*fullNode).Children[0].(*fullNode).Children[0].reference())
|
|
|
|
//fmt.Printf("%x\n", tr.root.(*fullNode).Children[0].(*fullNode).Children[1].reference())
|
|
|
|
_, root := tries[i].DeepHash(common.Hex2Bytes(fmt.Sprintf("021%061x", 0)))
|
|
|
|
fmt.Printf("Alex: %x\n", root)
|
|
|
|
_, root = tries[i].DeepHash(common.Hex2Bytes(fmt.Spritrie/resolver_stateful_test.go:400ntf("011%061x", 0)))
|
|
|
|
fmt.Printf("Alex: %x\n", root)
|
|
|
|
|
|
|
|
//fmt.Printf("%x\n", tr.root.(*fullNode).Children[15].(*fullNode).Children[15].reference())
|
|
|
|
} else {
|
|
|
|
err := resolver.ResolveStatefulCached(db, 0, true)
|
|
|
|
//fmt.Printf("%x\n", tr.root.(*fullNode).Children[0].(*fullNode).Children[1].reference())
|
|
|
|
require.NoError(err)
|
|
|
|
}
|
|
|
|
//assert.Equal(expectRootHash.String(), tr.Hash().String())
|
|
|
|
|
|
|
|
//_, found := tr.Get(storageKey(2, fmt.Sprintf("000%061x", 0)))
|
|
|
|
//assert.False(found) // exists in DB but not resolved, there is hashNode
|
|
|
|
|
|
|
|
storage, found := tries[i].Get(storageKey(2, fmt.Sprintf("011%061x", 0)))
|
|
|
|
assert.True(found)
|
|
|
|
require.Nil(storage) // deleted by empty value in cache bucket
|
|
|
|
|
|
|
|
//storage, found = tr.Get(storageKey(2, fmt.Sprintf("021%061x", 0)))
|
|
|
|
//assert.True(found)
|
|
|
|
//require.Equal(storage, common.Hex2Bytes("21"))
|
|
|
|
|
|
|
|
//storage, found = tr.Get(storageKey(2, fmt.Sprintf("051%061x", 0)))
|
|
|
|
//assert.True(found)
|
|
|
|
//assert.Nil(storage) // not exists in DB
|
|
|
|
|
|
|
|
//assert.Panics(func() {
|
|
|
|
// tr.Update(storageKey(2, fmt.Sprintf("001%061x", 0)), nil)
|
|
|
|
//})
|
|
|
|
assert.NotPanics(func() {
|
|
|
|
tries[i].Update(storageKey(2, fmt.Sprintf("011%061x", 0)), nil)
|
|
|
|
tries[i].Update(storageKey(2, fmt.Sprintf("021%061x", 0)), nil)
|
|
|
|
tries[i].Update(storageKey(2, fmt.Sprintf("051%061x", 0)), nil)
|
|
|
|
})
|
2020-02-12 13:52:59 +00:00
|
|
|
}
|
2020-01-31 04:11:20 +00:00
|
|
|
}
|
2020-04-18 20:09:44 +00:00
|
|
|
*/
|
2020-01-31 04:11:20 +00:00
|
|
|
}
|
2020-01-31 07:31:50 +00:00
|
|
|
|
2020-03-20 11:30:14 +00:00
|
|
|
func TestIsBefore(t *testing.T) {
|
2020-01-31 07:31:50 +00:00
|
|
|
assert := assert.New(t)
|
|
|
|
|
|
|
|
is, minKey := keyIsBefore([]byte("a"), []byte("b"))
|
|
|
|
assert.Equal(true, is)
|
2020-03-11 10:31:49 +00:00
|
|
|
assert.Equal("a", fmt.Sprintf("%s", minKey))
|
2020-01-31 07:31:50 +00:00
|
|
|
|
|
|
|
is, minKey = keyIsBefore([]byte("b"), []byte("a"))
|
|
|
|
assert.Equal(false, is)
|
2020-03-11 10:31:49 +00:00
|
|
|
assert.Equal("a", fmt.Sprintf("%s", minKey))
|
2020-01-31 07:31:50 +00:00
|
|
|
|
|
|
|
is, minKey = keyIsBefore([]byte("b"), []byte(""))
|
|
|
|
assert.Equal(false, is)
|
2020-03-11 10:31:49 +00:00
|
|
|
assert.Equal("", fmt.Sprintf("%s", minKey))
|
2020-01-31 07:31:50 +00:00
|
|
|
|
|
|
|
is, minKey = keyIsBefore(nil, []byte("b"))
|
|
|
|
assert.Equal(false, is)
|
2020-03-11 10:31:49 +00:00
|
|
|
assert.Equal("b", fmt.Sprintf("%s", minKey))
|
2020-01-31 07:31:50 +00:00
|
|
|
|
|
|
|
is, minKey = keyIsBefore([]byte("b"), nil)
|
|
|
|
assert.Equal(true, is)
|
2020-03-11 10:31:49 +00:00
|
|
|
assert.Equal("b", fmt.Sprintf("%s", minKey))
|
|
|
|
|
|
|
|
contract := fmt.Sprintf("2%063x", 0)
|
|
|
|
storageKey := common.Hex2Bytes(contract + "ffffffff" + fmt.Sprintf("10%062x", 0))
|
2020-04-16 07:42:25 +00:00
|
|
|
cacheKey := common.Hex2Bytes(contract + "ffffffff" + "20")
|
2020-03-11 10:31:49 +00:00
|
|
|
is, minKey = keyIsBefore(cacheKey, storageKey)
|
|
|
|
assert.False(is)
|
|
|
|
assert.Equal(fmt.Sprintf("%x", storageKey), fmt.Sprintf("%x", minKey))
|
|
|
|
|
|
|
|
storageKey = common.Hex2Bytes(contract + "ffffffffffffffff" + fmt.Sprintf("20%062x", 0))
|
2020-04-16 07:42:25 +00:00
|
|
|
cacheKey = common.Hex2Bytes(contract + "ffffffffffffffff" + "10")
|
2020-03-11 10:31:49 +00:00
|
|
|
is, minKey = keyIsBefore(cacheKey, storageKey)
|
|
|
|
assert.True(is)
|
|
|
|
assert.Equal(fmt.Sprintf("%x", cacheKey), fmt.Sprintf("%x", minKey))
|
2020-01-31 07:31:50 +00:00
|
|
|
}
|
2020-04-18 20:09:44 +00:00
|
|
|
|
|
|
|
func writeAccount(db ethdb.Putter, addrHash common.Hash, acc accounts.Account) error {
|
|
|
|
addrHashBytes := addrHash[:]
|
|
|
|
value := make([]byte, acc.EncodingLengthForStorage())
|
|
|
|
acc.EncodeForStorage(value)
|
2020-04-19 19:51:32 +00:00
|
|
|
if err := db.Put(dbutils.CurrentStateBucket, addrHashBytes, value); err != nil {
|
2020-04-18 20:09:44 +00:00
|
|
|
return err
|
|
|
|
}
|
2020-04-20 10:35:12 +00:00
|
|
|
if err := db.Put(dbutils.IntermediateTrieHashBucket, dbutils.GenerateStoragePrefix(addrHash, acc.Incarnation), acc.Root.Bytes()); err != nil {
|
2020-04-18 20:09:44 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|