mirror of
https://github.com/status-im/nimbus-eth1.git
synced 2025-01-12 13:24:21 +00:00
Add push raises to Fluffy state network code. (#2352)
* Add push raises to Fluffy state network code. * Refactor handling of rlp errors.
This commit is contained in:
parent
329a8f05bb
commit
7fd777cfa9
@ -5,6 +5,8 @@
|
||||
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
{.push raises: [].}
|
||||
|
||||
import ./content/content_keys, ./content/content_values, ./content/nibbles
|
||||
|
||||
export content_keys, content_values, nibbles
|
||||
|
@ -5,6 +5,8 @@
|
||||
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
{.push raises: [].}
|
||||
|
||||
import
|
||||
results,
|
||||
chronos,
|
||||
@ -23,46 +25,51 @@ logScope:
|
||||
proc getNextNodeHash(
|
||||
trieNode: TrieNode, nibbles: UnpackedNibbles, nibbleIdx: var int
|
||||
): Opt[(Nibbles, NodeHash)] =
|
||||
doAssert(nibbles.len() > 0)
|
||||
doAssert(nibbleIdx < nibbles.len())
|
||||
# the trie node should have already been validated against the lookup hash
|
||||
# so we expect that no rlp errors should be possible
|
||||
try:
|
||||
doAssert(nibbles.len() > 0)
|
||||
doAssert(nibbleIdx < nibbles.len())
|
||||
|
||||
let trieNodeRlp = rlpFromBytes(trieNode.asSeq())
|
||||
# the trie node should have already been validated
|
||||
doAssert(not trieNodeRlp.isEmpty())
|
||||
doAssert(trieNodeRlp.listLen() == 2 or trieNodeRlp.listLen() == 17)
|
||||
let trieNodeRlp = rlpFromBytes(trieNode.asSeq())
|
||||
|
||||
if trieNodeRlp.listLen() == 17:
|
||||
let nextNibble = nibbles[nibbleIdx]
|
||||
doAssert(nextNibble < 16)
|
||||
doAssert(not trieNodeRlp.isEmpty())
|
||||
doAssert(trieNodeRlp.listLen() == 2 or trieNodeRlp.listLen() == 17)
|
||||
|
||||
let nextHashBytes = trieNodeRlp.listElem(nextNibble.int)
|
||||
if trieNodeRlp.listLen() == 17:
|
||||
let nextNibble = nibbles[nibbleIdx]
|
||||
doAssert(nextNibble < 16)
|
||||
|
||||
let nextHashBytes = trieNodeRlp.listElem(nextNibble.int)
|
||||
doAssert(not nextHashBytes.isEmpty())
|
||||
|
||||
nibbleIdx += 1
|
||||
return Opt.some(
|
||||
(
|
||||
nibbles[0 ..< nibbleIdx].packNibbles(),
|
||||
KeccakHash.fromBytes(nextHashBytes.toBytes()),
|
||||
)
|
||||
)
|
||||
|
||||
# leaf or extension node
|
||||
let (_, isLeaf, prefix) = decodePrefix(trieNodeRlp.listElem(0))
|
||||
if isLeaf:
|
||||
return Opt.none((Nibbles, NodeHash))
|
||||
|
||||
# extension node
|
||||
nibbleIdx += prefix.unpackNibbles().len()
|
||||
|
||||
let nextHashBytes = trieNodeRlp.listElem(1)
|
||||
doAssert(not nextHashBytes.isEmpty())
|
||||
|
||||
nibbleIdx += 1
|
||||
return Opt.some(
|
||||
Opt.some(
|
||||
(
|
||||
nibbles[0 ..< nibbleIdx].packNibbles(),
|
||||
KeccakHash.fromBytes(nextHashBytes.toBytes()),
|
||||
)
|
||||
)
|
||||
|
||||
# leaf or extension node
|
||||
let (_, isLeaf, prefix) = decodePrefix(trieNodeRlp.listElem(0))
|
||||
if isLeaf:
|
||||
return Opt.none((Nibbles, NodeHash))
|
||||
|
||||
# extension node
|
||||
nibbleIdx += prefix.unpackNibbles().len()
|
||||
|
||||
let nextHashBytes = trieNodeRlp.listElem(1)
|
||||
doAssert(not nextHashBytes.isEmpty())
|
||||
|
||||
Opt.some(
|
||||
(
|
||||
nibbles[0 ..< nibbleIdx].packNibbles(),
|
||||
KeccakHash.fromBytes(nextHashBytes.toBytes()),
|
||||
)
|
||||
)
|
||||
except RlpError as e:
|
||||
raiseAssert(e.msg)
|
||||
|
||||
proc getAccountProof(
|
||||
n: StateNetwork, stateRoot: KeccakHash, address: Address
|
||||
|
@ -5,6 +5,8 @@
|
||||
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
{.push raises: [].}
|
||||
|
||||
import
|
||||
results,
|
||||
chronos,
|
||||
@ -41,26 +43,31 @@ func withKey*(
|
||||
(key: key, offer: offer)
|
||||
|
||||
func getParent(p: ProofWithPath): ProofWithPath =
|
||||
doAssert(p.path.len() > 0, "nibbles too short")
|
||||
doAssert(p.proof.len() > 1, "proof too short")
|
||||
# this function assumes that the proof contains valid rlp therefore
|
||||
# if required these proofs should be validated beforehand
|
||||
try:
|
||||
doAssert(p.path.len() > 0, "nibbles too short")
|
||||
doAssert(p.proof.len() > 1, "proof too short")
|
||||
|
||||
let
|
||||
parentProof = TrieProof.init(p.proof[0 ..^ 2])
|
||||
parentEndNode = rlpFromBytes(parentProof[^1].asSeq())
|
||||
let
|
||||
parentProof = TrieProof.init(p.proof[0 ..^ 2])
|
||||
parentEndNode = rlpFromBytes(parentProof[^1].asSeq())
|
||||
|
||||
# the trie proof should have already been validated when receiving the offer content
|
||||
doAssert(parentEndNode.listLen() == 2 or parentEndNode.listLen() == 17)
|
||||
# the trie proof should have already been validated when receiving the offer content
|
||||
doAssert(parentEndNode.listLen() == 2 or parentEndNode.listLen() == 17)
|
||||
|
||||
var unpackedNibbles = p.path.unpackNibbles()
|
||||
var unpackedNibbles = p.path.unpackNibbles()
|
||||
|
||||
if parentEndNode.listLen() == 17:
|
||||
# branch node so only need to remove a single nibble
|
||||
return parentProof.withPath(unpackedNibbles.dropN(1).packNibbles())
|
||||
if parentEndNode.listLen() == 17:
|
||||
# branch node so only need to remove a single nibble
|
||||
return parentProof.withPath(unpackedNibbles.dropN(1).packNibbles())
|
||||
|
||||
# leaf or extension node so we need to remove one or more nibbles
|
||||
let prefixNibbles = decodePrefix(parentEndNode.listElem(0))[2]
|
||||
# leaf or extension node so we need to remove one or more nibbles
|
||||
let (_, _, prefixNibbles) = decodePrefix(parentEndNode.listElem(0))
|
||||
|
||||
parentProof.withPath(unpackedNibbles.dropN(prefixNibbles.len()).packNibbles())
|
||||
parentProof.withPath(unpackedNibbles.dropN(prefixNibbles.len()).packNibbles())
|
||||
except RlpError as e:
|
||||
raiseAssert(e.msg)
|
||||
|
||||
func getParent*(offerWithKey: AccountTrieOfferWithKey): AccountTrieOfferWithKey =
|
||||
let
|
||||
|
@ -5,6 +5,8 @@
|
||||
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
{.push raises: [].}
|
||||
|
||||
import
|
||||
results,
|
||||
chronos,
|
||||
|
@ -5,11 +5,13 @@
|
||||
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
{.push raises: [].}
|
||||
|
||||
import results, eth/common, ./state_content
|
||||
|
||||
export results, common
|
||||
|
||||
func decodePrefix*(nodePrefixRlp: Rlp): (byte, bool, Nibbles) =
|
||||
func decodePrefix*(nodePrefixRlp: Rlp): (byte, bool, Nibbles) {.raises: RlpError.} =
|
||||
doAssert(not nodePrefixRlp.isEmpty())
|
||||
|
||||
let
|
||||
@ -23,36 +25,40 @@ func decodePrefix*(nodePrefixRlp: Rlp): (byte, bool, Nibbles) =
|
||||
(firstNibble.byte, isLeaf, nibbles)
|
||||
|
||||
func rlpDecodeAccountTrieNode*(accountTrieNode: TrieNode): Result[Account, string] =
|
||||
let accNodeRlp = rlpFromBytes(accountTrieNode.asSeq())
|
||||
if accNodeRlp.isEmpty() or accNodeRlp.listLen() != 2:
|
||||
return err("invalid account trie node - malformed")
|
||||
try:
|
||||
let accNodeRlp = rlpFromBytes(accountTrieNode.asSeq())
|
||||
if accNodeRlp.isEmpty() or accNodeRlp.listLen() != 2:
|
||||
return err("invalid account trie node - malformed")
|
||||
|
||||
let accNodePrefixRlp = accNodeRlp.listElem(0)
|
||||
if accNodePrefixRlp.isEmpty():
|
||||
return err("invalid account trie node - empty prefix")
|
||||
let accNodePrefixRlp = accNodeRlp.listElem(0)
|
||||
if accNodePrefixRlp.isEmpty():
|
||||
return err("invalid account trie node - empty prefix")
|
||||
|
||||
let (_, isLeaf, _) = decodePrefix(accNodePrefixRlp)
|
||||
if not isLeaf:
|
||||
return err("invalid account trie node - leaf prefix expected")
|
||||
let (_, isLeaf, _) = decodePrefix(accNodePrefixRlp)
|
||||
if not isLeaf:
|
||||
return err("invalid account trie node - leaf prefix expected")
|
||||
|
||||
decodeRlp(accNodeRlp.listElem(1).toBytes(), Account)
|
||||
|
||||
# TODO: test the below functions
|
||||
decodeRlp(accNodeRlp.listElem(1).toBytes(), Account)
|
||||
except RlpError as e:
|
||||
err(e.msg)
|
||||
|
||||
func rlpDecodeContractTrieNode*(contractTrieNode: TrieNode): Result[UInt256, string] =
|
||||
let storageNodeRlp = rlpFromBytes(contractTrieNode.asSeq())
|
||||
if storageNodeRlp.isEmpty() or storageNodeRlp.listLen() != 2:
|
||||
return err("invalid contract trie node - malformed")
|
||||
try:
|
||||
let storageNodeRlp = rlpFromBytes(contractTrieNode.asSeq())
|
||||
if storageNodeRlp.isEmpty() or storageNodeRlp.listLen() != 2:
|
||||
return err("invalid contract trie node - malformed")
|
||||
|
||||
let storageNodePrefixRlp = storageNodeRlp.listElem(0)
|
||||
if storageNodePrefixRlp.isEmpty():
|
||||
return err("invalid contract trie node - empty prefix")
|
||||
let storageNodePrefixRlp = storageNodeRlp.listElem(0)
|
||||
if storageNodePrefixRlp.isEmpty():
|
||||
return err("invalid contract trie node - empty prefix")
|
||||
|
||||
let (_, isLeaf, _) = decodePrefix(storageNodePrefixRlp)
|
||||
if not isLeaf:
|
||||
return err("invalid contract trie node - leaf prefix expected")
|
||||
let (_, isLeaf, _) = decodePrefix(storageNodePrefixRlp)
|
||||
if not isLeaf:
|
||||
return err("invalid contract trie node - leaf prefix expected")
|
||||
|
||||
decodeRlp(storageNodeRlp.listElem(1).toBytes(), UInt256)
|
||||
decodeRlp(storageNodeRlp.listElem(1).toBytes(), UInt256)
|
||||
except RlpError as e:
|
||||
err(e.msg)
|
||||
|
||||
func toAccount*(accountProof: TrieProof): Result[Account, string] {.inline.} =
|
||||
doAssert(accountProof.len() > 1)
|
||||
@ -67,8 +73,8 @@ func toSlot*(storageProof: TrieProof): Result[UInt256, string] {.inline.} =
|
||||
func toPath*(hash: KeccakHash): Nibbles {.inline.} =
|
||||
Nibbles.init(hash.data, isEven = true)
|
||||
|
||||
func toPath*(address: Address): Nibbles =
|
||||
func toPath*(address: Address): Nibbles {.inline.} =
|
||||
keccakHash(address).toPath()
|
||||
|
||||
func toPath*(slotKey: UInt256): Nibbles =
|
||||
func toPath*(slotKey: UInt256): Nibbles {.inline.} =
|
||||
keccakHash(toBytesBE(slotKey)).toPath()
|
||||
|
@ -5,6 +5,8 @@
|
||||
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
{.push raises: [].}
|
||||
|
||||
import results, eth/common, ../../common/common_utils, ./state_content, ./state_utils
|
||||
|
||||
export results, state_content
|
||||
@ -12,7 +14,9 @@ export results, state_content
|
||||
proc hashEquals(value: TrieNode | Bytecode, expectedHash: KeccakHash): bool {.inline.} =
|
||||
keccakHash(value.asSeq()) == expectedHash
|
||||
|
||||
proc isValidNextNode(thisNodeRlp: Rlp, rlpIdx: int, nextNode: TrieNode): bool =
|
||||
proc isValidNextNode(
|
||||
thisNodeRlp: Rlp, rlpIdx: int, nextNode: TrieNode
|
||||
): bool {.raises: RlpError.} =
|
||||
let hashOrShortRlp = thisNodeRlp.listElem(rlpIdx)
|
||||
if hashOrShortRlp.isEmpty():
|
||||
return false
|
||||
@ -63,45 +67,48 @@ proc validateTrieProof*(
|
||||
else:
|
||||
return err("proof has more nodes then expected for given path")
|
||||
|
||||
case thisNodeRlp.listLen()
|
||||
of 2:
|
||||
let nodePrefixRlp = thisNodeRlp.listElem(0)
|
||||
if nodePrefixRlp.isEmpty():
|
||||
return err("node prefix is empty")
|
||||
try:
|
||||
case thisNodeRlp.listLen()
|
||||
of 2:
|
||||
let nodePrefixRlp = thisNodeRlp.listElem(0)
|
||||
if nodePrefixRlp.isEmpty():
|
||||
return err("node prefix is empty")
|
||||
|
||||
let (prefix, isLeaf, prefixNibbles) = decodePrefix(nodePrefixRlp)
|
||||
if prefix >= 4:
|
||||
return err("invalid prefix in node")
|
||||
let (prefix, isLeaf, prefixNibbles) = decodePrefix(nodePrefixRlp)
|
||||
if prefix >= 4:
|
||||
return err("invalid prefix in node")
|
||||
|
||||
if not isLastNode or (isLeaf and allowKeyEndInPathForLeafs):
|
||||
let unpackedPrefix = prefixNibbles.unpackNibbles()
|
||||
if remainingNibbles < unpackedPrefix.len():
|
||||
return err("not enough nibbles to validate node prefix")
|
||||
if not isLastNode or (isLeaf and allowKeyEndInPathForLeafs):
|
||||
let unpackedPrefix = prefixNibbles.unpackNibbles()
|
||||
if remainingNibbles < unpackedPrefix.len():
|
||||
return err("not enough nibbles to validate node prefix")
|
||||
|
||||
let nibbleEndIdx = nibbleIdx + unpackedPrefix.len()
|
||||
if nibbles[nibbleIdx ..< nibbleEndIdx] != unpackedPrefix:
|
||||
return err("nibbles don't match node prefix")
|
||||
nibbleIdx += unpackedPrefix.len()
|
||||
let nibbleEndIdx = nibbleIdx + unpackedPrefix.len()
|
||||
if nibbles[nibbleIdx ..< nibbleEndIdx] != unpackedPrefix:
|
||||
return err("nibbles don't match node prefix")
|
||||
nibbleIdx += unpackedPrefix.len()
|
||||
|
||||
if not isLastNode:
|
||||
if isLeaf:
|
||||
return err("leaf node must be last node in the proof")
|
||||
else: # is extension node
|
||||
if not isValidNextNode(thisNodeRlp, 1, proof[proofIdx + 1]):
|
||||
return
|
||||
err("hash of next node doesn't match the expected extension node hash")
|
||||
of 17:
|
||||
if not isLastNode:
|
||||
let nextNibble = nibbles[nibbleIdx]
|
||||
if nextNibble >= 16:
|
||||
return err("invalid next nibble for branch node")
|
||||
if not isLastNode:
|
||||
if isLeaf:
|
||||
return err("leaf node must be last node in the proof")
|
||||
else: # is extension node
|
||||
if not isValidNextNode(thisNodeRlp, 1, proof[proofIdx + 1]):
|
||||
return
|
||||
err("hash of next node doesn't match the expected extension node hash")
|
||||
of 17:
|
||||
if not isLastNode:
|
||||
let nextNibble = nibbles[nibbleIdx]
|
||||
if nextNibble >= 16:
|
||||
return err("invalid next nibble for branch node")
|
||||
|
||||
if not isValidNextNode(thisNodeRlp, nextNibble.int, proof[proofIdx + 1]):
|
||||
return err("hash of next node doesn't match the expected branch node hash")
|
||||
if not isValidNextNode(thisNodeRlp, nextNibble.int, proof[proofIdx + 1]):
|
||||
return err("hash of next node doesn't match the expected branch node hash")
|
||||
|
||||
inc nibbleIdx
|
||||
else:
|
||||
return err("invalid rlp node, expected 2 or 17 elements")
|
||||
inc nibbleIdx
|
||||
else:
|
||||
return err("invalid rlp node, expected 2 or 17 elements")
|
||||
except RlpError as e:
|
||||
return err(e.msg)
|
||||
|
||||
if nibbleIdx < nibbles.len():
|
||||
err("path contains more nibbles than expected for proof")
|
||||
|
Loading…
x
Reference in New Issue
Block a user