mirror of https://github.com/status-im/nim-eth.git
implement hexary trie replicate iterator
This commit is contained in:
parent
038250b259
commit
e0e49b1711
|
@ -270,6 +270,50 @@ iterator pairs*(self: HexaryTrie): (BytesRange, BytesRange) =
|
||||||
let res = getPairsAux(self.db, stack)
|
let res = getPairsAux(self.db, stack)
|
||||||
yield res
|
yield res
|
||||||
|
|
||||||
|
iterator replicate*(self: HexaryTrie): (BytesRange, BytesRange) =
|
||||||
|
# this iterator helps 'rebuild' the entire trie without
|
||||||
|
# going through a trie algorithm, but it will pull the entire
|
||||||
|
# low level KV pairs. Thus the target db will only use put operations
|
||||||
|
# without del or contains, can speed up huge trie replication.
|
||||||
|
var
|
||||||
|
localBytes = keyToLocalBytes(self.db, self.root)
|
||||||
|
nodeRlp = rlpFromBytes localBytes
|
||||||
|
path = newRange[byte](0)
|
||||||
|
stack = @[(nodeRlp, initNibbleRange(path))]
|
||||||
|
|
||||||
|
template pushOrYield(elem: untyped) =
|
||||||
|
if elem.isList:
|
||||||
|
stack.add((elem, key))
|
||||||
|
else:
|
||||||
|
let rlpBytes = get(self.db, toOpenArray(elem.expectHash)).toRange
|
||||||
|
let nextLookup = rlpFromBytes(rlpBytes)
|
||||||
|
stack.add((nextLookup, key))
|
||||||
|
yield (elem.toBytes, rlpBytes)
|
||||||
|
|
||||||
|
yield (self.rootHash.toRange, localBytes)
|
||||||
|
while stack.len > 0:
|
||||||
|
let (nodeRlp, path) = stack.pop()
|
||||||
|
if not nodeRlp.hasData or nodeRlp.isEmpty:
|
||||||
|
continue
|
||||||
|
|
||||||
|
case nodeRlp.listLen
|
||||||
|
of 2:
|
||||||
|
let
|
||||||
|
(isLeaf, k) = nodeRlp.extensionNodeKey
|
||||||
|
key = path & k
|
||||||
|
value = nodeRlp.listElem(1)
|
||||||
|
if not isLeaf: pushOrYield(value)
|
||||||
|
of 17:
|
||||||
|
for i in 0 ..< 16:
|
||||||
|
var branch = nodeRlp.listElem(i)
|
||||||
|
if not branch.isEmpty:
|
||||||
|
var key = path.cloneAndReserveNibble()
|
||||||
|
key.replaceLastNibble(i.byte)
|
||||||
|
pushOrYield(branch)
|
||||||
|
else:
|
||||||
|
raise newException(CorruptedTrieError,
|
||||||
|
"HexaryTrie node with an unexpected number of children")
|
||||||
|
|
||||||
proc getValues*(self: HexaryTrie): seq[BytesRange] =
|
proc getValues*(self: HexaryTrie): seq[BytesRange] =
|
||||||
result = @[]
|
result = @[]
|
||||||
for v in self.values:
|
for v in self.values:
|
||||||
|
|
|
@ -413,3 +413,31 @@ suite "hexary trie":
|
||||||
for x in 0 ..< numKeyVal:
|
for x in 0 ..< numKeyVal:
|
||||||
var branch = trie2.getBranch(keys[x])
|
var branch = trie2.getBranch(keys[x])
|
||||||
check isValidBranch(branch, trie2.rootHash, keys[x], newVals[x])
|
check isValidBranch(branch, trie2.rootHash, keys[x], newVals[x])
|
||||||
|
|
||||||
|
test "replicate iterator":
|
||||||
|
const
|
||||||
|
numKeyVal = 30
|
||||||
|
|
||||||
|
var
|
||||||
|
memdb = newMemoryDB()
|
||||||
|
repdb = newMemoryDB()
|
||||||
|
pruningTrie = initHexaryTrie(memdb, isPruning = true)
|
||||||
|
|
||||||
|
let
|
||||||
|
keys = randList(BytesRange, randGen(5, 77), randGen(numKeyVal))
|
||||||
|
vals = randList(BytesRange, randGen(1, 57), randGen(numKeyVal))
|
||||||
|
|
||||||
|
for i in 0 ..< numKeyVal:
|
||||||
|
pruningTrie.put(keys[i], vals[i])
|
||||||
|
|
||||||
|
let rootHash = pruningTrie.rootHash
|
||||||
|
for k, v in pruningTrie.replicate:
|
||||||
|
repdb.put(k.toOpenArray, v.toOpenArray)
|
||||||
|
|
||||||
|
var trie = initHexaryTrie(repdb, rootHash, isPruning = true)
|
||||||
|
var numPairs = 0
|
||||||
|
for k, v in trie.pairs:
|
||||||
|
check k in keys
|
||||||
|
check v in vals
|
||||||
|
inc numPairs
|
||||||
|
check numPairs == numKeyVal
|
||||||
|
|
Loading…
Reference in New Issue