Add retrieval content validation to state network. (#2166)
* Add retrieval content validation to state network. * Complete state validation tests for retrieval content. * Improve naming functions and parameters.
This commit is contained in:
parent
143f2e99f5
commit
5c4358a969
|
@ -239,7 +239,7 @@ func packNibbles*(nibbles: seq[byte]): Nibbles =
|
|||
func unpackNibbles*(nibbles: Nibbles): seq[byte] =
|
||||
doAssert(nibbles.len() <= MAX_PACKED_NIBBLES_LEN, "Packed nibbles length is too long")
|
||||
|
||||
var output = newSeqOfCap[byte](nibbles.len * 2)
|
||||
var output = newSeqOfCap[byte](nibbles.len() * 2)
|
||||
|
||||
for i, pair in nibbles:
|
||||
if i == 0 and pair == 0x00:
|
||||
|
|
|
@ -14,7 +14,8 @@ import
|
|||
eth/p2p/discoveryv5/[protocol, enr],
|
||||
../../database/content_db,
|
||||
../wire/[portal_protocol, portal_stream, portal_protocol_config],
|
||||
./state_content
|
||||
./state_content,
|
||||
./state_validation
|
||||
|
||||
logScope:
|
||||
topics = "portal_state"
|
||||
|
@ -79,34 +80,25 @@ func decodeValue*(
|
|||
|
||||
Opt.some(value)
|
||||
|
||||
proc validateAccountTrieNode(
|
||||
n: StateNetwork, key: ContentKey, contentValue: RetrievalContentValue
|
||||
): bool =
|
||||
true
|
||||
|
||||
proc validateContractTrieNode(
|
||||
n: StateNetwork, key: ContentKey, contentValue: RetrievalContentValue
|
||||
): bool =
|
||||
true
|
||||
|
||||
proc validateContractCode(
|
||||
n: StateNetwork, key: ContentKey, contentValue: RetrievalContentValue
|
||||
): bool =
|
||||
true
|
||||
|
||||
proc validateContent*(
|
||||
n: StateNetwork, contentKey: ContentKey, contentValue: RetrievalContentValue
|
||||
): bool =
|
||||
doAssert(contentKey.contentType == contentValue.contentType)
|
||||
|
||||
case contentKey.contentType
|
||||
of unused:
|
||||
warn "Received content with unused content type"
|
||||
false
|
||||
of accountTrieNode:
|
||||
validateAccountTrieNode(n, contentKey, contentValue)
|
||||
validateFetchedAccountTrieNode(
|
||||
contentKey.accountTrieNodeKey, contentValue.accountTrieNode
|
||||
)
|
||||
of contractTrieNode:
|
||||
validateContractTrieNode(n, contentKey, contentValue)
|
||||
validateFetchedContractTrieNode(
|
||||
contentKey.contractTrieNodeKey, contentValue.contractTrieNode
|
||||
)
|
||||
of contractCode:
|
||||
validateContractCode(n, contentKey, contentValue)
|
||||
validateFetchedContractCode(contentKey.contractCodeKey, contentValue.contractCode)
|
||||
|
||||
proc getContent*(n: StateNetwork, key: ContentKey): Future[Opt[seq[byte]]] {.async.} =
|
||||
let
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
# Fluffy
|
||||
# Copyright (c) 2024 Status Research & Development GmbH
|
||||
# Licensed and distributed under either of
|
||||
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
|
||||
# * 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.
|
||||
|
||||
import eth/common, ./state_content
|
||||
|
||||
proc validateFetchedAccountTrieNode*(
|
||||
trustedAccountTrieNodeKey: AccountTrieNodeKey,
|
||||
accountTrieNode: AccountTrieNodeRetrieval,
|
||||
): bool =
|
||||
let expectedHash = trustedAccountTrieNodeKey.nodeHash
|
||||
let actualHash = keccakHash(accountTrieNode.node.asSeq())
|
||||
|
||||
expectedHash == actualHash
|
||||
|
||||
proc validateFetchedContractTrieNode*(
|
||||
trustedContractTrieNodeKey: ContractTrieNodeKey,
|
||||
contractTrieNode: ContractTrieNodeRetrieval,
|
||||
): bool =
|
||||
let expectedHash = trustedContractTrieNodeKey.nodeHash
|
||||
let actualHash = keccakHash(contractTrieNode.node.asSeq())
|
||||
|
||||
expectedHash == actualHash
|
||||
|
||||
proc validateFetchedContractCode*(
|
||||
trustedContractCodeKey: ContractCodeKey, contractCode: ContractCodeRetrieval
|
||||
): bool =
|
||||
let expectedHash = trustedContractCodeKey.codeHash
|
||||
let actualHash = keccakHash(contractCode.code.asSeq())
|
||||
|
||||
expectedHash == actualHash
|
|
@ -0,0 +1,143 @@
|
|||
# Fluffy
|
||||
# Copyright (c) 2023-2024 Status Research & Development GmbH
|
||||
# Licensed and distributed under either of
|
||||
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
|
||||
# * 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.
|
||||
|
||||
import
|
||||
std/os,
|
||||
unittest2,
|
||||
stew/byteutils,
|
||||
../../network/state/state_content,
|
||||
../../network/state/state_validation,
|
||||
../../eth_data/yaml_utils
|
||||
|
||||
const testVectorDir = "./vendor/portal-spec-tests/tests/mainnet/state/validation/"
|
||||
|
||||
type YamlTrieNodeRecursiveGossipKV = ref object
|
||||
content_key: string
|
||||
content_value_offer: string
|
||||
content_value_retrieval: string
|
||||
|
||||
type YamlTrieNodeKV = object
|
||||
content_key: string
|
||||
content_value_offer: string
|
||||
content_value_retrieval: string
|
||||
recursive_gossip: YamlTrieNodeRecursiveGossipKV
|
||||
|
||||
type YamlTrieNodeKVs = seq[YamlTrieNodeKV]
|
||||
|
||||
type YamlContractBytecodeKV = object
|
||||
content_key: string
|
||||
content_value_offer: string
|
||||
content_value_retrieval: string
|
||||
|
||||
type YamlContractBytecodeKVs = seq[YamlContractBytecodeKV]
|
||||
|
||||
suite "State Validation":
|
||||
test "Validate valid AccountTrieNodeRetrieval nodes":
|
||||
const file = testVectorDir / "account_trie_node.yaml"
|
||||
|
||||
let testCase = YamlTrieNodeKVs.loadFromYaml(file).valueOr:
|
||||
raiseAssert "Cannot read test vector: " & error
|
||||
|
||||
for testData in testCase:
|
||||
let contentKey = decode(testData.content_key.hexToSeqByte().ByteList).get()
|
||||
let contentValueRetrieval = SSZ.decode(
|
||||
testData.content_value_retrieval.hexToSeqByte(), AccountTrieNodeRetrieval
|
||||
)
|
||||
|
||||
check:
|
||||
validateFetchedAccountTrieNode(
|
||||
contentKey.accountTrieNodeKey, contentValueRetrieval
|
||||
)
|
||||
|
||||
test "Validate invalid AccountTrieNodeRetrieval nodes":
|
||||
const file = testVectorDir / "account_trie_node.yaml"
|
||||
|
||||
let testCase = YamlTrieNodeKVs.loadFromYaml(file).valueOr:
|
||||
raiseAssert "Cannot read test vector: " & error
|
||||
|
||||
for testData in testCase:
|
||||
let contentKey = decode(testData.content_key.hexToSeqByte().ByteList).get()
|
||||
var contentValueRetrieval = SSZ.decode(
|
||||
testData.content_value_retrieval.hexToSeqByte(), AccountTrieNodeRetrieval
|
||||
)
|
||||
|
||||
contentValueRetrieval.node[^1] += 1 # Modify node hash
|
||||
|
||||
check:
|
||||
not validateFetchedAccountTrieNode(
|
||||
contentKey.accountTrieNodeKey, contentValueRetrieval
|
||||
)
|
||||
|
||||
test "Validate valid ContractTrieNodeRetrieval nodes":
|
||||
const file = testVectorDir / "contract_storage_trie_node.yaml"
|
||||
|
||||
let testCase = YamlTrieNodeKVs.loadFromYaml(file).valueOr:
|
||||
raiseAssert "Cannot read test vector: " & error
|
||||
|
||||
for testData in testCase:
|
||||
let contentKey = decode(testData.content_key.hexToSeqByte().ByteList).get()
|
||||
let contentValueRetrieval = SSZ.decode(
|
||||
testData.content_value_retrieval.hexToSeqByte(), ContractTrieNodeRetrieval
|
||||
)
|
||||
|
||||
check:
|
||||
validateFetchedContractTrieNode(
|
||||
contentKey.contractTrieNodeKey, contentValueRetrieval
|
||||
)
|
||||
|
||||
test "Validate invalid ContractTrieNodeRetrieval nodes":
|
||||
const file = testVectorDir / "contract_storage_trie_node.yaml"
|
||||
|
||||
let testCase = YamlTrieNodeKVs.loadFromYaml(file).valueOr:
|
||||
raiseAssert "Cannot read test vector: " & error
|
||||
|
||||
for testData in testCase:
|
||||
let contentKey = decode(testData.content_key.hexToSeqByte().ByteList).get()
|
||||
var contentValueRetrieval = SSZ.decode(
|
||||
testData.content_value_retrieval.hexToSeqByte(), ContractTrieNodeRetrieval
|
||||
)
|
||||
|
||||
contentValueRetrieval.node[^1] += 1 # Modify node hash
|
||||
|
||||
check:
|
||||
not validateFetchedContractTrieNode(
|
||||
contentKey.contractTrieNodeKey, contentValueRetrieval
|
||||
)
|
||||
|
||||
test "Validate valid ContractCodeRetrieval nodes":
|
||||
const file = testVectorDir / "contract_bytecode.yaml"
|
||||
|
||||
let testCase = YamlContractBytecodeKVs.loadFromYaml(file).valueOr:
|
||||
raiseAssert "Cannot read test vector: " & error
|
||||
|
||||
for testData in testCase:
|
||||
let contentKey = decode(testData.content_key.hexToSeqByte().ByteList).get()
|
||||
let contentValueRetrieval = SSZ.decode(
|
||||
testData.content_value_retrieval.hexToSeqByte(), ContractCodeRetrieval
|
||||
)
|
||||
|
||||
check:
|
||||
validateFetchedContractCode(contentKey.contractCodeKey, contentValueRetrieval)
|
||||
|
||||
test "Validate invalid ContractCodeRetrieval nodes":
|
||||
const file = testVectorDir / "contract_bytecode.yaml"
|
||||
|
||||
let testCase = YamlContractBytecodeKVs.loadFromYaml(file).valueOr:
|
||||
raiseAssert "Cannot read test vector: " & error
|
||||
|
||||
for testData in testCase:
|
||||
let contentKey = decode(testData.content_key.hexToSeqByte().ByteList).get()
|
||||
var contentValueRetrieval = SSZ.decode(
|
||||
testData.content_value_retrieval.hexToSeqByte(), ContractCodeRetrieval
|
||||
)
|
||||
|
||||
contentValueRetrieval.code[^1] += 1 # Modify node hash
|
||||
|
||||
check:
|
||||
not validateFetchedContractCode(
|
||||
contentKey.contractCodeKey, contentValueRetrieval
|
||||
)
|
Loading…
Reference in New Issue