mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-18 19:00:46 +00:00
* cmd, core/state, light, trie, eth: add trie owner notion * all: refactor * tests: fix goimports * core/state/snapshot: fix ineffasigns Co-authored-by: rjl493456442 <garyrong0905@gmail.com> Co-authored-by: Martin Holst Swende <martin@swende.se>
This commit is contained in:
parent
b96310ebe7
commit
d52bfaa5ca
20 changed files with 216 additions and 140 deletions
|
|
@ -58,7 +58,7 @@ func NewXDCXTrie(root common.Hash, db *trie.Database) (*XDCXTrie, error) {
|
||||||
if db == nil {
|
if db == nil {
|
||||||
panic("trie.NewXDCXTrie called without a database")
|
panic("trie.NewXDCXTrie called without a database")
|
||||||
}
|
}
|
||||||
trie, err := trie.New(root, db)
|
trie, err := trie.New(common.Hash{}, root, db)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@ func NewXDCXTrie(root common.Hash, db *trie.Database) (*XDCXTrie, error) {
|
||||||
if db == nil {
|
if db == nil {
|
||||||
panic("trie.NewXDCXTrie called without a database")
|
panic("trie.NewXDCXTrie called without a database")
|
||||||
}
|
}
|
||||||
trie, err := trie.New(root, db)
|
trie, err := trie.New(common.Hash{}, root, db)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -529,7 +529,7 @@ func (bc *BlockChain) FastSyncCommitHead(hash common.Hash) error {
|
||||||
if block == nil {
|
if block == nil {
|
||||||
return fmt.Errorf("non existent block [%x..]", hash[:4])
|
return fmt.Errorf("non existent block [%x..]", hash[:4])
|
||||||
}
|
}
|
||||||
if _, err := trie.NewSecure(block.Root(), bc.stateCache.TrieDB()); err != nil {
|
if _, err := trie.NewSecure(common.Hash{}, block.Root(), bc.stateCache.TrieDB()); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -131,12 +131,12 @@ type cachingDB struct {
|
||||||
|
|
||||||
// OpenTrie opens the main account trie at a specific root hash.
|
// OpenTrie opens the main account trie at a specific root hash.
|
||||||
func (db *cachingDB) OpenTrie(root common.Hash) (Trie, error) {
|
func (db *cachingDB) OpenTrie(root common.Hash) (Trie, error) {
|
||||||
return trie.NewSecure(root, db.db)
|
return trie.NewSecure(common.Hash{}, root, db.db)
|
||||||
}
|
}
|
||||||
|
|
||||||
// OpenStorageTrie opens the storage trie of an account.
|
// OpenStorageTrie opens the storage trie of an account.
|
||||||
func (db *cachingDB) OpenStorageTrie(addrHash, root common.Hash) (Trie, error) {
|
func (db *cachingDB) OpenStorageTrie(addrHash, root common.Hash) (Trie, error) {
|
||||||
return trie.NewSecure(root, db.db)
|
return trie.NewSecure(addrHash, root, db.db)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CopyTrie returns an independent copy of the given trie.
|
// CopyTrie returns an independent copy of the given trie.
|
||||||
|
|
|
||||||
|
|
@ -104,7 +104,7 @@ func checkTrieConsistency(db ethdb.Database, root common.Hash) error {
|
||||||
if v, _ := db.Get(root[:]); v == nil {
|
if v, _ := db.Get(root[:]); v == nil {
|
||||||
return nil // Consider a non existent state consistent.
|
return nil // Consider a non existent state consistent.
|
||||||
}
|
}
|
||||||
trie, err := trie.New(root, trie.NewDatabase(db))
|
trie, err := trie.New(common.Hash{}, root, trie.NewDatabase(db))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -165,7 +165,7 @@ func testIterativeStateSync(t *testing.T, count int, commit bool, bypath bool) {
|
||||||
if commit {
|
if commit {
|
||||||
srcDb.TrieDB().Commit(srcRoot, false)
|
srcDb.TrieDB().Commit(srcRoot, false)
|
||||||
}
|
}
|
||||||
srcTrie, _ := trie.New(srcRoot, srcDb.TrieDB())
|
srcTrie, _ := trie.New(common.Hash{}, srcRoot, srcDb.TrieDB())
|
||||||
|
|
||||||
// Create a destination state and sync with the scheduler
|
// Create a destination state and sync with the scheduler
|
||||||
dstDb := rawdb.NewMemoryDatabase()
|
dstDb := rawdb.NewMemoryDatabase()
|
||||||
|
|
@ -206,7 +206,7 @@ func testIterativeStateSync(t *testing.T, count int, commit bool, bypath bool) {
|
||||||
if err := rlp.DecodeBytes(srcTrie.Get(path[0]), &acc); err != nil {
|
if err := rlp.DecodeBytes(srcTrie.Get(path[0]), &acc); err != nil {
|
||||||
t.Fatalf("failed to decode account on path %x: %v", path, err)
|
t.Fatalf("failed to decode account on path %x: %v", path, err)
|
||||||
}
|
}
|
||||||
stTrie, err := trie.New(acc.Root, srcDb.TrieDB())
|
stTrie, err := trie.New(common.BytesToHash(path[0]), acc.Root, srcDb.TrieDB())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to retriev storage trie for path %x: %v", path, err)
|
t.Fatalf("failed to retriev storage trie for path %x: %v", path, err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,7 @@ func TestDeriveSha(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
for len(txs) < 1000 {
|
for len(txs) < 1000 {
|
||||||
tr, _ := trie.New(common.Hash{}, trie.NewDatabase(rawdb.NewMemoryDatabase()))
|
exp := types.DeriveSha(txs, trie.NewEmpty(trie.NewDatabase(rawdb.NewMemoryDatabase())))
|
||||||
exp := types.DeriveSha(txs, tr)
|
|
||||||
got := types.DeriveSha(txs, trie.NewStackTrie(nil))
|
got := types.DeriveSha(txs, trie.NewStackTrie(nil))
|
||||||
if !bytes.Equal(got[:], exp[:]) {
|
if !bytes.Equal(got[:], exp[:]) {
|
||||||
t.Fatalf("%d txs: got %x exp %x", len(txs), got, exp)
|
t.Fatalf("%d txs: got %x exp %x", len(txs), got, exp)
|
||||||
|
|
@ -71,8 +70,7 @@ func BenchmarkDeriveSha200(b *testing.B) {
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
b.ReportAllocs()
|
b.ReportAllocs()
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
tr, _ := trie.New(common.Hash{}, trie.NewDatabase(rawdb.NewMemoryDatabase()))
|
exp = types.DeriveSha(txs, trie.NewEmpty(trie.NewDatabase(rawdb.NewMemoryDatabase())))
|
||||||
exp = types.DeriveSha(txs, tr)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -93,8 +91,7 @@ func TestFuzzDeriveSha(t *testing.T) {
|
||||||
rndSeed := mrand.Int()
|
rndSeed := mrand.Int()
|
||||||
for i := 0; i < 10; i++ {
|
for i := 0; i < 10; i++ {
|
||||||
seed := rndSeed + i
|
seed := rndSeed + i
|
||||||
tr, _ := trie.New(common.Hash{}, trie.NewDatabase(rawdb.NewMemoryDatabase()))
|
exp := types.DeriveSha(newDummy(i), trie.NewEmpty(trie.NewDatabase(rawdb.NewMemoryDatabase())))
|
||||||
exp := types.DeriveSha(newDummy(i), tr)
|
|
||||||
got := types.DeriveSha(newDummy(i), trie.NewStackTrie(nil))
|
got := types.DeriveSha(newDummy(i), trie.NewStackTrie(nil))
|
||||||
if !bytes.Equal(got[:], exp[:]) {
|
if !bytes.Equal(got[:], exp[:]) {
|
||||||
printList(newDummy(seed))
|
printList(newDummy(seed))
|
||||||
|
|
@ -122,8 +119,7 @@ func TestDerivableList(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for i, tc := range tcs[1:] {
|
for i, tc := range tcs[1:] {
|
||||||
tr, _ := trie.New(common.Hash{}, trie.NewDatabase(rawdb.NewMemoryDatabase()))
|
exp := types.DeriveSha(flatList(tc), trie.NewEmpty(trie.NewDatabase(rawdb.NewMemoryDatabase())))
|
||||||
exp := types.DeriveSha(flatList(tc), tr)
|
|
||||||
got := types.DeriveSha(flatList(tc), trie.NewStackTrie(nil))
|
got := types.DeriveSha(flatList(tc), trie.NewStackTrie(nil))
|
||||||
if !bytes.Equal(got[:], exp[:]) {
|
if !bytes.Equal(got[:], exp[:]) {
|
||||||
t.Fatalf("case %d: got %x exp %x", i, got, exp)
|
t.Fatalf("case %d: got %x exp %x", i, got, exp)
|
||||||
|
|
|
||||||
|
|
@ -488,11 +488,11 @@ func (api *DebugAPI) getModifiedAccounts(startBlock, endBlock *types.Block) ([]c
|
||||||
}
|
}
|
||||||
triedb := api.eth.BlockChain().StateCache().TrieDB()
|
triedb := api.eth.BlockChain().StateCache().TrieDB()
|
||||||
|
|
||||||
oldTrie, err := trie.NewSecure(startBlock.Root(), triedb)
|
oldTrie, err := trie.NewSecure(common.Hash{}, startBlock.Root(), triedb)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
newTrie, err := trie.NewSecure(endBlock.Root(), triedb)
|
newTrie, err := trie.NewSecure(common.Hash{}, endBlock.Root(), triedb)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -192,7 +192,7 @@ func (dl *downloadTester) CurrentFastBlock() *types.Block {
|
||||||
func (dl *downloadTester) FastSyncCommitHead(hash common.Hash) error {
|
func (dl *downloadTester) FastSyncCommitHead(hash common.Hash) error {
|
||||||
// For now only check that the state trie is correct
|
// For now only check that the state trie is correct
|
||||||
if block := dl.GetBlockByHash(hash); block != nil {
|
if block := dl.GetBlockByHash(hash); block != nil {
|
||||||
_, err := trie.NewSecure(block.Root(), trie.NewDatabase(dl.stateDb))
|
_, err := trie.NewSecure(common.Hash{}, block.Root(), trie.NewDatabase(dl.stateDb))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return fmt.Errorf("non existent block: %x", hash[:4])
|
return fmt.Errorf("non existent block: %x", hash[:4])
|
||||||
|
|
|
||||||
|
|
@ -23,13 +23,24 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// MissingNodeError is returned by the trie functions (TryGet, TryUpdate, TryDelete)
|
// MissingNodeError is returned by the trie functions (TryGet, TryUpdate, TryDelete)
|
||||||
// in the case where a trie Node is not present in the local database. It contains
|
// in the case where a trie node is not present in the local database. It contains
|
||||||
// information necessary for retrieving the missing Node.
|
// information necessary for retrieving the missing node.
|
||||||
type MissingNodeError struct {
|
type MissingNodeError struct {
|
||||||
NodeHash common.Hash // hash of the missing Node
|
Owner common.Hash // owner of the trie if it's 2-layered trie
|
||||||
Path []byte // hex-encoded path to the missing Node
|
NodeHash common.Hash // hash of the missing node
|
||||||
|
Path []byte // hex-encoded path to the missing node
|
||||||
|
err error // concrete error for missing trie node
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unwrap returns the concrete error for missing trie node which
|
||||||
|
// allows us for further analysis outside.
|
||||||
|
func (err *MissingNodeError) Unwrap() error {
|
||||||
|
return err.err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (err *MissingNodeError) Error() string {
|
func (err *MissingNodeError) Error() string {
|
||||||
return fmt.Sprintf("missing trie Node %x (path %x)", err.NodeHash, err.Path)
|
if err.Owner == (common.Hash{}) {
|
||||||
|
return fmt.Sprintf("missing trie node %x (path %x) %v", err.NodeHash, err.Path, err.err)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("missing trie node %x (owner %x) (path %x) %v", err.NodeHash, err.Owner, err.Path, err.err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,6 @@ import (
|
||||||
|
|
||||||
"github.com/XinFinOrg/XDPoSChain/common"
|
"github.com/XinFinOrg/XDPoSChain/common"
|
||||||
"github.com/XinFinOrg/XDPoSChain/core/rawdb"
|
"github.com/XinFinOrg/XDPoSChain/core/rawdb"
|
||||||
"github.com/XinFinOrg/XDPoSChain/core/types"
|
|
||||||
"github.com/XinFinOrg/XDPoSChain/crypto"
|
"github.com/XinFinOrg/XDPoSChain/crypto"
|
||||||
"github.com/XinFinOrg/XDPoSChain/ethdb"
|
"github.com/XinFinOrg/XDPoSChain/ethdb"
|
||||||
"github.com/XinFinOrg/XDPoSChain/ethdb/memorydb"
|
"github.com/XinFinOrg/XDPoSChain/ethdb/memorydb"
|
||||||
|
|
@ -298,7 +297,7 @@ func TestUnionIterator(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestIteratorNoDups(t *testing.T) {
|
func TestIteratorNoDups(t *testing.T) {
|
||||||
tr, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()))
|
tr := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase()))
|
||||||
for _, val := range testdata1 {
|
for _, val := range testdata1 {
|
||||||
tr.Update([]byte(val.k), []byte(val.v))
|
tr.Update([]byte(val.k), []byte(val.v))
|
||||||
}
|
}
|
||||||
|
|
@ -313,7 +312,7 @@ func testIteratorContinueAfterError(t *testing.T, memonly bool) {
|
||||||
diskdb := memorydb.New()
|
diskdb := memorydb.New()
|
||||||
triedb := NewDatabase(diskdb)
|
triedb := NewDatabase(diskdb)
|
||||||
|
|
||||||
tr, _ := New(types.EmptyRootHash, triedb)
|
tr := NewEmpty(triedb)
|
||||||
for _, val := range testdata1 {
|
for _, val := range testdata1 {
|
||||||
tr.Update([]byte(val.k), []byte(val.v))
|
tr.Update([]byte(val.k), []byte(val.v))
|
||||||
}
|
}
|
||||||
|
|
@ -338,7 +337,7 @@ func testIteratorContinueAfterError(t *testing.T, memonly bool) {
|
||||||
}
|
}
|
||||||
for i := 0; i < 20; i++ {
|
for i := 0; i < 20; i++ {
|
||||||
// Create trie that will load all nodes from DB.
|
// Create trie that will load all nodes from DB.
|
||||||
tr, _ := New(tr.Hash(), triedb)
|
tr, _ := New(common.Hash{}, tr.Hash(), triedb)
|
||||||
|
|
||||||
// Remove a random Node from the database. It can't be the root Node
|
// Remove a random Node from the database. It can't be the root Node
|
||||||
// because that one is already loaded.
|
// because that one is already loaded.
|
||||||
|
|
@ -404,7 +403,7 @@ func testIteratorContinueAfterSeekError(t *testing.T, memonly bool) {
|
||||||
diskdb := memorydb.New()
|
diskdb := memorydb.New()
|
||||||
triedb := NewDatabase(diskdb)
|
triedb := NewDatabase(diskdb)
|
||||||
|
|
||||||
ctr, _ := New(types.EmptyRootHash, triedb)
|
ctr := NewEmpty(triedb)
|
||||||
for _, val := range testdata1 {
|
for _, val := range testdata1 {
|
||||||
ctr.Update([]byte(val.k), []byte(val.v))
|
ctr.Update([]byte(val.k), []byte(val.v))
|
||||||
}
|
}
|
||||||
|
|
@ -425,8 +424,8 @@ func testIteratorContinueAfterSeekError(t *testing.T, memonly bool) {
|
||||||
diskdb.Delete(barNodeHash[:])
|
diskdb.Delete(barNodeHash[:])
|
||||||
}
|
}
|
||||||
// Create a new iterator that seeks to "bars". Seeking can't proceed because
|
// Create a new iterator that seeks to "bars". Seeking can't proceed because
|
||||||
// the Node is missing.
|
// the node is missing.
|
||||||
tr, _ := New(root, triedb)
|
tr, _ := New(common.Hash{}, root, triedb)
|
||||||
it := tr.NodeIterator([]byte("bars"))
|
it := tr.NodeIterator([]byte("bars"))
|
||||||
missing, ok := it.Error().(*MissingNodeError)
|
missing, ok := it.Error().(*MissingNodeError)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
|
@ -510,7 +509,7 @@ func makeLargeTestTrie() (*Database, *SecureTrie, *loggingDb) {
|
||||||
// Create an empty trie
|
// Create an empty trie
|
||||||
logDb := &loggingDb{0, memorydb.New()}
|
logDb := &loggingDb{0, memorydb.New()}
|
||||||
triedb := NewDatabase(logDb)
|
triedb := NewDatabase(logDb)
|
||||||
trie, _ := NewSecure(common.Hash{}, triedb)
|
trie, _ := NewSecure(common.Hash{}, common.Hash{}, triedb)
|
||||||
|
|
||||||
// Fill it with some arbitrary data
|
// Fill it with some arbitrary data
|
||||||
for i := 0; i < 10000; i++ {
|
for i := 0; i < 10000; i++ {
|
||||||
|
|
@ -543,9 +542,9 @@ func TestNodeIteratorLargeTrie(t *testing.T) {
|
||||||
|
|
||||||
func TestIteratorNodeBlob(t *testing.T) {
|
func TestIteratorNodeBlob(t *testing.T) {
|
||||||
var (
|
var (
|
||||||
db = memorydb.New()
|
db = memorydb.New()
|
||||||
triedb = NewDatabase(db)
|
triedb = NewDatabase(db)
|
||||||
trie, _ = New(common.Hash{}, triedb)
|
trie = NewEmpty(triedb)
|
||||||
)
|
)
|
||||||
vals := []struct{ k, v string }{
|
vals := []struct{ k, v string }{
|
||||||
{"do", "verb"},
|
{"do", "verb"},
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,7 @@ func TestProof(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestOneElementProof(t *testing.T) {
|
func TestOneElementProof(t *testing.T) {
|
||||||
trie, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()))
|
trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase()))
|
||||||
updateString(trie, "k", "v")
|
updateString(trie, "k", "v")
|
||||||
for i, prover := range makeProvers(trie) {
|
for i, prover := range makeProvers(trie) {
|
||||||
proof := prover([]byte("k"))
|
proof := prover([]byte("k"))
|
||||||
|
|
@ -126,7 +126,7 @@ func TestBadProof(t *testing.T) {
|
||||||
// Tests that missing keys can also be proven. The test explicitly uses a single
|
// Tests that missing keys can also be proven. The test explicitly uses a single
|
||||||
// entry trie and checks for missing keys both before and after the single entry.
|
// entry trie and checks for missing keys both before and after the single entry.
|
||||||
func TestMissingKeyProof(t *testing.T) {
|
func TestMissingKeyProof(t *testing.T) {
|
||||||
trie, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()))
|
trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase()))
|
||||||
updateString(trie, "k", "v")
|
updateString(trie, "k", "v")
|
||||||
|
|
||||||
for i, key := range []string{"a", "j", "l", "z"} {
|
for i, key := range []string{"a", "j", "l", "z"} {
|
||||||
|
|
@ -382,7 +382,7 @@ func TestOneElementRangeProof(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test the mini trie with only a single element.
|
// Test the mini trie with only a single element.
|
||||||
tinyTrie := new(Trie)
|
tinyTrie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase()))
|
||||||
entry := &kv{randBytes(32), randBytes(20), false}
|
entry := &kv{randBytes(32), randBytes(20), false}
|
||||||
tinyTrie.Update(entry.k, entry.v)
|
tinyTrie.Update(entry.k, entry.v)
|
||||||
|
|
||||||
|
|
@ -454,7 +454,7 @@ func TestAllElementsProof(t *testing.T) {
|
||||||
// TestSingleSideRangeProof tests the range starts from zero.
|
// TestSingleSideRangeProof tests the range starts from zero.
|
||||||
func TestSingleSideRangeProof(t *testing.T) {
|
func TestSingleSideRangeProof(t *testing.T) {
|
||||||
for i := 0; i < 64; i++ {
|
for i := 0; i < 64; i++ {
|
||||||
trie, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()))
|
trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase()))
|
||||||
var entries entrySlice
|
var entries entrySlice
|
||||||
for i := 0; i < 4096; i++ {
|
for i := 0; i < 4096; i++ {
|
||||||
value := &kv{randBytes(32), randBytes(20), false}
|
value := &kv{randBytes(32), randBytes(20), false}
|
||||||
|
|
@ -489,7 +489,7 @@ func TestSingleSideRangeProof(t *testing.T) {
|
||||||
// TestReverseSingleSideRangeProof tests the range ends with 0xffff...fff.
|
// TestReverseSingleSideRangeProof tests the range ends with 0xffff...fff.
|
||||||
func TestReverseSingleSideRangeProof(t *testing.T) {
|
func TestReverseSingleSideRangeProof(t *testing.T) {
|
||||||
for i := 0; i < 64; i++ {
|
for i := 0; i < 64; i++ {
|
||||||
trie, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()))
|
trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase()))
|
||||||
var entries entrySlice
|
var entries entrySlice
|
||||||
for i := 0; i < 4096; i++ {
|
for i := 0; i < 4096; i++ {
|
||||||
value := &kv{randBytes(32), randBytes(20), false}
|
value := &kv{randBytes(32), randBytes(20), false}
|
||||||
|
|
@ -596,7 +596,7 @@ func TestBadRangeProof(t *testing.T) {
|
||||||
// TestGappedRangeProof focuses on the small trie with embedded nodes.
|
// TestGappedRangeProof focuses on the small trie with embedded nodes.
|
||||||
// If the gapped node is embedded in the trie, it should be detected too.
|
// If the gapped node is embedded in the trie, it should be detected too.
|
||||||
func TestGappedRangeProof(t *testing.T) {
|
func TestGappedRangeProof(t *testing.T) {
|
||||||
trie, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()))
|
trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase()))
|
||||||
var entries []*kv // Sorted entries
|
var entries []*kv // Sorted entries
|
||||||
for i := byte(0); i < 10; i++ {
|
for i := byte(0); i < 10; i++ {
|
||||||
value := &kv{common.LeftPadBytes([]byte{i}, 32), []byte{i}, false}
|
value := &kv{common.LeftPadBytes([]byte{i}, 32), []byte{i}, false}
|
||||||
|
|
@ -670,7 +670,7 @@ func TestSameSideProofs(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHasRightElement(t *testing.T) {
|
func TestHasRightElement(t *testing.T) {
|
||||||
trie, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()))
|
trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase()))
|
||||||
var entries entrySlice
|
var entries entrySlice
|
||||||
for i := 0; i < 4096; i++ {
|
for i := 0; i < 4096; i++ {
|
||||||
value := &kv{randBytes(32), randBytes(20), false}
|
value := &kv{randBytes(32), randBytes(20), false}
|
||||||
|
|
@ -1023,7 +1023,7 @@ func benchmarkVerifyRangeNoProof(b *testing.B, size int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func randomTrie(n int) (*Trie, map[string]*kv) {
|
func randomTrie(n int) (*Trie, map[string]*kv) {
|
||||||
trie, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()))
|
trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase()))
|
||||||
vals := make(map[string]*kv)
|
vals := make(map[string]*kv)
|
||||||
for i := byte(0); i < 100; i++ {
|
for i := byte(0); i < 100; i++ {
|
||||||
value := &kv{common.LeftPadBytes([]byte{i}, 32), []byte{i}, false}
|
value := &kv{common.LeftPadBytes([]byte{i}, 32), []byte{i}, false}
|
||||||
|
|
@ -1048,7 +1048,7 @@ func randBytes(n int) []byte {
|
||||||
}
|
}
|
||||||
|
|
||||||
func nonRandomTrie(n int) (*Trie, map[string]*kv) {
|
func nonRandomTrie(n int) (*Trie, map[string]*kv) {
|
||||||
trie, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()))
|
trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase()))
|
||||||
vals := make(map[string]*kv)
|
vals := make(map[string]*kv)
|
||||||
max := uint64(0xffffffffffffffff)
|
max := uint64(0xffffffffffffffff)
|
||||||
for i := uint64(0); i < uint64(n); i++ {
|
for i := uint64(0); i < uint64(n); i++ {
|
||||||
|
|
@ -1073,7 +1073,7 @@ func TestRangeProofKeysWithSharedPrefix(t *testing.T) {
|
||||||
common.Hex2Bytes("02"),
|
common.Hex2Bytes("02"),
|
||||||
common.Hex2Bytes("03"),
|
common.Hex2Bytes("03"),
|
||||||
}
|
}
|
||||||
trie, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()))
|
trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase()))
|
||||||
for i, key := range keys {
|
for i, key := range keys {
|
||||||
trie.Update(key, vals[i])
|
trie.Update(key, vals[i])
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,22 +42,22 @@ type SecureTrie struct {
|
||||||
secKeyCacheOwner *SecureTrie // Pointer to self, replace the key Cache on mismatch
|
secKeyCacheOwner *SecureTrie // Pointer to self, replace the key Cache on mismatch
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSecure creates a trie with an existing root Node from a backing database
|
// NewSecure creates a trie with an existing root node from a backing database
|
||||||
// and optional intermediate in-memory Node pool.
|
// and optional intermediate in-memory node pool.
|
||||||
//
|
//
|
||||||
// If root is the zero hash or the sha3 hash of an empty string, the
|
// If root is the zero hash or the sha3 hash of an empty string, the
|
||||||
// trie is initially empty. Otherwise, New will panic if Db is nil
|
// trie is initially empty. Otherwise, New will panic if db is nil
|
||||||
// and returns MissingNodeError if the root Node cannot be found.
|
// and returns MissingNodeError if the root node cannot be found.
|
||||||
//
|
//
|
||||||
// Accessing the trie loads nodes from the database or Node pool on demand.
|
// Accessing the trie loads nodes from the database or node pool on demand.
|
||||||
// Loaded nodes are kept around until their 'Cache generation' expires.
|
// Loaded nodes are kept around until their 'cache generation' expires.
|
||||||
// A new Cache generation is created by each call to Commit.
|
// A new cache generation is created by each call to Commit.
|
||||||
// cachelimit sets the number of past Cache generations to keep.
|
// cachelimit sets the number of past cache generations to keep.
|
||||||
func NewSecure(root common.Hash, db *Database) (*SecureTrie, error) {
|
func NewSecure(owner common.Hash, root common.Hash, db *Database) (*SecureTrie, error) {
|
||||||
if db == nil {
|
if db == nil {
|
||||||
panic("trie.NewSecure called without a database")
|
panic("trie.NewSecure called without a database")
|
||||||
}
|
}
|
||||||
trie, err := New(root, db)
|
trie, err := New(owner, root, db)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func newEmptySecure() *SecureTrie {
|
func newEmptySecure() *SecureTrie {
|
||||||
trie, _ := NewSecure(common.Hash{}, NewDatabase(memorydb.New()))
|
trie, _ := NewSecure(common.Hash{}, common.Hash{}, NewDatabase(memorydb.New()))
|
||||||
return trie
|
return trie
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -36,7 +36,7 @@ func newEmptySecure() *SecureTrie {
|
||||||
func makeTestSecureTrie() (*Database, *SecureTrie, map[string][]byte) {
|
func makeTestSecureTrie() (*Database, *SecureTrie, map[string][]byte) {
|
||||||
// Create an empty trie
|
// Create an empty trie
|
||||||
triedb := NewDatabase(memorydb.New())
|
triedb := NewDatabase(memorydb.New())
|
||||||
trie, _ := NewSecure(common.Hash{}, triedb)
|
trie, _ := NewSecure(common.Hash{}, common.Hash{}, triedb)
|
||||||
|
|
||||||
// Fill it with some arbitrary data
|
// Fill it with some arbitrary data
|
||||||
content := make(map[string][]byte)
|
content := make(map[string][]byte)
|
||||||
|
|
|
||||||
|
|
@ -39,9 +39,10 @@ var stPool = sync.Pool{
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func stackTrieFromPool(db ethdb.KeyValueWriter) *StackTrie {
|
func stackTrieFromPool(db ethdb.KeyValueWriter, owner common.Hash) *StackTrie {
|
||||||
st := stPool.Get().(*StackTrie)
|
st := stPool.Get().(*StackTrie)
|
||||||
st.db = db
|
st.db = db
|
||||||
|
st.owner = owner
|
||||||
return st
|
return st
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -54,6 +55,7 @@ func returnToPool(st *StackTrie) {
|
||||||
// in order. Once it determines that a subtree will no longer be inserted
|
// in order. Once it determines that a subtree will no longer be inserted
|
||||||
// into, it will hash it and free up the memory it uses.
|
// into, it will hash it and free up the memory it uses.
|
||||||
type StackTrie struct {
|
type StackTrie struct {
|
||||||
|
owner common.Hash // the owner of the trie
|
||||||
nodeType uint8 // node type (as in branch, ext, leaf)
|
nodeType uint8 // node type (as in branch, ext, leaf)
|
||||||
val []byte // value contained by this node if it's a leaf
|
val []byte // value contained by this node if it's a leaf
|
||||||
key []byte // key chunk covered by this (leaf|ext) node
|
key []byte // key chunk covered by this (leaf|ext) node
|
||||||
|
|
@ -69,6 +71,16 @@ func NewStackTrie(db ethdb.KeyValueWriter) *StackTrie {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewStackTrieWithOwner allocates and initializes an empty trie, but with
|
||||||
|
// the additional owner field.
|
||||||
|
func NewStackTrieWithOwner(db ethdb.KeyValueWriter, owner common.Hash) *StackTrie {
|
||||||
|
return &StackTrie{
|
||||||
|
owner: owner,
|
||||||
|
nodeType: emptyNode,
|
||||||
|
db: db,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// NewFromBinary initialises a serialized stacktrie with the given db.
|
// NewFromBinary initialises a serialized stacktrie with the given db.
|
||||||
func NewFromBinary(data []byte, db ethdb.KeyValueWriter) (*StackTrie, error) {
|
func NewFromBinary(data []byte, db ethdb.KeyValueWriter) (*StackTrie, error) {
|
||||||
var st StackTrie
|
var st StackTrie
|
||||||
|
|
@ -89,10 +101,12 @@ func (st *StackTrie) MarshalBinary() (data []byte, err error) {
|
||||||
w = bufio.NewWriter(&b)
|
w = bufio.NewWriter(&b)
|
||||||
)
|
)
|
||||||
if err := gob.NewEncoder(w).Encode(struct {
|
if err := gob.NewEncoder(w).Encode(struct {
|
||||||
Nodetype uint8
|
Owner common.Hash
|
||||||
|
NodeType uint8
|
||||||
Val []byte
|
Val []byte
|
||||||
Key []byte
|
Key []byte
|
||||||
}{
|
}{
|
||||||
|
st.owner,
|
||||||
st.nodeType,
|
st.nodeType,
|
||||||
st.val,
|
st.val,
|
||||||
st.key,
|
st.key,
|
||||||
|
|
@ -123,12 +137,14 @@ func (st *StackTrie) UnmarshalBinary(data []byte) error {
|
||||||
|
|
||||||
func (st *StackTrie) unmarshalBinary(r io.Reader) error {
|
func (st *StackTrie) unmarshalBinary(r io.Reader) error {
|
||||||
var dec struct {
|
var dec struct {
|
||||||
Nodetype uint8
|
Owner common.Hash
|
||||||
|
NodeType uint8
|
||||||
Val []byte
|
Val []byte
|
||||||
Key []byte
|
Key []byte
|
||||||
}
|
}
|
||||||
gob.NewDecoder(r).Decode(&dec)
|
gob.NewDecoder(r).Decode(&dec)
|
||||||
st.nodeType = dec.Nodetype
|
st.owner = dec.Owner
|
||||||
|
st.nodeType = dec.NodeType
|
||||||
st.val = dec.Val
|
st.val = dec.Val
|
||||||
st.key = dec.Key
|
st.key = dec.Key
|
||||||
|
|
||||||
|
|
@ -155,16 +171,16 @@ func (st *StackTrie) setDb(db ethdb.KeyValueWriter) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func newLeaf(key, val []byte, db ethdb.KeyValueWriter) *StackTrie {
|
func newLeaf(owner common.Hash, key, val []byte, db ethdb.KeyValueWriter) *StackTrie {
|
||||||
st := stackTrieFromPool(db)
|
st := stackTrieFromPool(db, owner)
|
||||||
st.nodeType = leafNode
|
st.nodeType = leafNode
|
||||||
st.key = append(st.key, key...)
|
st.key = append(st.key, key...)
|
||||||
st.val = val
|
st.val = val
|
||||||
return st
|
return st
|
||||||
}
|
}
|
||||||
|
|
||||||
func newExt(key []byte, child *StackTrie, db ethdb.KeyValueWriter) *StackTrie {
|
func newExt(owner common.Hash, key []byte, child *StackTrie, db ethdb.KeyValueWriter) *StackTrie {
|
||||||
st := stackTrieFromPool(db)
|
st := stackTrieFromPool(db, owner)
|
||||||
st.nodeType = extNode
|
st.nodeType = extNode
|
||||||
st.key = append(st.key, key...)
|
st.key = append(st.key, key...)
|
||||||
st.children[0] = child
|
st.children[0] = child
|
||||||
|
|
@ -197,6 +213,7 @@ func (st *StackTrie) Update(key, value []byte) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *StackTrie) Reset() {
|
func (st *StackTrie) Reset() {
|
||||||
|
st.owner = common.Hash{}
|
||||||
st.db = nil
|
st.db = nil
|
||||||
st.key = st.key[:0]
|
st.key = st.key[:0]
|
||||||
st.val = nil
|
st.val = nil
|
||||||
|
|
@ -237,7 +254,7 @@ func (st *StackTrie) insert(key, value []byte) {
|
||||||
|
|
||||||
// Add new child
|
// Add new child
|
||||||
if st.children[idx] == nil {
|
if st.children[idx] == nil {
|
||||||
st.children[idx] = newLeaf(key[1:], value, st.db)
|
st.children[idx] = newLeaf(st.owner, key[1:], value, st.db)
|
||||||
} else {
|
} else {
|
||||||
st.children[idx].insert(key[1:], value)
|
st.children[idx].insert(key[1:], value)
|
||||||
}
|
}
|
||||||
|
|
@ -263,7 +280,7 @@ func (st *StackTrie) insert(key, value []byte) {
|
||||||
// node directly.
|
// node directly.
|
||||||
var n *StackTrie
|
var n *StackTrie
|
||||||
if diffidx < len(st.key)-1 {
|
if diffidx < len(st.key)-1 {
|
||||||
n = newExt(st.key[diffidx+1:], st.children[0], st.db)
|
n = newExt(st.owner, st.key[diffidx+1:], st.children[0], st.db)
|
||||||
} else {
|
} else {
|
||||||
// Break on the last byte, no need to insert
|
// Break on the last byte, no need to insert
|
||||||
// an extension node: reuse the current node
|
// an extension node: reuse the current node
|
||||||
|
|
@ -283,12 +300,12 @@ func (st *StackTrie) insert(key, value []byte) {
|
||||||
// the common prefix is at least one byte
|
// the common prefix is at least one byte
|
||||||
// long, insert a new intermediate branch
|
// long, insert a new intermediate branch
|
||||||
// node.
|
// node.
|
||||||
st.children[0] = stackTrieFromPool(st.db)
|
st.children[0] = stackTrieFromPool(st.db, st.owner)
|
||||||
st.children[0].nodeType = branchNode
|
st.children[0].nodeType = branchNode
|
||||||
p = st.children[0]
|
p = st.children[0]
|
||||||
}
|
}
|
||||||
// Create a leaf for the inserted part
|
// Create a leaf for the inserted part
|
||||||
o := newLeaf(key[diffidx+1:], value, st.db)
|
o := newLeaf(st.owner, key[diffidx+1:], value, st.db)
|
||||||
|
|
||||||
// Insert both child leaves where they belong:
|
// Insert both child leaves where they belong:
|
||||||
origIdx := st.key[diffidx]
|
origIdx := st.key[diffidx]
|
||||||
|
|
@ -324,7 +341,7 @@ func (st *StackTrie) insert(key, value []byte) {
|
||||||
// Convert current node into an ext,
|
// Convert current node into an ext,
|
||||||
// and insert a child branch node.
|
// and insert a child branch node.
|
||||||
st.nodeType = extNode
|
st.nodeType = extNode
|
||||||
st.children[0] = NewStackTrie(st.db)
|
st.children[0] = NewStackTrieWithOwner(st.db, st.owner)
|
||||||
st.children[0].nodeType = branchNode
|
st.children[0].nodeType = branchNode
|
||||||
p = st.children[0]
|
p = st.children[0]
|
||||||
}
|
}
|
||||||
|
|
@ -333,11 +350,11 @@ func (st *StackTrie) insert(key, value []byte) {
|
||||||
// value and another containing the new value. The child leaf
|
// value and another containing the new value. The child leaf
|
||||||
// is hashed directly in order to free up some memory.
|
// is hashed directly in order to free up some memory.
|
||||||
origIdx := st.key[diffidx]
|
origIdx := st.key[diffidx]
|
||||||
p.children[origIdx] = newLeaf(st.key[diffidx+1:], st.val, st.db)
|
p.children[origIdx] = newLeaf(st.owner, st.key[diffidx+1:], st.val, st.db)
|
||||||
p.children[origIdx].hash()
|
p.children[origIdx].hash()
|
||||||
|
|
||||||
newIdx := key[diffidx]
|
newIdx := key[diffidx]
|
||||||
p.children[newIdx] = newLeaf(key[diffidx+1:], value, st.db)
|
p.children[newIdx] = newLeaf(st.owner, key[diffidx+1:], value, st.db)
|
||||||
|
|
||||||
// Finally, cut off the key part that has been passed
|
// Finally, cut off the key part that has been passed
|
||||||
// over to the children.
|
// over to the children.
|
||||||
|
|
|
||||||
|
|
@ -188,7 +188,7 @@ func TestStackTrieInsertAndHash(t *testing.T) {
|
||||||
|
|
||||||
func TestSizeBug(t *testing.T) {
|
func TestSizeBug(t *testing.T) {
|
||||||
st := NewStackTrie(nil)
|
st := NewStackTrie(nil)
|
||||||
nt, _ := New(common.Hash{}, NewDatabase(memorydb.New()))
|
nt := NewEmpty(NewDatabase(memorydb.New()))
|
||||||
|
|
||||||
leaf := common.FromHex("290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563")
|
leaf := common.FromHex("290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563")
|
||||||
value := common.FromHex("94cf40d0d2b44f2b66e07cace1372ca42b73cf21a3")
|
value := common.FromHex("94cf40d0d2b44f2b66e07cace1372ca42b73cf21a3")
|
||||||
|
|
@ -203,7 +203,7 @@ func TestSizeBug(t *testing.T) {
|
||||||
|
|
||||||
func TestEmptyBug(t *testing.T) {
|
func TestEmptyBug(t *testing.T) {
|
||||||
st := NewStackTrie(nil)
|
st := NewStackTrie(nil)
|
||||||
nt, _ := New(common.Hash{}, NewDatabase(memorydb.New()))
|
nt := NewEmpty(NewDatabase(memorydb.New()))
|
||||||
|
|
||||||
//leaf := common.FromHex("290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563")
|
//leaf := common.FromHex("290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563")
|
||||||
//value := common.FromHex("94cf40d0d2b44f2b66e07cace1372ca42b73cf21a3")
|
//value := common.FromHex("94cf40d0d2b44f2b66e07cace1372ca42b73cf21a3")
|
||||||
|
|
@ -229,7 +229,7 @@ func TestEmptyBug(t *testing.T) {
|
||||||
|
|
||||||
func TestValLength56(t *testing.T) {
|
func TestValLength56(t *testing.T) {
|
||||||
st := NewStackTrie(nil)
|
st := NewStackTrie(nil)
|
||||||
nt, _ := New(common.Hash{}, NewDatabase(memorydb.New()))
|
nt := NewEmpty(NewDatabase(memorydb.New()))
|
||||||
|
|
||||||
//leaf := common.FromHex("290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563")
|
//leaf := common.FromHex("290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563")
|
||||||
//value := common.FromHex("94cf40d0d2b44f2b66e07cace1372ca42b73cf21a3")
|
//value := common.FromHex("94cf40d0d2b44f2b66e07cace1372ca42b73cf21a3")
|
||||||
|
|
@ -254,7 +254,8 @@ func TestValLength56(t *testing.T) {
|
||||||
// which causes a lot of node-within-node. This case was found via fuzzing.
|
// which causes a lot of node-within-node. This case was found via fuzzing.
|
||||||
func TestUpdateSmallNodes(t *testing.T) {
|
func TestUpdateSmallNodes(t *testing.T) {
|
||||||
st := NewStackTrie(nil)
|
st := NewStackTrie(nil)
|
||||||
nt, _ := New(common.Hash{}, NewDatabase(memorydb.New()))
|
nt := NewEmpty(NewDatabase(memorydb.New()))
|
||||||
|
|
||||||
kvs := []struct {
|
kvs := []struct {
|
||||||
K string
|
K string
|
||||||
V string
|
V string
|
||||||
|
|
@ -282,7 +283,8 @@ func TestUpdateSmallNodes(t *testing.T) {
|
||||||
func TestUpdateVariableKeys(t *testing.T) {
|
func TestUpdateVariableKeys(t *testing.T) {
|
||||||
t.SkipNow()
|
t.SkipNow()
|
||||||
st := NewStackTrie(nil)
|
st := NewStackTrie(nil)
|
||||||
nt, _ := New(common.Hash{}, NewDatabase(memorydb.New()))
|
nt := NewEmpty(NewDatabase(memorydb.New()))
|
||||||
|
|
||||||
kvs := []struct {
|
kvs := []struct {
|
||||||
K string
|
K string
|
||||||
V string
|
V string
|
||||||
|
|
@ -352,7 +354,7 @@ func TestStacktrieNotModifyValues(t *testing.T) {
|
||||||
func TestStacktrieSerialization(t *testing.T) {
|
func TestStacktrieSerialization(t *testing.T) {
|
||||||
var (
|
var (
|
||||||
st = NewStackTrie(nil)
|
st = NewStackTrie(nil)
|
||||||
nt, _ = New(common.Hash{}, NewDatabase(memorydb.New()))
|
nt = NewEmpty(NewDatabase(memorydb.New()))
|
||||||
keyB = big.NewInt(1)
|
keyB = big.NewInt(1)
|
||||||
keyDelta = big.NewInt(1)
|
keyDelta = big.NewInt(1)
|
||||||
vals [][]byte
|
vals [][]byte
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ import (
|
||||||
func makeTestTrie() (*Database, *SecureTrie, map[string][]byte) {
|
func makeTestTrie() (*Database, *SecureTrie, map[string][]byte) {
|
||||||
// Create an empty trie
|
// Create an empty trie
|
||||||
triedb := NewDatabase(memorydb.New())
|
triedb := NewDatabase(memorydb.New())
|
||||||
trie, _ := NewSecure(types.EmptyRootHash, triedb)
|
trie, _ := NewSecure(common.Hash{}, common.Hash{}, triedb)
|
||||||
|
|
||||||
// Fill it with some arbitrary data
|
// Fill it with some arbitrary data
|
||||||
content := make(map[string][]byte)
|
content := make(map[string][]byte)
|
||||||
|
|
@ -61,7 +61,7 @@ func makeTestTrie() (*Database, *SecureTrie, map[string][]byte) {
|
||||||
// content map.
|
// content map.
|
||||||
func checkTrieContents(t *testing.T, db *Database, root []byte, content map[string][]byte) {
|
func checkTrieContents(t *testing.T, db *Database, root []byte, content map[string][]byte) {
|
||||||
// Check root availability and trie contents
|
// Check root availability and trie contents
|
||||||
trie, err := NewSecure(common.BytesToHash(root), db)
|
trie, err := NewSecure(common.Hash{}, common.BytesToHash(root), db)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create trie at %x: %v", root, err)
|
t.Fatalf("failed to create trie at %x: %v", root, err)
|
||||||
}
|
}
|
||||||
|
|
@ -78,7 +78,7 @@ func checkTrieContents(t *testing.T, db *Database, root []byte, content map[stri
|
||||||
// checkTrieConsistency checks that all nodes in a trie are indeed present.
|
// checkTrieConsistency checks that all nodes in a trie are indeed present.
|
||||||
func checkTrieConsistency(db *Database, root common.Hash) error {
|
func checkTrieConsistency(db *Database, root common.Hash) error {
|
||||||
// Create and iterate a trie rooted in a subnode
|
// Create and iterate a trie rooted in a subnode
|
||||||
trie, err := NewSecure(root, db)
|
trie, err := NewSecure(common.Hash{}, root, db)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil // Consider a non existent state consistent
|
return nil // Consider a non existent state consistent
|
||||||
}
|
}
|
||||||
|
|
@ -92,8 +92,8 @@ func checkTrieConsistency(db *Database, root common.Hash) error {
|
||||||
func TestEmptySync(t *testing.T) {
|
func TestEmptySync(t *testing.T) {
|
||||||
dbA := NewDatabase(memorydb.New())
|
dbA := NewDatabase(memorydb.New())
|
||||||
dbB := NewDatabase(memorydb.New())
|
dbB := NewDatabase(memorydb.New())
|
||||||
emptyA, _ := New(types.EmptyRootHash, dbA)
|
emptyA := NewEmpty(dbA)
|
||||||
emptyB, _ := New(types.EmptyRootHash, dbB)
|
emptyB, _ := New(common.Hash{}, types.EmptyRootHash, dbB)
|
||||||
|
|
||||||
for i, trie := range []*Trie{emptyA, emptyB} {
|
for i, trie := range []*Trie{emptyA, emptyB} {
|
||||||
sync := NewSync(trie.Hash(), memorydb.New(), nil)
|
sync := NewSync(trie.Hash(), memorydb.New(), nil)
|
||||||
|
|
|
||||||
72
trie/trie.go
72
trie/trie.go
|
|
@ -52,8 +52,9 @@ type LeafCallback func(paths [][]byte, hexpath []byte, leaf []byte, parent commo
|
||||||
//
|
//
|
||||||
// Trie is not safe for concurrent use.
|
// Trie is not safe for concurrent use.
|
||||||
type Trie struct {
|
type Trie struct {
|
||||||
Db *Database
|
Db *Database
|
||||||
root node
|
root node
|
||||||
|
owner common.Hash
|
||||||
|
|
||||||
// Keep track of the number leaves which have been inserted since the last
|
// Keep track of the number leaves which have been inserted since the last
|
||||||
// hashing operation. This number will not directly map to the number of
|
// hashing operation. This number will not directly map to the number of
|
||||||
|
|
@ -75,33 +76,27 @@ func (t *Trie) Copy() *Trie {
|
||||||
return &Trie{
|
return &Trie{
|
||||||
Db: t.Db,
|
Db: t.Db,
|
||||||
root: t.root,
|
root: t.root,
|
||||||
|
owner: t.owner,
|
||||||
unhashed: t.unhashed,
|
unhashed: t.unhashed,
|
||||||
tracer: t.tracer.copy(),
|
tracer: t.tracer.copy(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a trie with an existing root node from db.
|
// New creates a trie with an existing root node from db and an assigned
|
||||||
|
// owner for storage proximity.
|
||||||
//
|
//
|
||||||
// If root is the zero hash or the sha3 hash of an empty string, the
|
// If root is the zero hash or the sha3 hash of an empty string, the
|
||||||
// trie is initially empty and does not require a database. Otherwise,
|
// trie is initially empty and does not require a database. Otherwise,
|
||||||
// New will panic if Db is nil and returns a MissingNodeError if root does
|
// New will panic if db is nil and returns a MissingNodeError if root does
|
||||||
// not exist in the database. Accessing the trie loads nodes from Db on demand.
|
// not exist in the database. Accessing the trie loads nodes from db on demand.
|
||||||
func New(root common.Hash, db *Database) (*Trie, error) {
|
func New(owner common.Hash, root common.Hash, db *Database) (*Trie, error) {
|
||||||
if db == nil {
|
return newTrie(owner, root, db)
|
||||||
panic("trie.New called without a database")
|
}
|
||||||
}
|
|
||||||
trie := &Trie{
|
// NewEmpty is a shortcut to create empty tree. It's mostly used in tests.
|
||||||
Db: db,
|
func NewEmpty(db *Database) *Trie {
|
||||||
//tracer: newTracer(),
|
tr, _ := newTrie(common.Hash{}, common.Hash{}, db)
|
||||||
}
|
return tr
|
||||||
if root != (common.Hash{}) && root != types.EmptyRootHash {
|
|
||||||
rootnode, err := trie.resolveHash(root[:], nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
trie.root = rootnode
|
|
||||||
}
|
|
||||||
return trie, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// newWithRootNode initializes the trie with the given root node.
|
// newWithRootNode initializes the trie with the given root node.
|
||||||
|
|
@ -114,6 +109,26 @@ func newWithRootNode(root node) *Trie {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// newTrie is the internal function used to construct the trie with given parameters.
|
||||||
|
func newTrie(owner common.Hash, root common.Hash, db *Database) (*Trie, error) {
|
||||||
|
if db == nil {
|
||||||
|
panic("trie.New called without a database")
|
||||||
|
}
|
||||||
|
trie := &Trie{
|
||||||
|
Db: db,
|
||||||
|
owner: owner,
|
||||||
|
//tracer: newTracer(),
|
||||||
|
}
|
||||||
|
if root != (common.Hash{}) && root != types.EmptyRootHash {
|
||||||
|
rootnode, err := trie.resolveHash(root[:], nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
trie.root = rootnode
|
||||||
|
}
|
||||||
|
return trie, nil
|
||||||
|
}
|
||||||
|
|
||||||
// NodeIterator returns an iterator that returns nodes of the trie. Iteration starts at
|
// NodeIterator returns an iterator that returns nodes of the trie. Iteration starts at
|
||||||
// the key after the given start key.
|
// the key after the given start key.
|
||||||
func (t *Trie) NodeIterator(start []byte) NodeIterator {
|
func (t *Trie) NodeIterator(start []byte) NodeIterator {
|
||||||
|
|
@ -717,7 +732,7 @@ func (t *Trie) resolveHash(n hashNode, prefix []byte) (node, error) {
|
||||||
if node := t.Db.node(hash); node != nil {
|
if node := t.Db.node(hash); node != nil {
|
||||||
return node, nil
|
return node, nil
|
||||||
}
|
}
|
||||||
return nil, &MissingNodeError{NodeHash: hash, Path: prefix}
|
return nil, &MissingNodeError{Owner: t.owner, NodeHash: hash, Path: prefix}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Trie) resolveBlob(n hashNode, prefix []byte) ([]byte, error) {
|
func (t *Trie) resolveBlob(n hashNode, prefix []byte) ([]byte, error) {
|
||||||
|
|
@ -726,7 +741,7 @@ func (t *Trie) resolveBlob(n hashNode, prefix []byte) ([]byte, error) {
|
||||||
if len(blob) != 0 {
|
if len(blob) != 0 {
|
||||||
return blob, nil
|
return blob, nil
|
||||||
}
|
}
|
||||||
return nil, &MissingNodeError{NodeHash: hash, Path: prefix}
|
return nil, &MissingNodeError{Owner: t.owner, NodeHash: hash, Path: prefix}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hash returns the root hash of the trie. It does not write to the
|
// Hash returns the root hash of the trie. It does not write to the
|
||||||
|
|
@ -757,7 +772,10 @@ func (t *Trie) Commit(onleaf LeafCallback) (common.Hash, int, error) {
|
||||||
// Do a quick check if we really need to commit, before we spin
|
// Do a quick check if we really need to commit, before we spin
|
||||||
// up goroutines. This can happen e.g. if we load a trie for reading storage
|
// up goroutines. This can happen e.g. if we load a trie for reading storage
|
||||||
// values, but don't write to it.
|
// values, but don't write to it.
|
||||||
if _, dirty := t.root.cache(); !dirty {
|
if hashedNode, dirty := t.root.cache(); !dirty {
|
||||||
|
// Replace the root node with the origin hash in order to
|
||||||
|
// ensure all resolved nodes are dropped after the commit.
|
||||||
|
t.root = hashedNode
|
||||||
return rootHash, 0, nil
|
return rootHash, 0, nil
|
||||||
}
|
}
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
|
|
@ -802,6 +820,12 @@ func (t *Trie) hashRoot() (node, node, error) {
|
||||||
// Reset drops the referenced root node and cleans all internal state.
|
// Reset drops the referenced root node and cleans all internal state.
|
||||||
func (t *Trie) Reset() {
|
func (t *Trie) Reset() {
|
||||||
t.root = nil
|
t.root = nil
|
||||||
|
t.owner = common.Hash{}
|
||||||
t.unhashed = 0
|
t.unhashed = 0
|
||||||
t.tracer.reset()
|
t.tracer.reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Owner returns the associated trie owner.
|
||||||
|
func (t *Trie) Owner() common.Hash {
|
||||||
|
return t.owner
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -48,12 +48,12 @@ func init() {
|
||||||
|
|
||||||
// Used for testing
|
// Used for testing
|
||||||
func newEmpty() *Trie {
|
func newEmpty() *Trie {
|
||||||
trie, _ := New(common.Hash{}, NewDatabase(memorydb.New()))
|
trie := NewEmpty(NewDatabase(memorydb.New()))
|
||||||
return trie
|
return trie
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEmptyTrie(t *testing.T) {
|
func TestEmptyTrie(t *testing.T) {
|
||||||
trie, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()))
|
trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase()))
|
||||||
res := trie.Hash()
|
res := trie.Hash()
|
||||||
exp := types.EmptyRootHash
|
exp := types.EmptyRootHash
|
||||||
if res != exp {
|
if res != exp {
|
||||||
|
|
@ -62,7 +62,7 @@ func TestEmptyTrie(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNull(t *testing.T) {
|
func TestNull(t *testing.T) {
|
||||||
trie, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()))
|
trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase()))
|
||||||
key := make([]byte, 32)
|
key := make([]byte, 32)
|
||||||
value := []byte("test")
|
value := []byte("test")
|
||||||
trie.Update(key, value)
|
trie.Update(key, value)
|
||||||
|
|
@ -72,7 +72,7 @@ func TestNull(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMissingRoot(t *testing.T) {
|
func TestMissingRoot(t *testing.T) {
|
||||||
trie, err := New(common.HexToHash("0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"), NewDatabase(memorydb.New()))
|
trie, err := New(common.Hash{}, common.HexToHash("0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"), NewDatabase(memorydb.New()))
|
||||||
if trie != nil {
|
if trie != nil {
|
||||||
t.Error("New returned non-nil trie for invalid root")
|
t.Error("New returned non-nil trie for invalid root")
|
||||||
}
|
}
|
||||||
|
|
@ -88,7 +88,7 @@ func testMissingNode(t *testing.T, memonly bool) {
|
||||||
diskdb := memorydb.New()
|
diskdb := memorydb.New()
|
||||||
triedb := NewDatabase(diskdb)
|
triedb := NewDatabase(diskdb)
|
||||||
|
|
||||||
trie, _ := New(common.Hash{}, triedb)
|
trie := NewEmpty(triedb)
|
||||||
updateString(trie, "120000", "qwerqwerqwerqwerqwerqwerqwerqwer")
|
updateString(trie, "120000", "qwerqwerqwerqwerqwerqwerqwerqwer")
|
||||||
updateString(trie, "123456", "asdfasdfasdfasdfasdfasdfasdfasdf")
|
updateString(trie, "123456", "asdfasdfasdfasdfasdfasdfasdfasdf")
|
||||||
root, _, _ := trie.Commit(nil)
|
root, _, _ := trie.Commit(nil)
|
||||||
|
|
@ -96,27 +96,27 @@ func testMissingNode(t *testing.T, memonly bool) {
|
||||||
triedb.Commit(root, true)
|
triedb.Commit(root, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
trie, _ = New(root, triedb)
|
trie, _ = New(common.Hash{}, root, triedb)
|
||||||
_, err := trie.TryGet([]byte("120000"))
|
_, err := trie.TryGet([]byte("120000"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error: %v", err)
|
t.Errorf("Unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
trie, _ = New(root, triedb)
|
trie, _ = New(common.Hash{}, root, triedb)
|
||||||
_, err = trie.TryGet([]byte("120099"))
|
_, err = trie.TryGet([]byte("120099"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error: %v", err)
|
t.Errorf("Unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
trie, _ = New(root, triedb)
|
trie, _ = New(common.Hash{}, root, triedb)
|
||||||
_, err = trie.TryGet([]byte("123456"))
|
_, err = trie.TryGet([]byte("123456"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error: %v", err)
|
t.Errorf("Unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
trie, _ = New(root, triedb)
|
trie, _ = New(common.Hash{}, root, triedb)
|
||||||
err = trie.TryUpdate([]byte("120099"), []byte("zxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcv"))
|
err = trie.TryUpdate([]byte("120099"), []byte("zxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcv"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error: %v", err)
|
t.Errorf("Unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
trie, _ = New(root, triedb)
|
trie, _ = New(common.Hash{}, root, triedb)
|
||||||
err = trie.TryDelete([]byte("123456"))
|
err = trie.TryDelete([]byte("123456"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error: %v", err)
|
t.Errorf("Unexpected error: %v", err)
|
||||||
|
|
@ -129,27 +129,27 @@ func testMissingNode(t *testing.T, memonly bool) {
|
||||||
diskdb.Delete(hash[:])
|
diskdb.Delete(hash[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
trie, _ = New(root, triedb)
|
trie, _ = New(common.Hash{}, root, triedb)
|
||||||
_, err = trie.TryGet([]byte("120000"))
|
_, err = trie.TryGet([]byte("120000"))
|
||||||
if _, ok := err.(*MissingNodeError); !ok {
|
if _, ok := err.(*MissingNodeError); !ok {
|
||||||
t.Errorf("Wrong error: %v", err)
|
t.Errorf("Wrong error: %v", err)
|
||||||
}
|
}
|
||||||
trie, _ = New(root, triedb)
|
trie, _ = New(common.Hash{}, root, triedb)
|
||||||
_, err = trie.TryGet([]byte("120099"))
|
_, err = trie.TryGet([]byte("120099"))
|
||||||
if _, ok := err.(*MissingNodeError); !ok {
|
if _, ok := err.(*MissingNodeError); !ok {
|
||||||
t.Errorf("Wrong error: %v", err)
|
t.Errorf("Wrong error: %v", err)
|
||||||
}
|
}
|
||||||
trie, _ = New(root, triedb)
|
trie, _ = New(common.Hash{}, root, triedb)
|
||||||
_, err = trie.TryGet([]byte("123456"))
|
_, err = trie.TryGet([]byte("123456"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error: %v", err)
|
t.Errorf("Unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
trie, _ = New(root, triedb)
|
trie, _ = New(common.Hash{}, root, triedb)
|
||||||
err = trie.TryUpdate([]byte("120099"), []byte("zxcv"))
|
err = trie.TryUpdate([]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)
|
||||||
}
|
}
|
||||||
trie, _ = New(root, triedb)
|
trie, _ = New(common.Hash{}, root, triedb)
|
||||||
err = trie.TryDelete([]byte("123456"))
|
err = trie.TryDelete([]byte("123456"))
|
||||||
if _, ok := err.(*MissingNodeError); !ok {
|
if _, ok := err.(*MissingNodeError); !ok {
|
||||||
t.Errorf("Wrong error: %v", err)
|
t.Errorf("Wrong error: %v", err)
|
||||||
|
|
@ -371,10 +371,10 @@ func runRandTestBool(rt randTest) bool {
|
||||||
|
|
||||||
func runRandTest(rt randTest) error {
|
func runRandTest(rt randTest) error {
|
||||||
var (
|
var (
|
||||||
triedb = NewDatabase(memorydb.New())
|
triedb = NewDatabase(memorydb.New())
|
||||||
tr, _ = New(common.Hash{}, triedb)
|
tr = NewEmpty(triedb)
|
||||||
values = make(map[string]string) // tracks content of the trie
|
values = make(map[string]string) // tracks content of the trie
|
||||||
origTrie, _ = New(common.Hash{}, triedb)
|
origTrie = NewEmpty(triedb)
|
||||||
)
|
)
|
||||||
tr.tracer = newTracer()
|
tr.tracer = newTracer()
|
||||||
|
|
||||||
|
|
@ -405,7 +405,7 @@ func runRandTest(rt randTest) error {
|
||||||
rt[i].err = err
|
rt[i].err = err
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
newtr, err := New(hash, triedb)
|
newtr, err := New(common.Hash{}, hash, triedb)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
rt[i].err = err
|
rt[i].err = err
|
||||||
return err
|
return err
|
||||||
|
|
@ -415,7 +415,7 @@ func runRandTest(rt randTest) error {
|
||||||
|
|
||||||
origTrie = tr.Copy()
|
origTrie = tr.Copy()
|
||||||
case opItercheckhash:
|
case opItercheckhash:
|
||||||
checktr, _ := New(common.Hash{}, triedb)
|
checktr := NewEmpty(triedb)
|
||||||
it := NewIterator(tr.NodeIterator(nil))
|
it := NewIterator(tr.NodeIterator(nil))
|
||||||
for it.Next() {
|
for it.Next() {
|
||||||
checktr.Update(it.Key, it.Value)
|
checktr.Update(it.Key, it.Value)
|
||||||
|
|
@ -598,7 +598,7 @@ func TestTinyTrie(t *testing.T) {
|
||||||
if exp, root := common.HexToHash("0608c1d1dc3905fa22204c7a0e43644831c3b6d3def0f274be623a948197e64a"), trie.Hash(); exp != root {
|
if exp, root := common.HexToHash("0608c1d1dc3905fa22204c7a0e43644831c3b6d3def0f274be623a948197e64a"), trie.Hash(); exp != root {
|
||||||
t.Errorf("3: got %x, exp %x", root, exp)
|
t.Errorf("3: got %x, exp %x", root, exp)
|
||||||
}
|
}
|
||||||
checktr, _ := New(common.Hash{}, trie.Db)
|
checktr := NewEmpty(trie.Db)
|
||||||
it := NewIterator(trie.NodeIterator(nil))
|
it := NewIterator(trie.NodeIterator(nil))
|
||||||
for it.Next() {
|
for it.Next() {
|
||||||
checktr.Update(it.Key, it.Value)
|
checktr.Update(it.Key, it.Value)
|
||||||
|
|
@ -701,7 +701,7 @@ func TestCommitSequenceStackTrie(t *testing.T) {
|
||||||
// This spongeDb is used to check the sequence of disk-db-writes
|
// This spongeDb is used to check the sequence of disk-db-writes
|
||||||
s := &spongeDb{sponge: sha3.NewLegacyKeccak256(), id: "a"}
|
s := &spongeDb{sponge: sha3.NewLegacyKeccak256(), id: "a"}
|
||||||
db := NewDatabase(s)
|
db := NewDatabase(s)
|
||||||
trie, _ := New(common.Hash{}, db)
|
trie := NewEmpty(db)
|
||||||
// Another sponge is used for the stacktrie commits
|
// Another sponge is used for the stacktrie commits
|
||||||
stackTrieSponge := &spongeDb{sponge: sha3.NewLegacyKeccak256(), id: "b"}
|
stackTrieSponge := &spongeDb{sponge: sha3.NewLegacyKeccak256(), id: "b"}
|
||||||
stTrie := NewStackTrie(stackTrieSponge)
|
stTrie := NewStackTrie(stackTrieSponge)
|
||||||
|
|
@ -757,7 +757,7 @@ func TestCommitSequenceStackTrie(t *testing.T) {
|
||||||
func TestCommitSequenceSmallRoot(t *testing.T) {
|
func TestCommitSequenceSmallRoot(t *testing.T) {
|
||||||
s := &spongeDb{sponge: sha3.NewLegacyKeccak256(), id: "a"}
|
s := &spongeDb{sponge: sha3.NewLegacyKeccak256(), id: "a"}
|
||||||
db := NewDatabase(s)
|
db := NewDatabase(s)
|
||||||
trie, _ := New(common.Hash{}, db)
|
trie := NewEmpty(db)
|
||||||
// Another sponge is used for the stacktrie commits
|
// Another sponge is used for the stacktrie commits
|
||||||
stackTrieSponge := &spongeDb{sponge: sha3.NewLegacyKeccak256(), id: "b"}
|
stackTrieSponge := &spongeDb{sponge: sha3.NewLegacyKeccak256(), id: "b"}
|
||||||
stTrie := NewStackTrie(stackTrieSponge)
|
stTrie := NewStackTrie(stackTrieSponge)
|
||||||
|
|
|
||||||
|
|
@ -19,14 +19,12 @@ package trie
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/XinFinOrg/XDPoSChain/common"
|
|
||||||
"github.com/XinFinOrg/XDPoSChain/core/rawdb"
|
"github.com/XinFinOrg/XDPoSChain/core/rawdb"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Tests if the trie diffs are tracked correctly.
|
// Tests if the trie diffs are tracked correctly.
|
||||||
func TestTrieTracer(t *testing.T) {
|
func TestTrieTracer(t *testing.T) {
|
||||||
db := NewDatabase(rawdb.NewMemoryDatabase())
|
trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase()))
|
||||||
trie, _ := New(common.Hash{}, db)
|
|
||||||
trie.tracer = newTracer()
|
trie.tracer = newTracer()
|
||||||
|
|
||||||
// Insert a batch of entries, all the nodes should be marked as inserted
|
// Insert a batch of entries, all the nodes should be marked as inserted
|
||||||
|
|
@ -93,8 +91,7 @@ func TestTrieTracer(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTrieTracerNoop(t *testing.T) {
|
func TestTrieTracerNoop(t *testing.T) {
|
||||||
db := NewDatabase(rawdb.NewMemoryDatabase())
|
trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase()))
|
||||||
trie, _ := New(common.Hash{}, db)
|
|
||||||
trie.tracer = newTracer()
|
trie.tracer = newTracer()
|
||||||
|
|
||||||
// Insert a batch of entries, all the nodes should be marked as inserted
|
// Insert a batch of entries, all the nodes should be marked as inserted
|
||||||
|
|
|
||||||
|
|
@ -29,24 +29,39 @@ package trie
|
||||||
// This tool can track all of them no matter the node is embedded in its
|
// This tool can track all of them no matter the node is embedded in its
|
||||||
// parent or not, but valueNode is never tracked.
|
// parent or not, but valueNode is never tracked.
|
||||||
//
|
//
|
||||||
|
// Besides, it's also used for recording the original value of the nodes
|
||||||
|
// when they are resolved from the disk. The pre-value of the nodes will
|
||||||
|
// be used to construct reverse-diffs in the future.
|
||||||
|
//
|
||||||
// Note tracer is not thread-safe, callers should be responsible for handling
|
// Note tracer is not thread-safe, callers should be responsible for handling
|
||||||
// the concurrency issues by themselves.
|
// the concurrency issues by themselves.
|
||||||
type tracer struct {
|
type tracer struct {
|
||||||
insert map[string]struct{}
|
insert map[string]struct{}
|
||||||
delete map[string]struct{}
|
delete map[string]struct{}
|
||||||
|
origin map[string][]byte
|
||||||
}
|
}
|
||||||
|
|
||||||
// newTracer initializes trie node diff tracer.
|
// newTracer initializes the tracer for capturing trie changes.
|
||||||
func newTracer() *tracer {
|
func newTracer() *tracer {
|
||||||
return &tracer{
|
return &tracer{
|
||||||
insert: make(map[string]struct{}),
|
insert: make(map[string]struct{}),
|
||||||
delete: make(map[string]struct{}),
|
delete: make(map[string]struct{}),
|
||||||
|
origin: make(map[string][]byte),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// onInsert tracks the newly inserted trie node. If it's already
|
// onRead tracks the newly loaded trie node and caches the rlp-encoded blob internally.
|
||||||
// in the deletion set(resurrected node), then just wipe it from
|
// Don't change the value outside of function since it's not deep-copied.
|
||||||
// the deletion set as it's untouched.
|
func (t *tracer) onRead(key []byte, val []byte) {
|
||||||
|
// Tracer isn't used right now, remove this check later.
|
||||||
|
if t == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
t.origin[string(key)] = val
|
||||||
|
}
|
||||||
|
|
||||||
|
// onInsert tracks the newly inserted trie node. If it's already in the deletion set
|
||||||
|
// (resurrected node), then just wipe it from the deletion set as the "untouched".
|
||||||
func (t *tracer) onInsert(key []byte) {
|
func (t *tracer) onInsert(key []byte) {
|
||||||
// Tracer isn't used right now, remove this check later.
|
// Tracer isn't used right now, remove this check later.
|
||||||
if t == nil {
|
if t == nil {
|
||||||
|
|
@ -100,6 +115,15 @@ func (t *tracer) deleteList() [][]byte {
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getPrev returns the cached original value of the specified node.
|
||||||
|
func (t *tracer) getPrev(key []byte) []byte {
|
||||||
|
// Don't panic on uninitialized tracer, it's possible in testing.
|
||||||
|
if t == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return t.origin[string(key)]
|
||||||
|
}
|
||||||
|
|
||||||
// reset clears the content tracked by tracer.
|
// reset clears the content tracked by tracer.
|
||||||
func (t *tracer) reset() {
|
func (t *tracer) reset() {
|
||||||
// Tracer isn't used right now, remove this check later.
|
// Tracer isn't used right now, remove this check later.
|
||||||
|
|
@ -108,6 +132,7 @@ func (t *tracer) reset() {
|
||||||
}
|
}
|
||||||
t.insert = make(map[string]struct{})
|
t.insert = make(map[string]struct{})
|
||||||
t.delete = make(map[string]struct{})
|
t.delete = make(map[string]struct{})
|
||||||
|
t.origin = make(map[string][]byte)
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy returns a deep copied tracer instance.
|
// copy returns a deep copied tracer instance.
|
||||||
|
|
@ -119,6 +144,7 @@ func (t *tracer) copy() *tracer {
|
||||||
var (
|
var (
|
||||||
insert = make(map[string]struct{})
|
insert = make(map[string]struct{})
|
||||||
delete = make(map[string]struct{})
|
delete = make(map[string]struct{})
|
||||||
|
origin = make(map[string][]byte)
|
||||||
)
|
)
|
||||||
for key := range t.insert {
|
for key := range t.insert {
|
||||||
insert[key] = struct{}{}
|
insert[key] = struct{}{}
|
||||||
|
|
@ -126,8 +152,12 @@ func (t *tracer) copy() *tracer {
|
||||||
for key := range t.delete {
|
for key := range t.delete {
|
||||||
delete[key] = struct{}{}
|
delete[key] = struct{}{}
|
||||||
}
|
}
|
||||||
|
for key, val := range t.origin {
|
||||||
|
origin[key] = val
|
||||||
|
}
|
||||||
return &tracer{
|
return &tracer{
|
||||||
insert: insert,
|
insert: insert,
|
||||||
delete: delete,
|
delete: delete,
|
||||||
|
origin: origin,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue