mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-17 09:23:48 +00:00
core, trie: minor cleanups, test fixes
This commit is contained in:
parent
0e91a178b7
commit
d2ec96e861
17 changed files with 255 additions and 138 deletions
|
|
@ -96,7 +96,6 @@ type BlockChain struct {
|
||||||
currentBlock *types.Block // Current head of the block chain
|
currentBlock *types.Block // Current head of the block chain
|
||||||
currentFastBlock *types.Block // Current head of the fast-sync chain (may be above the block chain!)
|
currentFastBlock *types.Block // Current head of the fast-sync chain (may be above the block chain!)
|
||||||
|
|
||||||
trieMemPool *trie.MemPool // Trie node memory pool to avoid storing everything to disk
|
|
||||||
stateCache state.Database // State database to reuse between imports (contains state cache)
|
stateCache state.Database // State database to reuse between imports (contains state cache)
|
||||||
bodyCache *lru.Cache // Cache for the most recent block bodies
|
bodyCache *lru.Cache // Cache for the most recent block bodies
|
||||||
bodyRLPCache *lru.Cache // Cache for the most recent block bodies in RLP encoded format
|
bodyRLPCache *lru.Cache // Cache for the most recent block bodies in RLP encoded format
|
||||||
|
|
@ -121,7 +120,6 @@ type BlockChain struct {
|
||||||
// available in the database. It initialises the default Ethereum Validator and
|
// available in the database. It initialises the default Ethereum Validator and
|
||||||
// Processor.
|
// Processor.
|
||||||
func NewBlockChain(chainDb ethdb.Database, config *params.ChainConfig, engine consensus.Engine, vmConfig vm.Config) (*BlockChain, error) {
|
func NewBlockChain(chainDb ethdb.Database, config *params.ChainConfig, engine consensus.Engine, vmConfig vm.Config) (*BlockChain, error) {
|
||||||
trieMemPool := trie.NewMemPool()
|
|
||||||
bodyCache, _ := lru.New(bodyCacheLimit)
|
bodyCache, _ := lru.New(bodyCacheLimit)
|
||||||
bodyRLPCache, _ := lru.New(bodyCacheLimit)
|
bodyRLPCache, _ := lru.New(bodyCacheLimit)
|
||||||
blockCache, _ := lru.New(blockCacheLimit)
|
blockCache, _ := lru.New(blockCacheLimit)
|
||||||
|
|
@ -131,8 +129,7 @@ func NewBlockChain(chainDb ethdb.Database, config *params.ChainConfig, engine co
|
||||||
bc := &BlockChain{
|
bc := &BlockChain{
|
||||||
config: config,
|
config: config,
|
||||||
chainDb: chainDb,
|
chainDb: chainDb,
|
||||||
trieMemPool: trieMemPool,
|
stateCache: state.NewDatabase(chainDb, trie.NewNodePool()),
|
||||||
stateCache: state.NewDatabase(chainDb, trieMemPool),
|
|
||||||
quit: make(chan struct{}),
|
quit: make(chan struct{}),
|
||||||
bodyCache: bodyCache,
|
bodyCache: bodyCache,
|
||||||
bodyRLPCache: bodyRLPCache,
|
bodyRLPCache: bodyRLPCache,
|
||||||
|
|
@ -597,7 +594,7 @@ func (bc *BlockChain) Stop() {
|
||||||
root := bc.CurrentHeader().Root
|
root := bc.CurrentHeader().Root
|
||||||
|
|
||||||
batch := bc.chainDb.NewBatch()
|
batch := bc.chainDb.NewBatch()
|
||||||
if err := bc.trieMemPool.Commit(root, batch); err != nil {
|
if err := bc.stateCache.NodePool().Commit(root, batch); err != nil {
|
||||||
log.Error("Failed to commit latest state trie", "err", err)
|
log.Error("Failed to commit latest state trie", "err", err)
|
||||||
}
|
}
|
||||||
if err := batch.Write(); err != nil {
|
if err := batch.Write(); err != nil {
|
||||||
|
|
@ -809,13 +806,14 @@ func (bc *BlockChain) WriteBlockAndState(block *types.Block, receipts []*types.R
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return NonStatTy, err
|
return NonStatTy, err
|
||||||
}
|
}
|
||||||
bc.trieMemPool.Reference(root, common.Hash{})
|
pool := bc.stateCache.NodePool()
|
||||||
|
pool.Reference(root, common.Hash{}) // metadata reference to keep trie alive
|
||||||
if number := block.NumberU64(); number > 192 {
|
if number := block.NumberU64(); number > 192 {
|
||||||
if (number-192)%128 == 0 {
|
if (number-192)%128 == 0 {
|
||||||
bc.trieMemPool.Commit(root, batch)
|
pool.Commit(root, batch)
|
||||||
}
|
}
|
||||||
header := bc.GetHeaderByNumber(block.NumberU64() - 192)
|
header := bc.GetHeaderByNumber(block.NumberU64() - 192)
|
||||||
bc.trieMemPool.Dereference(header.Root, common.Hash{})
|
pool.Dereference(header.Root, common.Hash{})
|
||||||
}
|
}
|
||||||
if err := WriteBlockReceipts(batch, block.Hash(), block.NumberU64(), receipts); err != nil {
|
if err := WriteBlockReceipts(batch, block.Hash(), block.NumberU64(), receipts); err != nil {
|
||||||
return NonStatTy, err
|
return NonStatTy, err
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
|
||||||
if _, err := bc.InsertChain(blocks); err != nil {
|
if _, err := bc.InsertChain(blocks); err != nil {
|
||||||
t.Fatalf("failed to import contra-fork chain for expansion: %v", err)
|
t.Fatalf("failed to import contra-fork chain for expansion: %v", err)
|
||||||
}
|
}
|
||||||
if err := bc.trieMemPool.Commit(bc.CurrentHeader().Root, db); err != nil {
|
if err := bc.stateCache.NodePool().Commit(bc.CurrentHeader().Root, db); err != nil {
|
||||||
t.Fatalf("failed to commit contra-fork head for expansion: %v", err)
|
t.Fatalf("failed to commit contra-fork head for expansion: %v", err)
|
||||||
}
|
}
|
||||||
blocks, _ = GenerateChain(&proConf, conBc.CurrentBlock(), ethash.NewFaker(), db, 1, func(i int, gen *BlockGen) {})
|
blocks, _ = GenerateChain(&proConf, conBc.CurrentBlock(), ethash.NewFaker(), db, 1, func(i int, gen *BlockGen) {})
|
||||||
|
|
@ -104,7 +104,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
|
||||||
if _, err := bc.InsertChain(blocks); err != nil {
|
if _, err := bc.InsertChain(blocks); err != nil {
|
||||||
t.Fatalf("failed to import pro-fork chain for expansion: %v", err)
|
t.Fatalf("failed to import pro-fork chain for expansion: %v", err)
|
||||||
}
|
}
|
||||||
if err := bc.trieMemPool.Commit(bc.CurrentHeader().Root, db); err != nil {
|
if err := bc.stateCache.NodePool().Commit(bc.CurrentHeader().Root, db); err != nil {
|
||||||
t.Fatalf("failed to commit pro-fork head for expansion: %v", err)
|
t.Fatalf("failed to commit pro-fork head for expansion: %v", err)
|
||||||
}
|
}
|
||||||
blocks, _ = GenerateChain(&conConf, proBc.CurrentBlock(), ethash.NewFaker(), db, 1, func(i int, gen *BlockGen) {})
|
blocks, _ = GenerateChain(&conConf, proBc.CurrentBlock(), ethash.NewFaker(), db, 1, func(i int, gen *BlockGen) {})
|
||||||
|
|
@ -130,7 +130,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
|
||||||
if _, err := bc.InsertChain(blocks); err != nil {
|
if _, err := bc.InsertChain(blocks); err != nil {
|
||||||
t.Fatalf("failed to import contra-fork chain for expansion: %v", err)
|
t.Fatalf("failed to import contra-fork chain for expansion: %v", err)
|
||||||
}
|
}
|
||||||
if err := bc.trieMemPool.Commit(bc.CurrentHeader().Root, db); err != nil {
|
if err := bc.stateCache.NodePool().Commit(bc.CurrentHeader().Root, db); err != nil {
|
||||||
t.Fatalf("failed to commit contra-fork head for expansion: %v", err)
|
t.Fatalf("failed to commit contra-fork head for expansion: %v", err)
|
||||||
}
|
}
|
||||||
blocks, _ = GenerateChain(&proConf, conBc.CurrentBlock(), ethash.NewFaker(), db, 1, func(i int, gen *BlockGen) {})
|
blocks, _ = GenerateChain(&proConf, conBc.CurrentBlock(), ethash.NewFaker(), db, 1, func(i int, gen *BlockGen) {})
|
||||||
|
|
@ -150,7 +150,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
|
||||||
if _, err := bc.InsertChain(blocks); err != nil {
|
if _, err := bc.InsertChain(blocks); err != nil {
|
||||||
t.Fatalf("failed to import pro-fork chain for expansion: %v", err)
|
t.Fatalf("failed to import pro-fork chain for expansion: %v", err)
|
||||||
}
|
}
|
||||||
if err := bc.trieMemPool.Commit(bc.CurrentHeader().Root, db); err != nil {
|
if err := bc.stateCache.NodePool().Commit(bc.CurrentHeader().Root, db); err != nil {
|
||||||
t.Fatalf("failed to commit pro-fork head for expansion: %v", err)
|
t.Fatalf("failed to commit pro-fork head for expansion: %v", err)
|
||||||
}
|
}
|
||||||
blocks, _ = GenerateChain(&conConf, proBc.CurrentBlock(), ethash.NewFaker(), db, 1, func(i int, gen *BlockGen) {})
|
blocks, _ = GenerateChain(&conConf, proBc.CurrentBlock(), ethash.NewFaker(), db, 1, func(i int, gen *BlockGen) {})
|
||||||
|
|
|
||||||
|
|
@ -46,14 +46,17 @@ type Database interface {
|
||||||
// OpenStorageTrie opens the storage trie of an account.
|
// OpenStorageTrie opens the storage trie of an account.
|
||||||
OpenStorageTrie(addrHash, root common.Hash) (Trie, error)
|
OpenStorageTrie(addrHash, root common.Hash) (Trie, error)
|
||||||
|
|
||||||
|
// CopyTrie returns an independent copy of the given trie.
|
||||||
|
CopyTrie(Trie) Trie
|
||||||
|
|
||||||
// ContractCode retrieves a particular contract's code.
|
// ContractCode retrieves a particular contract's code.
|
||||||
ContractCode(addrHash, codeHash common.Hash) ([]byte, error)
|
ContractCode(addrHash, codeHash common.Hash) ([]byte, error)
|
||||||
|
|
||||||
// ContractCode retrieves a particular contracts code's size.
|
// ContractCodeSize retrieves a particular contracts code's size.
|
||||||
ContractCodeSize(addrHash, codeHash common.Hash) (int, error)
|
ContractCodeSize(addrHash, codeHash common.Hash) (int, error)
|
||||||
|
|
||||||
// CopyTrie returns an independent copy of the given trie.
|
// NodePool retrieves any intermediate trie-node caching layer.
|
||||||
CopyTrie(Trie) Trie
|
NodePool() *trie.NodePool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trie is a Ethereum Merkle Trie.
|
// Trie is a Ethereum Merkle Trie.
|
||||||
|
|
@ -68,20 +71,23 @@ type Trie interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewDatabase creates a backing store for state. The returned database is safe for
|
// NewDatabase creates a backing store for state. The returned database is safe for
|
||||||
// concurrent use and retains cached trie nodes in memory.
|
// concurrent use and retains cached trie nodes in memory. The pool is an optional
|
||||||
func NewDatabase(db ethdb.Database, pool *trie.MemPool) Database {
|
// intermediate trie-node memory pool between the low level storage layer and the
|
||||||
|
// high level trie abstraction.
|
||||||
|
func NewDatabase(db ethdb.Database, pool *trie.NodePool) Database {
|
||||||
csc, _ := lru.New(codeSizeCacheSize)
|
csc, _ := lru.New(codeSizeCacheSize)
|
||||||
return &cachingDB{db: db, pool: pool, codeSizeCache: csc}
|
return &cachingDB{db: db, pastNodes: pool, codeSizeCache: csc}
|
||||||
}
|
}
|
||||||
|
|
||||||
type cachingDB struct {
|
type cachingDB struct {
|
||||||
db ethdb.Database
|
db ethdb.Database
|
||||||
pool *trie.MemPool
|
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
pastTries []*trie.SecureTrie
|
pastTries []*trie.SecureTrie
|
||||||
|
pastNodes *trie.NodePool
|
||||||
codeSizeCache *lru.Cache
|
codeSizeCache *lru.Cache
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OpenTrie opens the main account trie.
|
||||||
func (db *cachingDB) OpenTrie(root common.Hash) (Trie, error) {
|
func (db *cachingDB) OpenTrie(root common.Hash) (Trie, error) {
|
||||||
db.mu.Lock()
|
db.mu.Lock()
|
||||||
defer db.mu.Unlock()
|
defer db.mu.Unlock()
|
||||||
|
|
@ -91,7 +97,7 @@ func (db *cachingDB) OpenTrie(root common.Hash) (Trie, error) {
|
||||||
return cachedTrie{db.pastTries[i].Copy(), db}, nil
|
return cachedTrie{db.pastTries[i].Copy(), db}, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tr, err := trie.NewSecure(root, db.db, db.pool, MaxTrieCacheGen)
|
tr, err := trie.NewSecure(root, db.db, db.pastNodes, MaxTrieCacheGen)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -110,10 +116,12 @@ func (db *cachingDB) pushTrie(t *trie.SecureTrie) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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, db.pool, 0)
|
return trie.NewSecure(root, db.db, db.pastNodes, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CopyTrie returns an independent copy of the given trie.
|
||||||
func (db *cachingDB) CopyTrie(t Trie) Trie {
|
func (db *cachingDB) CopyTrie(t Trie) Trie {
|
||||||
switch t := t.(type) {
|
switch t := t.(type) {
|
||||||
case cachedTrie:
|
case cachedTrie:
|
||||||
|
|
@ -125,6 +133,7 @@ func (db *cachingDB) CopyTrie(t Trie) Trie {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ContractCode retrieves a particular contract's code.
|
||||||
func (db *cachingDB) ContractCode(addrHash, codeHash common.Hash) ([]byte, error) {
|
func (db *cachingDB) ContractCode(addrHash, codeHash common.Hash) ([]byte, error) {
|
||||||
code, err := db.db.Get(codeHash[:])
|
code, err := db.db.Get(codeHash[:])
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
|
@ -133,6 +142,7 @@ func (db *cachingDB) ContractCode(addrHash, codeHash common.Hash) ([]byte, error
|
||||||
return code, err
|
return code, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ContractCodeSize retrieves a particular contracts code's size.
|
||||||
func (db *cachingDB) ContractCodeSize(addrHash, codeHash common.Hash) (int, error) {
|
func (db *cachingDB) ContractCodeSize(addrHash, codeHash common.Hash) (int, error) {
|
||||||
if cached, ok := db.codeSizeCache.Get(codeHash); ok {
|
if cached, ok := db.codeSizeCache.Get(codeHash); ok {
|
||||||
return cached.(int), nil
|
return cached.(int), nil
|
||||||
|
|
@ -144,6 +154,11 @@ func (db *cachingDB) ContractCodeSize(addrHash, codeHash common.Hash) (int, erro
|
||||||
return len(code), err
|
return len(code), err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NodePool retrieves any intermediate trie-node caching layer.
|
||||||
|
func (db *cachingDB) NodePool() *trie.NodePool {
|
||||||
|
return db.pastNodes
|
||||||
|
}
|
||||||
|
|
||||||
// cachedTrie inserts its trie into a cachingDB on commit.
|
// cachedTrie inserts its trie into a cachingDB on commit.
|
||||||
type cachedTrie struct {
|
type cachedTrie struct {
|
||||||
*trie.SecureTrie
|
*trie.SecureTrie
|
||||||
|
|
|
||||||
|
|
@ -39,11 +39,17 @@ func TestNodeIteratorCoverage(t *testing.T) {
|
||||||
hashes[it.Hash] = struct{}{}
|
hashes[it.Hash] = struct{}{}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Cross check the iterated hashes and the database/nodepool content
|
||||||
// Cross check the hashes and the database itself
|
|
||||||
for hash := range hashes {
|
for hash := range hashes {
|
||||||
if _, err := mem.Get(hash.Bytes()); err != nil {
|
if db.NodePool().Fetch(hash) == nil {
|
||||||
t.Errorf("failed to retrieve reported node %x: %v", hash, err)
|
if _, err := mem.Get(hash.Bytes()); err != nil {
|
||||||
|
t.Errorf("failed to retrieve reported node %x", hash)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, hash := range db.NodePool().Nodes() {
|
||||||
|
if _, ok := hashes[hash]; !ok {
|
||||||
|
t.Errorf("state entry not reported %x", hash)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, key := range mem.Keys() {
|
for _, key := range mem.Keys() {
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ var addr = common.BytesToAddress([]byte("test"))
|
||||||
|
|
||||||
func create() (*ManagedState, *account) {
|
func create() (*ManagedState, *account) {
|
||||||
db, _ := ethdb.NewMemDatabase()
|
db, _ := ethdb.NewMemDatabase()
|
||||||
statedb, _ := New(common.Hash{}, NewDatabase(db, trie.NewMemPool()))
|
statedb, _ := New(common.Hash{}, NewDatabase(db, trie.NewNodePool()))
|
||||||
ms := ManageState(statedb)
|
ms := ManageState(statedb)
|
||||||
ms.StateDB.SetNonce(addr, 100)
|
ms.StateDB.SetNonce(addr, 100)
|
||||||
ms.accounts[addr] = newAccount(ms.StateDB.getStateObject(addr))
|
ms.accounts[addr] = newAccount(ms.StateDB.getStateObject(addr))
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,7 @@ func (s *StateSuite) TestDump(c *checker.C) {
|
||||||
|
|
||||||
func (s *StateSuite) SetUpTest(c *checker.C) {
|
func (s *StateSuite) SetUpTest(c *checker.C) {
|
||||||
s.db, _ = ethdb.NewMemDatabase()
|
s.db, _ = ethdb.NewMemDatabase()
|
||||||
s.state, _ = New(common.Hash{}, NewDatabase(s.db, trie.NewMemPool()))
|
s.state, _ = New(common.Hash{}, NewDatabase(s.db, trie.NewNodePool()))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *StateSuite) TestNull(c *checker.C) {
|
func (s *StateSuite) TestNull(c *checker.C) {
|
||||||
|
|
@ -135,7 +135,7 @@ func (s *StateSuite) TestSnapshotEmpty(c *checker.C) {
|
||||||
// printing/logging in tests (-check.vv does not work)
|
// printing/logging in tests (-check.vv does not work)
|
||||||
func TestSnapshot2(t *testing.T) {
|
func TestSnapshot2(t *testing.T) {
|
||||||
db, _ := ethdb.NewMemDatabase()
|
db, _ := ethdb.NewMemDatabase()
|
||||||
state, _ := New(common.Hash{}, NewDatabase(db, trie.NewMemPool()))
|
state, _ := New(common.Hash{}, NewDatabase(db, trie.NewNodePool()))
|
||||||
|
|
||||||
stateobjaddr0 := toAddr([]byte("so0"))
|
stateobjaddr0 := toAddr([]byte("so0"))
|
||||||
stateobjaddr1 := toAddr([]byte("so1"))
|
stateobjaddr1 := toAddr([]byte("so1"))
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ import (
|
||||||
func TestUpdateLeaks(t *testing.T) {
|
func TestUpdateLeaks(t *testing.T) {
|
||||||
// Create an empty state database
|
// Create an empty state database
|
||||||
db, _ := ethdb.NewMemDatabase()
|
db, _ := ethdb.NewMemDatabase()
|
||||||
state, _ := New(common.Hash{}, NewDatabase(db, trie.NewMemPool()))
|
state, _ := New(common.Hash{}, NewDatabase(db, trie.NewNodePool()))
|
||||||
|
|
||||||
// Update it with some accounts
|
// Update it with some accounts
|
||||||
for i := byte(0); i < 255; i++ {
|
for i := byte(0); i < 255; i++ {
|
||||||
|
|
@ -69,8 +69,8 @@ func TestIntermediateLeaks(t *testing.T) {
|
||||||
// Create two state databases, one transitioning to the final state, the other final from the beginning
|
// Create two state databases, one transitioning to the final state, the other final from the beginning
|
||||||
transDb, _ := ethdb.NewMemDatabase()
|
transDb, _ := ethdb.NewMemDatabase()
|
||||||
finalDb, _ := ethdb.NewMemDatabase()
|
finalDb, _ := ethdb.NewMemDatabase()
|
||||||
transState, _ := New(common.Hash{}, NewDatabase(transDb, trie.NewMemPool()))
|
transState, _ := New(common.Hash{}, NewDatabase(transDb, trie.NewNodePool()))
|
||||||
finalState, _ := New(common.Hash{}, NewDatabase(finalDb, trie.NewMemPool()))
|
finalState, _ := New(common.Hash{}, NewDatabase(finalDb, trie.NewNodePool()))
|
||||||
|
|
||||||
modify := func(state *StateDB, addr common.Address, i, tweak byte) {
|
modify := func(state *StateDB, addr common.Address, i, tweak byte) {
|
||||||
state.SetBalance(addr, big.NewInt(int64(11*i)+int64(tweak)))
|
state.SetBalance(addr, big.NewInt(int64(11*i)+int64(tweak)))
|
||||||
|
|
@ -124,7 +124,7 @@ func TestIntermediateLeaks(t *testing.T) {
|
||||||
func TestCopy(t *testing.T) {
|
func TestCopy(t *testing.T) {
|
||||||
// Create a random state test to copy and modify "independently"
|
// Create a random state test to copy and modify "independently"
|
||||||
mem, _ := ethdb.NewMemDatabase()
|
mem, _ := ethdb.NewMemDatabase()
|
||||||
orig, _ := New(common.Hash{}, NewDatabase(mem, trie.NewMemPool()))
|
orig, _ := New(common.Hash{}, NewDatabase(mem, trie.NewNodePool()))
|
||||||
|
|
||||||
for i := byte(0); i < 255; i++ {
|
for i := byte(0); i < 255; i++ {
|
||||||
obj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i}))
|
obj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i}))
|
||||||
|
|
@ -336,8 +336,8 @@ func (test *snapshotTest) run() bool {
|
||||||
// Run all actions and create snapshots.
|
// Run all actions and create snapshots.
|
||||||
var (
|
var (
|
||||||
db, _ = ethdb.NewMemDatabase()
|
db, _ = ethdb.NewMemDatabase()
|
||||||
mp = trie.NewMemPool()
|
mp = trie.NewNodePool()
|
||||||
state, _ = New(common.Hash{}, NewDatabase(db, trie.NewMemPool()))
|
state, _ = New(common.Hash{}, NewDatabase(db, trie.NewNodePool()))
|
||||||
snapshotRevs = make([]int, len(test.snapshots))
|
snapshotRevs = make([]int, len(test.snapshots))
|
||||||
sindex = 0
|
sindex = 0
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ type testAccount struct {
|
||||||
func makeTestState() (Database, *ethdb.MemDatabase, common.Hash, []*testAccount) {
|
func makeTestState() (Database, *ethdb.MemDatabase, common.Hash, []*testAccount) {
|
||||||
// Create an empty state
|
// Create an empty state
|
||||||
mem, _ := ethdb.NewMemDatabase()
|
mem, _ := ethdb.NewMemDatabase()
|
||||||
db := NewDatabase(mem, trie.NewMemPool())
|
db := NewDatabase(mem, trie.NewNodePool())
|
||||||
state, _ := New(common.Hash{}, db)
|
state, _ := New(common.Hash{}, db)
|
||||||
|
|
||||||
// Fill it with some arbitrary data
|
// Fill it with some arbitrary data
|
||||||
|
|
@ -71,7 +71,7 @@ func makeTestState() (Database, *ethdb.MemDatabase, common.Hash, []*testAccount)
|
||||||
// account array.
|
// account array.
|
||||||
func checkStateAccounts(t *testing.T, db ethdb.Database, root common.Hash, accounts []*testAccount) {
|
func checkStateAccounts(t *testing.T, db ethdb.Database, root common.Hash, accounts []*testAccount) {
|
||||||
// Check root availability and state contents
|
// Check root availability and state contents
|
||||||
state, err := New(root, NewDatabase(db, trie.NewMemPool()))
|
state, err := New(root, NewDatabase(db, trie.NewNodePool()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create state trie at %x: %v", root, err)
|
t.Fatalf("failed to create state trie at %x: %v", root, err)
|
||||||
}
|
}
|
||||||
|
|
@ -96,7 +96,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, db, trie.NewMemPool())
|
trie, err := trie.New(root, db, trie.NewNodePool())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -112,7 +112,7 @@ func checkStateConsistency(db ethdb.Database, root common.Hash) error {
|
||||||
if _, err := db.Get(root.Bytes()); err != nil {
|
if _, err := db.Get(root.Bytes()); err != nil {
|
||||||
return nil // Consider a non existent state consistent.
|
return nil // Consider a non existent state consistent.
|
||||||
}
|
}
|
||||||
state, err := New(root, NewDatabase(db, trie.NewMemPool()))
|
state, err := New(root, NewDatabase(db, trie.NewNodePool()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -138,7 +138,7 @@ func TestIterativeStateSyncBatched(t *testing.T) { testIterativeStateSync(t,
|
||||||
|
|
||||||
func testIterativeStateSync(t *testing.T, batch int) {
|
func testIterativeStateSync(t *testing.T, batch int) {
|
||||||
// Create a random state to copy
|
// Create a random state to copy
|
||||||
_, srcMem, srcRoot, srcAccounts := makeTestState()
|
srcDb, srcMem, srcRoot, srcAccounts := makeTestState()
|
||||||
|
|
||||||
// Create a destination state and sync with the scheduler
|
// Create a destination state and sync with the scheduler
|
||||||
dstDb, _ := ethdb.NewMemDatabase()
|
dstDb, _ := ethdb.NewMemDatabase()
|
||||||
|
|
@ -148,9 +148,14 @@ func testIterativeStateSync(t *testing.T, batch int) {
|
||||||
for len(queue) > 0 {
|
for len(queue) > 0 {
|
||||||
results := make([]trie.SyncResult, len(queue))
|
results := make([]trie.SyncResult, len(queue))
|
||||||
for i, hash := range queue {
|
for i, hash := range queue {
|
||||||
data, err := srcMem.Get(hash.Bytes())
|
var (
|
||||||
if err != nil {
|
data = srcDb.NodePool().Fetch(hash)
|
||||||
t.Fatalf("failed to retrieve node data for %x: %v", hash, err)
|
err error
|
||||||
|
)
|
||||||
|
if data == nil {
|
||||||
|
if data, err = srcMem.Get(hash.Bytes()); err != nil {
|
||||||
|
t.Fatalf("failed to retrieve node data for %x", hash)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
results[i] = trie.SyncResult{Hash: hash, Data: data}
|
results[i] = trie.SyncResult{Hash: hash, Data: data}
|
||||||
}
|
}
|
||||||
|
|
@ -170,7 +175,7 @@ func testIterativeStateSync(t *testing.T, batch int) {
|
||||||
// partial results are returned, and the others sent only later.
|
// partial results are returned, and the others sent only later.
|
||||||
func TestIterativeDelayedStateSync(t *testing.T) {
|
func TestIterativeDelayedStateSync(t *testing.T) {
|
||||||
// Create a random state to copy
|
// Create a random state to copy
|
||||||
_, srcMem, srcRoot, srcAccounts := makeTestState()
|
srcDb, srcMem, srcRoot, srcAccounts := makeTestState()
|
||||||
|
|
||||||
// Create a destination state and sync with the scheduler
|
// Create a destination state and sync with the scheduler
|
||||||
dstDb, _ := ethdb.NewMemDatabase()
|
dstDb, _ := ethdb.NewMemDatabase()
|
||||||
|
|
@ -181,9 +186,14 @@ func TestIterativeDelayedStateSync(t *testing.T) {
|
||||||
// Sync only half of the scheduled nodes
|
// Sync only half of the scheduled nodes
|
||||||
results := make([]trie.SyncResult, len(queue)/2+1)
|
results := make([]trie.SyncResult, len(queue)/2+1)
|
||||||
for i, hash := range queue[:len(results)] {
|
for i, hash := range queue[:len(results)] {
|
||||||
data, err := srcMem.Get(hash.Bytes())
|
var (
|
||||||
if err != nil {
|
data = srcDb.NodePool().Fetch(hash)
|
||||||
t.Fatalf("failed to retrieve node data for %x: %v", hash, err)
|
err error
|
||||||
|
)
|
||||||
|
if data == nil {
|
||||||
|
if data, err = srcMem.Get(hash.Bytes()); err != nil {
|
||||||
|
t.Fatalf("failed to retrieve node data for %x", hash)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
results[i] = trie.SyncResult{Hash: hash, Data: data}
|
results[i] = trie.SyncResult{Hash: hash, Data: data}
|
||||||
}
|
}
|
||||||
|
|
@ -207,7 +217,7 @@ func TestIterativeRandomStateSyncBatched(t *testing.T) { testIterativeRandomS
|
||||||
|
|
||||||
func testIterativeRandomStateSync(t *testing.T, batch int) {
|
func testIterativeRandomStateSync(t *testing.T, batch int) {
|
||||||
// Create a random state to copy
|
// Create a random state to copy
|
||||||
_, srcMem, srcRoot, srcAccounts := makeTestState()
|
srcDb, srcMem, srcRoot, srcAccounts := makeTestState()
|
||||||
|
|
||||||
// Create a destination state and sync with the scheduler
|
// Create a destination state and sync with the scheduler
|
||||||
dstDb, _ := ethdb.NewMemDatabase()
|
dstDb, _ := ethdb.NewMemDatabase()
|
||||||
|
|
@ -221,9 +231,14 @@ func testIterativeRandomStateSync(t *testing.T, batch int) {
|
||||||
// Fetch all the queued nodes in a random order
|
// Fetch all the queued nodes in a random order
|
||||||
results := make([]trie.SyncResult, 0, len(queue))
|
results := make([]trie.SyncResult, 0, len(queue))
|
||||||
for hash := range queue {
|
for hash := range queue {
|
||||||
data, err := srcMem.Get(hash.Bytes())
|
var (
|
||||||
if err != nil {
|
data = srcDb.NodePool().Fetch(hash)
|
||||||
t.Fatalf("failed to retrieve node data for %x: %v", hash, err)
|
err error
|
||||||
|
)
|
||||||
|
if data == nil {
|
||||||
|
if data, err = srcMem.Get(hash.Bytes()); err != nil {
|
||||||
|
t.Fatalf("failed to retrieve node data for %x", hash)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
results = append(results, trie.SyncResult{Hash: hash, Data: data})
|
results = append(results, trie.SyncResult{Hash: hash, Data: data})
|
||||||
}
|
}
|
||||||
|
|
@ -247,7 +262,7 @@ func testIterativeRandomStateSync(t *testing.T, batch int) {
|
||||||
// partial results are returned (Even those randomly), others sent only later.
|
// partial results are returned (Even those randomly), others sent only later.
|
||||||
func TestIterativeRandomDelayedStateSync(t *testing.T) {
|
func TestIterativeRandomDelayedStateSync(t *testing.T) {
|
||||||
// Create a random state to copy
|
// Create a random state to copy
|
||||||
_, srcMem, srcRoot, srcAccounts := makeTestState()
|
srcDb, srcMem, srcRoot, srcAccounts := makeTestState()
|
||||||
|
|
||||||
// Create a destination state and sync with the scheduler
|
// Create a destination state and sync with the scheduler
|
||||||
dstDb, _ := ethdb.NewMemDatabase()
|
dstDb, _ := ethdb.NewMemDatabase()
|
||||||
|
|
@ -263,9 +278,14 @@ func TestIterativeRandomDelayedStateSync(t *testing.T) {
|
||||||
for hash := range queue {
|
for hash := range queue {
|
||||||
delete(queue, hash)
|
delete(queue, hash)
|
||||||
|
|
||||||
data, err := srcMem.Get(hash.Bytes())
|
var (
|
||||||
if err != nil {
|
data = srcDb.NodePool().Fetch(hash)
|
||||||
t.Fatalf("failed to retrieve node data for %x: %v", hash, err)
|
err error
|
||||||
|
)
|
||||||
|
if data == nil {
|
||||||
|
if data, err = srcMem.Get(hash.Bytes()); err != nil {
|
||||||
|
t.Fatalf("failed to retrieve node data for %x", hash)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
results = append(results, trie.SyncResult{Hash: hash, Data: data})
|
results = append(results, trie.SyncResult{Hash: hash, Data: data})
|
||||||
|
|
||||||
|
|
@ -292,7 +312,7 @@ func TestIterativeRandomDelayedStateSync(t *testing.T) {
|
||||||
// the database.
|
// the database.
|
||||||
func TestIncompleteStateSync(t *testing.T) {
|
func TestIncompleteStateSync(t *testing.T) {
|
||||||
// Create a random state to copy
|
// Create a random state to copy
|
||||||
_, srcMem, srcRoot, srcAccounts := makeTestState()
|
srcDb, srcMem, srcRoot, srcAccounts := makeTestState()
|
||||||
|
|
||||||
checkTrieConsistency(srcMem, srcRoot)
|
checkTrieConsistency(srcMem, srcRoot)
|
||||||
|
|
||||||
|
|
@ -306,9 +326,14 @@ func TestIncompleteStateSync(t *testing.T) {
|
||||||
// Fetch a batch of state nodes
|
// Fetch a batch of state nodes
|
||||||
results := make([]trie.SyncResult, len(queue))
|
results := make([]trie.SyncResult, len(queue))
|
||||||
for i, hash := range queue {
|
for i, hash := range queue {
|
||||||
data, err := srcMem.Get(hash.Bytes())
|
var (
|
||||||
if err != nil {
|
data = srcDb.NodePool().Fetch(hash)
|
||||||
t.Fatalf("failed to retrieve node data for %x: %v", hash, err)
|
err error
|
||||||
|
)
|
||||||
|
if data == nil {
|
||||||
|
if data, err = srcMem.Get(hash.Bytes()); err != nil {
|
||||||
|
t.Fatalf("failed to retrieve node data for %x", hash)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
results[i] = trie.SyncResult{Hash: hash, Data: data}
|
results[i] = trie.SyncResult{Hash: hash, Data: data}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -293,7 +293,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(), dl.stateDb, 0)
|
_, err := trie.NewSecure(block.Root(), dl.stateDb, nil, 0) // nil trie node-cache, ensure we have everything on disk
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return fmt.Errorf("non existent block: %x", hash[:4])
|
return fmt.Errorf("non existent block: %x", hash[:4])
|
||||||
|
|
@ -660,7 +660,7 @@ func assertOwnForkedChain(t *testing.T, tester *downloadTester, common int, leng
|
||||||
index = len(tester.ownHashes) - lengths[len(lengths)-1] + int(tester.downloader.queue.fastSyncPivot)
|
index = len(tester.ownHashes) - lengths[len(lengths)-1] + int(tester.downloader.queue.fastSyncPivot)
|
||||||
}
|
}
|
||||||
if index > 0 {
|
if index > 0 {
|
||||||
if statedb, err := state.New(tester.ownHeaders[tester.ownHashes[index]].Root, state.NewDatabase(tester.stateDb)); statedb == nil || err != nil {
|
if statedb, err := state.New(tester.ownHeaders[tester.ownHashes[index]].Root, state.NewDatabase(tester.stateDb, nil)); statedb == nil || err != nil {
|
||||||
t.Fatalf("state reconstruction failed: %v", err)
|
t.Fatalf("state reconstruction failed: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,10 @@ func (db *odrDatabase) ContractCodeSize(addrHash, codeHash common.Hash) (int, er
|
||||||
return len(code), err
|
return len(code), err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (db *odrDatabase) NodePool() *trie.NodePool {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
type odrTrie struct {
|
type odrTrie struct {
|
||||||
db *odrDatabase
|
db *odrDatabase
|
||||||
id *TrieID
|
id *TrieID
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ func returnHasherToPool(h *hasher) {
|
||||||
|
|
||||||
// hash collapses a node down into a hash node, also returning a copy of the
|
// hash collapses a node down into a hash node, also returning a copy of the
|
||||||
// original node initialized with the computed hash to replace the original one.
|
// original node initialized with the computed hash to replace the original one.
|
||||||
func (h *hasher) hash(n node, pool *MemPool, force bool) (node, node, error) {
|
func (h *hasher) hash(n node, pool *NodePool, force bool) (node, node, error) {
|
||||||
// If we're not storing the node, just hashing, use available cached data
|
// If we're not storing the node, just hashing, use available cached data
|
||||||
if hash, dirty := n.cache(); hash != nil {
|
if hash, dirty := n.cache(); hash != nil {
|
||||||
if pool == nil {
|
if pool == nil {
|
||||||
|
|
@ -99,7 +99,7 @@ func (h *hasher) hash(n node, pool *MemPool, force bool) (node, node, error) {
|
||||||
// hashChildren replaces the children of a node with their hashes if the encoded
|
// hashChildren replaces the children of a node with their hashes if the encoded
|
||||||
// size of the child is larger than a hash, returning the collapsed node as well
|
// size of the child is larger than a hash, returning the collapsed node as well
|
||||||
// as a replacement for the original node with the child hashes cached in.
|
// as a replacement for the original node with the child hashes cached in.
|
||||||
func (h *hasher) hashChildren(original node, pool *MemPool) (node, node, []common.Hash, error) {
|
func (h *hasher) hashChildren(original node, pool *NodePool) (node, node, []common.Hash, error) {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
switch n := original.(type) {
|
switch n := original.(type) {
|
||||||
|
|
@ -181,7 +181,10 @@ func (h *hasher) externals(n node) []common.Hash {
|
||||||
return []common.Hash{account.Root}
|
return []common.Hash{account.Root}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *hasher) store(n node, refs []common.Hash, pool *MemPool, force bool) (node, []common.Hash, error) {
|
// store hashes the node n and if we have a storage layer specified, it writes
|
||||||
|
// the key/value pair to it and tracks any node->child references as well as any
|
||||||
|
// node->external trie references.
|
||||||
|
func (h *hasher) store(n node, refs []common.Hash, pool *NodePool, force bool) (node, []common.Hash, error) {
|
||||||
// Don't store hashes or empty nodes.
|
// Don't store hashes or empty nodes.
|
||||||
if _, isHash := n.(hashNode); n == nil || isHash {
|
if _, isHash := n.(hashNode); n == nil || isHash {
|
||||||
return n, refs, nil
|
return n, refs, nil
|
||||||
|
|
|
||||||
|
|
@ -278,45 +278,74 @@ func TestIteratorNoDups(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// This test checks that nodeIterator.Next can be retried after inserting missing trie nodes.
|
// This test checks that nodeIterator.Next can be retried after inserting missing trie nodes.
|
||||||
func TestIteratorContinueAfterError(t *testing.T) {
|
func TestIteratorContinueAfterErrorDirect(t *testing.T) { testIteratorContinueAfterError(t, false) }
|
||||||
db, _ := ethdb.NewMemDatabase()
|
func TestIteratorContinueAfterErrorPooled(t *testing.T) { testIteratorContinueAfterError(t, true) }
|
||||||
mp := NewMemPool()
|
|
||||||
|
|
||||||
tr, _ := New(common.Hash{}, db, mp)
|
func testIteratorContinueAfterError(t *testing.T, pooled bool) {
|
||||||
|
var pool *NodePool
|
||||||
|
if pooled {
|
||||||
|
pool = NewNodePool()
|
||||||
|
}
|
||||||
|
db, _ := ethdb.NewMemDatabase()
|
||||||
|
|
||||||
|
tr, _ := New(common.Hash{}, db, pool)
|
||||||
for _, val := range testdata1 {
|
for _, val := range testdata1 {
|
||||||
tr.Update([]byte(val.k), []byte(val.v))
|
tr.Update([]byte(val.k), []byte(val.v))
|
||||||
}
|
}
|
||||||
tr.Commit()
|
tr.Commit()
|
||||||
wantNodeCount := checkIteratorNoDups(t, tr.NodeIterator(nil), nil)
|
wantNodeCount := checkIteratorNoDups(t, tr.NodeIterator(nil), nil)
|
||||||
keys := db.Keys()
|
|
||||||
t.Log("node count", wantNodeCount)
|
|
||||||
|
|
||||||
|
var (
|
||||||
|
dbKeys [][]byte
|
||||||
|
poolKeys []common.Hash
|
||||||
|
)
|
||||||
|
if pooled {
|
||||||
|
poolKeys = pool.Nodes()
|
||||||
|
} else {
|
||||||
|
dbKeys = db.Keys()
|
||||||
|
}
|
||||||
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(), db, mp)
|
tr, _ := New(tr.Hash(), db, pool)
|
||||||
|
|
||||||
// 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.
|
||||||
var rkey []byte
|
var (
|
||||||
|
rkey common.Hash
|
||||||
|
rval []byte
|
||||||
|
)
|
||||||
for {
|
for {
|
||||||
if rkey = keys[rand.Intn(len(keys))]; !bytes.Equal(rkey, tr.Hash().Bytes()) {
|
if pooled {
|
||||||
|
rkey = poolKeys[rand.Intn(len(poolKeys))]
|
||||||
|
} else {
|
||||||
|
copy(rkey[:], dbKeys[rand.Intn(len(dbKeys))])
|
||||||
|
}
|
||||||
|
if rkey != tr.Hash() {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rval, _ := db.Get(rkey)
|
if pooled {
|
||||||
db.Delete(rkey)
|
rval, _ = pool.cache[rkey]
|
||||||
|
delete(pool.cache, rkey)
|
||||||
|
} else {
|
||||||
|
rval, _ = db.Get(rkey[:])
|
||||||
|
db.Delete(rkey[:])
|
||||||
|
}
|
||||||
// Iterate until the error is hit.
|
// Iterate until the error is hit.
|
||||||
seen := make(map[string]bool)
|
seen := make(map[string]bool)
|
||||||
it := tr.NodeIterator(nil)
|
it := tr.NodeIterator(nil)
|
||||||
checkIteratorNoDups(t, it, seen)
|
checkIteratorNoDups(t, it, seen)
|
||||||
missing, ok := it.Error().(*MissingNodeError)
|
missing, ok := it.Error().(*MissingNodeError)
|
||||||
if !ok || !bytes.Equal(missing.NodeHash[:], rkey) {
|
if !ok || missing.NodeHash != rkey {
|
||||||
t.Fatal("didn't hit missing node, got", it.Error())
|
t.Fatal("didn't hit missing node, got", it.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the node back and continue iteration.
|
// Add the node back and continue iteration.
|
||||||
db.Put(rkey, rval)
|
if pooled {
|
||||||
|
pool.cache[rkey] = rval
|
||||||
|
} else {
|
||||||
|
db.Put(rkey[:], rval)
|
||||||
|
}
|
||||||
checkIteratorNoDups(t, it, seen)
|
checkIteratorNoDups(t, it, seen)
|
||||||
if it.Error() != nil {
|
if it.Error() != nil {
|
||||||
t.Fatal("unexpected error", it.Error())
|
t.Fatal("unexpected error", it.Error())
|
||||||
|
|
@ -330,23 +359,40 @@ func TestIteratorContinueAfterError(t *testing.T) {
|
||||||
// Similar to the test above, this one checks that failure to create nodeIterator at a
|
// Similar to the test above, this one checks that failure to create nodeIterator at a
|
||||||
// certain key prefix behaves correctly when Next is called. The expectation is that Next
|
// certain key prefix behaves correctly when Next is called. The expectation is that Next
|
||||||
// should retry seeking before returning true for the first time.
|
// should retry seeking before returning true for the first time.
|
||||||
func TestIteratorContinueAfterSeekError(t *testing.T) {
|
func TestIteratorContinueAfterSeekErrorDirect(t *testing.T) {
|
||||||
// Commit test trie to db, then remove the node containing "bars".
|
testIteratorContinueAfterSeekError(t, false)
|
||||||
db, _ := ethdb.NewMemDatabase()
|
}
|
||||||
mp := NewMemPool()
|
func TestIteratorContinueAfterSeekErrorPooled(t *testing.T) {
|
||||||
|
testIteratorContinueAfterSeekError(t, true)
|
||||||
|
}
|
||||||
|
|
||||||
ctr, _ := New(common.Hash{}, db, mp)
|
func testIteratorContinueAfterSeekError(t *testing.T, pooled bool) {
|
||||||
|
// Commit test trie to db, then remove the node containing "bars".
|
||||||
|
var pool *NodePool
|
||||||
|
if pooled {
|
||||||
|
pool = NewNodePool()
|
||||||
|
}
|
||||||
|
db, _ := ethdb.NewMemDatabase()
|
||||||
|
|
||||||
|
ctr, _ := New(common.Hash{}, db, pool)
|
||||||
for _, val := range testdata1 {
|
for _, val := range testdata1 {
|
||||||
ctr.Update([]byte(val.k), []byte(val.v))
|
ctr.Update([]byte(val.k), []byte(val.v))
|
||||||
}
|
}
|
||||||
root, _ := ctr.Commit()
|
root, _ := ctr.Commit()
|
||||||
barNodeHash := common.HexToHash("05041990364eb72fcb1127652ce40d8bab765f2bfe53225b1170d276cc101c2e")
|
|
||||||
barNode, _ := db.Get(barNodeHash[:])
|
|
||||||
db.Delete(barNodeHash[:])
|
|
||||||
|
|
||||||
|
barNodeHash := common.HexToHash("05041990364eb72fcb1127652ce40d8bab765f2bfe53225b1170d276cc101c2e")
|
||||||
|
var barNodeBlob []byte
|
||||||
|
|
||||||
|
if pooled {
|
||||||
|
barNodeBlob = pool.cache[barNodeHash]
|
||||||
|
delete(pool.cache, barNodeHash)
|
||||||
|
} else {
|
||||||
|
barNodeBlob, _ = db.Get(barNodeHash[:])
|
||||||
|
db.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, db, mp)
|
tr, _ := New(root, db, pool)
|
||||||
it := tr.NodeIterator([]byte("bars"))
|
it := tr.NodeIterator([]byte("bars"))
|
||||||
missing, ok := it.Error().(*MissingNodeError)
|
missing, ok := it.Error().(*MissingNodeError)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
|
@ -354,10 +400,12 @@ func TestIteratorContinueAfterSeekError(t *testing.T) {
|
||||||
} else if missing.NodeHash != barNodeHash {
|
} else if missing.NodeHash != barNodeHash {
|
||||||
t.Fatal("wrong node missing")
|
t.Fatal("wrong node missing")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reinsert the missing node.
|
// Reinsert the missing node.
|
||||||
db.Put(barNodeHash[:], barNode[:])
|
if pooled {
|
||||||
|
pool.cache[barNodeHash] = barNodeBlob
|
||||||
|
} else {
|
||||||
|
db.Put(barNodeHash[:], barNodeBlob)
|
||||||
|
}
|
||||||
// Check that iteration produces the right set of values.
|
// Check that iteration produces the right set of values.
|
||||||
if err := checkIteratorOrder(testdata1[2:], NewIterator(it)); err != nil {
|
if err := checkIteratorOrder(testdata1[2:], NewIterator(it)); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
|
|
||||||
|
|
@ -24,10 +24,10 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MemPool is an intermediate write layer between the trie data structures and
|
// NodePool is an intermediate write layer between the trie data structures and
|
||||||
// the disk database. The aim is to accumulate trie writes in-memory and only
|
// the disk database. The aim is to accumulate trie writes in-memory and only
|
||||||
// periodically flush a couple tries to disk, garbage collecting the remainder.
|
// periodically flush a couple tries to disk, garbage collecting the remainder.
|
||||||
type MemPool struct {
|
type NodePool struct {
|
||||||
cache map[common.Hash][]byte // Cached data blocks of the trie nodes
|
cache map[common.Hash][]byte // Cached data blocks of the trie nodes
|
||||||
|
|
||||||
parents map[common.Hash]int // Number of live nodes referencing a given one
|
parents map[common.Hash]int // Number of live nodes referencing a given one
|
||||||
|
|
@ -41,10 +41,10 @@ type MemPool struct {
|
||||||
lock sync.RWMutex
|
lock sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewMemPool creates a new memory pool to store ephemeral trie nodes before they
|
// NewNodePool creates a new memory pool to store ephemeral trie nodes before they
|
||||||
// are written out to disk or garbage collected.
|
// are written out to disk or garbage collected.
|
||||||
func NewMemPool() *MemPool {
|
func NewNodePool() *NodePool {
|
||||||
pool := &MemPool{
|
pool := &NodePool{
|
||||||
cache: make(map[common.Hash][]byte),
|
cache: make(map[common.Hash][]byte),
|
||||||
parents: make(map[common.Hash]int),
|
parents: make(map[common.Hash]int),
|
||||||
children: make(map[common.Hash]map[common.Hash]struct{}),
|
children: make(map[common.Hash]map[common.Hash]struct{}),
|
||||||
|
|
@ -57,7 +57,7 @@ func NewMemPool() *MemPool {
|
||||||
// will make a copy of the slice.
|
// will make a copy of the slice.
|
||||||
//
|
//
|
||||||
// Note, this method assumes that the pool's lock is held!
|
// Note, this method assumes that the pool's lock is held!
|
||||||
func (pool *MemPool) insert(hash common.Hash, blob []byte) {
|
func (pool *NodePool) insert(hash common.Hash, blob []byte) {
|
||||||
if _, ok := pool.cache[hash]; ok {
|
if _, ok := pool.cache[hash]; ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -69,15 +69,29 @@ func (pool *MemPool) insert(hash common.Hash, blob []byte) {
|
||||||
|
|
||||||
// Fetch retrieves a cached trie node from memory, or returns nil if the pool
|
// Fetch retrieves a cached trie node from memory, or returns nil if the pool
|
||||||
// does not have this particular piece of data.
|
// does not have this particular piece of data.
|
||||||
func (pool *MemPool) Fetch(hash common.Hash) []byte {
|
func (pool *NodePool) Fetch(hash common.Hash) []byte {
|
||||||
pool.lock.RLock()
|
pool.lock.RLock()
|
||||||
defer pool.lock.RUnlock()
|
defer pool.lock.RUnlock()
|
||||||
|
|
||||||
return pool.cache[hash]
|
return pool.cache[hash]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Nodes retrieves the hashes of all the nodes cached within the node pool. This
|
||||||
|
// method is extremely expensive and should only be used in test code to validate
|
||||||
|
// internal states.
|
||||||
|
func (pool *NodePool) Nodes() []common.Hash {
|
||||||
|
pool.lock.RLock()
|
||||||
|
defer pool.lock.RUnlock()
|
||||||
|
|
||||||
|
var hashes = make([]common.Hash, 0, len(pool.cache))
|
||||||
|
for hash := range pool.cache {
|
||||||
|
hashes = append(hashes, hash)
|
||||||
|
}
|
||||||
|
return hashes
|
||||||
|
}
|
||||||
|
|
||||||
// Reference adds a new reference from parent to node.
|
// Reference adds a new reference from parent to node.
|
||||||
func (pool *MemPool) Reference(node common.Hash, parent common.Hash) {
|
func (pool *NodePool) Reference(node common.Hash, parent common.Hash) {
|
||||||
pool.lock.RLock()
|
pool.lock.RLock()
|
||||||
defer pool.lock.RUnlock()
|
defer pool.lock.RUnlock()
|
||||||
|
|
||||||
|
|
@ -85,7 +99,7 @@ func (pool *MemPool) Reference(node common.Hash, parent common.Hash) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// reference is the private locked version of Reference.
|
// reference is the private locked version of Reference.
|
||||||
func (pool *MemPool) reference(node common.Hash, parent common.Hash) {
|
func (pool *NodePool) reference(node common.Hash, parent common.Hash) {
|
||||||
// If the node does not exist, it's a node pulled from disk, skip
|
// If the node does not exist, it's a node pulled from disk, skip
|
||||||
if _, ok := pool.cache[node]; !ok {
|
if _, ok := pool.cache[node]; !ok {
|
||||||
return
|
return
|
||||||
|
|
@ -95,7 +109,7 @@ func (pool *MemPool) reference(node common.Hash, parent common.Hash) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dereference removes an existing reference from parent to node.
|
// Dereference removes an existing reference from parent to node.
|
||||||
func (pool *MemPool) Dereference(node common.Hash, parent common.Hash) {
|
func (pool *NodePool) Dereference(node common.Hash, parent common.Hash) {
|
||||||
pool.lock.Lock()
|
pool.lock.Lock()
|
||||||
defer pool.lock.Unlock()
|
defer pool.lock.Unlock()
|
||||||
|
|
||||||
|
|
@ -108,7 +122,7 @@ func (pool *MemPool) Dereference(node common.Hash, parent common.Hash) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// dereference is the private locked version of Dereference.
|
// dereference is the private locked version of Dereference.
|
||||||
func (pool *MemPool) dereference(node common.Hash, parent common.Hash) {
|
func (pool *NodePool) dereference(node common.Hash, parent common.Hash) {
|
||||||
// If the node does not exist, it's a previously comitted node.
|
// If the node does not exist, it's a previously comitted node.
|
||||||
blob, ok := pool.cache[node]
|
blob, ok := pool.cache[node]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
|
@ -132,7 +146,7 @@ func (pool *MemPool) dereference(node common.Hash, parent common.Hash) {
|
||||||
|
|
||||||
// Commit iterates over all the children of a particular node, writes them out
|
// Commit iterates over all the children of a particular node, writes them out
|
||||||
// to disk, forcefully tearing down all references in both directions.
|
// to disk, forcefully tearing down all references in both directions.
|
||||||
func (pool *MemPool) Commit(node common.Hash, db DatabaseWriter) error {
|
func (pool *NodePool) Commit(node common.Hash, db DatabaseWriter) error {
|
||||||
pool.lock.Lock()
|
pool.lock.Lock()
|
||||||
defer pool.lock.Unlock()
|
defer pool.lock.Unlock()
|
||||||
|
|
||||||
|
|
@ -158,7 +172,7 @@ func (pool *MemPool) Commit(node common.Hash, db DatabaseWriter) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// commit is the private locked version of Commit.
|
// commit is the private locked version of Commit.
|
||||||
func (pool *MemPool) commit(node common.Hash, db DatabaseWriter) error {
|
func (pool *NodePool) commit(node common.Hash, db DatabaseWriter) error {
|
||||||
// If the node does not exist, it's a previously comitted node.
|
// If the node does not exist, it's a previously comitted node.
|
||||||
blob, ok := pool.cache[node]
|
blob, ok := pool.cache[node]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
|
@ -45,17 +45,18 @@ 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 db.
|
// NewSecure creates a trie with an existing root node from a backing database
|
||||||
|
// 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 db 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, pool *MemPool, cachelimit uint16) (*SecureTrie, error) {
|
func NewSecure(root common.Hash, db Database, pool *NodePool, cachelimit uint16) (*SecureTrie, error) {
|
||||||
if db == nil {
|
if db == nil {
|
||||||
panic("NewSecure called with nil database")
|
panic("NewSecure called with nil database")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ import (
|
||||||
|
|
||||||
func newEmptySecure() *SecureTrie {
|
func newEmptySecure() *SecureTrie {
|
||||||
db, _ := ethdb.NewMemDatabase()
|
db, _ := ethdb.NewMemDatabase()
|
||||||
trie, _ := NewSecure(common.Hash{}, db, NewMemPool(), 0)
|
trie, _ := NewSecure(common.Hash{}, db, NewNodePool(), 0)
|
||||||
return trie
|
return trie
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -37,7 +37,7 @@ func newEmptySecure() *SecureTrie {
|
||||||
func makeTestSecureTrie() (ethdb.Database, *SecureTrie, map[string][]byte) {
|
func makeTestSecureTrie() (ethdb.Database, *SecureTrie, map[string][]byte) {
|
||||||
// Create an empty trie
|
// Create an empty trie
|
||||||
db, _ := ethdb.NewMemDatabase()
|
db, _ := ethdb.NewMemDatabase()
|
||||||
trie, _ := NewSecure(common.Hash{}, db, NewMemPool(), 0)
|
trie, _ := NewSecure(common.Hash{}, db, NewNodePool(), 0)
|
||||||
|
|
||||||
// Fill it with some arbitrary data
|
// Fill it with some arbitrary data
|
||||||
content := make(map[string][]byte)
|
content := make(map[string][]byte)
|
||||||
|
|
|
||||||
10
trie/trie.go
10
trie/trie.go
|
|
@ -85,7 +85,7 @@ type DatabaseWriter interface {
|
||||||
type Trie struct {
|
type Trie struct {
|
||||||
root node
|
root node
|
||||||
db Database
|
db Database
|
||||||
pool *MemPool
|
pool *NodePool
|
||||||
originalRoot common.Hash
|
originalRoot common.Hash
|
||||||
|
|
||||||
// Cache generation values.
|
// Cache generation values.
|
||||||
|
|
@ -112,7 +112,7 @@ func (t *Trie) newFlag() nodeFlag {
|
||||||
// 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, pool *MemPool) (*Trie, error) {
|
func New(root common.Hash, db Database, pool *NodePool) (*Trie, error) {
|
||||||
trie := &Trie{db: db, pool: pool, originalRoot: root}
|
trie := &Trie{db: db, pool: pool, originalRoot: root}
|
||||||
if (root != common.Hash{}) && root != emptyRoot {
|
if (root != common.Hash{}) && root != emptyRoot {
|
||||||
if db == nil {
|
if db == nil {
|
||||||
|
|
@ -496,12 +496,12 @@ func (t *Trie) Commit() (root common.Hash, err error) {
|
||||||
// database before using the trie.
|
// database before using the trie.
|
||||||
func (t *Trie) CommitTo(db DatabaseWriter) (root common.Hash, err error) {
|
func (t *Trie) CommitTo(db DatabaseWriter) (root common.Hash, err error) {
|
||||||
// Retrieve the intermedia trie node memory cache if really writing
|
// Retrieve the intermedia trie node memory cache if really writing
|
||||||
var pool *MemPool
|
var pool *NodePool
|
||||||
if db != nil {
|
if db != nil {
|
||||||
if pool = t.pool; pool == nil {
|
if pool = t.pool; pool == nil {
|
||||||
// If the trie has no intermediate memory pool, but actual database write was
|
// If the trie has no intermediate memory pool, but actual database write was
|
||||||
// nonetheless requested, store into an emphemeral pool and flush out to disk.
|
// nonetheless requested, store into an emphemeral pool and flush out to disk.
|
||||||
pool = NewMemPool()
|
pool = NewNodePool()
|
||||||
defer func() {
|
defer func() {
|
||||||
for hash, blob := range pool.cache {
|
for hash, blob := range pool.cache {
|
||||||
db.Put(hash[:], blob)
|
db.Put(hash[:], blob)
|
||||||
|
|
@ -519,7 +519,7 @@ func (t *Trie) CommitTo(db DatabaseWriter) (root common.Hash, err error) {
|
||||||
return common.BytesToHash(hash.(hashNode)), nil
|
return common.BytesToHash(hash.(hashNode)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Trie) hashRoot(pool *MemPool) (node, node, error) {
|
func (t *Trie) hashRoot(pool *NodePool) (node, node, error) {
|
||||||
if t.root == nil {
|
if t.root == nil {
|
||||||
return hashNode(emptyRoot.Bytes()), nil, nil
|
return hashNode(emptyRoot.Bytes()), nil, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ func init() {
|
||||||
// Used for testing
|
// Used for testing
|
||||||
func newEmpty() *Trie {
|
func newEmpty() *Trie {
|
||||||
db, _ := ethdb.NewMemDatabase()
|
db, _ := ethdb.NewMemDatabase()
|
||||||
trie, _ := New(common.Hash{}, db, NewMemPool())
|
trie, _ := New(common.Hash{}, db, NewNodePool())
|
||||||
return trie
|
return trie
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -69,7 +69,7 @@ func TestNull(t *testing.T) {
|
||||||
|
|
||||||
func TestMissingRoot(t *testing.T) {
|
func TestMissingRoot(t *testing.T) {
|
||||||
db, _ := ethdb.NewMemDatabase()
|
db, _ := ethdb.NewMemDatabase()
|
||||||
trie, err := New(common.HexToHash("0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"), db, NewMemPool())
|
trie, err := New(common.HexToHash("0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"), db, NewNodePool())
|
||||||
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")
|
||||||
}
|
}
|
||||||
|
|
@ -78,72 +78,75 @@ func TestMissingRoot(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMissingNode(t *testing.T) {
|
func TestMissingNodeDirect(t *testing.T) { testMissingNode(t, false) }
|
||||||
db, _ := ethdb.NewMemDatabase()
|
func TestMissingNodePooled(t *testing.T) { testMissingNode(t, true) }
|
||||||
mp := NewMemPool()
|
|
||||||
|
|
||||||
trie, _ := New(common.Hash{}, db, mp)
|
func testMissingNode(t *testing.T, pooled bool) {
|
||||||
|
var pool *NodePool
|
||||||
|
if pooled {
|
||||||
|
pool = NewNodePool()
|
||||||
|
}
|
||||||
|
db, _ := ethdb.NewMemDatabase()
|
||||||
|
|
||||||
|
trie, _ := New(common.Hash{}, db, pool)
|
||||||
updateString(trie, "120000", "qwerqwerqwerqwerqwerqwerqwerqwer")
|
updateString(trie, "120000", "qwerqwerqwerqwerqwerqwerqwerqwer")
|
||||||
updateString(trie, "123456", "asdfasdfasdfasdfasdfasdfasdfasdf")
|
updateString(trie, "123456", "asdfasdfasdfasdfasdfasdfasdfasdf")
|
||||||
root, _ := trie.Commit()
|
root, _ := trie.Commit()
|
||||||
|
|
||||||
trie, _ = New(root, db, mp)
|
trie, _ = New(root, db, pool)
|
||||||
_, 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, db, pool)
|
||||||
trie, _ = New(root, db, mp)
|
|
||||||
_, 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, db, pool)
|
||||||
trie, _ = New(root, db, mp)
|
|
||||||
_, 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, db, pool)
|
||||||
trie, _ = New(root, db, mp)
|
|
||||||
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, db, pool)
|
||||||
trie, _ = New(root, db, mp)
|
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
db.Delete(common.FromHex("e1d943cc8f061a0c0b98162830b970395ac9315654824bf21b73b891365262f9"))
|
hash := common.HexToHash("0xe1d943cc8f061a0c0b98162830b970395ac9315654824bf21b73b891365262f9")
|
||||||
|
if pooled {
|
||||||
|
delete(pool.cache, hash)
|
||||||
|
} else {
|
||||||
|
db.Delete(hash[:])
|
||||||
|
}
|
||||||
|
|
||||||
trie, _ = New(root, db, mp)
|
trie, _ = New(root, db, pool)
|
||||||
_, 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, db, pool)
|
||||||
trie, _ = New(root, db, mp)
|
|
||||||
_, 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, db, pool)
|
||||||
trie, _ = New(root, db, mp)
|
|
||||||
_, 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, db, pool)
|
||||||
trie, _ = New(root, db, mp)
|
|
||||||
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, db, pool)
|
||||||
trie, _ = New(root, db, mp)
|
|
||||||
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)
|
||||||
|
|
@ -410,7 +413,7 @@ func (randTest) Generate(r *rand.Rand, size int) reflect.Value {
|
||||||
|
|
||||||
func runRandTest(rt randTest) bool {
|
func runRandTest(rt randTest) bool {
|
||||||
db, _ := ethdb.NewMemDatabase()
|
db, _ := ethdb.NewMemDatabase()
|
||||||
mp := NewMemPool()
|
mp := NewNodePool()
|
||||||
|
|
||||||
tr, _ := New(common.Hash{}, db, mp)
|
tr, _ := New(common.Hash{}, db, mp)
|
||||||
values := make(map[string]string) // tracks content of the trie
|
values := make(map[string]string) // tracks content of the trie
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue