Updates to Fluffy to support hive tests. (#2333)

* Updates to Fluffy book for hive tests.

* Add support to disable state root checks for state content from the command line.

* Update portal_stateStore endpoint to support decoding offer and storing retrieval value.
This commit is contained in:
web3-developer 2024-06-11 21:01:35 +08:00 committed by GitHub
parent eb041abba7
commit 9c26fa3298
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 234 additions and 94 deletions

View File

@ -299,6 +299,13 @@ type
name: "disable-poke" name: "disable-poke"
.}: bool .}: bool
disableStateRootValidation* {.
hidden,
desc: "Disables state root validation for content received by the state network.",
defaultValue: false,
name: "disable-state-root-validation"
.}: bool
case cmd* {.command, defaultValue: noCommand.}: PortalCmd case cmd* {.command, defaultValue: noCommand.}: PortalCmd
of noCommand: of noCommand:
discard discard

View File

@ -1,27 +1,27 @@
# Fluffy with Portal-hive # Fluffy with Portal-hive
Fluffy is one of the Portal clients that is being tested with [portal-hive](https://github.com/ethereum/portal-hive). Fluffy is one of the Portal clients that is being tested with [hive](https://github.com/ethereum/hive).
To see the status of the tests for the current version you can access [https://portal-hive.ethdevops.io/](https://portal-hive.ethdevops.io/). To see the status of the tests for the current version you can access [https://portal-hive.ethdevops.io/](https://portal-hive.ethdevops.io/).
## Run the hive tests locally ## Run the hive tests locally
Build portal-hive: Build hive:
```sh ```sh
git clone https://github.com/ethereum/portal-hive.git git clone https://github.com/ethereum/hive.git
cd ./portal-hive cd ./hive
go build . go build .
``` ```
Example commands for running test suites: Example commands for running test suites:
```sh ```sh
# Run the rpc-compat tests with the 3 different clients # Run the history tests with the 3 different clients
./hive --sim rpc-compat --client fluffy,trin,ultralight ./hive --sim history --client fluffy,trin,ultralight
# Run the portal-interop tests with only the fluffy client # Run the state tests with only the fluffy client
./hive --sim portal-interop --client fluffy ./hive --sim state --client fluffy
# Access results through web-ui: # Access results through web-ui:
```sh ```sh
@ -30,7 +30,7 @@ go build ./cmd/hiveview
``` ```
!!! note !!! note
You can see all the implemented simulators in [https://github.com/ethereum/portal-hive/tree/main/simulators](https://github.com/ethereum/portal-hive/tree/main/simulators) You can see all the implemented simulators in [https://github.com/ethereum/hive/tree/master/simulators](https://github.com/ethereum/hive/tree/master/simulators)
## Build a local development Docker image for portal-hive ## Build a local development Docker image for portal-hive
@ -55,4 +55,3 @@ docker build --tag fluffy-dev --file ./fluffy/tools/docker/Dockerfile.portalhive
The `./vendors` dir is dockerignored and cached. If you have to make local The `./vendors` dir is dockerignored and cached. If you have to make local
changes to one of the dependencies in that directory you will have to remove changes to one of the dependencies in that directory you will have to remove
`vendors/` from `./fluffy/tools/docker/Dockerfile.portalhive.dockerignore`. `vendors/` from `./fluffy/tools/docker/Dockerfile.portalhive.dockerignore`.

View File

@ -234,6 +234,7 @@ proc run(config: PortalConf) {.raises: [CatchableError].} =
bootstrapRecords = bootstrapRecords, bootstrapRecords = bootstrapRecords,
portalConfig = portalConfig, portalConfig = portalConfig,
historyNetwork = historyNetwork, historyNetwork = historyNetwork,
not config.disableStateRootValidation,
) )
) )
else: else:

View File

@ -32,6 +32,7 @@ type StateNetwork* = ref object
contentQueue*: AsyncQueue[(Opt[NodeId], ContentKeysList, seq[seq[byte]])] contentQueue*: AsyncQueue[(Opt[NodeId], ContentKeysList, seq[seq[byte]])]
processContentLoop: Future[void] processContentLoop: Future[void]
historyNetwork: Opt[HistoryNetwork] historyNetwork: Opt[HistoryNetwork]
validateStateIsCanonical: bool
func toContentIdHandler(contentKey: ByteList): results.Opt[ContentId] = func toContentIdHandler(contentKey: ByteList): results.Opt[ContentId] =
ok(toContentId(contentKey)) ok(toContentId(contentKey))
@ -44,6 +45,7 @@ proc new*(
bootstrapRecords: openArray[Record] = [], bootstrapRecords: openArray[Record] = [],
portalConfig: PortalProtocolConfig = defaultPortalProtocolConfig, portalConfig: PortalProtocolConfig = defaultPortalProtocolConfig,
historyNetwork = Opt.none(HistoryNetwork), historyNetwork = Opt.none(HistoryNetwork),
validateStateIsCanonical = true,
): T = ): T =
let cq = newAsyncQueue[(Opt[NodeId], ContentKeysList, seq[seq[byte]])](50) let cq = newAsyncQueue[(Opt[NodeId], ContentKeysList, seq[seq[byte]])](50)
@ -67,6 +69,7 @@ proc new*(
contentDB: contentDB, contentDB: contentDB,
contentQueue: cq, contentQueue: cq,
historyNetwork: historyNetwork, historyNetwork: historyNetwork,
validateStateIsCanonical: validateStateIsCanonical,
) )
proc getContent( proc getContent(
@ -146,10 +149,15 @@ proc processOffer*(
let contentValue = V.decode(contentValueBytes).valueOr: let contentValue = V.decode(contentValueBytes).valueOr:
return err("Unable to decode offered content value") return err("Unable to decode offered content value")
let res =
if n.validateStateIsCanonical:
let stateRoot = (await n.getStateRootByBlockHash(contentValue.blockHash)).valueOr: let stateRoot = (await n.getStateRootByBlockHash(contentValue.blockHash)).valueOr:
return err("Failed to get state root by block hash") return err("Failed to get state root by block hash")
validateOffer(Opt.some(stateRoot), contentKey, contentValue)
else:
# Skip state root validation
validateOffer(Opt.none(KeccakHash), contentKey, contentValue)
let res = validateOffer(stateRoot, contentKey, contentValue)
if res.isErr(): if res.isErr():
return err("Offered content failed validation: " & res.error()) return err("Offered content failed validation: " & res.error())

View File

@ -30,7 +30,7 @@ proc isValidNextNode(thisNodeRlp: Rlp, rlpIdx: int, nextNode: TrieNode): bool =
nextNode.hashEquals(nextHash) nextNode.hashEquals(nextHash)
proc validateTrieProof*( proc validateTrieProof*(
expectedRootHash: KeccakHash, expectedRootHash: Opt[KeccakHash],
path: Nibbles, path: Nibbles,
proof: TrieProof, proof: TrieProof,
allowKeyEndInPathForLeafs = false, allowKeyEndInPathForLeafs = false,
@ -38,7 +38,9 @@ proc validateTrieProof*(
if proof.len() == 0: if proof.len() == 0:
return err("proof is empty") return err("proof is empty")
if not proof[0].hashEquals(expectedRootHash): # TODO: Remove this once the hive tests support passing in state roots from the history network
if expectedRootHash.isSome():
if not proof[0].hashEquals(expectedRootHash.get()):
return err("hash of proof root node doesn't match the expected root hash") return err("hash of proof root node doesn't match the expected root hash")
let nibbles = path.unpackNibbles() let nibbles = path.unpackNibbles()
@ -131,14 +133,18 @@ proc validateRetrieval*(
err("hash of bytecode doesn't match the expected code hash") err("hash of bytecode doesn't match the expected code hash")
proc validateOffer*( proc validateOffer*(
trustedStateRoot: KeccakHash, key: AccountTrieNodeKey, offer: AccountTrieNodeOffer trustedStateRoot: Opt[KeccakHash],
key: AccountTrieNodeKey,
offer: AccountTrieNodeOffer,
): Result[void, string] = ): Result[void, string] =
?validateTrieProof(trustedStateRoot, key.path, offer.proof) ?validateTrieProof(trustedStateRoot, key.path, offer.proof)
validateRetrieval(key, offer.toRetrievalValue()) validateRetrieval(key, offer.toRetrievalValue())
proc validateOffer*( proc validateOffer*(
trustedStateRoot: KeccakHash, key: ContractTrieNodeKey, offer: ContractTrieNodeOffer trustedStateRoot: Opt[KeccakHash],
key: ContractTrieNodeKey,
offer: ContractTrieNodeOffer,
): Result[void, string] = ): Result[void, string] =
?validateTrieProof( ?validateTrieProof(
trustedStateRoot, trustedStateRoot,
@ -149,12 +155,12 @@ proc validateOffer*(
let account = ?offer.accountProof.toAccount() let account = ?offer.accountProof.toAccount()
?validateTrieProof(account.storageRoot, key.path, offer.storageProof) ?validateTrieProof(Opt.some(account.storageRoot), key.path, offer.storageProof)
validateRetrieval(key, offer.toRetrievalValue()) validateRetrieval(key, offer.toRetrievalValue())
proc validateOffer*( proc validateOffer*(
trustedStateRoot: KeccakHash, key: ContractCodeKey, offer: ContractCodeOffer trustedStateRoot: Opt[KeccakHash], key: ContractCodeKey, offer: ContractCodeOffer
): Result[void, string] = ): Result[void, string] =
?validateTrieProof( ?validateTrieProof(
trustedStateRoot, trustedStateRoot,

View File

@ -13,6 +13,7 @@ import
json_serialization/std/tables, json_serialization/std/tables,
stew/byteutils, stew/byteutils,
../network/wire/portal_protocol, ../network/wire/portal_protocol,
../network/state/state_content,
./rpc_types ./rpc_types
{.warning[UnusedImport]: off.} {.warning[UnusedImport]: off.}
@ -42,6 +43,12 @@ TraceResponse.useDefaultSerializationIn JrpcConv
proc installPortalApiHandlers*( proc installPortalApiHandlers*(
rpcServer: RpcServer | RpcProxy, p: PortalProtocol, network: static string rpcServer: RpcServer | RpcProxy, p: PortalProtocol, network: static string
) = ) =
let
invalidKeyErr =
(ref errors.InvalidRequest)(code: -32602, msg: "Invalid content key")
invalidValueErr =
(ref errors.InvalidRequest)(code: -32602, msg: "Invalid content value")
rpcServer.rpc("portal_" & network & "NodeInfo") do() -> NodeInfo: rpcServer.rpc("portal_" & network & "NodeInfo") do() -> NodeInfo:
return p.routingTable.getNodeInfo() return p.routingTable.getNodeInfo()
@ -212,14 +219,39 @@ proc installPortalApiHandlers*(
rpcServer.rpc("portal_" & network & "Store") do( rpcServer.rpc("portal_" & network & "Store") do(
contentKey: string, contentValue: string contentKey: string, contentValue: string
) -> bool: ) -> bool:
let key = ByteList.init(hexToSeqByte(contentKey)) let
let contentId = p.toContentId(key) key = ByteList.init(hexToSeqByte(contentKey))
contentValueBytes = hexToSeqByte(contentValue)
let valueToStore =
if network == "state":
let decodedKey = ContentKey.decode(key).valueOr:
raise invalidKeyErr
case decodedKey.contentType
of unused:
raise invalidKeyErr
of accountTrieNode:
let offerValue = AccountTrieNodeOffer.decode(contentValueBytes).valueOr:
raise invalidValueErr
offerValue.toRetrievalValue.encode()
of contractTrieNode:
let offerValue = ContractTrieNodeOffer.decode(contentValueBytes).valueOr:
raise invalidValueErr
offerValue.toRetrievalValue.encode()
of contractCode:
let offerValue = ContractCodeOffer.decode(contentValueBytes).valueOr:
raise invalidValueErr
offerValue.toRetrievalValue.encode()
else:
contentValueBytes
let contentId = p.toContentId(key)
if contentId.isSome(): if contentId.isSome():
p.storeContent(key, contentId.get(), hexToSeqByte(contentValue)) p.storeContent(key, contentId.get(), valueToStore)
return true return true
else: else:
raise (ref errors.InvalidRequest)(code: -32602, msg: "Invalid content key") raise invalidKeyErr
rpcServer.rpc("portal_" & network & "LocalContent") do(contentKey: string) -> string: rpcServer.rpc("portal_" & network & "LocalContent") do(contentKey: string) -> string:
let let

View File

@ -42,12 +42,16 @@ suite "State Gossip getParent - Genesis JSON Files":
# validate each parent offer until getting to the root node # validate each parent offer until getting to the root node
var parent = offer.withKey(key).getParent() var parent = offer.withKey(key).getParent()
check validateOffer(accountState.rootHash(), parent.key, parent.offer).isOk() check validateOffer(Opt.some(accountState.rootHash()), parent.key, parent.offer)
.isOk()
db.put(parent.key.nodeHash.data, parent.offer.toRetrievalValue().node.asSeq()) db.put(parent.key.nodeHash.data, parent.offer.toRetrievalValue().node.asSeq())
for i in proof.low ..< proof.high - 1: for i in proof.low ..< proof.high - 1:
parent = parent.getParent() parent = parent.getParent()
check validateOffer(accountState.rootHash(), parent.key, parent.offer).isOk() check validateOffer(
Opt.some(accountState.rootHash()), parent.key, parent.offer
)
.isOk()
db.put(parent.key.nodeHash.data, parent.offer.toRetrievalValue().node.asSeq()) db.put(parent.key.nodeHash.data, parent.offer.toRetrievalValue().node.asSeq())
# after putting all parent nodes into the trie, verify can lookup the leaf # after putting all parent nodes into the trie, verify can lookup the leaf
@ -89,14 +93,19 @@ suite "State Gossip getParent - Genesis JSON Files":
# validate each parent offer until getting to the root node # validate each parent offer until getting to the root node
var parent = offer.withKey(key).getParent() var parent = offer.withKey(key).getParent()
check validateOffer(accountState.rootHash(), parent.key, parent.offer).isOk() check validateOffer(
Opt.some(accountState.rootHash()), parent.key, parent.offer
)
.isOk()
db.put( db.put(
parent.key.nodeHash.data, parent.offer.toRetrievalValue().node.asSeq() parent.key.nodeHash.data, parent.offer.toRetrievalValue().node.asSeq()
) )
for i in storageProof.low ..< storageProof.high - 1: for i in storageProof.low ..< storageProof.high - 1:
parent = parent.getParent() parent = parent.getParent()
check validateOffer(accountState.rootHash(), parent.key, parent.offer) check validateOffer(
Opt.some(accountState.rootHash()), parent.key, parent.offer
)
.isOk() .isOk()
db.put( db.put(
parent.key.nodeHash.data, parent.offer.toRetrievalValue().node.asSeq() parent.key.nodeHash.data, parent.offer.toRetrievalValue().node.asSeq()

View File

@ -34,15 +34,17 @@ template checkValidProofsForExistingLeafs(
path: accountPath, nodeHash: keccakHash(accountProof[^1].asSeq()) path: accountPath, nodeHash: keccakHash(accountProof[^1].asSeq())
) )
accountTrieOffer = AccountTrieNodeOffer(proof: accountProof) accountTrieOffer = AccountTrieNodeOffer(proof: accountProof)
proofResult = proofResult = validateOffer(
validateOffer(accountState.rootHash(), accountTrieNodeKey, accountTrieOffer) Opt.some(accountState.rootHash()), accountTrieNodeKey, accountTrieOffer
)
check proofResult.isOk() check proofResult.isOk()
let let
contractCodeKey = ContractCodeKey(address: address, codeHash: acc.codeHash) contractCodeKey = ContractCodeKey(address: address, codeHash: acc.codeHash)
contractCode = contractCode =
ContractCodeOffer(code: Bytecode.init(account.code), accountProof: accountProof) ContractCodeOffer(code: Bytecode.init(account.code), accountProof: accountProof)
codeResult = validateOffer(accountState.rootHash(), contractCodeKey, contractCode) codeResult =
validateOffer(Opt.some(accountState.rootHash()), contractCodeKey, contractCode)
check codeResult.isOk() check codeResult.isOk()
if account.code.len() > 0: if account.code.len() > 0:
@ -64,7 +66,7 @@ template checkValidProofsForExistingLeafs(
storageProof: storageProof, accountProof: accountProof storageProof: storageProof, accountProof: accountProof
) )
proofResult = validateOffer( proofResult = validateOffer(
accountState.rootHash(), contractTrieNodeKey, contractTrieOffer Opt.some(accountState.rootHash()), contractTrieNodeKey, contractTrieOffer
) )
check proofResult.isOk() check proofResult.isOk()
@ -88,8 +90,9 @@ template checkInvalidProofsWithBadValue(
accountProof[^1][^1] += 1 # bad account leaf value accountProof[^1][^1] += 1 # bad account leaf value
let let
accountTrieOffer = AccountTrieNodeOffer(proof: accountProof) accountTrieOffer = AccountTrieNodeOffer(proof: accountProof)
proofResult = proofResult = validateOffer(
validateOffer(accountState.rootHash(), accountTrieNodeKey, accountTrieOffer) Opt.some(accountState.rootHash()), accountTrieNodeKey, accountTrieOffer
)
check proofResult.isErr() check proofResult.isErr()
let let
@ -98,7 +101,8 @@ template checkInvalidProofsWithBadValue(
code: Bytecode.init(@[1u8, 2, 3]), # bad code value code: Bytecode.init(@[1u8, 2, 3]), # bad code value
accountProof: accountProof, accountProof: accountProof,
) )
codeResult = validateOffer(accountState.rootHash(), contractCodeKey, contractCode) codeResult =
validateOffer(Opt.some(accountState.rootHash()), contractCodeKey, contractCode)
check codeResult.isErr() check codeResult.isErr()
if account.code.len() > 0: if account.code.len() > 0:
@ -122,7 +126,7 @@ template checkInvalidProofsWithBadValue(
storageProof: storageProof, accountProof: accountProof storageProof: storageProof, accountProof: accountProof
) )
proofResult = validateOffer( proofResult = validateOffer(
accountState.rootHash(), contractTrieNodeKey, contractTrieOffer Opt.some(accountState.rootHash()), contractTrieNodeKey, contractTrieOffer
) )
check proofResult.isErr() check proofResult.isErr()

View File

@ -38,7 +38,7 @@ suite "State Validation - validateTrieProof":
let let
kv = getKeyBytes(i) kv = getKeyBytes(i)
proof = trie.getTrieProof(kv) proof = trie.getTrieProof(kv)
res = validateTrieProof(rootHash, kv.asNibbles(), proof, true) res = validateTrieProof(Opt.some(rootHash), kv.asNibbles(), proof, true)
check: check:
res.isOk() res.isOk()
@ -55,7 +55,7 @@ suite "State Validation - validateTrieProof":
rootHash = trie.rootHash() rootHash = trie.rootHash()
key = getKeyBytes(numValues + 1) key = getKeyBytes(numValues + 1)
proof = trie.getTrieProof(key) proof = trie.getTrieProof(key)
res = validateTrieProof(rootHash, key.asNibbles(), proof, true) res = validateTrieProof(Opt.some(rootHash), key.asNibbles(), proof, true)
check: check:
res.isErr() res.isErr()
@ -68,7 +68,7 @@ suite "State Validation - validateTrieProof":
rootHash = trie.rootHash() rootHash = trie.rootHash()
key = "not-exist".toBytes key = "not-exist".toBytes
proof = trie.getTrieProof(key) proof = trie.getTrieProof(key)
res = validateTrieProof(rootHash, key.asNibbles(), proof, true) res = validateTrieProof(Opt.some(rootHash), key.asNibbles(), proof, true)
check: check:
res.isErr() res.isErr()
@ -83,7 +83,7 @@ suite "State Validation - validateTrieProof":
let let
rootHash = trie.rootHash rootHash = trie.rootHash
proof = trie.getTrieProof(key) proof = trie.getTrieProof(key)
res = validateTrieProof(rootHash, key.asNibbles(), proof, true) res = validateTrieProof(Opt.some(rootHash), key.asNibbles(), proof, true)
check: check:
res.isOk() res.isOk()
@ -101,25 +101,25 @@ suite "State Validation - validateTrieProof":
let let
key = "doe".toBytes key = "doe".toBytes
proof = trie.getTrieProof(key) proof = trie.getTrieProof(key)
check validateTrieProof(rootHash, key.asNibbles(), proof, true).isOk() check validateTrieProof(Opt.some(rootHash), key.asNibbles(), proof, true).isOk()
block: block:
let let
key = "dog".toBytes key = "dog".toBytes
proof = trie.getTrieProof(key) proof = trie.getTrieProof(key)
check validateTrieProof(rootHash, key.asNibbles(), proof, true).isOk() check validateTrieProof(Opt.some(rootHash), key.asNibbles(), proof, true).isOk()
block: block:
let let
key = "dogglesworth".toBytes key = "dogglesworth".toBytes
proof = trie.getTrieProof(key) proof = trie.getTrieProof(key)
check validateTrieProof(rootHash, key.asNibbles(), proof, true).isOk() check validateTrieProof(Opt.some(rootHash), key.asNibbles(), proof, true).isOk()
block: block:
let let
key = "dogg".toBytes key = "dogg".toBytes
proof = trie.getTrieProof(key) proof = trie.getTrieProof(key)
res = validateTrieProof(rootHash, key.asNibbles(), proof, true) res = validateTrieProof(Opt.some(rootHash), key.asNibbles(), proof, true)
check: check:
res.isErr() res.isErr()
res.error() == "not enough nibbles to validate node prefix" res.error() == "not enough nibbles to validate node prefix"
@ -128,7 +128,7 @@ suite "State Validation - validateTrieProof":
let let
key = "dogz".toBytes key = "dogz".toBytes
proof = trie.getTrieProof(key) proof = trie.getTrieProof(key)
res = validateTrieProof(rootHash, key.asNibbles(), proof, true) res = validateTrieProof(Opt.some(rootHash), key.asNibbles(), proof, true)
check: check:
res.isErr() res.isErr()
res.error() == "path contains more nibbles than expected for proof" res.error() == "path contains more nibbles than expected for proof"
@ -137,7 +137,7 @@ suite "State Validation - validateTrieProof":
let let
key = "doe".toBytes key = "doe".toBytes
proof = newSeq[seq[byte]]().asTrieProof() proof = newSeq[seq[byte]]().asTrieProof()
res = validateTrieProof(rootHash, key.asNibbles(), proof, true) res = validateTrieProof(Opt.some(rootHash), key.asNibbles(), proof, true)
check: check:
res.isErr() res.isErr()
res.error() == "proof is empty" res.error() == "proof is empty"
@ -146,7 +146,7 @@ suite "State Validation - validateTrieProof":
let let
key = "doe".toBytes key = "doe".toBytes
proof = @["aaa".toBytes, "ccc".toBytes].asTrieProof() proof = @["aaa".toBytes, "ccc".toBytes].asTrieProof()
res = validateTrieProof(rootHash, key.asNibbles(), proof, true) res = validateTrieProof(Opt.some(rootHash), key.asNibbles(), proof, true)
check: check:
res.isErr() res.isErr()
res.error() == "hash of proof root node doesn't match the expected root hash" res.error() == "hash of proof root node doesn't match the expected root hash"
@ -185,23 +185,59 @@ suite "State Validation - validateTrieProof":
let rootHash = trie.rootHash let rootHash = trie.rootHash
check: check:
validateTrieProof(rootHash, kv1.asNibbles(), trie.getTrieProof(kv1), true).isOk() validateTrieProof(
validateTrieProof(rootHash, kv2.asNibbles(), trie.getTrieProof(kv2), false).isOk() Opt.some(rootHash), kv1.asNibbles(), trie.getTrieProof(kv1), true
validateTrieProof(rootHash, kv3.asNibbles(), trie.getTrieProof(kv3), true).isOk() )
validateTrieProof(rootHash, kv4.asNibbles(), trie.getTrieProof(kv4), false).isOk() .isOk()
validateTrieProof(rootHash, kv5.asNibbles(), trie.getTrieProof(kv5)).isOk()
validateTrieProof(rootHash, kv6.asNibbles(), trie.getTrieProof(kv6)).isOk()
validateTrieProof(rootHash, kv7.asNibbles(), trie.getTrieProof(kv7)).isOk()
validateTrieProof(rootHash, kv8.asNibbles(), trie.getTrieProof(kv8)).isOk()
validateTrieProof(rootHash, kv9.asNibbles(), trie.getTrieProof(kv9)).isErr() validateTrieProof(
validateTrieProof(rootHash, kv10.asNibbles(), trie.getTrieProof(kv10)).isErr() Opt.some(rootHash), kv2.asNibbles(), trie.getTrieProof(kv2), false
validateTrieProof(rootHash, kv11.asNibbles(), trie.getTrieProof(kv11)).isErr() )
validateTrieProof(rootHash, kv12.asNibbles(), trie.getTrieProof(kv12)).isErr() .isOk()
validateTrieProof(rootHash, kv13.asNibbles(), trie.getTrieProof(kv13)).isErr()
validateTrieProof(rootHash, kv14.asNibbles(), trie.getTrieProof(kv14), false) validateTrieProof(
Opt.some(rootHash), kv3.asNibbles(), trie.getTrieProof(kv3), true
)
.isOk()
validateTrieProof(
Opt.some(rootHash), kv4.asNibbles(), trie.getTrieProof(kv4), false
)
.isOk()
validateTrieProof(Opt.some(rootHash), kv5.asNibbles(), trie.getTrieProof(kv5))
.isOk()
validateTrieProof(Opt.some(rootHash), kv6.asNibbles(), trie.getTrieProof(kv6))
.isOk()
validateTrieProof(Opt.some(rootHash), kv7.asNibbles(), trie.getTrieProof(kv7))
.isOk()
validateTrieProof(Opt.some(rootHash), kv8.asNibbles(), trie.getTrieProof(kv8))
.isOk()
validateTrieProof(Opt.some(rootHash), kv9.asNibbles(), trie.getTrieProof(kv9))
.isErr() .isErr()
validateTrieProof(rootHash, kv15.asNibbles(), trie.getTrieProof(kv15), false) validateTrieProof(Opt.some(rootHash), kv10.asNibbles(), trie.getTrieProof(kv10))
.isErr()
validateTrieProof(Opt.some(rootHash), kv11.asNibbles(), trie.getTrieProof(kv11))
.isErr()
validateTrieProof(Opt.some(rootHash), kv12.asNibbles(), trie.getTrieProof(kv12))
.isErr()
validateTrieProof(Opt.some(rootHash), kv13.asNibbles(), trie.getTrieProof(kv13))
.isErr()
validateTrieProof(
Opt.some(rootHash), kv14.asNibbles(), trie.getTrieProof(kv14), false
)
.isErr()
validateTrieProof(
Opt.some(rootHash), kv15.asNibbles(), trie.getTrieProof(kv15), false
)
.isErr() .isErr()

View File

@ -144,7 +144,9 @@ suite "State Validation - Test Vectors":
AccountTrieNodeOffer.decode(testData.content_value_offer.hexToSeqByte()).get() AccountTrieNodeOffer.decode(testData.content_value_offer.hexToSeqByte()).get()
check: check:
validateOffer(stateRoot, contentKey.accountTrieNodeKey, contentValueOffer) validateOffer(
Opt.some(stateRoot), contentKey.accountTrieNodeKey, contentValueOffer
)
.isOk() .isOk()
if i == 1: if i == 1:
@ -158,7 +160,10 @@ suite "State Validation - Test Vectors":
.get() .get()
check: check:
validateOffer(stateRoot, contentKey.accountTrieNodeKey, contentValueOffer).isOk() validateOffer(
Opt.some(stateRoot), contentKey.accountTrieNodeKey, contentValueOffer
)
.isOk()
test "Validate invalid AccountTrieNodeOffer nodes - bad state roots": test "Validate invalid AccountTrieNodeOffer nodes - bad state roots":
const file = testVectorDir / "account_trie_node.yaml" const file = testVectorDir / "account_trie_node.yaml"
@ -179,8 +184,9 @@ suite "State Validation - Test Vectors":
let contentValueOffer = let contentValueOffer =
AccountTrieNodeOffer.decode(testData.content_value_offer.hexToSeqByte()).get() AccountTrieNodeOffer.decode(testData.content_value_offer.hexToSeqByte()).get()
let res = let res = validateOffer(
validateOffer(stateRoot, contentKey.accountTrieNodeKey, contentValueOffer) Opt.some(stateRoot), contentKey.accountTrieNodeKey, contentValueOffer
)
check: check:
res.isErr() res.isErr()
res.error() == "hash of proof root node doesn't match the expected root hash" res.error() == "hash of proof root node doesn't match the expected root hash"
@ -201,8 +207,9 @@ suite "State Validation - Test Vectors":
contentValueOffer.proof[0][0] += 1.byte contentValueOffer.proof[0][0] += 1.byte
let res = let res = validateOffer(
validateOffer(stateRoot, contentKey.accountTrieNodeKey, contentValueOffer) Opt.some(stateRoot), contentKey.accountTrieNodeKey, contentValueOffer
)
check: check:
res.isErr() res.isErr()
res.error() == "hash of proof root node doesn't match the expected root hash" res.error() == "hash of proof root node doesn't match the expected root hash"
@ -219,8 +226,9 @@ suite "State Validation - Test Vectors":
contentValueOffer.proof[^2][^2] += 1.byte contentValueOffer.proof[^2][^2] += 1.byte
let res = let res = validateOffer(
validateOffer(stateRoot, contentKey.accountTrieNodeKey, contentValueOffer) Opt.some(stateRoot), contentKey.accountTrieNodeKey, contentValueOffer
)
check: check:
res.isErr() res.isErr()
"hash of next node doesn't match the expected" in res.error() "hash of next node doesn't match the expected" in res.error()
@ -235,8 +243,9 @@ suite "State Validation - Test Vectors":
contentValueOffer.proof[^1][^1] += 1.byte contentValueOffer.proof[^1][^1] += 1.byte
let res = let res = validateOffer(
validateOffer(stateRoot, contentKey.accountTrieNodeKey, contentValueOffer) Opt.some(stateRoot), contentKey.accountTrieNodeKey, contentValueOffer
)
check: check:
res.isErr() res.isErr()
@ -259,7 +268,9 @@ suite "State Validation - Test Vectors":
.get() .get()
check: check:
validateOffer(stateRoot, contentKey.contractTrieNodeKey, contentValueOffer) validateOffer(
Opt.some(stateRoot), contentKey.contractTrieNodeKey, contentValueOffer
)
.isOk() .isOk()
if i == 1: if i == 1:
@ -273,7 +284,10 @@ suite "State Validation - Test Vectors":
.get() .get()
check: check:
validateOffer(stateRoot, contentKey.contractTrieNodeKey, contentValueOffer).isOk() validateOffer(
Opt.some(stateRoot), contentKey.contractTrieNodeKey, contentValueOffer
)
.isOk()
test "Validate invalid ContractTrieNodeOffer nodes - bad state roots": test "Validate invalid ContractTrieNodeOffer nodes - bad state roots":
const file = testVectorDir / "contract_storage_trie_node.yaml" const file = testVectorDir / "contract_storage_trie_node.yaml"
@ -293,8 +307,9 @@ suite "State Validation - Test Vectors":
let contentValueOffer = let contentValueOffer =
ContractTrieNodeOffer.decode(testData.content_value_offer.hexToSeqByte()).get() ContractTrieNodeOffer.decode(testData.content_value_offer.hexToSeqByte()).get()
let res = let res = validateOffer(
validateOffer(stateRoot, contentKey.contractTrieNodeKey, contentValueOffer) Opt.some(stateRoot), contentKey.contractTrieNodeKey, contentValueOffer
)
check: check:
res.isErr() res.isErr()
res.error() == "hash of proof root node doesn't match the expected root hash" res.error() == "hash of proof root node doesn't match the expected root hash"
@ -317,8 +332,9 @@ suite "State Validation - Test Vectors":
contentValueOffer.accountProof[0][0] += 1.byte contentValueOffer.accountProof[0][0] += 1.byte
let res = let res = validateOffer(
validateOffer(stateRoot, contentKey.contractTrieNodeKey, contentValueOffer) Opt.some(stateRoot), contentKey.contractTrieNodeKey, contentValueOffer
)
check: check:
res.isErr() res.isErr()
res.error() == "hash of proof root node doesn't match the expected root hash" res.error() == "hash of proof root node doesn't match the expected root hash"
@ -332,8 +348,9 @@ suite "State Validation - Test Vectors":
contentValueOffer.storageProof[0][0] += 1.byte contentValueOffer.storageProof[0][0] += 1.byte
let res = let res = validateOffer(
validateOffer(stateRoot, contentKey.contractTrieNodeKey, contentValueOffer) Opt.some(stateRoot), contentKey.contractTrieNodeKey, contentValueOffer
)
check: check:
res.isErr() res.isErr()
res.error() == "hash of proof root node doesn't match the expected root hash" res.error() == "hash of proof root node doesn't match the expected root hash"
@ -348,7 +365,9 @@ suite "State Validation - Test Vectors":
contentValueOffer.accountProof[^1][^1] += 1.byte contentValueOffer.accountProof[^1][^1] += 1.byte
check: check:
validateOffer(stateRoot, contentKey.contractTrieNodeKey, contentValueOffer) validateOffer(
Opt.some(stateRoot), contentKey.contractTrieNodeKey, contentValueOffer
)
.isErr() .isErr()
block: block:
@ -361,7 +380,9 @@ suite "State Validation - Test Vectors":
contentValueOffer.storageProof[^1][^1] += 1.byte contentValueOffer.storageProof[^1][^1] += 1.byte
check: check:
validateOffer(stateRoot, contentKey.contractTrieNodeKey, contentValueOffer) validateOffer(
Opt.some(stateRoot), contentKey.contractTrieNodeKey, contentValueOffer
)
.isErr() .isErr()
block: block:
@ -374,7 +395,9 @@ suite "State Validation - Test Vectors":
contentValueOffer.accountProof[^2][^2] += 1.byte contentValueOffer.accountProof[^2][^2] += 1.byte
check: check:
validateOffer(stateRoot, contentKey.contractTrieNodeKey, contentValueOffer) validateOffer(
Opt.some(stateRoot), contentKey.contractTrieNodeKey, contentValueOffer
)
.isErr() .isErr()
# Contract bytecode offer validation tests # Contract bytecode offer validation tests
@ -394,7 +417,10 @@ suite "State Validation - Test Vectors":
ContractCodeOffer.decode(testData.content_value_offer.hexToSeqByte()).get() ContractCodeOffer.decode(testData.content_value_offer.hexToSeqByte()).get()
check: check:
validateOffer(stateRoot, contentKey.contractCodeKey, contentValueOffer).isOk() validateOffer(
Opt.some(stateRoot), contentKey.contractCodeKey, contentValueOffer
)
.isOk()
test "Validate invalid ContractCodeOffer nodes - bad state root": test "Validate invalid ContractCodeOffer nodes - bad state root":
const file = testVectorDir / "contract_bytecode.yaml" const file = testVectorDir / "contract_bytecode.yaml"
@ -412,7 +438,9 @@ suite "State Validation - Test Vectors":
let contentValueOffer = let contentValueOffer =
ContractCodeOffer.decode(testData.content_value_offer.hexToSeqByte()).get() ContractCodeOffer.decode(testData.content_value_offer.hexToSeqByte()).get()
let res = validateOffer(stateRoot, contentKey.contractCodeKey, contentValueOffer) let res = validateOffer(
Opt.some(stateRoot), contentKey.contractCodeKey, contentValueOffer
)
check: check:
res.isErr() res.isErr()
res.error() == "hash of proof root node doesn't match the expected root hash" res.error() == "hash of proof root node doesn't match the expected root hash"
@ -434,8 +462,9 @@ suite "State Validation - Test Vectors":
contentValueOffer.accountProof[0][0] += 1.byte contentValueOffer.accountProof[0][0] += 1.byte
let res = let res = validateOffer(
validateOffer(stateRoot, contentKey.contractCodeKey, contentValueOffer) Opt.some(stateRoot), contentKey.contractCodeKey, contentValueOffer
)
check: check:
res.isErr() res.isErr()
res.error() == "hash of proof root node doesn't match the expected root hash" res.error() == "hash of proof root node doesn't match the expected root hash"
@ -448,8 +477,9 @@ suite "State Validation - Test Vectors":
contentValueOffer.code[0] += 1.byte contentValueOffer.code[0] += 1.byte
let res = let res = validateOffer(
validateOffer(stateRoot, contentKey.contractCodeKey, contentValueOffer) Opt.some(stateRoot), contentKey.contractCodeKey, contentValueOffer
)
check: check:
res.isErr() res.isErr()
res.error() == res.error() ==
@ -464,7 +494,10 @@ suite "State Validation - Test Vectors":
contentValueOffer.accountProof[^1][^1] += 1.byte contentValueOffer.accountProof[^1][^1] += 1.byte
check: check:
validateOffer(stateRoot, contentKey.contractCodeKey, contentValueOffer).isErr() validateOffer(
Opt.some(stateRoot), contentKey.contractCodeKey, contentValueOffer
)
.isErr()
block: block:
let contentKey = let contentKey =
@ -474,8 +507,9 @@ suite "State Validation - Test Vectors":
contentValueOffer.code[^1] += 1.byte contentValueOffer.code[^1] += 1.byte
let res = let res = validateOffer(
validateOffer(stateRoot, contentKey.contractCodeKey, contentValueOffer) Opt.some(stateRoot), contentKey.contractCodeKey, contentValueOffer
)
check: check:
res.isErr() res.isErr()
res.error() == res.error() ==
@ -506,7 +540,9 @@ suite "State Validation - Test Vectors":
AccountTrieNodeOffer.decode(kv.content_value.hexToSeqByte()).get() AccountTrieNodeOffer.decode(kv.content_value.hexToSeqByte()).get()
check: check:
validateOffer(stateRoot, contentKey.accountTrieNodeKey, contentValueOffer) validateOffer(
Opt.some(stateRoot), contentKey.accountTrieNodeKey, contentValueOffer
)
.isOk() .isOk()
test "Validate valid ContractTrieNodeOffer recursive gossip nodes": test "Validate valid ContractTrieNodeOffer recursive gossip nodes":
@ -527,5 +563,7 @@ suite "State Validation - Test Vectors":
ContractTrieNodeOffer.decode(kv.content_value.hexToSeqByte()).get() ContractTrieNodeOffer.decode(kv.content_value.hexToSeqByte()).get()
check: check:
validateOffer(stateRoot, contentKey.contractTrieNodeKey, contentValueOffer) validateOffer(
Opt.some(stateRoot), contentKey.contractTrieNodeKey, contentValueOffer
)
.isOk() .isOk()