dev: fix: more wsl lint issues

This commit is contained in:
marcello33 2023-06-15 15:10:57 +02:00
parent 131d7b221f
commit 6223765aab
37 changed files with 407 additions and 1 deletions

View file

@ -195,7 +195,9 @@ func (db *cachingDB) ContractCode(addrHash, codeHash common.Hash) ([]byte, error
if len(code) > 0 { if len(code) > 0 {
return code, nil return code, nil
} }
code = rawdb.ReadCode(db.disk, codeHash) code = rawdb.ReadCode(db.disk, codeHash)
if len(code) > 0 { if len(code) > 0 {
db.codeCache.Add(codeHash, code) db.codeCache.Add(codeHash, code)
db.codeSizeCache.Add(codeHash, len(code)) db.codeSizeCache.Add(codeHash, len(code))
@ -212,7 +214,9 @@ func (db *cachingDB) ContractCodeWithPrefix(addrHash, codeHash common.Hash) ([]b
if len(code) > 0 { if len(code) > 0 {
return code, nil return code, nil
} }
code = rawdb.ReadCodeWithPrefix(db.disk, codeHash) code = rawdb.ReadCodeWithPrefix(db.disk, codeHash)
if len(code) > 0 { if len(code) > 0 {
db.codeCache.Add(codeHash, code) db.codeCache.Add(codeHash, code)
db.codeSizeCache.Add(codeHash, len(code)) db.codeSizeCache.Add(codeHash, len(code))

View file

@ -169,10 +169,12 @@ func (s *StateDB) DumpToCollector(c DumpCollector, conf *DumpConfig) (nextKey []
if !conf.SkipStorage { if !conf.SkipStorage {
account.Storage = make(map[common.Hash]string) account.Storage = make(map[common.Hash]string)
tr, err := obj.getTrie(s.db) tr, err := obj.getTrie(s.db)
if err != nil { if err != nil {
log.Error("Failed to load storage trie", "err", err) log.Error("Failed to load storage trie", "err", err)
continue continue
} }
storageIt := trie.NewIterator(tr.NodeIterator(nil)) storageIt := trie.NewIterator(tr.NodeIterator(nil))
for storageIt.Next() { for storageIt.Next() {
_, content, _, err := rlp.Split(storageIt.Value) _, content, _, err := rlp.Split(storageIt.Value)

View file

@ -109,7 +109,9 @@ func (it *NodeIterator) step() error {
if err := rlp.Decode(bytes.NewReader(it.stateIt.LeafBlob()), &account); err != nil { if err := rlp.Decode(bytes.NewReader(it.stateIt.LeafBlob()), &account); err != nil {
return err return err
} }
dataTrie, err := it.state.db.OpenStorageTrie(it.state.originalRoot, common.BytesToHash(it.stateIt.LeafKey()), account.Root) dataTrie, err := it.state.db.OpenStorageTrie(it.state.originalRoot, common.BytesToHash(it.stateIt.LeafKey()), account.Root)
if err != nil { if err != nil {
return err return err
} }
@ -117,6 +119,7 @@ func (it *NodeIterator) step() error {
if !it.dataIt.Next(true) { if !it.dataIt.Next(true) {
it.dataIt = nil it.dataIt = nil
} }
if !bytes.Equal(account.CodeHash, types.EmptyCodeHash.Bytes()) { if !bytes.Equal(account.CodeHash, types.EmptyCodeHash.Bytes()) {
it.codeHash = common.BytesToHash(account.CodeHash) it.codeHash = common.BytesToHash(account.CodeHash)
addrHash := common.BytesToHash(it.stateIt.LeafKey()) addrHash := common.BytesToHash(it.stateIt.LeafKey())

View file

@ -159,6 +159,7 @@ func (ch createObjectChange) dirtied() *common.Address {
func (ch resetObjectChange) revert(s *StateDB) { func (ch resetObjectChange) revert(s *StateDB) {
s.setStateObject(ch.prev) s.setStateObject(ch.prev)
RevertWrite(s, blockstm.NewAddressKey(ch.prev.address)) RevertWrite(s, blockstm.NewAddressKey(ch.prev.address))
if !ch.prevdestruct { if !ch.prevdestruct {
delete(s.stateObjectsDestruct, ch.prev.address) delete(s.stateObjectsDestruct, ch.prev.address)
} }

View file

@ -86,6 +86,7 @@ func NewPruner(db ethdb.Database, config Config) (*Pruner, error) {
if headBlock == nil { if headBlock == nil {
return nil, errors.New("failed to load head block") return nil, errors.New("failed to load head block")
} }
snapconfig := snapshot.Config{ snapconfig := snapshot.Config{
CacheSize: 256, CacheSize: 256,
Recovery: false, Recovery: false,
@ -101,6 +102,7 @@ func NewPruner(db ethdb.Database, config Config) (*Pruner, error) {
log.Warn("Sanitizing bloomfilter size", "provided(MB)", config.BloomSize, "updated(MB)", 256) log.Warn("Sanitizing bloomfilter size", "provided(MB)", config.BloomSize, "updated(MB)", 256)
config.BloomSize = 256 config.BloomSize = 256
} }
stateBloom, err := newStateBloomWithSize(config.BloomSize) stateBloom, err := newStateBloomWithSize(config.BloomSize)
if err != nil { if err != nil {
return nil, err return nil, err
@ -327,6 +329,7 @@ func (p *Pruner) Prune(root common.Hash) error {
if err := extractGenesis(p.db, p.stateBloom); err != nil { if err := extractGenesis(p.db, p.stateBloom); err != nil {
return err return err
} }
filterName := bloomFilterName(p.config.Datadir, root) filterName := bloomFilterName(p.config.Datadir, root)
log.Info("Writing state bloom to disk", "name", filterName) log.Info("Writing state bloom to disk", "name", filterName)
@ -418,6 +421,7 @@ func extractGenesis(db ethdb.Database, stateBloom *stateBloom) error {
if genesis == nil { if genesis == nil {
return errors.New("missing genesis block") return errors.New("missing genesis block")
} }
t, err := trie.NewStateTrie(trie.StateTrieID(genesis.Root()), trie.NewDatabase(db)) t, err := trie.NewStateTrie(trie.StateTrieID(genesis.Root()), trie.NewDatabase(db))
if err != nil { if err != nil {
return err return err
@ -437,6 +441,7 @@ func extractGenesis(db ethdb.Database, stateBloom *stateBloom) error {
if err := rlp.DecodeBytes(accIter.LeafBlob(), &acc); err != nil { if err := rlp.DecodeBytes(accIter.LeafBlob(), &acc); err != nil {
return err return err
} }
if acc.Root != types.EmptyRootHash { if acc.Root != types.EmptyRootHash {
id := trie.StorageTrieID(genesis.Root(), common.BytesToHash(accIter.LeafKey()), acc.Root) id := trie.StorageTrieID(genesis.Root(), common.BytesToHash(accIter.LeafKey()), acc.Root)
storageTrie, err := trie.NewStateTrie(id, trie.NewDatabase(db)) storageTrie, err := trie.NewStateTrie(id, trie.NewDatabase(db))
@ -454,6 +459,7 @@ func extractGenesis(db ethdb.Database, stateBloom *stateBloom) error {
return storageIter.Error() return storageIter.Error()
} }
} }
if !bytes.Equal(acc.CodeHash, types.EmptyCodeHash.Bytes()) { if !bytes.Equal(acc.CodeHash, types.EmptyCodeHash.Bytes()) {
stateBloom.Put(acc.CodeHash, nil) stateBloom.Put(acc.CodeHash, nil)
} }

View file

@ -45,6 +45,7 @@ func SlimAccount(nonce uint64, balance *big.Int, root common.Hash, codehash []by
if root != types.EmptyRootHash { if root != types.EmptyRootHash {
slim.Root = root[:] slim.Root = root[:]
} }
if !bytes.Equal(codehash, types.EmptyCodeHash[:]) { if !bytes.Equal(codehash, types.EmptyCodeHash[:]) {
slim.CodeHash = codehash slim.CodeHash = codehash
} }

View file

@ -82,6 +82,7 @@ func (gs *generatorStats) Log(msg string, root common.Hash, marker []byte) {
}...) }...)
} }
} }
log.Info(msg, ctx...) log.Info(msg, ctx...)
} }
@ -105,6 +106,7 @@ func newGeneratorContext(stats *generatorStats, db ethdb.KeyValueStore, accMarke
} }
ctx.openIterator(snapAccount, accMarker) ctx.openIterator(snapAccount, accMarker)
ctx.openIterator(snapStorage, storageMarker) ctx.openIterator(snapStorage, storageMarker)
return ctx return ctx
} }
@ -115,8 +117,10 @@ func (ctx *generatorContext) openIterator(kind string, start []byte) {
if kind == snapAccount { if kind == snapAccount {
iter := ctx.db.NewIterator(rawdb.SnapshotAccountPrefix, start) iter := ctx.db.NewIterator(rawdb.SnapshotAccountPrefix, start)
ctx.account = newHoldableIterator(rawdb.NewKeyLengthIterator(iter, 1+common.HashLength)) ctx.account = newHoldableIterator(rawdb.NewKeyLengthIterator(iter, 1+common.HashLength))
return return
} }
iter := ctx.db.NewIterator(rawdb.SnapshotStoragePrefix, start) iter := ctx.db.NewIterator(rawdb.SnapshotStoragePrefix, start)
ctx.storage = newHoldableIterator(rawdb.NewKeyLengthIterator(iter, 1+2*common.HashLength)) ctx.storage = newHoldableIterator(rawdb.NewKeyLengthIterator(iter, 1+2*common.HashLength))
} }
@ -130,17 +134,23 @@ func (ctx *generatorContext) reopenIterator(kind string) {
if kind == snapStorage { if kind == snapStorage {
iter = ctx.storage iter = ctx.storage
} }
hasNext := iter.Next() hasNext := iter.Next()
if !hasNext { if !hasNext {
// Iterator exhausted, release forever and create an already exhausted virtual iterator // Iterator exhausted, release forever and create an already exhausted virtual iterator
iter.Release() iter.Release()
if kind == snapAccount { if kind == snapAccount {
ctx.account = newHoldableIterator(memorydb.New().NewIterator(nil, nil)) ctx.account = newHoldableIterator(memorydb.New().NewIterator(nil, nil))
return return
} }
ctx.storage = newHoldableIterator(memorydb.New().NewIterator(nil, nil)) ctx.storage = newHoldableIterator(memorydb.New().NewIterator(nil, nil))
return return
} }
next := iter.Key() next := iter.Key()
iter.Release() iter.Release()
ctx.openIterator(kind, next[1:]) ctx.openIterator(kind, next[1:])
@ -157,6 +167,7 @@ func (ctx *generatorContext) iterator(kind string) *holdableIterator {
if kind == snapAccount { if kind == snapAccount {
return ctx.account return ctx.account
} }
return ctx.storage return ctx.storage
} }
@ -170,6 +181,7 @@ func (ctx *generatorContext) removeStorageBefore(account common.Hash) {
start = time.Now() start = time.Now()
iter = ctx.storage iter = ctx.storage
) )
for iter.Next() { for iter.Next() {
key := iter.Key() key := iter.Key()
if bytes.Compare(key[1:1+common.HashLength], account.Bytes()) >= 0 { if bytes.Compare(key[1:1+common.HashLength], account.Bytes()) >= 0 {
@ -178,12 +190,15 @@ func (ctx *generatorContext) removeStorageBefore(account common.Hash) {
} }
count++ count++
ctx.batch.Delete(key) ctx.batch.Delete(key)
if ctx.batch.ValueSize() > ethdb.IdealBatchSize { if ctx.batch.ValueSize() > ethdb.IdealBatchSize {
ctx.batch.Write() ctx.batch.Write()
ctx.batch.Reset() ctx.batch.Reset()
} }
} }
ctx.stats.dangling += count ctx.stats.dangling += count
snapStorageCleanCounter.Inc(time.Since(start).Nanoseconds()) snapStorageCleanCounter.Inc(time.Since(start).Nanoseconds())
} }
@ -197,18 +212,22 @@ func (ctx *generatorContext) removeStorageAt(account common.Hash) error {
start = time.Now() start = time.Now()
iter = ctx.storage iter = ctx.storage
) )
for iter.Next() { for iter.Next() {
key := iter.Key() key := iter.Key()
cmp := bytes.Compare(key[1:1+common.HashLength], account.Bytes()) cmp := bytes.Compare(key[1:1+common.HashLength], account.Bytes())
if cmp < 0 { if cmp < 0 {
return errors.New("invalid iterator position") return errors.New("invalid iterator position")
} }
if cmp > 0 { if cmp > 0 {
iter.Hold() iter.Hold()
break break
} }
count++ count++
ctx.batch.Delete(key) ctx.batch.Delete(key)
if ctx.batch.ValueSize() > ethdb.IdealBatchSize { if ctx.batch.ValueSize() > ethdb.IdealBatchSize {
ctx.batch.Write() ctx.batch.Write()
ctx.batch.Reset() ctx.batch.Reset()
@ -216,6 +235,7 @@ func (ctx *generatorContext) removeStorageAt(account common.Hash) error {
} }
snapWipedStorageMeter.Mark(count) snapWipedStorageMeter.Mark(count)
snapStorageCleanCounter.Inc(time.Since(start).Nanoseconds()) snapStorageCleanCounter.Inc(time.Since(start).Nanoseconds())
return nil return nil
} }
@ -227,14 +247,17 @@ func (ctx *generatorContext) removeStorageLeft() {
start = time.Now() start = time.Now()
iter = ctx.storage iter = ctx.storage
) )
for iter.Next() { for iter.Next() {
count++ count++
ctx.batch.Delete(iter.Key()) ctx.batch.Delete(iter.Key())
if ctx.batch.ValueSize() > ethdb.IdealBatchSize { if ctx.batch.ValueSize() > ethdb.IdealBatchSize {
ctx.batch.Write() ctx.batch.Write()
ctx.batch.Reset() ctx.batch.Reset()
} }
} }
ctx.stats.dangling += count ctx.stats.dangling += count
snapDanglingStorageMeter.Mark(int64(count)) snapDanglingStorageMeter.Mark(int64(count))
snapStorageCleanCounter.Inc(time.Since(start).Nanoseconds()) snapStorageCleanCounter.Inc(time.Since(start).Nanoseconds())

View file

@ -369,6 +369,7 @@ func stackTrieGenerate(db ethdb.KeyValueWriter, scheme string, owner common.Hash
rawdb.WriteTrieNode(db, owner, path, hash, blob, scheme) rawdb.WriteTrieNode(db, owner, path, hash, blob, scheme)
} }
} }
t := trie.NewStackTrieWithOwner(nodeWriter, owner) t := trie.NewStackTrieWithOwner(nodeWriter, owner)
for leaf := range in { for leaf := range in {
t.Update(leaf.key[:], leaf.value) t.Update(leaf.key[:], leaf.value)

View file

@ -361,11 +361,14 @@ func (dl *diskLayer) generateRange(ctx *generatorContext, trieId *trie.ID, prefi
for i, key := range result.keys { for i, key := range result.keys {
snapTrie.Update(key, result.vals[i]) snapTrie.Update(key, result.vals[i])
} }
root, nodes := snapTrie.Commit(false) root, nodes := snapTrie.Commit(false)
if nodes != nil { if nodes != nil {
tdb.Update(trie.NewWithNodeSet(nodes)) tdb.Update(trie.NewWithNodeSet(nodes))
tdb.Commit(root, false) tdb.Commit(root, false)
} }
resolver = func(owner common.Hash, path []byte, hash common.Hash) []byte { resolver = func(owner common.Hash, path []byte, hash common.Hash) []byte {
return rawdb.ReadTrieNode(mdb, owner, path, hash, tdb.Scheme()) return rawdb.ReadTrieNode(mdb, owner, path, hash, tdb.Scheme())
} }
@ -397,6 +400,7 @@ func (dl *diskLayer) generateRange(ctx *generatorContext, trieId *trie.ID, prefi
start = time.Now() start = time.Now()
internal time.Duration internal time.Duration
) )
nodeIt.AddResolver(resolver) nodeIt.AddResolver(resolver)
for iter.Next() { for iter.Next() {
@ -457,6 +461,7 @@ func (dl *diskLayer) generateRange(ctx *generatorContext, trieId *trie.ID, prefi
} else { } else {
snapAccountTrieReadCounter.Inc((time.Since(start) - internal).Nanoseconds()) snapAccountTrieReadCounter.Inc((time.Since(start) - internal).Nanoseconds())
} }
logger.Debug("Regenerated state range", "root", trieId.Root, "last", hexutil.Encode(last), logger.Debug("Regenerated state range", "root", trieId.Root, "last", hexutil.Encode(last),
"count", count, "created", created, "updated", updated, "untouched", untouched, "deleted", deleted) "count", count, "created", created, "updated", updated, "untouched", untouched, "deleted", deleted)
@ -473,6 +478,7 @@ func (dl *diskLayer) checkAndFlush(ctx *generatorContext, current []byte) error
case abort = <-dl.genAbort: case abort = <-dl.genAbort:
default: default:
} }
if ctx.batch.ValueSize() > ethdb.IdealBatchSize || abort != nil { if ctx.batch.ValueSize() > ethdb.IdealBatchSize || abort != nil {
if bytes.Compare(current, dl.genMarker) < 0 { if bytes.Compare(current, dl.genMarker) < 0 {
log.Error("Snapshot generator went backwards", "current", fmt.Sprintf("%x", current), "genMarker", fmt.Sprintf("%x", dl.genMarker)) log.Error("Snapshot generator went backwards", "current", fmt.Sprintf("%x", current), "genMarker", fmt.Sprintf("%x", dl.genMarker))
@ -485,6 +491,7 @@ func (dl *diskLayer) checkAndFlush(ctx *generatorContext, current []byte) error
if err := ctx.batch.Write(); err != nil { if err := ctx.batch.Write(); err != nil {
return err return err
} }
ctx.batch.Reset() ctx.batch.Reset()
dl.lock.Lock() dl.lock.Lock()
@ -499,10 +506,12 @@ func (dl *diskLayer) checkAndFlush(ctx *generatorContext, current []byte) error
ctx.reopenIterator(snapAccount) ctx.reopenIterator(snapAccount)
ctx.reopenIterator(snapStorage) ctx.reopenIterator(snapStorage)
} }
if time.Since(ctx.logged) > 8*time.Second { if time.Since(ctx.logged) > 8*time.Second {
ctx.stats.Log("Generating state snapshot", dl.root, current) ctx.stats.Log("Generating state snapshot", dl.root, current)
ctx.logged = time.Now() ctx.logged = time.Now()
} }
return nil return nil
} }
@ -518,14 +527,17 @@ func generateStorages(ctx *generatorContext, dl *diskLayer, stateRoot common.Has
if delete { if delete {
rawdb.DeleteStorageSnapshot(ctx.batch, account, common.BytesToHash(key)) rawdb.DeleteStorageSnapshot(ctx.batch, account, common.BytesToHash(key))
snapWipedStorageMeter.Mark(1) snapWipedStorageMeter.Mark(1)
return nil return nil
} }
if write { if write {
rawdb.WriteStorageSnapshot(ctx.batch, account, common.BytesToHash(key), val) rawdb.WriteStorageSnapshot(ctx.batch, account, common.BytesToHash(key), val)
snapGeneratedStorageMeter.Mark(1) snapGeneratedStorageMeter.Mark(1)
} else { } else {
snapRecoveredStorageMeter.Mark(1) snapRecoveredStorageMeter.Mark(1)
} }
ctx.stats.storage += common.StorageSize(1 + 2*common.HashLength + len(val)) ctx.stats.storage += common.StorageSize(1 + 2*common.HashLength + len(val))
ctx.stats.slots++ ctx.stats.slots++
@ -537,9 +549,11 @@ func generateStorages(ctx *generatorContext, dl *diskLayer, stateRoot common.Has
} }
// Loop for re-generating the missing storage slots. // Loop for re-generating the missing storage slots.
var origin = common.CopyBytes(storeMarker) var origin = common.CopyBytes(storeMarker)
for { for {
id := trie.StorageTrieID(stateRoot, account, storageRoot) id := trie.StorageTrieID(stateRoot, account, storageRoot)
exhausted, last, err := dl.generateRange(ctx, id, append(rawdb.SnapshotStoragePrefix, account.Bytes()...), snapStorage, origin, storageCheckRange, onStorage, nil) exhausted, last, err := dl.generateRange(ctx, id, append(rawdb.SnapshotStoragePrefix, account.Bytes()...), snapStorage, origin, storageCheckRange, onStorage, nil)
if err != nil { if err != nil {
return err // The procedure it aborted, either by external signal or internal error. return err // The procedure it aborted, either by external signal or internal error.
} }
@ -547,10 +561,12 @@ func generateStorages(ctx *generatorContext, dl *diskLayer, stateRoot common.Has
if exhausted { if exhausted {
break break
} }
if origin = increaseKey(last); origin == nil { if origin = increaseKey(last); origin == nil {
break // special case, the last is 0xffffffff...fff break // special case, the last is 0xffffffff...fff
} }
} }
return nil return nil
} }
@ -589,6 +605,7 @@ func generateAccounts(ctx *generatorContext, dl *diskLayer, accMarker []byte) er
if bytes.Equal(acc.CodeHash, types.EmptyCodeHash[:]) { if bytes.Equal(acc.CodeHash, types.EmptyCodeHash[:]) {
dataLen -= 32 dataLen -= 32
} }
if acc.Root == types.EmptyRootHash { if acc.Root == types.EmptyRootHash {
dataLen -= 32 dataLen -= 32
} }
@ -599,6 +616,7 @@ func generateAccounts(ctx *generatorContext, dl *diskLayer, accMarker []byte) er
rawdb.WriteAccountSnapshot(ctx.batch, account, data) rawdb.WriteAccountSnapshot(ctx.batch, account, data)
snapGeneratedAccountMeter.Mark(1) snapGeneratedAccountMeter.Mark(1)
} }
ctx.stats.storage += common.StorageSize(1 + common.HashLength + dataLen) ctx.stats.storage += common.StorageSize(1 + common.HashLength + dataLen)
ctx.stats.accounts++ ctx.stats.accounts++
} }
@ -612,6 +630,7 @@ func generateAccounts(ctx *generatorContext, dl *diskLayer, accMarker []byte) er
if err := dl.checkAndFlush(ctx, marker); err != nil { if err := dl.checkAndFlush(ctx, marker); err != nil {
return err return err
} }
snapAccountWriteCounter.Inc(time.Since(start).Nanoseconds()) // let's count flush time as well snapAccountWriteCounter.Inc(time.Since(start).Nanoseconds()) // let's count flush time as well
// If the iterated account is the contract, create a further loop to // If the iterated account is the contract, create a further loop to
@ -637,6 +656,7 @@ func generateAccounts(ctx *generatorContext, dl *diskLayer, accMarker []byte) er
if len(accMarker) > 0 { if len(accMarker) > 0 {
accountRange = 1 accountRange = 1
} }
origin := common.CopyBytes(accMarker) origin := common.CopyBytes(accMarker)
for { for {
id := trie.StateTrieID(dl.root) id := trie.StateTrieID(dl.root)
@ -644,6 +664,7 @@ func generateAccounts(ctx *generatorContext, dl *diskLayer, accMarker []byte) er
if err != nil { if err != nil {
return err // The procedure it aborted, either by external signal or internal error. return err // The procedure it aborted, either by external signal or internal error.
} }
origin = increaseKey(last) origin = increaseKey(last)
// Last step, cleanup the storages after the last account. // Last step, cleanup the storages after the last account.
@ -654,6 +675,7 @@ func generateAccounts(ctx *generatorContext, dl *diskLayer, accMarker []byte) er
} }
accountRange = accountCheckRange accountRange = accountCheckRange
} }
return nil return nil
} }
@ -666,9 +688,11 @@ func (dl *diskLayer) generate(stats *generatorStats) {
accMarker []byte accMarker []byte
abort chan *generatorStats abort chan *generatorStats
) )
if len(dl.genMarker) > 0 { // []byte{} is the start, use nil for that if len(dl.genMarker) > 0 { // []byte{} is the start, use nil for that
accMarker = dl.genMarker[:common.HashLength] accMarker = dl.genMarker[:common.HashLength]
} }
stats.Log("Resuming state snapshot generation", dl.root, dl.genMarker) stats.Log("Resuming state snapshot generation", dl.root, dl.genMarker)
// Initialize the global generator context. The snapshot iterators are // Initialize the global generator context. The snapshot iterators are
@ -692,12 +716,14 @@ func (dl *diskLayer) generate(stats *generatorStats) {
abort = <-dl.genAbort abort = <-dl.genAbort
} }
abort <- stats abort <- stats
return return
} }
// Snapshot fully generated, set the marker to nil. // Snapshot fully generated, set the marker to nil.
// Note even there is nothing to commit, persist the // Note even there is nothing to commit, persist the
// generator anyway to mark the snapshot is complete. // generator anyway to mark the snapshot is complete.
journalProgress(ctx.batch, nil, stats) journalProgress(ctx.batch, nil, stats)
if err := ctx.batch.Write(); err != nil { if err := ctx.batch.Write(); err != nil {
log.Error("Failed to flush batch", "err", err) log.Error("Failed to flush batch", "err", err)
@ -705,6 +731,7 @@ func (dl *diskLayer) generate(stats *generatorStats) {
abort <- stats abort <- stats
return return
} }
ctx.batch.Reset() ctx.batch.Reset()
log.Info("Generated state snapshot", "accounts", stats.accounts, "slots", stats.slots, log.Info("Generated state snapshot", "accounts", stats.accounts, "slots", stats.slots,

View file

@ -35,10 +35,13 @@ import (
func hashData(input []byte) common.Hash { func hashData(input []byte) common.Hash {
var hasher = sha3.NewLegacyKeccak256() var hasher = sha3.NewLegacyKeccak256()
var hash common.Hash var hash common.Hash
hasher.Reset() hasher.Reset()
hasher.Write(input) hasher.Write(input)
hasher.Sum(hash[:0]) hasher.Sum(hash[:0])
return hash return hash
} }
@ -135,6 +138,7 @@ func checkSnapRoot(t *testing.T, snap *diskLayer, trieRoot common.Hash) {
if snapRoot != trieRoot { if snapRoot != trieRoot {
t.Fatalf("snaproot: %#x != trieroot #%x", snapRoot, trieRoot) t.Fatalf("snaproot: %#x != trieroot #%x", snapRoot, trieRoot)
} }
if err := CheckDanglingStorage(snap.diskdb); err != nil { if err := CheckDanglingStorage(snap.diskdb); err != nil {
t.Fatalf("Detected dangling storages: %v", err) t.Fatalf("Detected dangling storages: %v", err)
} }
@ -188,10 +192,13 @@ func (t *testHelper) makeStorageTrie(stateRoot, owner common.Hash, keys []string
for i, k := range keys { for i, k := range keys {
stTrie.MustUpdate([]byte(k), []byte(vals[i])) stTrie.MustUpdate([]byte(k), []byte(vals[i]))
} }
if !commit { if !commit {
return stTrie.Hash().Bytes() return stTrie.Hash().Bytes()
} }
root, nodes := stTrie.Commit(false) root, nodes := stTrie.Commit(false)
if nodes != nil { if nodes != nil {
t.nodes.Merge(nodes) t.nodes.Merge(nodes)
} }
@ -205,6 +212,7 @@ func (t *testHelper) Commit() common.Hash {
} }
t.triedb.Update(t.nodes) t.triedb.Update(t.nodes)
t.triedb.Commit(root, false) t.triedb.Commit(root, false)
return root return root
} }
@ -517,12 +525,14 @@ func TestGenerateWithExtraAccounts(t *testing.T) {
rawdb.WriteStorageSnapshot(helper.diskdb, key, hashData([]byte("b-key-2")), []byte("b-val-2")) rawdb.WriteStorageSnapshot(helper.diskdb, key, hashData([]byte("b-key-2")), []byte("b-val-2"))
rawdb.WriteStorageSnapshot(helper.diskdb, key, hashData([]byte("b-key-3")), []byte("b-val-3")) rawdb.WriteStorageSnapshot(helper.diskdb, key, hashData([]byte("b-key-3")), []byte("b-val-3"))
} }
root := helper.Commit() root := helper.Commit()
// To verify the test: If we now inspect the snap db, there should exist extraneous storage items // To verify the test: If we now inspect the snap db, there should exist extraneous storage items
if data := rawdb.ReadStorageSnapshot(helper.diskdb, hashData([]byte("acc-2")), hashData([]byte("b-key-1"))); data == nil { if data := rawdb.ReadStorageSnapshot(helper.diskdb, hashData([]byte("acc-2")), hashData([]byte("b-key-1"))); data == nil {
t.Fatalf("expected snap storage to exist") t.Fatalf("expected snap storage to exist")
} }
snap := generateSnapshot(helper.diskdb, helper.triedb, 16, root) snap := generateSnapshot(helper.diskdb, helper.triedb, 16, root)
select { select {
case <-snap.genPending: case <-snap.genPending:
@ -552,6 +562,7 @@ func TestGenerateWithManyExtraAccounts(t *testing.T) {
if false { if false {
enableLogging() enableLogging()
} }
helper := newHelper() helper := newHelper()
{ {
// Account one in the trie // Account one in the trie
@ -580,6 +591,7 @@ func TestGenerateWithManyExtraAccounts(t *testing.T) {
rawdb.WriteAccountSnapshot(helper.diskdb, key, val) rawdb.WriteAccountSnapshot(helper.diskdb, key, val)
} }
} }
root, snap := helper.CommitAndGenerate() root, snap := helper.CommitAndGenerate()
select { select {
case <-snap.genPending: case <-snap.genPending:
@ -609,6 +621,7 @@ func TestGenerateWithExtraBeforeAndAfter(t *testing.T) {
if false { if false {
enableLogging() enableLogging()
} }
helper := newHelper() helper := newHelper()
{ {
acc := &Account{Balance: big.NewInt(1), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()} acc := &Account{Balance: big.NewInt(1), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()}
@ -624,6 +637,7 @@ func TestGenerateWithExtraBeforeAndAfter(t *testing.T) {
rawdb.WriteAccountSnapshot(helper.diskdb, common.HexToHash("0x06"), val) rawdb.WriteAccountSnapshot(helper.diskdb, common.HexToHash("0x06"), val)
rawdb.WriteAccountSnapshot(helper.diskdb, common.HexToHash("0x07"), val) rawdb.WriteAccountSnapshot(helper.diskdb, common.HexToHash("0x07"), val)
} }
root, snap := helper.CommitAndGenerate() root, snap := helper.CommitAndGenerate()
select { select {
case <-snap.genPending: case <-snap.genPending:
@ -646,6 +660,7 @@ func TestGenerateWithMalformedSnapdata(t *testing.T) {
if false { if false {
enableLogging() enableLogging()
} }
helper := newHelper() helper := newHelper()
{ {
acc := &Account{Balance: big.NewInt(1), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()} acc := &Account{Balance: big.NewInt(1), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()}
@ -659,6 +674,7 @@ func TestGenerateWithMalformedSnapdata(t *testing.T) {
rawdb.WriteAccountSnapshot(helper.diskdb, common.HexToHash("0x04"), junk) rawdb.WriteAccountSnapshot(helper.diskdb, common.HexToHash("0x04"), junk)
rawdb.WriteAccountSnapshot(helper.diskdb, common.HexToHash("0x05"), junk) rawdb.WriteAccountSnapshot(helper.diskdb, common.HexToHash("0x05"), junk)
} }
root, snap := helper.CommitAndGenerate() root, snap := helper.CommitAndGenerate()
select { select {
case <-snap.genPending: case <-snap.genPending:
@ -689,6 +705,7 @@ func TestGenerateFromEmptySnap(t *testing.T) {
helper.addTrieAccount(fmt.Sprintf("acc-%d", i), helper.addTrieAccount(fmt.Sprintf("acc-%d", i),
&Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
} }
root, snap := helper.CommitAndGenerate() root, snap := helper.CommitAndGenerate()
t.Logf("Root: %#x\n", root) // Root: 0x6f7af6d2e1a1bf2b84a3beb3f8b64388465fbc1e274ca5d5d3fc787ca78f59e4 t.Logf("Root: %#x\n", root) // Root: 0x6f7af6d2e1a1bf2b84a3beb3f8b64388465fbc1e274ca5d5d3fc787ca78f59e4
@ -735,6 +752,7 @@ func TestGenerateWithIncompleteStorage(t *testing.T) {
} }
helper.addSnapStorage(accKey, moddedKeys, moddedVals) helper.addSnapStorage(accKey, moddedKeys, moddedVals)
} }
root, snap := helper.CommitAndGenerate() root, snap := helper.CommitAndGenerate()
t.Logf("Root: %#x\n", root) // Root: 0xca73f6f05ba4ca3024ef340ef3dfca8fdabc1b677ff13f5a9571fd49c16e67ff t.Logf("Root: %#x\n", root) // Root: 0xca73f6f05ba4ca3024ef340ef3dfca8fdabc1b677ff13f5a9571fd49c16e67ff
@ -759,6 +777,7 @@ func incKey(key []byte) []byte {
break break
} }
} }
return key return key
} }
@ -769,6 +788,7 @@ func decKey(key []byte) []byte {
break break
} }
} }
return key return key
} }

View file

@ -42,6 +42,7 @@ func (it *holdableIterator) Hold() {
if it.it.Key() == nil { if it.it.Key() == nil {
return // nothing to hold return // nothing to hold
} }
it.key = common.CopyBytes(it.it.Key()) it.key = common.CopyBytes(it.it.Key())
it.val = common.CopyBytes(it.it.Value()) it.val = common.CopyBytes(it.it.Value())
it.atHeld = false it.atHeld = false
@ -57,9 +58,11 @@ func (it *holdableIterator) Next() bool {
it.key = nil it.key = nil
it.val = nil it.val = nil
} }
if it.key != nil { if it.key != nil {
return true // shifted to locally held value return true // shifted to locally held value
} }
return it.it.Next() return it.it.Next()
} }
@ -83,6 +86,7 @@ func (it *holdableIterator) Key() []byte {
if it.key != nil { if it.key != nil {
return it.key return it.key
} }
return it.it.Key() return it.it.Key()
} }
@ -93,5 +97,6 @@ func (it *holdableIterator) Value() []byte {
if it.val != nil { if it.val != nil {
return it.val return it.val
} }
return it.it.Value() return it.it.Value()
} }

View file

@ -33,6 +33,7 @@ func TestIteratorHold(t *testing.T) {
order = []string{"k1", "k2", "k3"} order = []string{"k1", "k2", "k3"}
db = rawdb.NewMemoryDatabase() db = rawdb.NewMemoryDatabase()
) )
for key, val := range content { for key, val := range content {
if err := db.Put([]byte(key), []byte(val)); err != nil { if err := db.Put([]byte(key), []byte(val)); err != nil {
t.Fatalf("failed to insert item %s:%s into database: %v", key, val, err) t.Fatalf("failed to insert item %s:%s into database: %v", key, val, err)
@ -49,9 +50,11 @@ func TestIteratorHold(t *testing.T) {
t.Errorf("more items than expected: checking idx=%d (key %q), expecting len=%d", idx, it.Key(), len(order)) t.Errorf("more items than expected: checking idx=%d (key %q), expecting len=%d", idx, it.Key(), len(order))
break break
} }
if !bytes.Equal(it.Key(), []byte(order[idx])) { if !bytes.Equal(it.Key(), []byte(order[idx])) {
t.Errorf("item %d: key mismatch: have %s, want %s", idx, string(it.Key()), order[idx]) t.Errorf("item %d: key mismatch: have %s, want %s", idx, string(it.Key()), order[idx])
} }
if !bytes.Equal(it.Value(), []byte(content[order[idx]])) { if !bytes.Equal(it.Value(), []byte(content[order[idx]])) {
t.Errorf("item %d: value mismatch: have %s, want %s", idx, string(it.Value()), content[order[idx]]) t.Errorf("item %d: value mismatch: have %s, want %s", idx, string(it.Value()), content[order[idx]])
} }
@ -61,9 +64,11 @@ func TestIteratorHold(t *testing.T) {
// Shift iterator to the discarded element // Shift iterator to the discarded element
it.Next() it.Next()
if !bytes.Equal(it.Key(), []byte(order[idx])) { if !bytes.Equal(it.Key(), []byte(order[idx])) {
t.Errorf("item %d: key mismatch: have %s, want %s", idx, string(it.Key()), order[idx]) t.Errorf("item %d: key mismatch: have %s, want %s", idx, string(it.Key()), order[idx])
} }
if !bytes.Equal(it.Value(), []byte(content[order[idx]])) { if !bytes.Equal(it.Value(), []byte(content[order[idx]])) {
t.Errorf("item %d: value mismatch: have %s, want %s", idx, string(it.Value()), content[order[idx]]) t.Errorf("item %d: value mismatch: have %s, want %s", idx, string(it.Value()), content[order[idx]])
} }
@ -71,20 +76,25 @@ func TestIteratorHold(t *testing.T) {
// Discard/Next combo should work always // Discard/Next combo should work always
it.Hold() it.Hold()
it.Next() it.Next()
if !bytes.Equal(it.Key(), []byte(order[idx])) { if !bytes.Equal(it.Key(), []byte(order[idx])) {
t.Errorf("item %d: key mismatch: have %s, want %s", idx, string(it.Key()), order[idx]) t.Errorf("item %d: key mismatch: have %s, want %s", idx, string(it.Key()), order[idx])
} }
if !bytes.Equal(it.Value(), []byte(content[order[idx]])) { if !bytes.Equal(it.Value(), []byte(content[order[idx]])) {
t.Errorf("item %d: value mismatch: have %s, want %s", idx, string(it.Value()), content[order[idx]]) t.Errorf("item %d: value mismatch: have %s, want %s", idx, string(it.Value()), content[order[idx]])
} }
idx++ idx++
} }
if err := it.Error(); err != nil { if err := it.Error(); err != nil {
t.Errorf("iteration failed: %v", err) t.Errorf("iteration failed: %v", err)
} }
if idx != len(order) { if idx != len(order) {
t.Errorf("iteration terminated prematurely: have %d, want %d", idx, len(order)) t.Errorf("iteration terminated prematurely: have %d, want %d", idx, len(order))
} }
db.Close() db.Close()
} }
@ -110,13 +120,16 @@ func TestReopenIterator(t *testing.T) {
} }
db = rawdb.NewMemoryDatabase() db = rawdb.NewMemoryDatabase()
) )
for key, val := range content { for key, val := range content {
rawdb.WriteAccountSnapshot(db, key, []byte(val)) rawdb.WriteAccountSnapshot(db, key, []byte(val))
} }
checkVal := func(it *holdableIterator, index int) { checkVal := func(it *holdableIterator, index int) {
if !bytes.Equal(it.Key(), append(rawdb.SnapshotAccountPrefix, order[index].Bytes()...)) { if !bytes.Equal(it.Key(), append(rawdb.SnapshotAccountPrefix, order[index].Bytes()...)) {
t.Fatalf("Unexpected data entry key, want %v got %v", order[index], it.Key()) t.Fatalf("Unexpected data entry key, want %v got %v", order[index], it.Key())
} }
if !bytes.Equal(it.Value(), []byte(content[order[index]])) { if !bytes.Equal(it.Value(), []byte(content[order[index]])) {
t.Fatalf("Unexpected data entry key, want %v got %v", []byte(content[order[index]]), it.Value()) t.Fatalf("Unexpected data entry key, want %v got %v", []byte(content[order[index]]), it.Value())
} }
@ -125,11 +138,13 @@ func TestReopenIterator(t *testing.T) {
ctx, idx := newGeneratorContext(&generatorStats{}, db, nil, nil), -1 ctx, idx := newGeneratorContext(&generatorStats{}, db, nil, nil), -1
idx++ idx++
ctx.account.Next() ctx.account.Next()
checkVal(ctx.account, idx) checkVal(ctx.account, idx)
ctx.reopenIterator(snapAccount) ctx.reopenIterator(snapAccount)
idx++ idx++
ctx.account.Next() ctx.account.Next()
checkVal(ctx.account, idx) checkVal(ctx.account, idx)
@ -137,6 +152,7 @@ func TestReopenIterator(t *testing.T) {
ctx.reopenIterator(snapAccount) ctx.reopenIterator(snapAccount)
ctx.reopenIterator(snapAccount) ctx.reopenIterator(snapAccount)
idx++ idx++
ctx.account.Next() ctx.account.Next()
checkVal(ctx.account, idx) checkVal(ctx.account, idx)
@ -145,6 +161,7 @@ func TestReopenIterator(t *testing.T) {
ctx.account.Hold() ctx.account.Hold()
ctx.reopenIterator(snapAccount) ctx.reopenIterator(snapAccount)
idx++ idx++
ctx.account.Next() ctx.account.Next()
checkVal(ctx.account, idx) checkVal(ctx.account, idx)
@ -154,6 +171,7 @@ func TestReopenIterator(t *testing.T) {
ctx.reopenIterator(snapAccount) ctx.reopenIterator(snapAccount)
ctx.reopenIterator(snapAccount) ctx.reopenIterator(snapAccount)
idx++ idx++
ctx.account.Next() ctx.account.Next()
checkVal(ctx.account, idx) checkVal(ctx.account, idx)
@ -161,6 +179,7 @@ func TestReopenIterator(t *testing.T) {
ctx.account.Next() // the end ctx.account.Next() // the end
ctx.reopenIterator(snapAccount) ctx.reopenIterator(snapAccount)
ctx.account.Next() ctx.account.Next()
if ctx.account.Key() != nil { if ctx.account.Key() != nil {
t.Fatal("Unexpected iterated entry") t.Fatal("Unexpected iterated entry")
} }

View file

@ -109,6 +109,7 @@ func loadAndParseJournal(db ethdb.KeyValueStore, base *diskLayer) (snapshot, jou
// is not matched with disk layer; or the it's the legacy-format journal, // is not matched with disk layer; or the it's the legacy-format journal,
// etc.), we just discard all diffs and try to recover them later. // etc.), we just discard all diffs and try to recover them later.
var current snapshot = base var current snapshot = base
err := iterateJournal(db, func(parent common.Hash, root common.Hash, destructSet map[common.Hash]struct{}, accountData map[common.Hash][]byte, storageData map[common.Hash]map[common.Hash][]byte) error { err := iterateJournal(db, func(parent common.Hash, root common.Hash, destructSet map[common.Hash]struct{}, accountData map[common.Hash][]byte, storageData map[common.Hash]map[common.Hash][]byte) error {
current = newDiffLayer(current, root, destructSet, accountData, storageData) current = newDiffLayer(current, root, destructSet, accountData, storageData)
return nil return nil
@ -116,6 +117,7 @@ func loadAndParseJournal(db ethdb.KeyValueStore, base *diskLayer) (snapshot, jou
if err != nil { if err != nil {
return base, generator, nil return base, generator, nil
} }
return current, generator, nil return current, generator, nil
} }
@ -285,6 +287,7 @@ func iterateJournal(db ethdb.KeyValueReader, callback journalCallback) error {
log.Warn("Loaded snapshot journal", "diffs", "missing") log.Warn("Loaded snapshot journal", "diffs", "missing")
return nil return nil
} }
r := rlp.NewStream(bytes.NewReader(journal), 0) r := rlp.NewStream(bytes.NewReader(journal), 0)
// Firstly, resolve the first element as the journal version // Firstly, resolve the first element as the journal version
version, err := r.Uint64() version, err := r.Uint64()
@ -292,6 +295,7 @@ func iterateJournal(db ethdb.KeyValueReader, callback journalCallback) error {
log.Warn("Failed to resolve the journal version", "error", err) log.Warn("Failed to resolve the journal version", "error", err)
return errors.New("failed to resolve journal version") return errors.New("failed to resolve journal version")
} }
if version != journalVersion { if version != journalVersion {
log.Warn("Discarded the snapshot journal with wrong version", "required", journalVersion, "got", version) log.Warn("Discarded the snapshot journal with wrong version", "required", journalVersion, "got", version)
return errors.New("wrong journal version") return errors.New("wrong journal version")
@ -303,10 +307,12 @@ func iterateJournal(db ethdb.KeyValueReader, callback journalCallback) error {
if err := r.Decode(&parent); err != nil { if err := r.Decode(&parent); err != nil {
return errors.New("missing disk layer root") return errors.New("missing disk layer root")
} }
if baseRoot := rawdb.ReadSnapshotRoot(db); baseRoot != parent { if baseRoot := rawdb.ReadSnapshotRoot(db); baseRoot != parent {
log.Warn("Loaded snapshot journal", "diskroot", baseRoot, "diffs", "unmatched") log.Warn("Loaded snapshot journal", "diskroot", baseRoot, "diffs", "unmatched")
return fmt.Errorf("mismatched disk and diff layers") return fmt.Errorf("mismatched disk and diff layers")
} }
for { for {
var ( var (
root common.Hash root common.Hash
@ -323,20 +329,26 @@ func iterateJournal(db ethdb.KeyValueReader, callback journalCallback) error {
if errors.Is(err, io.EOF) { if errors.Is(err, io.EOF) {
return nil return nil
} }
return fmt.Errorf("load diff root: %v", err) return fmt.Errorf("load diff root: %v", err)
} }
if err := r.Decode(&destructs); err != nil { if err := r.Decode(&destructs); err != nil {
return fmt.Errorf("load diff destructs: %v", err) return fmt.Errorf("load diff destructs: %v", err)
} }
if err := r.Decode(&accounts); err != nil { if err := r.Decode(&accounts); err != nil {
return fmt.Errorf("load diff accounts: %v", err) return fmt.Errorf("load diff accounts: %v", err)
} }
if err := r.Decode(&storage); err != nil { if err := r.Decode(&storage); err != nil {
return fmt.Errorf("load diff storage: %v", err) return fmt.Errorf("load diff storage: %v", err)
} }
for _, entry := range destructs { for _, entry := range destructs {
destructSet[entry.Hash] = struct{}{} destructSet[entry.Hash] = struct{}{}
} }
for _, entry := range accounts { for _, entry := range accounts {
if len(entry.Blob) > 0 { // RLP loses nil-ness, but `[]byte{}` is not a valid item, so reinterpret that if len(entry.Blob) > 0 { // RLP loses nil-ness, but `[]byte{}` is not a valid item, so reinterpret that
accountData[entry.Hash] = entry.Blob accountData[entry.Hash] = entry.Blob
@ -344,8 +356,10 @@ func iterateJournal(db ethdb.KeyValueReader, callback journalCallback) error {
accountData[entry.Hash] = nil accountData[entry.Hash] = nil
} }
} }
for _, entry := range storage { for _, entry := range storage {
slots := make(map[common.Hash][]byte) slots := make(map[common.Hash][]byte)
for i, key := range entry.Keys { for i, key := range entry.Keys {
if len(entry.Vals[i]) > 0 { // RLP loses nil-ness, but `[]byte{}` is not a valid item, so reinterpret that if len(entry.Vals[i]) > 0 { // RLP loses nil-ness, but `[]byte{}` is not a valid item, so reinterpret that
slots[key] = entry.Vals[i] slots[key] = entry.Vals[i]
@ -353,11 +367,14 @@ func iterateJournal(db ethdb.KeyValueReader, callback journalCallback) error {
slots[key] = nil slots[key] = nil
} }
} }
storageData[entry.Hash] = slots storageData[entry.Hash] = slots
} }
if err := callback(parent, root, destructSet, accountData, storageData); err != nil { if err := callback(parent, root, destructSet, accountData, storageData); err != nil {
return err return err
} }
parent = root parent = root
} }
} }

View file

@ -211,6 +211,7 @@ func New(config Config, diskdb ethdb.KeyValueStore, triedb *trie.Database, root
} }
if err != nil { if err != nil {
log.Warn("Failed to load snapshot", "err", err) log.Warn("Failed to load snapshot", "err", err)
if !config.NoBuild { if !config.NoBuild {
snap.Rebuild(root) snap.Rebuild(root)
return snap, nil return snap, nil

View file

@ -34,6 +34,7 @@ func CheckDanglingStorage(chaindb ethdb.KeyValueStore) error {
if err := checkDanglingDiskStorage(chaindb); err != nil { if err := checkDanglingDiskStorage(chaindb); err != nil {
log.Error("Database check error", "err", err) log.Error("Database check error", "err", err)
} }
return checkDanglingMemStorage(chaindb) return checkDanglingMemStorage(chaindb)
} }
@ -46,27 +47,34 @@ func checkDanglingDiskStorage(chaindb ethdb.KeyValueStore) error {
lastKey []byte lastKey []byte
it = rawdb.NewKeyLengthIterator(chaindb.NewIterator(rawdb.SnapshotStoragePrefix, nil), 1+2*common.HashLength) it = rawdb.NewKeyLengthIterator(chaindb.NewIterator(rawdb.SnapshotStoragePrefix, nil), 1+2*common.HashLength)
) )
log.Info("Checking dangling snapshot disk storage") log.Info("Checking dangling snapshot disk storage")
defer it.Release() defer it.Release()
for it.Next() { for it.Next() {
k := it.Key() k := it.Key()
accKey := k[1:33] accKey := k[1:33]
if bytes.Equal(accKey, lastKey) { if bytes.Equal(accKey, lastKey) {
// No need to look up for every slot // No need to look up for every slot
continue continue
} }
lastKey = common.CopyBytes(accKey) lastKey = common.CopyBytes(accKey)
if time.Since(lastReport) > time.Second*8 { if time.Since(lastReport) > time.Second*8 {
log.Info("Iterating snap storage", "at", fmt.Sprintf("%#x", accKey), "elapsed", common.PrettyDuration(time.Since(start))) log.Info("Iterating snap storage", "at", fmt.Sprintf("%#x", accKey), "elapsed", common.PrettyDuration(time.Since(start)))
lastReport = time.Now() lastReport = time.Now()
} }
if data := rawdb.ReadAccountSnapshot(chaindb, common.BytesToHash(accKey)); len(data) == 0 { if data := rawdb.ReadAccountSnapshot(chaindb, common.BytesToHash(accKey)); len(data) == 0 {
log.Warn("Dangling storage - missing account", "account", fmt.Sprintf("%#x", accKey), "storagekey", fmt.Sprintf("%#x", k)) log.Warn("Dangling storage - missing account", "account", fmt.Sprintf("%#x", accKey), "storagekey", fmt.Sprintf("%#x", k))
return fmt.Errorf("dangling snapshot storage account %#x", accKey) return fmt.Errorf("dangling snapshot storage account %#x", accKey)
} }
} }
log.Info("Verified the snapshot disk storage", "time", common.PrettyDuration(time.Since(start)), "err", it.Error()) log.Info("Verified the snapshot disk storage", "time", common.PrettyDuration(time.Since(start)), "err", it.Error())
return nil return nil
} }
@ -74,7 +82,9 @@ func checkDanglingDiskStorage(chaindb ethdb.KeyValueStore) error {
// snapshot difflayers. // snapshot difflayers.
func checkDanglingMemStorage(db ethdb.KeyValueStore) error { func checkDanglingMemStorage(db ethdb.KeyValueStore) error {
start := time.Now() start := time.Now()
log.Info("Checking dangling journalled storage") log.Info("Checking dangling journalled storage")
err := iterateJournal(db, func(pRoot, root common.Hash, destructs map[common.Hash]struct{}, accounts map[common.Hash][]byte, storage map[common.Hash]map[common.Hash][]byte) error { err := iterateJournal(db, func(pRoot, root common.Hash, destructs map[common.Hash]struct{}, accounts map[common.Hash][]byte, storage map[common.Hash]map[common.Hash][]byte) error {
for accHash := range storage { for accHash := range storage {
if _, ok := accounts[accHash]; !ok { if _, ok := accounts[accHash]; !ok {
@ -83,11 +93,14 @@ func checkDanglingMemStorage(db ethdb.KeyValueStore) error {
} }
return nil return nil
}) })
if err != nil { if err != nil {
log.Info("Failed to resolve snapshot journal", "err", err) log.Info("Failed to resolve snapshot journal", "err", err)
return err return err
} }
log.Info("Verified the snapshot journalled storage", "time", common.PrettyDuration(time.Since(start))) log.Info("Verified the snapshot journalled storage", "time", common.PrettyDuration(time.Since(start)))
return nil return nil
} }
@ -97,11 +110,14 @@ func CheckJournalAccount(db ethdb.KeyValueStore, hash common.Hash) error {
// Look up the disk layer first // Look up the disk layer first
baseRoot := rawdb.ReadSnapshotRoot(db) baseRoot := rawdb.ReadSnapshotRoot(db)
fmt.Printf("Disklayer: Root: %x\n", baseRoot) fmt.Printf("Disklayer: Root: %x\n", baseRoot)
if data := rawdb.ReadAccountSnapshot(db, hash); data != nil { if data := rawdb.ReadAccountSnapshot(db, hash); data != nil {
account := new(Account) account := new(Account)
if err := rlp.DecodeBytes(data, account); err != nil { if err := rlp.DecodeBytes(data, account); err != nil {
panic(err) panic(err)
} }
fmt.Printf("\taccount.nonce: %d\n", account.Nonce) fmt.Printf("\taccount.nonce: %d\n", account.Nonce)
fmt.Printf("\taccount.balance: %x\n", account.Balance) fmt.Printf("\taccount.balance: %x\n", account.Balance)
fmt.Printf("\taccount.root: %x\n", account.Root) fmt.Printf("\taccount.root: %x\n", account.Root)
@ -117,6 +133,7 @@ func CheckJournalAccount(db ethdb.KeyValueStore, hash common.Hash) error {
} }
it.Release() it.Release()
} }
var depth = 0 var depth = 0
return iterateJournal(db, func(pRoot, root common.Hash, destructs map[common.Hash]struct{}, accounts map[common.Hash][]byte, storage map[common.Hash]map[common.Hash][]byte) error { return iterateJournal(db, func(pRoot, root common.Hash, destructs map[common.Hash]struct{}, accounts map[common.Hash][]byte, storage map[common.Hash]map[common.Hash][]byte) error {

View file

@ -146,9 +146,11 @@ func (s *stateObject) getTrie(db Database) (Trie, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
s.trie = tr s.trie = tr
} }
} }
return s.trie, nil return s.trie, nil
} }
@ -197,10 +199,12 @@ func (s *stateObject) GetCommittedState(db Database, key common.Hash) common.Has
if s.db.snap == nil || err != nil { if s.db.snap == nil || err != nil {
start := time.Now() start := time.Now()
tr, err := s.getTrie(db) tr, err := s.getTrie(db)
if err != nil { if err != nil {
s.db.setError(err) s.db.setError(err)
return common.Hash{} return common.Hash{}
} }
enc, err = tr.GetStorage(s.address, key.Bytes()) enc, err = tr.GetStorage(s.address, key.Bytes())
if metrics.EnabledExpensive { if metrics.EnabledExpensive {
s.db.StorageReads += time.Since(start) s.db.StorageReads += time.Since(start)
@ -252,6 +256,7 @@ func (s *stateObject) finalise(prefetch bool) {
slotsToPrefetch = append(slotsToPrefetch, common.CopyBytes(key[:])) // Copy needed for closure slotsToPrefetch = append(slotsToPrefetch, common.CopyBytes(key[:])) // Copy needed for closure
} }
} }
if s.db.prefetcher != nil && prefetch && len(slotsToPrefetch) > 0 && s.data.Root != types.EmptyRootHash { if s.db.prefetcher != nil && prefetch && len(slotsToPrefetch) > 0 && s.data.Root != types.EmptyRootHash {
s.db.prefetcher.prefetch(s.addrHash, s.data.Root, s.address, slotsToPrefetch) s.db.prefetcher.prefetch(s.addrHash, s.data.Root, s.address, slotsToPrefetch)
} }
@ -278,7 +283,9 @@ func (s *stateObject) updateTrie(db Database) (Trie, error) {
storage map[common.Hash][]byte storage map[common.Hash][]byte
hasher = s.db.hasher hasher = s.db.hasher
) )
tr, err := s.getTrie(db) tr, err := s.getTrie(db)
if err != nil { if err != nil {
s.db.setError(err) s.db.setError(err)
return nil, err return nil, err
@ -327,6 +334,7 @@ func (s *stateObject) updateTrie(db Database) (Trie, error) {
if len(s.pendingStorage) > 0 { if len(s.pendingStorage) > 0 {
s.pendingStorage = make(Storage) s.pendingStorage = make(Storage)
} }
return tr, nil return tr, nil
} }
@ -345,6 +353,7 @@ func (s *stateObject) updateRoot(db Database) {
if metrics.EnabledExpensive { if metrics.EnabledExpensive {
defer func(start time.Time) { s.db.StorageHashes += time.Since(start) }(time.Now()) defer func(start time.Time) { s.db.StorageHashes += time.Since(start) }(time.Now())
} }
s.data.Root = tr.Hash() s.data.Root = tr.Hash()
} }
@ -364,8 +373,10 @@ func (s *stateObject) commitTrie(db Database) (*trie.NodeSet, error) {
if metrics.EnabledExpensive { if metrics.EnabledExpensive {
defer func(start time.Time) { s.db.StorageCommits += time.Since(start) }(time.Now()) defer func(start time.Time) { s.db.StorageCommits += time.Since(start) }(time.Now())
} }
root, nodes := tr.Commit(false) root, nodes := tr.Commit(false)
s.data.Root = root s.data.Root = root
return nodes, nil return nodes, nil
} }
@ -433,6 +444,7 @@ func (s *stateObject) Code(db Database) []byte {
if s.code != nil { if s.code != nil {
return s.code return s.code
} }
if bytes.Equal(s.CodeHash(), types.EmptyCodeHash.Bytes()) { if bytes.Equal(s.CodeHash(), types.EmptyCodeHash.Bytes()) {
return nil return nil
} }
@ -451,6 +463,7 @@ func (s *stateObject) CodeSize(db Database) int {
if s.code != nil { if s.code != nil {
return len(s.code) return len(s.code)
} }
if bytes.Equal(s.CodeHash(), types.EmptyCodeHash.Bytes()) { if bytes.Equal(s.CodeHash(), types.EmptyCodeHash.Bytes()) {
return 0 return 0
} }

View file

@ -662,11 +662,14 @@ func (s *StateDB) GetStorageProof(a common.Address, key common.Hash) ([][]byte,
if trie == nil { if trie == nil {
return nil, errors.New("storage trie for requested address does not exist") return nil, errors.New("storage trie for requested address does not exist")
} }
var proof proofList var proof proofList
err = trie.Prove(crypto.Keccak256(key.Bytes()), 0, &proof) err = trie.Prove(crypto.Keccak256(key.Bytes()), 0, &proof)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return proof, nil return proof, nil
} }
@ -696,6 +699,7 @@ func (s *StateDB) StorageTrie(addr common.Address) (Trie, error) {
return nil, nil return nil, nil
} }
cpy := stateObject.deepCopy(s) cpy := stateObject.deepCopy(s)
if _, err := cpy.updateTrie(s.db); err != nil { if _, err := cpy.updateTrie(s.db); err != nil {
return nil, err return nil, err
} }
@ -794,6 +798,7 @@ func (s *StateDB) SetStorage(addr common.Address, storage map[common.Hash]common
// to a previous incarnation of the object. // to a previous incarnation of the object.
s.stateObjectsDestruct[addr] = struct{}{} s.stateObjectsDestruct[addr] = struct{}{}
stateObject := s.GetOrNewStateObject(addr) stateObject := s.GetOrNewStateObject(addr)
for k, v := range storage { for k, v := range storage {
stateObject.SetState(s.db, k, v) stateObject.SetState(s.db, k, v)
} }

View file

@ -1396,6 +1396,7 @@ func TestFlushOrderDataLoss(t *testing.T) {
for a := byte(0); a < 10; a++ { for a := byte(0); a < 10; a++ {
state.CreateAccount(common.Address{a}) state.CreateAccount(common.Address{a})
for s := byte(0); s < 10; s++ { for s := byte(0); s < 10; s++ {
state.SetState(common.Address{a}, common.Hash{a, s}, common.Hash{a, s}) state.SetState(common.Address{a}, common.Hash{a, s}, common.Hash{a, s})
} }

View file

@ -111,6 +111,7 @@ func checkTrieConsistency(db ethdb.Database, root common.Hash) error {
if err != nil { if err != nil {
return err return err
} }
it := t.NodeIterator(nil) it := t.NodeIterator(nil)
for it.Next(true) { for it.Next(true) {
} }
@ -189,6 +190,7 @@ func testIterativeStateSync(t *testing.T, count int, commit bool, bypath bool) {
nodeElements []stateElement nodeElements []stateElement
codeElements []stateElement codeElements []stateElement
) )
paths, nodes, codes := sched.Missing(count) paths, nodes, codes := sched.Missing(count)
for i := 0; i < len(paths); i++ { for i := 0; i < len(paths); i++ {
@ -559,6 +561,7 @@ func TestIterativeRandomDelayedStateSync(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("failed to retrieve node data for %x", element.hash) t.Fatalf("failed to retrieve node data for %x", element.hash)
} }
results = append(results, trie.NodeSyncResult{Path: path, Data: data}) results = append(results, trie.NodeSyncResult{Path: path, Data: data})
if len(results) >= cap(results) { if len(results) >= cap(results) {

View file

@ -222,6 +222,7 @@ func (d *hashToHumanReadable) Reset() {
func (d *hashToHumanReadable) Update(i []byte, i2 []byte) error { func (d *hashToHumanReadable) Update(i []byte, i2 []byte) error {
l := fmt.Sprintf("%x %x\n", i, i2) l := fmt.Sprintf("%x %x\n", i, i2)
d.data = append(d.data, []byte(l)...) d.data = append(d.data, []byte(l)...)
return nil return nil
} }

View file

@ -250,6 +250,7 @@ func TestWriteExpectedValues(t *testing.T) {
pc = uint64(0) pc = uint64(0)
interpreter = env.interpreter interpreter = env.interpreter
) )
result := make([]TwoOperandTestcase, len(args)) result := make([]TwoOperandTestcase, len(args))
for i, param := range args { for i, param := range args {

View file

@ -32,6 +32,7 @@ func main() {
} }
crasher := os.Args[1] crasher := os.Args[1]
data, err := os.ReadFile(crasher) data, err := os.ReadFile(crasher)
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "error loading crasher %v: %v", crasher, err) fmt.Fprintf(os.Stderr, "error loading crasher %v: %v", crasher, err)
os.Exit(1) os.Exit(1)

View file

@ -30,6 +30,7 @@ func main() {
} }
crasher := os.Args[1] crasher := os.Args[1]
data, err := os.ReadFile(crasher) data, err := os.ReadFile(crasher)
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "error loading crasher %v: %v", crasher, err) fmt.Fprintf(os.Stderr, "error loading crasher %v: %v", crasher, err)
os.Exit(1) os.Exit(1)

View file

@ -60,6 +60,7 @@ func TestIterator(t *testing.T) {
all[val.k] = val.v all[val.k] = val.v
trie.MustUpdate([]byte(val.k), []byte(val.v)) trie.MustUpdate([]byte(val.k), []byte(val.v))
} }
root, nodes := trie.Commit(false) root, nodes := trie.Commit(false)
db.Update(NewWithNodeSet(nodes)) db.Update(NewWithNodeSet(nodes))
@ -89,6 +90,7 @@ func TestIteratorLargeData(t *testing.T) {
for i := byte(0); i < 255; i++ { for i := byte(0); i < 255; i++ {
value := &kv{common.LeftPadBytes([]byte{i}, 32), []byte{i}, false} value := &kv{common.LeftPadBytes([]byte{i}, 32), []byte{i}, false}
value2 := &kv{common.LeftPadBytes([]byte{10, i}, 32), []byte{i}, false} value2 := &kv{common.LeftPadBytes([]byte{10, i}, 32), []byte{i}, false}
trie.MustUpdate(value.k, value.v) trie.MustUpdate(value.k, value.v)
trie.MustUpdate(value2.k, value2.v) trie.MustUpdate(value2.k, value2.v)
vals[string(value.k)] = value vals[string(value.k)] = value
@ -222,6 +224,7 @@ func TestDifferenceIterator(t *testing.T) {
for _, val := range testdata1 { for _, val := range testdata1 {
triea.MustUpdate([]byte(val.k), []byte(val.v)) triea.MustUpdate([]byte(val.k), []byte(val.v))
} }
rootA, nodesA := triea.Commit(false) rootA, nodesA := triea.Commit(false)
dba.Update(NewWithNodeSet(nodesA)) dba.Update(NewWithNodeSet(nodesA))
triea, _ = New(TrieID(rootA), dba) triea, _ = New(TrieID(rootA), dba)
@ -231,6 +234,7 @@ func TestDifferenceIterator(t *testing.T) {
for _, val := range testdata2 { for _, val := range testdata2 {
trieb.MustUpdate([]byte(val.k), []byte(val.v)) trieb.MustUpdate([]byte(val.k), []byte(val.v))
} }
rootB, nodesB := trieb.Commit(false) rootB, nodesB := trieb.Commit(false)
dbb.Update(NewWithNodeSet(nodesB)) dbb.Update(NewWithNodeSet(nodesB))
trieb, _ = New(TrieID(rootB), dbb) trieb, _ = New(TrieID(rootB), dbb)
@ -264,6 +268,7 @@ func TestUnionIterator(t *testing.T) {
for _, val := range testdata1 { for _, val := range testdata1 {
triea.MustUpdate([]byte(val.k), []byte(val.v)) triea.MustUpdate([]byte(val.k), []byte(val.v))
} }
rootA, nodesA := triea.Commit(false) rootA, nodesA := triea.Commit(false)
dba.Update(NewWithNodeSet(nodesA)) dba.Update(NewWithNodeSet(nodesA))
triea, _ = New(TrieID(rootA), dba) triea, _ = New(TrieID(rootA), dba)
@ -273,6 +278,7 @@ func TestUnionIterator(t *testing.T) {
for _, val := range testdata2 { for _, val := range testdata2 {
trieb.MustUpdate([]byte(val.k), []byte(val.v)) trieb.MustUpdate([]byte(val.k), []byte(val.v))
} }
rootB, nodesB := trieb.Commit(false) rootB, nodesB := trieb.Commit(false)
dbb.Update(NewWithNodeSet(nodesB)) dbb.Update(NewWithNodeSet(nodesB))
trieb, _ = New(TrieID(rootB), dbb) trieb, _ = New(TrieID(rootB), dbb)
@ -331,6 +337,7 @@ func testIteratorContinueAfterError(t *testing.T, memonly bool) {
for _, val := range testdata1 { for _, val := range testdata1 {
tr.MustUpdate([]byte(val.k), []byte(val.v)) tr.MustUpdate([]byte(val.k), []byte(val.v))
} }
_, nodes := tr.Commit(false) _, nodes := tr.Commit(false)
triedb.Update(NewWithNodeSet(nodes)) triedb.Update(NewWithNodeSet(nodes))
if !memonly { if !memonly {
@ -423,6 +430,7 @@ func testIteratorContinueAfterSeekError(t *testing.T, memonly bool) {
for _, val := range testdata1 { for _, val := range testdata1 {
ctr.MustUpdate([]byte(val.k), []byte(val.v)) ctr.MustUpdate([]byte(val.k), []byte(val.v))
} }
root, nodes := ctr.Commit(false) root, nodes := ctr.Commit(false)
triedb.Update(NewWithNodeSet(nodes)) triedb.Update(NewWithNodeSet(nodes))
if !memonly { if !memonly {
@ -542,6 +550,7 @@ func makeLargeTestTrie() (*Database, *StateTrie, *loggingDb) {
val = crypto.Keccak256(val) val = crypto.Keccak256(val)
trie.MustUpdate(key, val) trie.MustUpdate(key, val)
} }
_, nodes := trie.Commit(false) _, nodes := trie.Commit(false)
triedb.Update(NewWithNodeSet(nodes)) triedb.Update(NewWithNodeSet(nodes))
// Return the generated trie // Return the generated trie
@ -582,6 +591,7 @@ func TestIteratorNodeBlob(t *testing.T) {
all[val.k] = val.v all[val.k] = val.v
trie.MustUpdate([]byte(val.k), []byte(val.v)) trie.MustUpdate([]byte(val.k), []byte(val.v))
} }
_, nodes := trie.Commit(false) _, nodes := trie.Commit(false)
triedb.Update(NewWithNodeSet(nodes)) triedb.Update(NewWithNodeSet(nodes))
triedb.Cap(0) triedb.Cap(0)

View file

@ -104,6 +104,7 @@ func BenchmarkEncodeShortNode(b *testing.B) {
Key: []byte{0x1, 0x2}, Key: []byte{0x1, 0x2},
Val: hashNode(randBytes(32)), Val: hashNode(randBytes(32)),
} }
b.ResetTimer() b.ResetTimer()
b.ReportAllocs() b.ReportAllocs()
@ -182,6 +183,7 @@ func BenchmarkDecodeFullNode(b *testing.B) {
for i := 0; i < 16; i++ { for i := 0; i < 16; i++ {
node.Children[i] = hashNode(randBytes(32)) node.Children[i] = hashNode(randBytes(32))
} }
blob := nodeToBytes(node) blob := nodeToBytes(node)
hash := crypto.Keccak256(blob) hash := crypto.Keccak256(blob)
@ -203,6 +205,7 @@ func BenchmarkDecodeFullNodeUnsafe(b *testing.B) {
for i := 0; i < 16; i++ { for i := 0; i < 16; i++ {
node.Children[i] = hashNode(randBytes(32)) node.Children[i] = hashNode(randBytes(32))
} }
blob := nodeToBytes(node) blob := nodeToBytes(node)
hash := crypto.Keccak256(blob) hash := crypto.Keccak256(blob)

View file

@ -51,6 +51,7 @@ func (store *preimageStore) insertPreimage(preimages map[common.Hash][]byte) {
if _, ok := store.preimages[hash]; ok { if _, ok := store.preimages[hash]; ok {
continue continue
} }
store.preimages[hash] = preimage store.preimages[hash] = preimage
store.preimagesSize += common.StorageSize(common.HashLength + len(preimage)) store.preimagesSize += common.StorageSize(common.HashLength + len(preimage))
} }
@ -66,6 +67,7 @@ func (store *preimageStore) preimage(hash common.Hash) []byte {
if preimage != nil { if preimage != nil {
return preimage return preimage
} }
return rawdb.ReadPreimage(store.disk, hash) return rawdb.ReadPreimage(store.disk, hash)
} }
@ -77,12 +79,16 @@ func (store *preimageStore) commit(force bool) error {
if store.preimagesSize <= 4*1024*1024 && !force { if store.preimagesSize <= 4*1024*1024 && !force {
return nil return nil
} }
batch := store.disk.NewBatch() batch := store.disk.NewBatch()
rawdb.WritePreimages(batch, store.preimages) rawdb.WritePreimages(batch, store.preimages)
if err := batch.Write(); err != nil { if err := batch.Write(); err != nil {
return err return err
} }
store.preimages, store.preimagesSize = make(map[common.Hash][]byte), 0 store.preimages, store.preimagesSize = make(map[common.Hash][]byte), 0
return nil return nil
} }

View file

@ -40,12 +40,14 @@ func initRnd() *mrand.Rand {
crand.Read(seed[:]) crand.Read(seed[:])
rnd := mrand.New(mrand.NewSource(int64(binary.LittleEndian.Uint64(seed[:])))) rnd := mrand.New(mrand.NewSource(int64(binary.LittleEndian.Uint64(seed[:]))))
fmt.Printf("Seed: %x\n", seed) fmt.Printf("Seed: %x\n", seed)
return rnd return rnd
} }
func randBytes(n int) []byte { func randBytes(n int) []byte {
r := make([]byte, n) r := make([]byte, n)
prng.Read(r) prng.Read(r)
return r return r
} }
@ -1047,6 +1049,7 @@ func randomTrie(n int) (*Trie, 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}
value2 := &kv{common.LeftPadBytes([]byte{i + 10}, 32), []byte{i}, false} value2 := &kv{common.LeftPadBytes([]byte{i + 10}, 32), []byte{i}, false}
trie.MustUpdate(value.k, value.v) trie.MustUpdate(value.k, value.v)
trie.MustUpdate(value2.k, value2.v) trie.MustUpdate(value2.k, value2.v)
vals[string(value.k)] = value vals[string(value.k)] = value

View file

@ -34,6 +34,7 @@ func NewSecure(stateRoot common.Hash, owner common.Hash, root common.Hash, db *D
Owner: owner, Owner: owner,
Root: root, Root: root,
} }
return NewStateTrie(id, db) return NewStateTrie(id, db)
} }
@ -64,10 +65,12 @@ func NewStateTrie(id *ID, db *Database) (*StateTrie, error) {
if db == nil { if db == nil {
panic("trie.NewStateTrie called without a database") panic("trie.NewStateTrie called without a database")
} }
trie, err := New(id, db) trie, err := New(id, db)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &StateTrie{trie: *trie, preimages: db.preimages}, nil return &StateTrie{trie: *trie, preimages: db.preimages}, nil
} }
@ -96,8 +99,10 @@ func (t *StateTrie) GetAccount(address common.Address) (*types.StateAccount, err
if res == nil || err != nil { if res == nil || err != nil {
return nil, err return nil, err
} }
ret := new(types.StateAccount) ret := new(types.StateAccount)
err = rlp.DecodeBytes(res, ret) err = rlp.DecodeBytes(res, ret)
return ret, err return ret, err
} }
@ -109,8 +114,10 @@ func (t *StateTrie) GetAccountByHash(addrHash common.Hash) (*types.StateAccount,
if res == nil || err != nil { if res == nil || err != nil {
return nil, err return nil, err
} }
ret := new(types.StateAccount) ret := new(types.StateAccount)
err = rlp.DecodeBytes(res, ret) err = rlp.DecodeBytes(res, ret)
return ret, err return ret, err
} }
@ -134,6 +141,7 @@ func (t *StateTrie) GetNode(path []byte) ([]byte, int, error) {
func (t *StateTrie) MustUpdate(key, value []byte) { func (t *StateTrie) MustUpdate(key, value []byte) {
hk := t.hashKey(key) hk := t.hashKey(key)
t.trie.MustUpdate(hk, value) t.trie.MustUpdate(hk, value)
t.getSecKeyCache()[string(hk)] = common.CopyBytes(key) t.getSecKeyCache()[string(hk)] = common.CopyBytes(key)
} }
@ -159,13 +167,17 @@ func (t *StateTrie) UpdateStorage(_ common.Address, key, value []byte) error {
func (t *StateTrie) UpdateAccount(address common.Address, acc *types.StateAccount) error { func (t *StateTrie) UpdateAccount(address common.Address, acc *types.StateAccount) error {
hk := t.hashKey(address.Bytes()) hk := t.hashKey(address.Bytes())
data, err := rlp.EncodeToBytes(acc) data, err := rlp.EncodeToBytes(acc)
if err != nil { if err != nil {
return err return err
} }
if err := t.trie.Update(hk, data); err != nil { if err := t.trie.Update(hk, data); err != nil {
return err return err
} }
t.getSecKeyCache()[string(hk)] = address.Bytes() t.getSecKeyCache()[string(hk)] = address.Bytes()
return nil return nil
} }
@ -183,6 +195,7 @@ func (t *StateTrie) MustDelete(key []byte) {
func (t *StateTrie) DeleteStorage(_ common.Address, key []byte) error { func (t *StateTrie) DeleteStorage(_ common.Address, key []byte) error {
hk := t.hashKey(key) hk := t.hashKey(key)
delete(t.getSecKeyCache(), string(hk)) delete(t.getSecKeyCache(), string(hk))
return t.trie.Delete(hk) return t.trie.Delete(hk)
} }
@ -190,6 +203,7 @@ func (t *StateTrie) DeleteStorage(_ common.Address, key []byte) error {
func (t *StateTrie) DeleteAccount(address common.Address) error { func (t *StateTrie) DeleteAccount(address common.Address) error {
hk := t.hashKey(address.Bytes()) hk := t.hashKey(address.Bytes())
delete(t.getSecKeyCache(), string(hk)) delete(t.getSecKeyCache(), string(hk))
return t.trie.Delete(hk) return t.trie.Delete(hk)
} }
@ -199,9 +213,11 @@ func (t *StateTrie) GetKey(shaKey []byte) []byte {
if key, ok := t.getSecKeyCache()[string(shaKey)]; ok { if key, ok := t.getSecKeyCache()[string(shaKey)]; ok {
return key return key
} }
if t.preimages == nil { if t.preimages == nil {
return nil return nil
} }
return t.preimages.preimage(common.BytesToHash(shaKey)) return t.preimages.preimage(common.BytesToHash(shaKey))
} }
@ -220,6 +236,7 @@ func (t *StateTrie) Commit(collectLeaf bool) (common.Hash, *NodeSet) {
for hk, key := range t.secKeyCache { for hk, key := range t.secKeyCache {
preimages[common.BytesToHash([]byte(hk))] = key preimages[common.BytesToHash([]byte(hk))] = key
} }
t.preimages.insertPreimage(preimages) t.preimages.insertPreimage(preimages)
} }
t.secKeyCache = make(map[string][]byte) t.secKeyCache = make(map[string][]byte)

View file

@ -58,7 +58,9 @@ func makeTestStateTrie() (*Database, *StateTrie, map[string][]byte) {
trie.MustUpdate(key, val) trie.MustUpdate(key, val)
} }
} }
root, nodes := trie.Commit(false) root, nodes := trie.Commit(false)
if err := triedb.Update(NewWithNodeSet(nodes)); err != nil { if err := triedb.Update(NewWithNodeSet(nodes)); err != nil {
panic(fmt.Errorf("failed to commit db %v", err)) panic(fmt.Errorf("failed to commit db %v", err))
} }

View file

@ -144,9 +144,11 @@ func (st *StackTrie) unmarshalBinary(r io.Reader) error {
Val []byte Val []byte
Key []byte Key []byte
} }
if err := gob.NewDecoder(r).Decode(&dec); err != nil { if err := gob.NewDecoder(r).Decode(&dec); err != nil {
return err return err
} }
st.owner = dec.Owner st.owner = dec.Owner
st.nodeType = dec.NodeType st.nodeType = dec.NodeType
st.val = dec.Val st.val = dec.Val
@ -160,6 +162,7 @@ func (st *StackTrie) unmarshalBinary(r io.Reader) error {
continue continue
} }
var child StackTrie var child StackTrie
if err := child.unmarshalBinary(r); err != nil { if err := child.unmarshalBinary(r); err != nil {
return err return err
} }
@ -208,6 +211,7 @@ func (st *StackTrie) Update(key, value []byte) error {
if len(value) == 0 { if len(value) == 0 {
panic("deletion not supported") panic("deletion not supported")
} }
st.insert(k[:len(k)-1], value, nil) st.insert(k[:len(k)-1], value, nil)
return nil return nil
} }
@ -426,6 +430,7 @@ func (st *StackTrie) hashRec(hasher *hasher, path []byte) {
nodes[i] = nilValueNode nodes[i] = nilValueNode
continue continue
} }
child.hashRec(hasher, append(path, byte(i))) child.hashRec(hasher, append(path, byte(i)))
if len(child.val) < 32 { if len(child.val) < 32 {
nodes[i] = rawNode(child.val) nodes[i] = rawNode(child.val)

View file

@ -188,10 +188,13 @@ func (s *Sync) AddSubTrie(root common.Hash, path []byte, parent common.Hash, par
if root == types.EmptyRootHash { if root == types.EmptyRootHash {
return return
} }
if s.membatch.hasNode(path) { if s.membatch.hasNode(path) {
return return
} }
owner, inner := ResolvePath(path) owner, inner := ResolvePath(path)
if rawdb.HasTrieNode(s.database, owner, inner, root, s.scheme) { if rawdb.HasTrieNode(s.database, owner, inner, root, s.scheme) {
return return
} }
@ -210,6 +213,7 @@ func (s *Sync) AddSubTrie(root common.Hash, path []byte, parent common.Hash, par
ancestor.deps++ ancestor.deps++
req.parent = ancestor req.parent = ancestor
} }
s.scheduleNodeRequest(req) s.scheduleNodeRequest(req)
} }
@ -246,6 +250,7 @@ func (s *Sync) AddCodeEntry(hash common.Hash, path []byte, parent common.Hash, p
ancestor.deps++ ancestor.deps++
req.parents = append(req.parents, ancestor) req.parents = append(req.parents, ancestor)
} }
s.scheduleCodeRequest(req) s.scheduleCodeRequest(req)
} }
@ -280,10 +285,12 @@ func (s *Sync) Missing(max int) ([]string, []common.Hash, []common.Hash) {
log.Error("Missing node request", "path", item) log.Error("Missing node request", "path", item)
continue // System very wrong, shouldn't happen continue // System very wrong, shouldn't happen
} }
nodePaths = append(nodePaths, item) nodePaths = append(nodePaths, item)
nodeHashes = append(nodeHashes, req.hash) nodeHashes = append(nodeHashes, req.hash)
} }
} }
return nodePaths, nodeHashes, codeHashes return nodePaths, nodeHashes, codeHashes
} }
@ -299,10 +306,13 @@ func (s *Sync) ProcessCode(result CodeSyncResult) error {
if req == nil { if req == nil {
return ErrNotRequested return ErrNotRequested
} }
if req.data != nil { if req.data != nil {
return ErrAlreadyProcessed return ErrAlreadyProcessed
} }
req.data = result.Data req.data = result.Data
return s.commitCodeRequest(req) return s.commitCodeRequest(req)
} }
@ -318,6 +328,7 @@ func (s *Sync) ProcessNode(result NodeSyncResult) error {
if req == nil { if req == nil {
return ErrNotRequested return ErrNotRequested
} }
if req.data != nil { if req.data != nil {
return ErrAlreadyProcessed return ErrAlreadyProcessed
} }
@ -326,6 +337,7 @@ func (s *Sync) ProcessNode(result NodeSyncResult) error {
if err != nil { if err != nil {
return err return err
} }
req.data = result.Data req.data = result.Data
// Create and schedule a request for all the children nodes // Create and schedule a request for all the children nodes
@ -333,6 +345,7 @@ func (s *Sync) ProcessNode(result NodeSyncResult) error {
if err != nil { if err != nil {
return err return err
} }
if len(requests) == 0 && req.deps == 0 { if len(requests) == 0 && req.deps == 0 {
s.commitNodeRequest(req) s.commitNodeRequest(req)
} else { } else {
@ -352,6 +365,7 @@ func (s *Sync) Commit(dbw ethdb.Batch) error {
owner, inner := ResolvePath([]byte(path)) owner, inner := ResolvePath([]byte(path))
rawdb.WriteTrieNode(dbw, owner, inner, s.membatch.hashes[path], value, s.scheme) rawdb.WriteTrieNode(dbw, owner, inner, s.membatch.hashes[path], value, s.scheme)
} }
for hash, value := range s.membatch.codes { for hash, value := range s.membatch.codes {
rawdb.WriteCode(dbw, hash, value) rawdb.WriteCode(dbw, hash, value)
} }
@ -394,6 +408,7 @@ func (s *Sync) scheduleCodeRequest(req *codeRequest) {
old.parents = append(old.parents, req.parents...) old.parents = append(old.parents, req.parents...)
return return
} }
s.codeReqs[req.hash] = req s.codeReqs[req.hash] = req
// Schedule the request for future retrieval. This queue is shared // Schedule the request for future retrieval. This queue is shared
@ -413,6 +428,7 @@ func (s *Sync) children(req *nodeRequest, object node) ([]*nodeRequest, error) {
path []byte path []byte
node node node node
} }
var children []childNode var children []childNode
switch node := (object).(type) { switch node := (object).(type) {
@ -421,6 +437,7 @@ func (s *Sync) children(req *nodeRequest, object node) ([]*nodeRequest, error) {
if hasTerm(key) { if hasTerm(key) {
key = key[:len(key)-1] key = key[:len(key)-1]
} }
children = []childNode{{ children = []childNode{{
node: node.Val, node: node.Val,
path: append(append([]byte(nil), req.path...), key...), path: append(append([]byte(nil), req.path...), key...),
@ -453,6 +470,7 @@ func (s *Sync) children(req *nodeRequest, object node) ([]*nodeRequest, error) {
paths = append(paths, hexToKeybytes(child.path[:2*common.HashLength])) paths = append(paths, hexToKeybytes(child.path[:2*common.HashLength]))
paths = append(paths, hexToKeybytes(child.path[2*common.HashLength:])) paths = append(paths, hexToKeybytes(child.path[2*common.HashLength:]))
} }
if err := req.callback(paths, child.path, node, req.hash, req.path); err != nil { if err := req.callback(paths, child.path, node, req.hash, req.path); err != nil {
return nil, err return nil, err
} }
@ -466,6 +484,7 @@ func (s *Sync) children(req *nodeRequest, object node) ([]*nodeRequest, error) {
} }
// Check the presence of children concurrently // Check the presence of children concurrently
pending.Add(1) pending.Add(1)
go func(child childNode) { go func(child childNode) {
defer pending.Done() defer pending.Done()
@ -475,6 +494,7 @@ func (s *Sync) children(req *nodeRequest, object node) ([]*nodeRequest, error) {
chash = common.BytesToHash(node) chash = common.BytesToHash(node)
owner, inner = ResolvePath(child.path) owner, inner = ResolvePath(child.path)
) )
if rawdb.HasTrieNode(s.database, owner, inner, chash, s.scheme) { if rawdb.HasTrieNode(s.database, owner, inner, chash, s.scheme) {
return return
} }
@ -488,9 +508,11 @@ func (s *Sync) children(req *nodeRequest, object node) ([]*nodeRequest, error) {
}(child) }(child)
} }
} }
pending.Wait() pending.Wait()
requests := make([]*nodeRequest, 0, len(children)) requests := make([]*nodeRequest, 0, len(children))
for done := false; !done; { for done := false; !done; {
select { select {
case miss := <-missing: case miss := <-missing:
@ -525,6 +547,7 @@ func (s *Sync) commitNodeRequest(req *nodeRequest) error {
} }
} }
} }
return nil return nil
} }
@ -558,5 +581,6 @@ func ResolvePath(path []byte) (common.Hash, []byte) {
owner = common.BytesToHash(hexToKeybytes(path[:2*common.HashLength])) owner = common.BytesToHash(hexToKeybytes(path[:2*common.HashLength]))
path = path[2*common.HashLength:] path = path[2*common.HashLength:]
} }
return owner, path return owner, path
} }

View file

@ -53,7 +53,9 @@ func makeTestTrie() (*Database, *StateTrie, map[string][]byte) {
trie.MustUpdate(key, val) trie.MustUpdate(key, val)
} }
} }
root, nodes := trie.Commit(false) root, nodes := trie.Commit(false)
if err := triedb.Update(NewWithNodeSet(nodes)); err != nil { if err := triedb.Update(NewWithNodeSet(nodes)); err != nil {
panic(fmt.Errorf("failed to commit db %v", err)) panic(fmt.Errorf("failed to commit db %v", err))
} }
@ -135,6 +137,7 @@ func testIterativeSync(t *testing.T, count int, bypath bool) {
// at the testing trie. // at the testing trie.
paths, nodes, _ := sched.Missing(count) paths, nodes, _ := sched.Missing(count)
var elements []trieElement var elements []trieElement
for i := 0; i < len(paths); i++ { for i := 0; i < len(paths); i++ {
elements = append(elements, trieElement{ elements = append(elements, trieElement{
path: paths[i], path: paths[i],
@ -142,14 +145,17 @@ func testIterativeSync(t *testing.T, count int, bypath bool) {
syncPath: NewSyncPath([]byte(paths[i])), syncPath: NewSyncPath([]byte(paths[i])),
}) })
} }
for len(elements) > 0 { for len(elements) > 0 {
results := make([]NodeSyncResult, len(elements)) results := make([]NodeSyncResult, len(elements))
if !bypath { if !bypath {
for i, element := range elements { for i, element := range elements {
data, err := srcDb.Node(element.hash) data, err := srcDb.Node(element.hash)
if err != nil { if err != nil {
t.Fatalf("failed to retrieve node data for hash %x: %v", element.hash, err) t.Fatalf("failed to retrieve node data for hash %x: %v", element.hash, err)
} }
results[i] = NodeSyncResult{element.path, data} results[i] = NodeSyncResult{element.path, data}
} }
} else { } else {
@ -174,6 +180,7 @@ func testIterativeSync(t *testing.T, count int, bypath bool) {
paths, nodes, _ = sched.Missing(count) paths, nodes, _ = sched.Missing(count)
elements = elements[:0] elements = elements[:0]
for i := 0; i < len(paths); i++ { for i := 0; i < len(paths); i++ {
elements = append(elements, trieElement{ elements = append(elements, trieElement{
path: paths[i], path: paths[i],
@ -201,6 +208,7 @@ func TestIterativeDelayedSync(t *testing.T) {
// at the testing trie. // at the testing trie.
paths, nodes, _ := sched.Missing(10000) paths, nodes, _ := sched.Missing(10000)
var elements []trieElement var elements []trieElement
for i := 0; i < len(paths); i++ { for i := 0; i < len(paths); i++ {
elements = append(elements, trieElement{ elements = append(elements, trieElement{
path: paths[i], path: paths[i],
@ -208,6 +216,7 @@ func TestIterativeDelayedSync(t *testing.T) {
syncPath: NewSyncPath([]byte(paths[i])), syncPath: NewSyncPath([]byte(paths[i])),
}) })
} }
for len(elements) > 0 { for len(elements) > 0 {
// Sync only half of the scheduled nodes // Sync only half of the scheduled nodes
results := make([]NodeSyncResult, len(elements)/2+1) results := make([]NodeSyncResult, len(elements)/2+1)
@ -216,6 +225,7 @@ func TestIterativeDelayedSync(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("failed to retrieve node data for %x: %v", element.hash, err) t.Fatalf("failed to retrieve node data for %x: %v", element.hash, err)
} }
results[i] = NodeSyncResult{element.path, data} results[i] = NodeSyncResult{element.path, data}
} }
for _, result := range results { for _, result := range results {
@ -231,6 +241,7 @@ func TestIterativeDelayedSync(t *testing.T) {
paths, nodes, _ = sched.Missing(10000) paths, nodes, _ = sched.Missing(10000)
elements = elements[len(results):] elements = elements[len(results):]
for i := 0; i < len(paths); i++ { for i := 0; i < len(paths); i++ {
elements = append(elements, trieElement{ elements = append(elements, trieElement{
path: paths[i], path: paths[i],
@ -262,6 +273,7 @@ func testIterativeRandomSync(t *testing.T, count int) {
// at the testing trie. // at the testing trie.
paths, nodes, _ := sched.Missing(count) paths, nodes, _ := sched.Missing(count)
queue := make(map[string]trieElement) queue := make(map[string]trieElement)
for i, path := range paths { for i, path := range paths {
queue[path] = trieElement{ queue[path] = trieElement{
path: paths[i], path: paths[i],
@ -272,11 +284,13 @@ func testIterativeRandomSync(t *testing.T, count int) {
for len(queue) > 0 { for len(queue) > 0 {
// Fetch all the queued nodes in a random order // Fetch all the queued nodes in a random order
results := make([]NodeSyncResult, 0, len(queue)) results := make([]NodeSyncResult, 0, len(queue))
for path, element := range queue { for path, element := range queue {
data, err := srcDb.Node(element.hash) data, err := srcDb.Node(element.hash)
if err != nil { if err != nil {
t.Fatalf("failed to retrieve node data for %x: %v", element.hash, err) t.Fatalf("failed to retrieve node data for %x: %v", element.hash, err)
} }
results = append(results, NodeSyncResult{path, data}) results = append(results, NodeSyncResult{path, data})
} }
// Feed the retrieved results back and queue new tasks // Feed the retrieved results back and queue new tasks
@ -293,6 +307,7 @@ func testIterativeRandomSync(t *testing.T, count int) {
paths, nodes, _ = sched.Missing(count) paths, nodes, _ = sched.Missing(count)
queue = make(map[string]trieElement) queue = make(map[string]trieElement)
for i, path := range paths { for i, path := range paths {
queue[path] = trieElement{ queue[path] = trieElement{
path: path, path: path,
@ -320,6 +335,7 @@ func TestIterativeRandomDelayedSync(t *testing.T) {
// at the testing trie. // at the testing trie.
paths, nodes, _ := sched.Missing(10000) paths, nodes, _ := sched.Missing(10000)
queue := make(map[string]trieElement) queue := make(map[string]trieElement)
for i, path := range paths { for i, path := range paths {
queue[path] = trieElement{ queue[path] = trieElement{
path: path, path: path,
@ -330,11 +346,13 @@ func TestIterativeRandomDelayedSync(t *testing.T) {
for len(queue) > 0 { for len(queue) > 0 {
// Sync only half of the scheduled nodes, even those in random order // Sync only half of the scheduled nodes, even those in random order
results := make([]NodeSyncResult, 0, len(queue)/2+1) results := make([]NodeSyncResult, 0, len(queue)/2+1)
for path, element := range queue { for path, element := range queue {
data, err := srcDb.Node(element.hash) data, err := srcDb.Node(element.hash)
if err != nil { if err != nil {
t.Fatalf("failed to retrieve node data for %x: %v", element.hash, err) t.Fatalf("failed to retrieve node data for %x: %v", element.hash, err)
} }
results = append(results, NodeSyncResult{path, data}) results = append(results, NodeSyncResult{path, data})
if len(results) >= cap(results) { if len(results) >= cap(results) {
@ -355,7 +373,9 @@ func TestIterativeRandomDelayedSync(t *testing.T) {
for _, result := range results { for _, result := range results {
delete(queue, result.Path) delete(queue, result.Path)
} }
paths, nodes, _ = sched.Missing(10000) paths, nodes, _ = sched.Missing(10000)
for i, path := range paths { for i, path := range paths {
queue[path] = trieElement{ queue[path] = trieElement{
path: path, path: path,
@ -383,6 +403,7 @@ func TestDuplicateAvoidanceSync(t *testing.T) {
// at the testing trie. // at the testing trie.
paths, nodes, _ := sched.Missing(0) paths, nodes, _ := sched.Missing(0)
var elements []trieElement var elements []trieElement
for i := 0; i < len(paths); i++ { for i := 0; i < len(paths); i++ {
elements = append(elements, trieElement{ elements = append(elements, trieElement{
path: paths[i], path: paths[i],
@ -394,14 +415,17 @@ func TestDuplicateAvoidanceSync(t *testing.T) {
for len(elements) > 0 { for len(elements) > 0 {
results := make([]NodeSyncResult, len(elements)) results := make([]NodeSyncResult, len(elements))
for i, element := range elements { for i, element := range elements {
data, err := srcDb.Node(element.hash) data, err := srcDb.Node(element.hash)
if err != nil { if err != nil {
t.Fatalf("failed to retrieve node data for %x: %v", element.hash, err) t.Fatalf("failed to retrieve node data for %x: %v", element.hash, err)
} }
if _, ok := requested[element.hash]; ok { if _, ok := requested[element.hash]; ok {
t.Errorf("hash %x already requested once", element.hash) t.Errorf("hash %x already requested once", element.hash)
} }
requested[element.hash] = struct{}{} requested[element.hash] = struct{}{}
results[i] = NodeSyncResult{element.path, data} results[i] = NodeSyncResult{element.path, data}
@ -419,6 +443,7 @@ func TestDuplicateAvoidanceSync(t *testing.T) {
paths, nodes, _ = sched.Missing(0) paths, nodes, _ = sched.Missing(0)
elements = elements[:0] elements = elements[:0]
for i := 0; i < len(paths); i++ { for i := 0; i < len(paths); i++ {
elements = append(elements, trieElement{ elements = append(elements, trieElement{
path: paths[i], path: paths[i],
@ -451,6 +476,7 @@ func TestIncompleteSync(t *testing.T) {
root = srcTrie.Hash() root = srcTrie.Hash()
) )
paths, nodes, _ := sched.Missing(1) paths, nodes, _ := sched.Missing(1)
for i := 0; i < len(paths); i++ { for i := 0; i < len(paths); i++ {
elements = append(elements, trieElement{ elements = append(elements, trieElement{
path: paths[i], path: paths[i],
@ -458,14 +484,17 @@ func TestIncompleteSync(t *testing.T) {
syncPath: NewSyncPath([]byte(paths[i])), syncPath: NewSyncPath([]byte(paths[i])),
}) })
} }
for len(elements) > 0 { for len(elements) > 0 {
// Fetch a batch of trie nodes // Fetch a batch of trie nodes
results := make([]NodeSyncResult, len(elements)) results := make([]NodeSyncResult, len(elements))
for i, element := range elements { for i, element := range elements {
data, err := srcDb.Node(element.hash) data, err := srcDb.Node(element.hash)
if err != nil { if err != nil {
t.Fatalf("failed to retrieve node data for %x: %v", element.hash, err) t.Fatalf("failed to retrieve node data for %x: %v", element.hash, err)
} }
results[i] = NodeSyncResult{element.path, data} results[i] = NodeSyncResult{element.path, data}
} }
// Process each of the trie nodes // Process each of the trie nodes
@ -493,6 +522,7 @@ func TestIncompleteSync(t *testing.T) {
// Fetch the next batch to retrieve // Fetch the next batch to retrieve
paths, nodes, _ = sched.Missing(1) paths, nodes, _ = sched.Missing(1)
elements = elements[:0] elements = elements[:0]
for i := 0; i < len(paths); i++ { for i := 0; i < len(paths); i++ {
elements = append(elements, trieElement{ elements = append(elements, trieElement{
path: paths[i], path: paths[i],
@ -505,6 +535,7 @@ func TestIncompleteSync(t *testing.T) {
for _, hash := range added { for _, hash := range added {
value, _ := diskdb.Get(hash.Bytes()) value, _ := diskdb.Get(hash.Bytes())
diskdb.Delete(hash.Bytes()) diskdb.Delete(hash.Bytes())
if err := checkTrieConsistency(triedb, root); err == nil { if err := checkTrieConsistency(triedb, root); err == nil {
t.Fatalf("trie inconsistency not caught, missing: %x", hash) t.Fatalf("trie inconsistency not caught, missing: %x", hash)
} }
@ -529,23 +560,28 @@ func TestSyncOrdering(t *testing.T) {
reqs []SyncPath reqs []SyncPath
elements []trieElement elements []trieElement
) )
paths, nodes, _ := sched.Missing(1) paths, nodes, _ := sched.Missing(1)
for i := 0; i < len(paths); i++ { for i := 0; i < len(paths); i++ {
elements = append(elements, trieElement{ elements = append(elements, trieElement{
path: paths[i], path: paths[i],
hash: nodes[i], hash: nodes[i],
syncPath: NewSyncPath([]byte(paths[i])), syncPath: NewSyncPath([]byte(paths[i])),
}) })
reqs = append(reqs, NewSyncPath([]byte(paths[i]))) reqs = append(reqs, NewSyncPath([]byte(paths[i])))
} }
for len(elements) > 0 { for len(elements) > 0 {
results := make([]NodeSyncResult, len(elements)) results := make([]NodeSyncResult, len(elements))
for i, element := range elements { for i, element := range elements {
data, err := srcDb.Node(element.hash) data, err := srcDb.Node(element.hash)
if err != nil { if err != nil {
t.Fatalf("failed to retrieve node data for %x: %v", element.hash, err) t.Fatalf("failed to retrieve node data for %x: %v", element.hash, err)
} }
results[i] = NodeSyncResult{element.path, data} results[i] = NodeSyncResult{element.path, data}
} }
for _, result := range results { for _, result := range results {
@ -561,16 +597,18 @@ func TestSyncOrdering(t *testing.T) {
paths, nodes, _ = sched.Missing(1) paths, nodes, _ = sched.Missing(1)
elements = elements[:0] elements = elements[:0]
for i := 0; i < len(paths); i++ { for i := 0; i < len(paths); i++ {
elements = append(elements, trieElement{ elements = append(elements, trieElement{
path: paths[i], path: paths[i],
hash: nodes[i], hash: nodes[i],
syncPath: NewSyncPath([]byte(paths[i])), syncPath: NewSyncPath([]byte(paths[i])),
}) })
reqs = append(reqs, NewSyncPath([]byte(paths[i]))) reqs = append(reqs, NewSyncPath([]byte(paths[i])))
} }
} }
// Cross check that the two tries are in sync // Cross-check that the two tries are in sync
checkTrieContents(t, triedb, srcTrie.Hash().Bytes(), srcData) checkTrieContents(t, triedb, srcTrie.Hash().Bytes(), srcData)
// Check that the trie nodes have been requested path-ordered // Check that the trie nodes have been requested path-ordered

View file

@ -67,6 +67,7 @@ func (t *tracer) onInsert(path []byte) {
delete(t.deletes, string(path)) delete(t.deletes, string(path))
return return
} }
t.inserts[string(path)] = struct{}{} t.inserts[string(path)] = struct{}{}
} }
@ -78,6 +79,7 @@ func (t *tracer) onDelete(path []byte) {
delete(t.inserts, string(path)) delete(t.inserts, string(path))
return return
} }
t.deletes[string(path)] = struct{}{} t.deletes[string(path)] = struct{}{}
} }
@ -95,15 +97,19 @@ func (t *tracer) copy() *tracer {
deletes = make(map[string]struct{}) deletes = make(map[string]struct{})
accessList = make(map[string][]byte) accessList = make(map[string][]byte)
) )
for path := range t.inserts { for path := range t.inserts {
inserts[path] = struct{}{} inserts[path] = struct{}{}
} }
for path := range t.deletes { for path := range t.deletes {
deletes[path] = struct{}{} deletes[path] = struct{}{}
} }
for path, blob := range t.accessList { for path, blob := range t.accessList {
accessList[path] = common.CopyBytes(blob) accessList[path] = common.CopyBytes(blob)
} }
return &tracer{ return &tracer{
inserts: inserts, inserts: inserts,
deletes: deletes, deletes: deletes,
@ -120,6 +126,7 @@ func (t *tracer) markDeletions(set *NodeSet) {
if _, ok := set.accessList[path]; !ok { if _, ok := set.accessList[path]; !ok {
continue continue
} }
set.markDeleted([]byte(path)) set.markDeleted([]byte(path))
} }
} }

View file

@ -69,6 +69,7 @@ func testTrieTracer(t *testing.T, vals []struct{ k, v string }) {
for _, val := range vals { for _, val := range vals {
trie.MustUpdate([]byte(val.k), []byte(val.v)) trie.MustUpdate([]byte(val.k), []byte(val.v))
} }
insertSet := copySet(trie.tracer.inserts) // copy before commit insertSet := copySet(trie.tracer.inserts) // copy before commit
deleteSet := copySet(trie.tracer.deletes) // copy before commit deleteSet := copySet(trie.tracer.deletes) // copy before commit
root, nodes := trie.Commit(false) root, nodes := trie.Commit(false)
@ -78,6 +79,7 @@ func testTrieTracer(t *testing.T, vals []struct{ k, v string }) {
if !compareSet(insertSet, seen) { if !compareSet(insertSet, seen) {
t.Fatal("Unexpected insertion set") t.Fatal("Unexpected insertion set")
} }
if !compareSet(deleteSet, nil) { if !compareSet(deleteSet, nil) {
t.Fatal("Unexpected deletion set") t.Fatal("Unexpected deletion set")
} }
@ -87,10 +89,13 @@ func testTrieTracer(t *testing.T, vals []struct{ k, v string }) {
for _, val := range vals { for _, val := range vals {
trie.MustDelete([]byte(val.k)) trie.MustDelete([]byte(val.k))
} }
insertSet, deleteSet = copySet(trie.tracer.inserts), copySet(trie.tracer.deletes) insertSet, deleteSet = copySet(trie.tracer.inserts), copySet(trie.tracer.deletes)
if !compareSet(insertSet, nil) { if !compareSet(insertSet, nil) {
t.Fatal("Unexpected insertion set") t.Fatal("Unexpected insertion set")
} }
if !compareSet(deleteSet, seen) { if !compareSet(deleteSet, seen) {
t.Fatal("Unexpected deletion set") t.Fatal("Unexpected deletion set")
} }
@ -112,12 +117,15 @@ func testTrieTracerNoop(t *testing.T, vals []struct{ k, v string }) {
for _, val := range vals { for _, val := range vals {
trie.MustUpdate([]byte(val.k), []byte(val.v)) trie.MustUpdate([]byte(val.k), []byte(val.v))
} }
for _, val := range vals { for _, val := range vals {
trie.MustDelete([]byte(val.k)) trie.MustDelete([]byte(val.k))
} }
if len(trie.tracer.inserts) != 0 { if len(trie.tracer.inserts) != 0 {
t.Fatal("Unexpected insertion set") t.Fatal("Unexpected insertion set")
} }
if len(trie.tracer.deletes) != 0 { if len(trie.tracer.deletes) != 0 {
t.Fatal("Unexpected deletion set") t.Fatal("Unexpected deletion set")
} }
@ -143,6 +151,7 @@ func testAccessList(t *testing.T, vals []struct{ k, v string }) {
for _, val := range vals { for _, val := range vals {
trie.MustUpdate([]byte(val.k), []byte(val.v)) trie.MustUpdate([]byte(val.k), []byte(val.v))
} }
root, nodes := trie.Commit(false) root, nodes := trie.Commit(false)
db.Update(NewWithNodeSet(nodes)) db.Update(NewWithNodeSet(nodes))
@ -154,9 +163,11 @@ func testAccessList(t *testing.T, vals []struct{ k, v string }) {
// Update trie // Update trie
trie, _ = New(TrieID(root), db) trie, _ = New(TrieID(root), db)
orig = trie.Copy() orig = trie.Copy()
for _, val := range vals { for _, val := range vals {
trie.MustUpdate([]byte(val.k), randBytes(32)) trie.MustUpdate([]byte(val.k), randBytes(32))
} }
root, nodes = trie.Commit(false) root, nodes = trie.Commit(false)
db.Update(NewWithNodeSet(nodes)) db.Update(NewWithNodeSet(nodes))
@ -169,11 +180,13 @@ func testAccessList(t *testing.T, vals []struct{ k, v string }) {
trie, _ = New(TrieID(root), db) trie, _ = New(TrieID(root), db)
orig = trie.Copy() orig = trie.Copy()
var keys []string var keys []string
for i := 0; i < 30; i++ { for i := 0; i < 30; i++ {
key := randBytes(32) key := randBytes(32)
keys = append(keys, string(key)) keys = append(keys, string(key))
trie.MustUpdate(key, randBytes(32)) trie.MustUpdate(key, randBytes(32))
} }
root, nodes = trie.Commit(false) root, nodes = trie.Commit(false)
db.Update(NewWithNodeSet(nodes)) db.Update(NewWithNodeSet(nodes))
@ -185,9 +198,11 @@ func testAccessList(t *testing.T, vals []struct{ k, v string }) {
// Partial deletions // Partial deletions
trie, _ = New(TrieID(root), db) trie, _ = New(TrieID(root), db)
orig = trie.Copy() orig = trie.Copy()
for _, key := range keys { for _, key := range keys {
trie.MustUpdate([]byte(key), nil) trie.MustUpdate([]byte(key), nil)
} }
root, nodes = trie.Commit(false) root, nodes = trie.Commit(false)
db.Update(NewWithNodeSet(nodes)) db.Update(NewWithNodeSet(nodes))
@ -199,9 +214,11 @@ func testAccessList(t *testing.T, vals []struct{ k, v string }) {
// Delete all // Delete all
trie, _ = New(TrieID(root), db) trie, _ = New(TrieID(root), db)
orig = trie.Copy() orig = trie.Copy()
for _, val := range vals { for _, val := range vals {
trie.MustUpdate([]byte(val.k), nil) trie.MustUpdate([]byte(val.k), nil)
} }
root, nodes = trie.Commit(false) root, nodes = trie.Commit(false)
db.Update(NewWithNodeSet(nodes)) db.Update(NewWithNodeSet(nodes))
@ -214,6 +231,7 @@ func testAccessList(t *testing.T, vals []struct{ k, v string }) {
// Tests origin values won't be tracked in Iterator or Prover // Tests origin values won't be tracked in Iterator or Prover
func TestAccessListLeak(t *testing.T) { func TestAccessListLeak(t *testing.T) {
t.Parallel() t.Parallel()
var ( var (
db = NewDatabase(rawdb.NewMemoryDatabase()) db = NewDatabase(rawdb.NewMemoryDatabase())
trie = NewEmpty(db) trie = NewEmpty(db)
@ -222,6 +240,7 @@ func TestAccessListLeak(t *testing.T) {
for _, val := range standard { for _, val := range standard {
trie.MustUpdate([]byte(val.k), []byte(val.v)) trie.MustUpdate([]byte(val.k), []byte(val.v))
} }
root, nodes := trie.Commit(false) root, nodes := trie.Commit(false)
db.Update(NewWithNodeSet(nodes)) db.Update(NewWithNodeSet(nodes))
@ -250,6 +269,7 @@ func TestAccessListLeak(t *testing.T) {
}, },
}, },
} }
for _, c := range cases { for _, c := range cases {
trie, _ = New(TrieID(root), db) trie, _ = New(TrieID(root), db)
n1 := len(trie.tracer.accessList) n1 := len(trie.tracer.accessList)
@ -266,21 +286,26 @@ func TestAccessListLeak(t *testing.T) {
// in its parent due to the smaller size of the original tree node. // in its parent due to the smaller size of the original tree node.
func TestTinyTree(t *testing.T) { func TestTinyTree(t *testing.T) {
t.Parallel() t.Parallel()
var ( var (
db = NewDatabase(rawdb.NewMemoryDatabase()) db = NewDatabase(rawdb.NewMemoryDatabase())
trie = NewEmpty(db) trie = NewEmpty(db)
) )
for _, val := range tiny { for _, val := range tiny {
trie.MustUpdate([]byte(val.k), randBytes(32)) trie.MustUpdate([]byte(val.k), randBytes(32))
} }
root, set := trie.Commit(false) root, set := trie.Commit(false)
db.Update(NewWithNodeSet(set)) db.Update(NewWithNodeSet(set))
trie, _ = New(TrieID(root), db) trie, _ = New(TrieID(root), db)
orig := trie.Copy() orig := trie.Copy()
for _, val := range tiny { for _, val := range tiny {
trie.MustUpdate([]byte(val.k), []byte(val.v)) trie.MustUpdate([]byte(val.k), []byte(val.v))
} }
root, set = trie.Commit(false) root, set = trie.Commit(false)
db.Update(NewWithNodeSet(set)) db.Update(NewWithNodeSet(set))
@ -294,11 +319,13 @@ func compareSet(setA, setB map[string]struct{}) bool {
if len(setA) != len(setB) { if len(setA) != len(setB) {
return false return false
} }
for key := range setA { for key := range setA {
if _, ok := setB[key]; !ok { if _, ok := setB[key]; !ok {
return false return false
} }
} }
return true return true
} }
@ -307,12 +334,15 @@ func forNodes(tr *Trie) map[string][]byte {
it = tr.NodeIterator(nil) it = tr.NodeIterator(nil)
nodes = make(map[string][]byte) nodes = make(map[string][]byte)
) )
for it.Next(true) { for it.Next(true) {
if it.Leaf() { if it.Leaf() {
continue continue
} }
nodes[string(it.Path())] = common.CopyBytes(it.NodeBlob()) nodes[string(it.Path())] = common.CopyBytes(it.NodeBlob())
} }
return nodes return nodes
} }
@ -326,12 +356,15 @@ func forHashedNodes(tr *Trie) map[string][]byte {
it = tr.NodeIterator(nil) it = tr.NodeIterator(nil)
nodes = make(map[string][]byte) nodes = make(map[string][]byte)
) )
for it.Next(true) { for it.Next(true) {
if it.Hash() == (common.Hash{}) { if it.Hash() == (common.Hash{}) {
continue continue
} }
nodes[string(it.Path())] = common.CopyBytes(it.NodeBlob()) nodes[string(it.Path())] = common.CopyBytes(it.NodeBlob())
} }
return nodes return nodes
} }
@ -343,22 +376,28 @@ func diffTries(trieA, trieB *Trie) (map[string][]byte, map[string][]byte, map[st
inB = make(map[string][]byte) // hashed nodes in trie b but not a inB = make(map[string][]byte) // hashed nodes in trie b but not a
both = make(map[string][]byte) // hashed nodes in both tries but different value both = make(map[string][]byte) // hashed nodes in both tries but different value
) )
for path, blobA := range nodesA { for path, blobA := range nodesA {
if blobB, ok := nodesB[path]; ok { if blobB, ok := nodesB[path]; ok {
if bytes.Equal(blobA, blobB) { if bytes.Equal(blobA, blobB) {
continue continue
} }
both[path] = blobA both[path] = blobA
continue continue
} }
inA[path] = blobA inA[path] = blobA
} }
for path, blobB := range nodesB { for path, blobB := range nodesB {
if _, ok := nodesA[path]; ok { if _, ok := nodesA[path]; ok {
continue continue
} }
inB[path] = blobB inB[path] = blobB
} }
return inA, inB, both return inA, inB, both
} }
@ -367,6 +406,7 @@ func setKeys(set map[string][]byte) map[string]struct{} {
for k := range set { for k := range set {
keys[k] = struct{}{} keys[k] = struct{}{}
} }
return keys return keys
} }
@ -375,5 +415,6 @@ func copySet(set map[string]struct{}) map[string]struct{} {
for k := range set { for k := range set {
copied[k] = struct{}{} copied[k] = struct{}{}
} }
return copied return copied
} }

View file

@ -83,6 +83,7 @@ func New(id *ID, db NodeReader) (*Trie, error) {
reader: reader, reader: reader,
tracer: newTracer(), tracer: newTracer(),
} }
if id.Root != (common.Hash{}) && id.Root != types.EmptyRootHash { if id.Root != (common.Hash{}) && id.Root != types.EmptyRootHash {
rootnode, err := trie.resolveAndTrack(id.Root[:], nil) rootnode, err := trie.resolveAndTrack(id.Root[:], nil)
if err != nil { if err != nil {
@ -139,6 +140,7 @@ func (t *Trie) get(origNode node, key []byte, pos int) (value []byte, newnode no
// key not found in trie // key not found in trie
return nil, n, false, nil return nil, n, false, nil
} }
value, newnode, didResolve, err = t.get(n.Val, key, pos+len(n.Key)) value, newnode, didResolve, err = t.get(n.Val, key, pos+len(n.Key))
if err == nil && didResolve { if err == nil && didResolve {
n = n.copy() n = n.copy()
@ -157,6 +159,7 @@ func (t *Trie) get(origNode node, key []byte, pos int) (value []byte, newnode no
if err != nil { if err != nil {
return nil, n, true, err return nil, n, true, err
} }
value, newnode, _, err := t.get(child, key, pos) value, newnode, _, err := t.get(child, key, pos)
return value, newnode, true, err return value, newnode, true, err
default: default:
@ -171,6 +174,7 @@ func (t *Trie) MustGetNode(path []byte) ([]byte, int) {
if err != nil { if err != nil {
log.Error("Unhandled trie error in Trie.GetNode", "err", err) log.Error("Unhandled trie error in Trie.GetNode", "err", err)
} }
return item, resolved return item, resolved
} }
@ -190,6 +194,7 @@ func (t *Trie) GetNode(path []byte) ([]byte, int, error) {
if item == nil { if item == nil {
return nil, resolved, nil return nil, resolved, nil
} }
return item, resolved, nil return item, resolved, nil
} }
@ -212,6 +217,7 @@ func (t *Trie) getNode(origNode node, path []byte, pos int) (item []byte, newnod
if hash == nil { if hash == nil {
return nil, origNode, 0, errors.New("non-consensus node") return nil, origNode, 0, errors.New("non-consensus node")
} }
blob, err := t.reader.nodeBlob(path, common.BytesToHash(hash)) blob, err := t.reader.nodeBlob(path, common.BytesToHash(hash))
return blob, origNode, 1, err return blob, origNode, 1, err
} }
@ -226,6 +232,7 @@ func (t *Trie) getNode(origNode node, path []byte, pos int) (item []byte, newnod
// Path branches off from short node // Path branches off from short node
return nil, n, 0, nil return nil, n, 0, nil
} }
item, newnode, resolved, err = t.getNode(n.Val, path, pos+len(n.Key)) item, newnode, resolved, err = t.getNode(n.Val, path, pos+len(n.Key))
if err == nil && resolved > 0 { if err == nil && resolved > 0 {
n = n.copy() n = n.copy()
@ -246,6 +253,7 @@ func (t *Trie) getNode(origNode node, path []byte, pos int) (item []byte, newnod
if err != nil { if err != nil {
return nil, n, 1, err return nil, n, 1, err
} }
item, newnode, resolved, err := t.getNode(child, path, pos) item, newnode, resolved, err := t.getNode(child, path, pos)
return item, newnode, resolved + 1, err return item, newnode, resolved + 1, err
@ -553,7 +561,9 @@ func (t *Trie) resolveAndTrack(n hashNode, prefix []byte) (node, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
t.tracer.onRead(prefix, blob) t.tracer.onRead(prefix, blob)
return mustDecodeNode(n, blob), nil return mustDecodeNode(n, blob), nil
} }
@ -595,7 +605,9 @@ func (t *Trie) Commit(collectLeaf bool) (common.Hash, *NodeSet) {
t.root = hashedNode t.root = hashedNode
return rootHash, nil return rootHash, nil
} }
t.root = newCommitter(nodes, collectLeaf).Commit(t.root) t.root = newCommitter(nodes, collectLeaf).Commit(t.root)
return rootHash, nodes return rootHash, nodes
} }
@ -608,9 +620,11 @@ func (t *Trie) hashRoot() (node, node) {
h := newHasher(t.unhashed >= 100) h := newHasher(t.unhashed >= 100)
defer func() { defer func() {
returnHasherToPool(h) returnHasherToPool(h)
t.unhashed = 0 t.unhashed = 0
}() }()
hashed, cached := h.hash(t.root, true) hashed, cached := h.hash(t.root, true)
return hashed, cached return hashed, cached
} }

View file

@ -56,6 +56,7 @@ func newTrieReader(stateRoot, owner common.Hash, db NodeReader) (*trieReader, er
if reader == nil { if reader == nil {
return nil, fmt.Errorf("state not found #%x", stateRoot) return nil, fmt.Errorf("state not found #%x", stateRoot)
} }
return &trieReader{owner: owner, reader: reader}, nil return &trieReader{owner: owner, reader: reader}, nil
} }
@ -75,13 +76,17 @@ func (r *trieReader) node(path []byte, hash common.Hash) (node, error) {
return nil, &MissingNodeError{Owner: r.owner, NodeHash: hash, Path: path} return nil, &MissingNodeError{Owner: r.owner, NodeHash: hash, Path: path}
} }
} }
if r.reader == nil { if r.reader == nil {
return nil, &MissingNodeError{Owner: r.owner, NodeHash: hash, Path: path} return nil, &MissingNodeError{Owner: r.owner, NodeHash: hash, Path: path}
} }
node, err := r.reader.Node(r.owner, path, hash) node, err := r.reader.Node(r.owner, path, hash)
if err != nil || node == nil { if err != nil || node == nil {
return nil, &MissingNodeError{Owner: r.owner, NodeHash: hash, Path: path, err: err} return nil, &MissingNodeError{Owner: r.owner, NodeHash: hash, Path: path, err: err}
} }
return node, nil return node, nil
} }
@ -95,12 +100,16 @@ func (r *trieReader) nodeBlob(path []byte, hash common.Hash) ([]byte, error) {
return nil, &MissingNodeError{Owner: r.owner, NodeHash: hash, Path: path} return nil, &MissingNodeError{Owner: r.owner, NodeHash: hash, Path: path}
} }
} }
if r.reader == nil { if r.reader == nil {
return nil, &MissingNodeError{Owner: r.owner, NodeHash: hash, Path: path} return nil, &MissingNodeError{Owner: r.owner, NodeHash: hash, Path: path}
} }
blob, err := r.reader.NodeBlob(r.owner, path, hash) blob, err := r.reader.NodeBlob(r.owner, path, hash)
if err != nil || len(blob) == 0 { if err != nil || len(blob) == 0 {
return nil, &MissingNodeError{Owner: r.owner, NodeHash: hash, Path: path, err: err} return nil, &MissingNodeError{Owner: r.owner, NodeHash: hash, Path: path, err: err}
} }
return blob, nil return blob, nil
} }

View file

@ -57,6 +57,7 @@ func TestNull(t *testing.T) {
key := make([]byte, 32) key := make([]byte, 32)
value := []byte("test") value := []byte("test")
trie.MustUpdate(key, value) trie.MustUpdate(key, value)
if !bytes.Equal(trie.MustGet(key), value) { if !bytes.Equal(trie.MustGet(key), value) {
t.Fatal("wrong value") t.Fatal("wrong value")
} }
@ -94,21 +95,25 @@ func testMissingNode(t *testing.T, memonly bool) {
if err != nil { if err != nil {
t.Errorf("Unexpected error: %v", err) t.Errorf("Unexpected error: %v", err)
} }
trie, _ = New(TrieID(root), triedb) trie, _ = New(TrieID(root), triedb)
_, err = trie.Get([]byte("120099")) _, err = trie.Get([]byte("120099"))
if err != nil { if err != nil {
t.Errorf("Unexpected error: %v", err) t.Errorf("Unexpected error: %v", err)
} }
trie, _ = New(TrieID(root), triedb) trie, _ = New(TrieID(root), triedb)
_, err = trie.Get([]byte("123456")) _, err = trie.Get([]byte("123456"))
if err != nil { if err != nil {
t.Errorf("Unexpected error: %v", err) t.Errorf("Unexpected error: %v", err)
} }
trie, _ = New(TrieID(root), triedb) trie, _ = New(TrieID(root), triedb)
err = trie.Update([]byte("120099"), []byte("zxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcv")) err = trie.Update([]byte("120099"), []byte("zxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcv"))
if err != nil { if err != nil {
t.Errorf("Unexpected error: %v", err) t.Errorf("Unexpected error: %v", err)
} }
trie, _ = New(TrieID(root), triedb) trie, _ = New(TrieID(root), triedb)
err = trie.Delete([]byte("123456")) err = trie.Delete([]byte("123456"))
if err != nil { if err != nil {
@ -127,21 +132,25 @@ func testMissingNode(t *testing.T, memonly bool) {
if _, ok := err.(*MissingNodeError); !ok { if _, ok := err.(*MissingNodeError); !ok {
t.Errorf("Wrong error: %v", err) t.Errorf("Wrong error: %v", err)
} }
trie, _ = New(TrieID(root), triedb) trie, _ = New(TrieID(root), triedb)
_, err = trie.Get([]byte("120099")) _, err = trie.Get([]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(TrieID(root), triedb) trie, _ = New(TrieID(root), triedb)
_, err = trie.Get([]byte("123456")) _, err = trie.Get([]byte("123456"))
if err != nil { if err != nil {
t.Errorf("Unexpected error: %v", err) t.Errorf("Unexpected error: %v", err)
} }
trie, _ = New(TrieID(root), triedb) trie, _ = New(TrieID(root), triedb)
err = trie.Update([]byte("120099"), []byte("zxcv")) err = trie.Update([]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(TrieID(root), triedb) trie, _ = New(TrieID(root), triedb)
err = trie.Delete([]byte("123456")) err = trie.Delete([]byte("123456"))
if _, ok := err.(*MissingNodeError); !ok { if _, ok := err.(*MissingNodeError); !ok {
@ -191,6 +200,7 @@ func TestGet(t *testing.T) {
if i == 1 { if i == 1 {
return return
} }
root, nodes := trie.Commit(false) root, nodes := trie.Commit(false)
db.Update(NewWithNodeSet(nodes)) db.Update(NewWithNodeSet(nodes))
trie, _ = New(TrieID(root), db) trie, _ = New(TrieID(root), db)
@ -263,6 +273,7 @@ func TestReplication(t *testing.T) {
for _, val := range vals { for _, val := range vals {
updateString(trie, val.k, val.v) updateString(trie, val.k, val.v)
} }
exp, nodes := trie.Commit(false) exp, nodes := trie.Commit(false)
triedb.Update(NewWithNodeSet(nodes)) triedb.Update(NewWithNodeSet(nodes))
@ -276,6 +287,7 @@ func TestReplication(t *testing.T) {
t.Errorf("trie2 doesn't have %q => %q", kv.k, kv.v) t.Errorf("trie2 doesn't have %q => %q", kv.k, kv.v)
} }
} }
hash, nodes := trie2.Commit(false) hash, nodes := trie2.Commit(false)
if hash != exp { if hash != exp {
t.Errorf("root failure. expected %x got %x", exp, hash) t.Errorf("root failure. expected %x got %x", exp, hash)
@ -285,7 +297,9 @@ func TestReplication(t *testing.T) {
if nodes != nil { if nodes != nil {
triedb.Update(NewWithNodeSet(nodes)) triedb.Update(NewWithNodeSet(nodes))
} }
trie2, err = New(TrieID(hash), triedb) trie2, err = New(TrieID(hash), triedb)
if err != nil { if err != nil {
t.Fatalf("can't recreate trie at %x: %v", exp, err) t.Fatalf("can't recreate trie at %x: %v", exp, err)
} }
@ -411,7 +425,9 @@ func verifyAccessList(oldTrie *Trie, newTrie *Trie, set *NodeSet) error {
if !ok || n.isDeleted() { if !ok || n.isDeleted() {
return errors.New("expect new node") return errors.New("expect new node")
} }
_, ok = set.accessList[path] _, ok = set.accessList[path]
if ok { if ok {
return errors.New("unexpected origin value") return errors.New("unexpected origin value")
} }
@ -422,10 +438,13 @@ func verifyAccessList(oldTrie *Trie, newTrie *Trie, set *NodeSet) error {
if !ok || !n.isDeleted() { if !ok || !n.isDeleted() {
return errors.New("expect deleted node") return errors.New("expect deleted node")
} }
v, ok := set.accessList[path] v, ok := set.accessList[path]
if !ok { if !ok {
return errors.New("expect origin value") return errors.New("expect origin value")
} }
if !bytes.Equal(v, blob) { if !bytes.Equal(v, blob) {
return errors.New("invalid origin value") return errors.New("invalid origin value")
} }
@ -436,14 +455,18 @@ func verifyAccessList(oldTrie *Trie, newTrie *Trie, set *NodeSet) error {
if !ok || n.isDeleted() { if !ok || n.isDeleted() {
return errors.New("expect updated node") return errors.New("expect updated node")
} }
v, ok := set.accessList[path] v, ok := set.accessList[path]
if !ok { if !ok {
return errors.New("expect origin value") return errors.New("expect origin value")
} }
if !bytes.Equal(v, blob) { if !bytes.Equal(v, blob) {
return errors.New("invalid origin value") return errors.New("invalid origin value")
} }
} }
return nil return nil
} }
@ -476,12 +499,16 @@ func runRandTest(rt randTest) bool {
if hash == types.EmptyRootHash { if hash == types.EmptyRootHash {
continue continue
} }
proofDb := rawdb.NewMemoryDatabase() proofDb := rawdb.NewMemoryDatabase()
err := tr.Prove(step.key, 0, proofDb) err := tr.Prove(step.key, 0, proofDb)
if err != nil { if err != nil {
rt[i].err = fmt.Errorf("failed for proving key %#x, %v", step.key, err) rt[i].err = fmt.Errorf("failed for proving key %#x, %v", step.key, err)
} }
_, err = VerifyProof(hash, step.key, proofDb) _, err = VerifyProof(hash, step.key, proofDb)
if err != nil { if err != nil {
rt[i].err = fmt.Errorf("failed for verifying key %#x, %v", step.key, err) rt[i].err = fmt.Errorf("failed for verifying key %#x, %v", step.key, err)
} }
@ -492,11 +519,13 @@ func runRandTest(rt randTest) bool {
if nodes != nil { if nodes != nil {
triedb.Update(NewWithNodeSet(nodes)) triedb.Update(NewWithNodeSet(nodes))
} }
newtr, err := New(TrieID(root), triedb) newtr, err := New(TrieID(root), triedb)
if err != nil { if err != nil {
rt[i].err = err rt[i].err = err
return false return false
} }
if nodes != nil { if nodes != nil {
if err := verifyAccessList(origTrie, newtr, nodes); err != nil { if err := verifyAccessList(origTrie, newtr, nodes); err != nil {
rt[i].err = err rt[i].err = err
@ -521,45 +550,56 @@ func runRandTest(rt randTest) bool {
origSeen = make(map[string]struct{}) origSeen = make(map[string]struct{})
curSeen = make(map[string]struct{}) curSeen = make(map[string]struct{})
) )
for origIter.Next(true) { for origIter.Next(true) {
if origIter.Leaf() { if origIter.Leaf() {
continue continue
} }
origSeen[string(origIter.Path())] = struct{}{} origSeen[string(origIter.Path())] = struct{}{}
} }
for curIter.Next(true) { for curIter.Next(true) {
if curIter.Leaf() { if curIter.Leaf() {
continue continue
} }
curSeen[string(curIter.Path())] = struct{}{} curSeen[string(curIter.Path())] = struct{}{}
} }
var ( var (
insertExp = make(map[string]struct{}) insertExp = make(map[string]struct{})
deleteExp = make(map[string]struct{}) deleteExp = make(map[string]struct{})
) )
for path := range curSeen { for path := range curSeen {
_, present := origSeen[path] _, present := origSeen[path]
if !present { if !present {
insertExp[path] = struct{}{} insertExp[path] = struct{}{}
} }
} }
for path := range origSeen { for path := range origSeen {
_, present := curSeen[path] _, present := curSeen[path]
if !present { if !present {
deleteExp[path] = struct{}{} deleteExp[path] = struct{}{}
} }
} }
if len(insertExp) != len(tr.tracer.inserts) { if len(insertExp) != len(tr.tracer.inserts) {
rt[i].err = fmt.Errorf("insert set mismatch") rt[i].err = fmt.Errorf("insert set mismatch")
} }
if len(deleteExp) != len(tr.tracer.deletes) { if len(deleteExp) != len(tr.tracer.deletes) {
rt[i].err = fmt.Errorf("delete set mismatch") rt[i].err = fmt.Errorf("delete set mismatch")
} }
for insert := range tr.tracer.inserts { for insert := range tr.tracer.inserts {
if _, present := insertExp[insert]; !present { if _, present := insertExp[insert]; !present {
rt[i].err = fmt.Errorf("missing inserted node") rt[i].err = fmt.Errorf("missing inserted node")
} }
} }
for del := range tr.tracer.deletes { for del := range tr.tracer.deletes {
if _, present := deleteExp[del]; !present { if _, present := deleteExp[del]; !present {
rt[i].err = fmt.Errorf("missing deleted node") rt[i].err = fmt.Errorf("missing deleted node")
@ -691,19 +731,24 @@ func TestTinyTrie(t *testing.T) {
if exp, root := common.HexToHash("8c6a85a4d9fda98feff88450299e574e5378e32391f75a055d470ac0653f1005"), trie.Hash(); exp != root { if exp, root := common.HexToHash("8c6a85a4d9fda98feff88450299e574e5378e32391f75a055d470ac0653f1005"), trie.Hash(); exp != root {
t.Errorf("1: got %x, exp %x", root, exp) t.Errorf("1: got %x, exp %x", root, exp)
} }
trie.MustUpdate(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000001338"), accounts[4]) trie.MustUpdate(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000001338"), accounts[4])
if exp, root := common.HexToHash("ec63b967e98a5720e7f720482151963982890d82c9093c0d486b7eb8883a66b1"), trie.Hash(); exp != root { if exp, root := common.HexToHash("ec63b967e98a5720e7f720482151963982890d82c9093c0d486b7eb8883a66b1"), trie.Hash(); exp != root {
t.Errorf("2: got %x, exp %x", root, exp) t.Errorf("2: got %x, exp %x", root, exp)
} }
trie.MustUpdate(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000001339"), accounts[4]) trie.MustUpdate(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000001339"), accounts[4])
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 := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) checktr := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase()))
it := NewIterator(trie.NodeIterator(nil)) it := NewIterator(trie.NodeIterator(nil))
for it.Next() { for it.Next() {
checktr.MustUpdate(it.Key, it.Value) checktr.MustUpdate(it.Key, it.Value)
} }
if troot, itroot := trie.Hash(), checktr.Hash(); troot != itroot { if troot, itroot := trie.Hash(), checktr.Hash(); troot != itroot {
t.Fatalf("hash mismatch in opItercheckhash, trie: %x, check: %x", troot, itroot) t.Fatalf("hash mismatch in opItercheckhash, trie: %x, check: %x", troot, itroot)
} }
@ -721,10 +766,13 @@ func TestCommitAfterHash(t *testing.T) {
trie.Commit(false) trie.Commit(false)
root := trie.Hash() root := trie.Hash()
exp := common.HexToHash("72f9d3f3fe1e1dd7b8936442e7642aef76371472d94319900790053c493f3fe6") exp := common.HexToHash("72f9d3f3fe1e1dd7b8936442e7642aef76371472d94319900790053c493f3fe6")
if exp != root { if exp != root {
t.Errorf("got %x, exp %x", root, exp) t.Errorf("got %x, exp %x", root, exp)
} }
root, _ = trie.Commit(false) root, _ = trie.Commit(false)
if exp != root { if exp != root {
t.Errorf("got %x, exp %x", root, exp) t.Errorf("got %x, exp %x", root, exp)
} }
@ -1019,7 +1067,9 @@ func BenchmarkHashFixedSize(b *testing.B) {
func benchmarkHashFixedSize(b *testing.B, addresses [][20]byte, accounts [][]byte) { func benchmarkHashFixedSize(b *testing.B, addresses [][20]byte, accounts [][]byte) {
b.ReportAllocs() b.ReportAllocs()
trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase()))
for i := 0; i < len(addresses); i++ { for i := 0; i < len(addresses); i++ {
trie.MustUpdate(crypto.Keccak256(addresses[i][:]), accounts[i]) trie.MustUpdate(crypto.Keccak256(addresses[i][:]), accounts[i])
} }
@ -1070,7 +1120,9 @@ func BenchmarkCommitAfterHashFixedSize(b *testing.B) {
func benchmarkCommitAfterHashFixedSize(b *testing.B, addresses [][20]byte, accounts [][]byte) { func benchmarkCommitAfterHashFixedSize(b *testing.B, addresses [][20]byte, accounts [][]byte) {
b.ReportAllocs() b.ReportAllocs()
trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase()))
for i := 0; i < len(addresses); i++ { for i := 0; i < len(addresses); i++ {
trie.MustUpdate(crypto.Keccak256(addresses[i][:]), accounts[i]) trie.MustUpdate(crypto.Keccak256(addresses[i][:]), accounts[i])
} }
@ -1122,8 +1174,10 @@ func BenchmarkDerefRootFixedSize(b *testing.B) {
func benchmarkDerefRootFixedSize(b *testing.B, addresses [][20]byte, accounts [][]byte) { func benchmarkDerefRootFixedSize(b *testing.B, addresses [][20]byte, accounts [][]byte) {
b.ReportAllocs() b.ReportAllocs()
triedb := NewDatabase(rawdb.NewMemoryDatabase()) triedb := NewDatabase(rawdb.NewMemoryDatabase())
trie := NewEmpty(triedb) trie := NewEmpty(triedb)
for i := 0; i < len(addresses); i++ { for i := 0; i < len(addresses); i++ {
trie.MustUpdate(crypto.Keccak256(addresses[i][:]), accounts[i]) trie.MustUpdate(crypto.Keccak256(addresses[i][:]), accounts[i])
} }