mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-27 07:06:42 +00:00
dev: fix: more wsl lint issues
This commit is contained in:
parent
131d7b221f
commit
6223765aab
37 changed files with 407 additions and 1 deletions
|
|
@ -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))
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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())
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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())
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
24
trie/sync.go
24
trie/sync.go
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
14
trie/trie.go
14
trie/trie.go
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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])
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue