mirror of
https://github.com/status-im/nim-eth.git
synced 2025-01-12 15:24:21 +00:00
2c236f6495
Currently only setting `--styleCheck:hint` as there are some dependency fixes required and the compiler seems to trip over the findnode MessageKind, findnode Message field and the findNode proc. Also over protocol.Protocol usage.
169 lines
5.1 KiB
Nim
169 lines
5.1 KiB
Nim
import
|
|
"."/[trie_defs, binary, binaries, db, trie_utils, trie_bitseq]
|
|
|
|
type
|
|
DB = TrieDatabaseRef
|
|
|
|
# TODO: replace the usages of this with regular asserts
|
|
InvalidKeyError* = object of Defect
|
|
|
|
template query(db: DB, nodeHash: TrieNodeKey): seq[byte] =
|
|
db.get(nodeHash)
|
|
|
|
proc checkIfBranchExistImpl(db: DB; nodeHash: TrieNodeKey; keyPrefix: TrieBitSeq): bool =
|
|
if nodeHash == zeroHash:
|
|
return false
|
|
|
|
let node = parseNode(db.query(nodeHash))
|
|
|
|
case node.kind:
|
|
of LEAF_TYPE:
|
|
if keyPrefix.len != 0: return false
|
|
return true
|
|
of KV_TYPE:
|
|
if keyPrefix.len == 0: return true
|
|
if keyPrefix.len < node.keyPath.len:
|
|
if keyPrefix == node.keyPath[0..<keyPrefix.len]: return true
|
|
return false
|
|
else:
|
|
if keyPrefix[0..<node.keyPath.len] == node.keyPath:
|
|
return checkIfBranchExistImpl(db, node.child, keyPrefix.sliceToEnd(node.keyPath.len))
|
|
return false
|
|
of BRANCH_TYPE:
|
|
if keyPrefix.len == 0: return true
|
|
if keyPrefix[0] == false:
|
|
return checkIfBranchExistImpl(db, node.leftChild, keyPrefix.sliceToEnd(1))
|
|
else:
|
|
return checkIfBranchExistImpl(db, node.rightChild, keyPrefix.sliceToEnd(1))
|
|
|
|
proc checkIfBranchExist*(db: DB; rootHash: TrieNodeKey, keyPrefix: openArray[byte]): bool =
|
|
## Given a key prefix, return whether this prefix is
|
|
## the prefix of an existing key in the trie.
|
|
checkValidHashZ(rootHash)
|
|
var keyPrefixBits = bits keyPrefix
|
|
checkIfBranchExistImpl(db, rootHash, keyPrefixBits)
|
|
|
|
proc getBranchImpl(db: DB; nodeHash: TrieNodeKey, keyPath: TrieBitSeq, output: var seq[seq[byte]]) =
|
|
if nodeHash == zeroHash: return
|
|
|
|
let nodeVal = db.query(nodeHash)
|
|
let node = parseNode(nodeVal)
|
|
|
|
case node.kind
|
|
of LEAF_TYPE:
|
|
if keyPath.len == 0:
|
|
output.add nodeVal
|
|
else:
|
|
raise newException(InvalidKeyError, "Key too long")
|
|
|
|
of KV_TYPE:
|
|
if keyPath.len == 0:
|
|
raise newException(InvalidKeyError, "Key too short")
|
|
|
|
output.add nodeVal
|
|
let sliceLen = min(keyPath.len, node.keyPath.len)
|
|
if keyPath[0..<sliceLen] == node.keyPath:
|
|
getBranchImpl(db, node.child, keyPath.sliceToEnd(sliceLen), output)
|
|
|
|
of BRANCH_TYPE:
|
|
if keyPath.len == 0:
|
|
raise newException(InvalidKeyError, "Key too short")
|
|
|
|
output.add nodeVal
|
|
if keyPath[0] == false:
|
|
getBranchImpl(db, node.leftChild, keyPath.sliceToEnd(1), output)
|
|
else:
|
|
getBranchImpl(db, node.rightChild, keyPath.sliceToEnd(1), output)
|
|
|
|
proc getBranch*(db: DB; rootHash: seq[byte]; key: openArray[byte]): seq[seq[byte]] =
|
|
## Get a long-format Merkle branch
|
|
checkValidHashZ(rootHash)
|
|
result = @[]
|
|
var keyBits = bits key
|
|
getBranchImpl(db, rootHash, keyBits, result)
|
|
|
|
proc isValidBranch*(branch: seq[seq[byte]], rootHash: seq[byte], key, value: openArray[byte]): bool =
|
|
checkValidHashZ(rootHash)
|
|
# branch must not be empty
|
|
doAssert(branch.len != 0)
|
|
|
|
var db = newMemoryDB()
|
|
for node in branch:
|
|
doAssert(node.len != 0)
|
|
let nodeHash = keccakHash(node)
|
|
db.put(nodeHash.data, node)
|
|
|
|
var trie = initBinaryTrie(db, rootHash)
|
|
result = trie.get(key) == value
|
|
|
|
proc getTrieNodesImpl(db: DB; nodeHash: TrieNodeKey, output: var seq[seq[byte]]): bool =
|
|
## Get full trie of a given root node
|
|
|
|
if nodeHash.isZeroHash(): return false
|
|
|
|
var nodeVal: seq[byte]
|
|
if nodeHash in db:
|
|
nodeVal = db.query(nodeHash)
|
|
else:
|
|
return false
|
|
|
|
let node = parseNode(nodeVal)
|
|
|
|
case node.kind
|
|
of KV_TYPE:
|
|
output.add nodeVal
|
|
result = getTrieNodesImpl(db, node.child, output)
|
|
of BRANCH_TYPE:
|
|
output.add nodeVal
|
|
result = getTrieNodesImpl(db, node.leftChild, output)
|
|
result = getTrieNodesImpl(db, node.rightChild, output)
|
|
of LEAF_TYPE:
|
|
output.add nodeVal
|
|
|
|
proc getTrieNodes*(db: DB; nodeHash: TrieNodeKey): seq[seq[byte]] =
|
|
checkValidHashZ(nodeHash)
|
|
result = @[]
|
|
discard getTrieNodesImpl(db, nodeHash, result)
|
|
|
|
proc getWitnessImpl*(db: DB; nodeHash: TrieNodeKey; keyPath: TrieBitSeq; output: var seq[seq[byte]]) =
|
|
if keyPath.len == 0:
|
|
if not getTrieNodesImpl(db, nodeHash, output): return
|
|
|
|
if nodeHash.isZeroHash(): return
|
|
|
|
var nodeVal: seq[byte]
|
|
if nodeHash in db:
|
|
nodeVal = db.query(nodeHash)
|
|
else:
|
|
return
|
|
|
|
let node = parseNode(nodeVal)
|
|
|
|
case node.kind
|
|
of LEAF_TYPE:
|
|
if keyPath.len != 0:
|
|
raise newException(InvalidKeyError, "Key too long")
|
|
of KV_TYPE:
|
|
output.add nodeVal
|
|
if keyPath.len < node.keyPath.len and node.keyPath[0..<keyPath.len] == keyPath:
|
|
if not getTrieNodesImpl(db, node.child, output): return
|
|
elif keyPath[0..<node.keyPath.len] == node.keyPath:
|
|
getWitnessImpl(db, node.child, keyPath.sliceToEnd(node.keyPath.len), output)
|
|
of BRANCH_TYPE:
|
|
output.add nodeVal
|
|
if keyPath[0] == false:
|
|
getWitnessImpl(db, node.leftChild, keyPath.sliceToEnd(1), output)
|
|
else:
|
|
getWitnessImpl(db, node.rightChild, keyPath.sliceToEnd(1), output)
|
|
|
|
proc getWitness*(db: DB; nodeHash: TrieNodeKey; key: openArray[byte]): seq[seq[byte]] =
|
|
## Get all witness given a keyPath prefix.
|
|
## Include
|
|
##
|
|
## 1. witness along the keyPath and
|
|
## 2. witness in the subtrie of the last node in keyPath
|
|
checkValidHashZ(nodeHash)
|
|
result = @[]
|
|
var keyBits = bits key
|
|
getWitnessImpl(db, nodeHash, keyBits, result)
|