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:
parent
eb041abba7
commit
9c26fa3298
|
@ -299,6 +299,13 @@ type
|
|||
name: "disable-poke"
|
||||
.}: 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
|
||||
of noCommand:
|
||||
discard
|
||||
|
|
|
@ -1,27 +1,27 @@
|
|||
# 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/).
|
||||
|
||||
## Run the hive tests locally
|
||||
|
||||
Build portal-hive:
|
||||
Build hive:
|
||||
|
||||
```sh
|
||||
git clone https://github.com/ethereum/portal-hive.git
|
||||
cd ./portal-hive
|
||||
git clone https://github.com/ethereum/hive.git
|
||||
cd ./hive
|
||||
go build .
|
||||
```
|
||||
|
||||
Example commands for running test suites:
|
||||
|
||||
```sh
|
||||
# Run the rpc-compat tests with the 3 different clients
|
||||
./hive --sim rpc-compat --client fluffy,trin,ultralight
|
||||
# Run the history tests with the 3 different clients
|
||||
./hive --sim history --client fluffy,trin,ultralight
|
||||
|
||||
# Run the portal-interop tests with only the fluffy client
|
||||
./hive --sim portal-interop --client fluffy
|
||||
# Run the state tests with only the fluffy client
|
||||
./hive --sim state --client fluffy
|
||||
|
||||
# Access results through web-ui:
|
||||
```sh
|
||||
|
@ -30,7 +30,7 @@ go build ./cmd/hiveview
|
|||
```
|
||||
|
||||
!!! 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
|
||||
|
||||
|
@ -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
|
||||
changes to one of the dependencies in that directory you will have to remove
|
||||
`vendors/` from `./fluffy/tools/docker/Dockerfile.portalhive.dockerignore`.
|
||||
|
||||
|
|
|
@ -234,6 +234,7 @@ proc run(config: PortalConf) {.raises: [CatchableError].} =
|
|||
bootstrapRecords = bootstrapRecords,
|
||||
portalConfig = portalConfig,
|
||||
historyNetwork = historyNetwork,
|
||||
not config.disableStateRootValidation,
|
||||
)
|
||||
)
|
||||
else:
|
||||
|
|
|
@ -32,6 +32,7 @@ type StateNetwork* = ref object
|
|||
contentQueue*: AsyncQueue[(Opt[NodeId], ContentKeysList, seq[seq[byte]])]
|
||||
processContentLoop: Future[void]
|
||||
historyNetwork: Opt[HistoryNetwork]
|
||||
validateStateIsCanonical: bool
|
||||
|
||||
func toContentIdHandler(contentKey: ByteList): results.Opt[ContentId] =
|
||||
ok(toContentId(contentKey))
|
||||
|
@ -44,6 +45,7 @@ proc new*(
|
|||
bootstrapRecords: openArray[Record] = [],
|
||||
portalConfig: PortalProtocolConfig = defaultPortalProtocolConfig,
|
||||
historyNetwork = Opt.none(HistoryNetwork),
|
||||
validateStateIsCanonical = true,
|
||||
): T =
|
||||
let cq = newAsyncQueue[(Opt[NodeId], ContentKeysList, seq[seq[byte]])](50)
|
||||
|
||||
|
@ -67,6 +69,7 @@ proc new*(
|
|||
contentDB: contentDB,
|
||||
contentQueue: cq,
|
||||
historyNetwork: historyNetwork,
|
||||
validateStateIsCanonical: validateStateIsCanonical,
|
||||
)
|
||||
|
||||
proc getContent(
|
||||
|
@ -146,10 +149,15 @@ proc processOffer*(
|
|||
let contentValue = V.decode(contentValueBytes).valueOr:
|
||||
return err("Unable to decode offered content value")
|
||||
|
||||
let stateRoot = (await n.getStateRootByBlockHash(contentValue.blockHash)).valueOr:
|
||||
return err("Failed to get state root by block hash")
|
||||
let res =
|
||||
if n.validateStateIsCanonical:
|
||||
let stateRoot = (await n.getStateRootByBlockHash(contentValue.blockHash)).valueOr:
|
||||
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():
|
||||
return err("Offered content failed validation: " & res.error())
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ proc isValidNextNode(thisNodeRlp: Rlp, rlpIdx: int, nextNode: TrieNode): bool =
|
|||
nextNode.hashEquals(nextHash)
|
||||
|
||||
proc validateTrieProof*(
|
||||
expectedRootHash: KeccakHash,
|
||||
expectedRootHash: Opt[KeccakHash],
|
||||
path: Nibbles,
|
||||
proof: TrieProof,
|
||||
allowKeyEndInPathForLeafs = false,
|
||||
|
@ -38,8 +38,10 @@ proc validateTrieProof*(
|
|||
if proof.len() == 0:
|
||||
return err("proof is empty")
|
||||
|
||||
if not proof[0].hashEquals(expectedRootHash):
|
||||
return err("hash of proof root node doesn't match the expected root hash")
|
||||
# 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")
|
||||
|
||||
let nibbles = path.unpackNibbles()
|
||||
if nibbles.len() == 0:
|
||||
|
@ -131,14 +133,18 @@ proc validateRetrieval*(
|
|||
err("hash of bytecode doesn't match the expected code hash")
|
||||
|
||||
proc validateOffer*(
|
||||
trustedStateRoot: KeccakHash, key: AccountTrieNodeKey, offer: AccountTrieNodeOffer
|
||||
trustedStateRoot: Opt[KeccakHash],
|
||||
key: AccountTrieNodeKey,
|
||||
offer: AccountTrieNodeOffer,
|
||||
): Result[void, string] =
|
||||
?validateTrieProof(trustedStateRoot, key.path, offer.proof)
|
||||
|
||||
validateRetrieval(key, offer.toRetrievalValue())
|
||||
|
||||
proc validateOffer*(
|
||||
trustedStateRoot: KeccakHash, key: ContractTrieNodeKey, offer: ContractTrieNodeOffer
|
||||
trustedStateRoot: Opt[KeccakHash],
|
||||
key: ContractTrieNodeKey,
|
||||
offer: ContractTrieNodeOffer,
|
||||
): Result[void, string] =
|
||||
?validateTrieProof(
|
||||
trustedStateRoot,
|
||||
|
@ -149,12 +155,12 @@ proc validateOffer*(
|
|||
|
||||
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())
|
||||
|
||||
proc validateOffer*(
|
||||
trustedStateRoot: KeccakHash, key: ContractCodeKey, offer: ContractCodeOffer
|
||||
trustedStateRoot: Opt[KeccakHash], key: ContractCodeKey, offer: ContractCodeOffer
|
||||
): Result[void, string] =
|
||||
?validateTrieProof(
|
||||
trustedStateRoot,
|
||||
|
|
|
@ -13,6 +13,7 @@ import
|
|||
json_serialization/std/tables,
|
||||
stew/byteutils,
|
||||
../network/wire/portal_protocol,
|
||||
../network/state/state_content,
|
||||
./rpc_types
|
||||
|
||||
{.warning[UnusedImport]: off.}
|
||||
|
@ -42,6 +43,12 @@ TraceResponse.useDefaultSerializationIn JrpcConv
|
|||
proc installPortalApiHandlers*(
|
||||
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:
|
||||
return p.routingTable.getNodeInfo()
|
||||
|
||||
|
@ -212,14 +219,39 @@ proc installPortalApiHandlers*(
|
|||
rpcServer.rpc("portal_" & network & "Store") do(
|
||||
contentKey: string, contentValue: string
|
||||
) -> bool:
|
||||
let key = ByteList.init(hexToSeqByte(contentKey))
|
||||
let contentId = p.toContentId(key)
|
||||
let
|
||||
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():
|
||||
p.storeContent(key, contentId.get(), hexToSeqByte(contentValue))
|
||||
p.storeContent(key, contentId.get(), valueToStore)
|
||||
return true
|
||||
else:
|
||||
raise (ref errors.InvalidRequest)(code: -32602, msg: "Invalid content key")
|
||||
raise invalidKeyErr
|
||||
|
||||
rpcServer.rpc("portal_" & network & "LocalContent") do(contentKey: string) -> string:
|
||||
let
|
||||
|
|
|
@ -42,12 +42,16 @@ suite "State Gossip getParent - Genesis JSON Files":
|
|||
|
||||
# validate each parent offer until getting to the root node
|
||||
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())
|
||||
|
||||
for i in proof.low ..< proof.high - 1:
|
||||
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())
|
||||
|
||||
# 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
|
||||
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()
|
||||
)
|
||||
|
||||
for i in storageProof.low ..< storageProof.high - 1:
|
||||
parent = parent.getParent()
|
||||
check validateOffer(accountState.rootHash(), parent.key, parent.offer)
|
||||
check validateOffer(
|
||||
Opt.some(accountState.rootHash()), parent.key, parent.offer
|
||||
)
|
||||
.isOk()
|
||||
db.put(
|
||||
parent.key.nodeHash.data, parent.offer.toRetrievalValue().node.asSeq()
|
||||
|
|
|
@ -34,15 +34,17 @@ template checkValidProofsForExistingLeafs(
|
|||
path: accountPath, nodeHash: keccakHash(accountProof[^1].asSeq())
|
||||
)
|
||||
accountTrieOffer = AccountTrieNodeOffer(proof: accountProof)
|
||||
proofResult =
|
||||
validateOffer(accountState.rootHash(), accountTrieNodeKey, accountTrieOffer)
|
||||
proofResult = validateOffer(
|
||||
Opt.some(accountState.rootHash()), accountTrieNodeKey, accountTrieOffer
|
||||
)
|
||||
check proofResult.isOk()
|
||||
|
||||
let
|
||||
contractCodeKey = ContractCodeKey(address: address, codeHash: acc.codeHash)
|
||||
contractCode =
|
||||
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()
|
||||
|
||||
if account.code.len() > 0:
|
||||
|
@ -64,7 +66,7 @@ template checkValidProofsForExistingLeafs(
|
|||
storageProof: storageProof, accountProof: accountProof
|
||||
)
|
||||
proofResult = validateOffer(
|
||||
accountState.rootHash(), contractTrieNodeKey, contractTrieOffer
|
||||
Opt.some(accountState.rootHash()), contractTrieNodeKey, contractTrieOffer
|
||||
)
|
||||
check proofResult.isOk()
|
||||
|
||||
|
@ -88,8 +90,9 @@ template checkInvalidProofsWithBadValue(
|
|||
accountProof[^1][^1] += 1 # bad account leaf value
|
||||
let
|
||||
accountTrieOffer = AccountTrieNodeOffer(proof: accountProof)
|
||||
proofResult =
|
||||
validateOffer(accountState.rootHash(), accountTrieNodeKey, accountTrieOffer)
|
||||
proofResult = validateOffer(
|
||||
Opt.some(accountState.rootHash()), accountTrieNodeKey, accountTrieOffer
|
||||
)
|
||||
check proofResult.isErr()
|
||||
|
||||
let
|
||||
|
@ -98,7 +101,8 @@ template checkInvalidProofsWithBadValue(
|
|||
code: Bytecode.init(@[1u8, 2, 3]), # bad code value
|
||||
accountProof: accountProof,
|
||||
)
|
||||
codeResult = validateOffer(accountState.rootHash(), contractCodeKey, contractCode)
|
||||
codeResult =
|
||||
validateOffer(Opt.some(accountState.rootHash()), contractCodeKey, contractCode)
|
||||
check codeResult.isErr()
|
||||
|
||||
if account.code.len() > 0:
|
||||
|
@ -122,7 +126,7 @@ template checkInvalidProofsWithBadValue(
|
|||
storageProof: storageProof, accountProof: accountProof
|
||||
)
|
||||
proofResult = validateOffer(
|
||||
accountState.rootHash(), contractTrieNodeKey, contractTrieOffer
|
||||
Opt.some(accountState.rootHash()), contractTrieNodeKey, contractTrieOffer
|
||||
)
|
||||
check proofResult.isErr()
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ suite "State Validation - validateTrieProof":
|
|||
let
|
||||
kv = getKeyBytes(i)
|
||||
proof = trie.getTrieProof(kv)
|
||||
res = validateTrieProof(rootHash, kv.asNibbles(), proof, true)
|
||||
res = validateTrieProof(Opt.some(rootHash), kv.asNibbles(), proof, true)
|
||||
|
||||
check:
|
||||
res.isOk()
|
||||
|
@ -55,7 +55,7 @@ suite "State Validation - validateTrieProof":
|
|||
rootHash = trie.rootHash()
|
||||
key = getKeyBytes(numValues + 1)
|
||||
proof = trie.getTrieProof(key)
|
||||
res = validateTrieProof(rootHash, key.asNibbles(), proof, true)
|
||||
res = validateTrieProof(Opt.some(rootHash), key.asNibbles(), proof, true)
|
||||
|
||||
check:
|
||||
res.isErr()
|
||||
|
@ -68,7 +68,7 @@ suite "State Validation - validateTrieProof":
|
|||
rootHash = trie.rootHash()
|
||||
key = "not-exist".toBytes
|
||||
proof = trie.getTrieProof(key)
|
||||
res = validateTrieProof(rootHash, key.asNibbles(), proof, true)
|
||||
res = validateTrieProof(Opt.some(rootHash), key.asNibbles(), proof, true)
|
||||
|
||||
check:
|
||||
res.isErr()
|
||||
|
@ -83,7 +83,7 @@ suite "State Validation - validateTrieProof":
|
|||
let
|
||||
rootHash = trie.rootHash
|
||||
proof = trie.getTrieProof(key)
|
||||
res = validateTrieProof(rootHash, key.asNibbles(), proof, true)
|
||||
res = validateTrieProof(Opt.some(rootHash), key.asNibbles(), proof, true)
|
||||
|
||||
check:
|
||||
res.isOk()
|
||||
|
@ -101,25 +101,25 @@ suite "State Validation - validateTrieProof":
|
|||
let
|
||||
key = "doe".toBytes
|
||||
proof = trie.getTrieProof(key)
|
||||
check validateTrieProof(rootHash, key.asNibbles(), proof, true).isOk()
|
||||
check validateTrieProof(Opt.some(rootHash), key.asNibbles(), proof, true).isOk()
|
||||
|
||||
block:
|
||||
let
|
||||
key = "dog".toBytes
|
||||
proof = trie.getTrieProof(key)
|
||||
check validateTrieProof(rootHash, key.asNibbles(), proof, true).isOk()
|
||||
check validateTrieProof(Opt.some(rootHash), key.asNibbles(), proof, true).isOk()
|
||||
|
||||
block:
|
||||
let
|
||||
key = "dogglesworth".toBytes
|
||||
proof = trie.getTrieProof(key)
|
||||
check validateTrieProof(rootHash, key.asNibbles(), proof, true).isOk()
|
||||
check validateTrieProof(Opt.some(rootHash), key.asNibbles(), proof, true).isOk()
|
||||
|
||||
block:
|
||||
let
|
||||
key = "dogg".toBytes
|
||||
proof = trie.getTrieProof(key)
|
||||
res = validateTrieProof(rootHash, key.asNibbles(), proof, true)
|
||||
res = validateTrieProof(Opt.some(rootHash), key.asNibbles(), proof, true)
|
||||
check:
|
||||
res.isErr()
|
||||
res.error() == "not enough nibbles to validate node prefix"
|
||||
|
@ -128,7 +128,7 @@ suite "State Validation - validateTrieProof":
|
|||
let
|
||||
key = "dogz".toBytes
|
||||
proof = trie.getTrieProof(key)
|
||||
res = validateTrieProof(rootHash, key.asNibbles(), proof, true)
|
||||
res = validateTrieProof(Opt.some(rootHash), key.asNibbles(), proof, true)
|
||||
check:
|
||||
res.isErr()
|
||||
res.error() == "path contains more nibbles than expected for proof"
|
||||
|
@ -137,7 +137,7 @@ suite "State Validation - validateTrieProof":
|
|||
let
|
||||
key = "doe".toBytes
|
||||
proof = newSeq[seq[byte]]().asTrieProof()
|
||||
res = validateTrieProof(rootHash, key.asNibbles(), proof, true)
|
||||
res = validateTrieProof(Opt.some(rootHash), key.asNibbles(), proof, true)
|
||||
check:
|
||||
res.isErr()
|
||||
res.error() == "proof is empty"
|
||||
|
@ -146,7 +146,7 @@ suite "State Validation - validateTrieProof":
|
|||
let
|
||||
key = "doe".toBytes
|
||||
proof = @["aaa".toBytes, "ccc".toBytes].asTrieProof()
|
||||
res = validateTrieProof(rootHash, key.asNibbles(), proof, true)
|
||||
res = validateTrieProof(Opt.some(rootHash), key.asNibbles(), proof, true)
|
||||
check:
|
||||
res.isErr()
|
||||
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
|
||||
|
||||
check:
|
||||
validateTrieProof(rootHash, kv1.asNibbles(), trie.getTrieProof(kv1), true).isOk()
|
||||
validateTrieProof(rootHash, kv2.asNibbles(), trie.getTrieProof(kv2), false).isOk()
|
||||
validateTrieProof(rootHash, kv3.asNibbles(), trie.getTrieProof(kv3), true).isOk()
|
||||
validateTrieProof(rootHash, kv4.asNibbles(), trie.getTrieProof(kv4), false).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(
|
||||
Opt.some(rootHash), kv1.asNibbles(), trie.getTrieProof(kv1), true
|
||||
)
|
||||
.isOk()
|
||||
|
||||
validateTrieProof(rootHash, kv9.asNibbles(), trie.getTrieProof(kv9)).isErr()
|
||||
validateTrieProof(rootHash, kv10.asNibbles(), trie.getTrieProof(kv10)).isErr()
|
||||
validateTrieProof(rootHash, kv11.asNibbles(), trie.getTrieProof(kv11)).isErr()
|
||||
validateTrieProof(rootHash, kv12.asNibbles(), trie.getTrieProof(kv12)).isErr()
|
||||
validateTrieProof(rootHash, kv13.asNibbles(), trie.getTrieProof(kv13)).isErr()
|
||||
validateTrieProof(
|
||||
Opt.some(rootHash), kv2.asNibbles(), trie.getTrieProof(kv2), false
|
||||
)
|
||||
.isOk()
|
||||
|
||||
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()
|
||||
|
||||
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()
|
||||
|
|
|
@ -144,7 +144,9 @@ suite "State Validation - Test Vectors":
|
|||
AccountTrieNodeOffer.decode(testData.content_value_offer.hexToSeqByte()).get()
|
||||
|
||||
check:
|
||||
validateOffer(stateRoot, contentKey.accountTrieNodeKey, contentValueOffer)
|
||||
validateOffer(
|
||||
Opt.some(stateRoot), contentKey.accountTrieNodeKey, contentValueOffer
|
||||
)
|
||||
.isOk()
|
||||
|
||||
if i == 1:
|
||||
|
@ -158,7 +160,10 @@ suite "State Validation - Test Vectors":
|
|||
.get()
|
||||
|
||||
check:
|
||||
validateOffer(stateRoot, contentKey.accountTrieNodeKey, contentValueOffer).isOk()
|
||||
validateOffer(
|
||||
Opt.some(stateRoot), contentKey.accountTrieNodeKey, contentValueOffer
|
||||
)
|
||||
.isOk()
|
||||
|
||||
test "Validate invalid AccountTrieNodeOffer nodes - bad state roots":
|
||||
const file = testVectorDir / "account_trie_node.yaml"
|
||||
|
@ -179,8 +184,9 @@ suite "State Validation - Test Vectors":
|
|||
let contentValueOffer =
|
||||
AccountTrieNodeOffer.decode(testData.content_value_offer.hexToSeqByte()).get()
|
||||
|
||||
let res =
|
||||
validateOffer(stateRoot, contentKey.accountTrieNodeKey, contentValueOffer)
|
||||
let res = validateOffer(
|
||||
Opt.some(stateRoot), contentKey.accountTrieNodeKey, contentValueOffer
|
||||
)
|
||||
check:
|
||||
res.isErr()
|
||||
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
|
||||
|
||||
let res =
|
||||
validateOffer(stateRoot, contentKey.accountTrieNodeKey, contentValueOffer)
|
||||
let res = validateOffer(
|
||||
Opt.some(stateRoot), contentKey.accountTrieNodeKey, contentValueOffer
|
||||
)
|
||||
check:
|
||||
res.isErr()
|
||||
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
|
||||
|
||||
let res =
|
||||
validateOffer(stateRoot, contentKey.accountTrieNodeKey, contentValueOffer)
|
||||
let res = validateOffer(
|
||||
Opt.some(stateRoot), contentKey.accountTrieNodeKey, contentValueOffer
|
||||
)
|
||||
check:
|
||||
res.isErr()
|
||||
"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
|
||||
|
||||
let res =
|
||||
validateOffer(stateRoot, contentKey.accountTrieNodeKey, contentValueOffer)
|
||||
let res = validateOffer(
|
||||
Opt.some(stateRoot), contentKey.accountTrieNodeKey, contentValueOffer
|
||||
)
|
||||
check:
|
||||
res.isErr()
|
||||
|
||||
|
@ -259,7 +268,9 @@ suite "State Validation - Test Vectors":
|
|||
.get()
|
||||
|
||||
check:
|
||||
validateOffer(stateRoot, contentKey.contractTrieNodeKey, contentValueOffer)
|
||||
validateOffer(
|
||||
Opt.some(stateRoot), contentKey.contractTrieNodeKey, contentValueOffer
|
||||
)
|
||||
.isOk()
|
||||
|
||||
if i == 1:
|
||||
|
@ -273,7 +284,10 @@ suite "State Validation - Test Vectors":
|
|||
.get()
|
||||
|
||||
check:
|
||||
validateOffer(stateRoot, contentKey.contractTrieNodeKey, contentValueOffer).isOk()
|
||||
validateOffer(
|
||||
Opt.some(stateRoot), contentKey.contractTrieNodeKey, contentValueOffer
|
||||
)
|
||||
.isOk()
|
||||
|
||||
test "Validate invalid ContractTrieNodeOffer nodes - bad state roots":
|
||||
const file = testVectorDir / "contract_storage_trie_node.yaml"
|
||||
|
@ -293,8 +307,9 @@ suite "State Validation - Test Vectors":
|
|||
let contentValueOffer =
|
||||
ContractTrieNodeOffer.decode(testData.content_value_offer.hexToSeqByte()).get()
|
||||
|
||||
let res =
|
||||
validateOffer(stateRoot, contentKey.contractTrieNodeKey, contentValueOffer)
|
||||
let res = validateOffer(
|
||||
Opt.some(stateRoot), contentKey.contractTrieNodeKey, contentValueOffer
|
||||
)
|
||||
check:
|
||||
res.isErr()
|
||||
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
|
||||
|
||||
let res =
|
||||
validateOffer(stateRoot, contentKey.contractTrieNodeKey, contentValueOffer)
|
||||
let res = validateOffer(
|
||||
Opt.some(stateRoot), contentKey.contractTrieNodeKey, contentValueOffer
|
||||
)
|
||||
check:
|
||||
res.isErr()
|
||||
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
|
||||
|
||||
let res =
|
||||
validateOffer(stateRoot, contentKey.contractTrieNodeKey, contentValueOffer)
|
||||
let res = validateOffer(
|
||||
Opt.some(stateRoot), contentKey.contractTrieNodeKey, contentValueOffer
|
||||
)
|
||||
check:
|
||||
res.isErr()
|
||||
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
|
||||
|
||||
check:
|
||||
validateOffer(stateRoot, contentKey.contractTrieNodeKey, contentValueOffer)
|
||||
validateOffer(
|
||||
Opt.some(stateRoot), contentKey.contractTrieNodeKey, contentValueOffer
|
||||
)
|
||||
.isErr()
|
||||
|
||||
block:
|
||||
|
@ -361,7 +380,9 @@ suite "State Validation - Test Vectors":
|
|||
contentValueOffer.storageProof[^1][^1] += 1.byte
|
||||
|
||||
check:
|
||||
validateOffer(stateRoot, contentKey.contractTrieNodeKey, contentValueOffer)
|
||||
validateOffer(
|
||||
Opt.some(stateRoot), contentKey.contractTrieNodeKey, contentValueOffer
|
||||
)
|
||||
.isErr()
|
||||
|
||||
block:
|
||||
|
@ -374,7 +395,9 @@ suite "State Validation - Test Vectors":
|
|||
contentValueOffer.accountProof[^2][^2] += 1.byte
|
||||
|
||||
check:
|
||||
validateOffer(stateRoot, contentKey.contractTrieNodeKey, contentValueOffer)
|
||||
validateOffer(
|
||||
Opt.some(stateRoot), contentKey.contractTrieNodeKey, contentValueOffer
|
||||
)
|
||||
.isErr()
|
||||
|
||||
# Contract bytecode offer validation tests
|
||||
|
@ -394,7 +417,10 @@ suite "State Validation - Test Vectors":
|
|||
ContractCodeOffer.decode(testData.content_value_offer.hexToSeqByte()).get()
|
||||
|
||||
check:
|
||||
validateOffer(stateRoot, contentKey.contractCodeKey, contentValueOffer).isOk()
|
||||
validateOffer(
|
||||
Opt.some(stateRoot), contentKey.contractCodeKey, contentValueOffer
|
||||
)
|
||||
.isOk()
|
||||
|
||||
test "Validate invalid ContractCodeOffer nodes - bad state root":
|
||||
const file = testVectorDir / "contract_bytecode.yaml"
|
||||
|
@ -412,7 +438,9 @@ suite "State Validation - Test Vectors":
|
|||
let contentValueOffer =
|
||||
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:
|
||||
res.isErr()
|
||||
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
|
||||
|
||||
let res =
|
||||
validateOffer(stateRoot, contentKey.contractCodeKey, contentValueOffer)
|
||||
let res = validateOffer(
|
||||
Opt.some(stateRoot), contentKey.contractCodeKey, contentValueOffer
|
||||
)
|
||||
check:
|
||||
res.isErr()
|
||||
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
|
||||
|
||||
let res =
|
||||
validateOffer(stateRoot, contentKey.contractCodeKey, contentValueOffer)
|
||||
let res = validateOffer(
|
||||
Opt.some(stateRoot), contentKey.contractCodeKey, contentValueOffer
|
||||
)
|
||||
check:
|
||||
res.isErr()
|
||||
res.error() ==
|
||||
|
@ -464,7 +494,10 @@ suite "State Validation - Test Vectors":
|
|||
contentValueOffer.accountProof[^1][^1] += 1.byte
|
||||
|
||||
check:
|
||||
validateOffer(stateRoot, contentKey.contractCodeKey, contentValueOffer).isErr()
|
||||
validateOffer(
|
||||
Opt.some(stateRoot), contentKey.contractCodeKey, contentValueOffer
|
||||
)
|
||||
.isErr()
|
||||
|
||||
block:
|
||||
let contentKey =
|
||||
|
@ -474,8 +507,9 @@ suite "State Validation - Test Vectors":
|
|||
|
||||
contentValueOffer.code[^1] += 1.byte
|
||||
|
||||
let res =
|
||||
validateOffer(stateRoot, contentKey.contractCodeKey, contentValueOffer)
|
||||
let res = validateOffer(
|
||||
Opt.some(stateRoot), contentKey.contractCodeKey, contentValueOffer
|
||||
)
|
||||
check:
|
||||
res.isErr()
|
||||
res.error() ==
|
||||
|
@ -506,7 +540,9 @@ suite "State Validation - Test Vectors":
|
|||
AccountTrieNodeOffer.decode(kv.content_value.hexToSeqByte()).get()
|
||||
|
||||
check:
|
||||
validateOffer(stateRoot, contentKey.accountTrieNodeKey, contentValueOffer)
|
||||
validateOffer(
|
||||
Opt.some(stateRoot), contentKey.accountTrieNodeKey, contentValueOffer
|
||||
)
|
||||
.isOk()
|
||||
|
||||
test "Validate valid ContractTrieNodeOffer recursive gossip nodes":
|
||||
|
@ -527,5 +563,7 @@ suite "State Validation - Test Vectors":
|
|||
ContractTrieNodeOffer.decode(kv.content_value.hexToSeqByte()).get()
|
||||
|
||||
check:
|
||||
validateOffer(stateRoot, contentKey.contractTrieNodeKey, contentValueOffer)
|
||||
validateOffer(
|
||||
Opt.some(stateRoot), contentKey.contractTrieNodeKey, contentValueOffer
|
||||
)
|
||||
.isOk()
|
||||
|
|
Loading…
Reference in New Issue