mirror of https://github.com/status-im/nim-eth.git
Added maybeGet, for working with incomplete DBs. (#595)
This commit is contained in:
parent
9e89f0dccc
commit
4754543605
|
@ -1,7 +1,7 @@
|
||||||
{.push raises: [Defect].}
|
{.push raises: [Defect].}
|
||||||
|
|
||||||
import
|
import
|
||||||
std/[tables, hashes, sets],
|
std/[options, tables, hashes, sets],
|
||||||
"."/[trie_defs, db_tracing]
|
"."/[trie_defs, db_tracing]
|
||||||
|
|
||||||
type
|
type
|
||||||
|
@ -234,6 +234,15 @@ proc contains*(db: TrieDatabaseRef, key: openArray[byte]): bool =
|
||||||
if db.containsProc != nil:
|
if db.containsProc != nil:
|
||||||
result = db.containsProc(db.obj, key)
|
result = db.containsProc(db.obj, key)
|
||||||
|
|
||||||
|
proc maybeGet*(db: TrieDatabaseRef, key: openArray[byte]): Option[seq[byte]] =
|
||||||
|
# FIXME-Adam: Could duplicate the structure of get, but for now let's just
|
||||||
|
# do this (I still don't know whether this overall approach makes any sense
|
||||||
|
# at all.)
|
||||||
|
if db.contains(key):
|
||||||
|
some(db.get(key))
|
||||||
|
else:
|
||||||
|
none[seq[byte]]()
|
||||||
|
|
||||||
# TransactionID imitate subset of JournalDB behaviour
|
# TransactionID imitate subset of JournalDB behaviour
|
||||||
# but there is no need to rollback or dispose
|
# but there is no need to rollback or dispose
|
||||||
# TransactionID, because it will be handled elsewhere
|
# TransactionID, because it will be handled elsewhere
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import
|
import
|
||||||
std/tables,
|
std/[options, tables],
|
||||||
nimcrypto/[keccak, hash],
|
nimcrypto/[keccak, hash],
|
||||||
../rlp,
|
../rlp,
|
||||||
"."/[trie_defs, nibbles, db]
|
"."/[trie_defs, nibbles, db]
|
||||||
|
@ -688,3 +688,102 @@ proc isValidBranch*(branch: seq[seq[byte]], rootHash: KeccakHash, key, value: se
|
||||||
|
|
||||||
var trie = initHexaryTrie(db, rootHash)
|
var trie = initHexaryTrie(db, rootHash)
|
||||||
result = trie.get(key) == value
|
result = trie.get(key) == value
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# The code below has a lot of duplication with the code above; I needed
|
||||||
|
# versions of get/put/del that don't just assume that all the nodes exist.
|
||||||
|
# Maybe there's some way to eliminate the duplication without screwing
|
||||||
|
# up performance? But for now I don't want to meddle with the existing
|
||||||
|
# code, for fear of breaking it. --Adam, Nov. 2022
|
||||||
|
|
||||||
|
proc db*(self: SecureHexaryTrie): TrieDatabaseRef = HexaryTrie(self).db
|
||||||
|
|
||||||
|
template maybeKeyToLocalBytes(db: DB, k: TrieNodeKey): Option[seq[byte]] =
|
||||||
|
if k.len < 32:
|
||||||
|
some(k.getLocalBytes)
|
||||||
|
else:
|
||||||
|
db.maybeGet(k.asDbKey)
|
||||||
|
|
||||||
|
proc maybeGetAux(db: DB, nodeRlp: Rlp, path: NibblesSeq): Option[seq[byte]]
|
||||||
|
{.gcsafe, raises: [RlpError, Defect].}
|
||||||
|
|
||||||
|
proc maybeGetAuxByHash(db: DB, node: TrieNodeKey, path: NibblesSeq): Option[seq[byte]] =
|
||||||
|
let maybeBytes = maybeKeyToLocalBytes(db, node)
|
||||||
|
if maybeBytes.isNone:
|
||||||
|
return none[seq[byte]]()
|
||||||
|
else:
|
||||||
|
let bytes = maybeBytes.get
|
||||||
|
var nodeRlp = rlpFromBytes(bytes)
|
||||||
|
return maybeGetAux(db, nodeRlp, path)
|
||||||
|
|
||||||
|
proc maybeGetLookup(db: DB, elem: Rlp): Option[Rlp] =
|
||||||
|
if elem.isList:
|
||||||
|
some(elem)
|
||||||
|
else:
|
||||||
|
let h = elem.expectHash
|
||||||
|
let maybeBytes = db.maybeGet(h)
|
||||||
|
if maybeBytes.isNone:
|
||||||
|
none[Rlp]()
|
||||||
|
else:
|
||||||
|
let bytes = maybeBytes.get
|
||||||
|
some(rlpFromBytes(bytes))
|
||||||
|
|
||||||
|
proc maybeGetAux(db: DB, nodeRlp: Rlp, path: NibblesSeq): Option[seq[byte]]
|
||||||
|
{.gcsafe, raises: [RlpError, Defect].} =
|
||||||
|
# FIXME-Adam: do I need to distinguish between these two cases?
|
||||||
|
if not nodeRlp.hasData:
|
||||||
|
let zero: seq[byte] = @[]
|
||||||
|
return some(zero)
|
||||||
|
# return none[seq[byte]]()
|
||||||
|
if nodeRlp.isEmpty:
|
||||||
|
# FIXME-Adam: I am REALLY not sure this is the right thing to do. But toGenesisHeader
|
||||||
|
# failing is a pretty clear indication. So let's try this. I wonder whether the
|
||||||
|
# above case needs to do this too.
|
||||||
|
let zero: seq[byte] = @[]
|
||||||
|
return some(zero)
|
||||||
|
# return none[seq[byte]]()
|
||||||
|
|
||||||
|
case nodeRlp.listLen
|
||||||
|
of 2:
|
||||||
|
let (isLeaf, k) = nodeRlp.extensionNodeKey
|
||||||
|
let sharedNibbles = sharedPrefixLen(path, k)
|
||||||
|
|
||||||
|
if sharedNibbles == k.len:
|
||||||
|
let value = nodeRlp.listElem(1)
|
||||||
|
if sharedNibbles == path.len and isLeaf:
|
||||||
|
return some(value.toBytes)
|
||||||
|
elif not isLeaf:
|
||||||
|
let maybeNextLookup = maybeGetLookup(db, value)
|
||||||
|
if maybeNextLookup.isNone:
|
||||||
|
return none[seq[byte]]()
|
||||||
|
else:
|
||||||
|
return maybeGetAux(db, maybeNextLookup.get, path.slice(sharedNibbles))
|
||||||
|
else:
|
||||||
|
raise newException(RlpError, "isLeaf is true but the shared nibbles didn't exhaust the path?")
|
||||||
|
else:
|
||||||
|
let zero: seq[byte] = @[]
|
||||||
|
return some(zero)
|
||||||
|
of 17:
|
||||||
|
if path.len == 0:
|
||||||
|
return some(nodeRlp.listElem(16).toBytes)
|
||||||
|
var branch = nodeRlp.listElem(path[0].int)
|
||||||
|
if branch.isEmpty:
|
||||||
|
let zero: seq[byte] = @[]
|
||||||
|
return some(zero)
|
||||||
|
else:
|
||||||
|
let maybeNextLookup = maybeGetLookup(db, branch)
|
||||||
|
if maybeNextLookup.isNone:
|
||||||
|
return none[seq[byte]]()
|
||||||
|
else:
|
||||||
|
return maybeGetAux(db, maybeNextLookup.get, path.slice(1))
|
||||||
|
else:
|
||||||
|
raise newException(CorruptedTrieDatabase,
|
||||||
|
"HexaryTrie node with an unexpected number of children")
|
||||||
|
|
||||||
|
proc maybeGet*(self: HexaryTrie; key: openArray[byte]): Option[seq[byte]] =
|
||||||
|
return maybeGetAuxByHash(self.db, self.root, initNibbleRange(key))
|
||||||
|
|
||||||
|
proc maybeGet*(self: SecureHexaryTrie; key: openArray[byte]): Option[seq[byte]] =
|
||||||
|
return maybeGet(HexaryTrie(self), key.keccakHash.data)
|
||||||
|
|
Loading…
Reference in New Issue