state network test vectors update (#2003)
* state network test vectors update * nibbles codec * moving test vectors into portal-spec-tests * fix copyright year in all_fluffy_tests
This commit is contained in:
parent
f1e9ca8526
commit
9c53c73173
|
@ -18,6 +18,14 @@ import
|
||||||
|
|
||||||
export ssz_serialization, common_types, hash, results
|
export ssz_serialization, common_types, hash, results
|
||||||
|
|
||||||
|
const
|
||||||
|
MAX_PACKED_NIBBLES_LEN = 32
|
||||||
|
MAX_UNPACKED_NIBBLES_LEN = 64
|
||||||
|
|
||||||
|
MAX_TRIE_NODE_LEN = 1024
|
||||||
|
MAX_TRIE_PROOF_LEN = 65
|
||||||
|
MAX_BYTECODE_LEN = 32768
|
||||||
|
|
||||||
type
|
type
|
||||||
NodeHash* = KeccakHash
|
NodeHash* = KeccakHash
|
||||||
CodeHash* = KeccakHash
|
CodeHash* = KeccakHash
|
||||||
|
@ -39,19 +47,12 @@ type
|
||||||
NibblePair* = byte
|
NibblePair* = byte
|
||||||
Nibbles* = object
|
Nibbles* = object
|
||||||
isOddLength*: bool
|
isOddLength*: bool
|
||||||
packedNibbles*: List[NibblePair, 32]
|
packedNibbles*: List[NibblePair, MAX_PACKED_NIBBLES_LEN]
|
||||||
|
|
||||||
WitnessNode* = List[byte, 1024]
|
TrieNode* = List[byte, MAX_TRIE_NODE_LEN]
|
||||||
Witness* = List[WitnessNode, 1024]
|
TrieProof* = List[TrieNode, MAX_TRIE_PROOF_LEN]
|
||||||
|
|
||||||
StateWitness* = object
|
Bytecode* = List[byte, MAX_BYTECODE_LEN]
|
||||||
key*: Nibbles
|
|
||||||
proof*: Witness
|
|
||||||
|
|
||||||
StorageWitness* = object
|
|
||||||
key*: Nibbles
|
|
||||||
proof*: Witness
|
|
||||||
stateWitness*: StateWitness
|
|
||||||
|
|
||||||
AccountTrieNodeKey* = object
|
AccountTrieNodeKey* = object
|
||||||
path*: Nibbles
|
path*: Nibbles
|
||||||
|
@ -78,26 +79,27 @@ type
|
||||||
contractCodeKey*: ContractCodeKey
|
contractCodeKey*: ContractCodeKey
|
||||||
|
|
||||||
AccountTrieNodeOffer* = object
|
AccountTrieNodeOffer* = object
|
||||||
proof*: StateWitness
|
proof*: TrieProof
|
||||||
blockHash*: BlockHash
|
blockHash*: BlockHash
|
||||||
|
|
||||||
AccountTrieNodeRetrieval* = object
|
AccountTrieNodeRetrieval* = object
|
||||||
node*: WitnessNode
|
node*: TrieNode
|
||||||
|
|
||||||
ContractTrieNodeOffer* = object
|
ContractTrieNodeOffer* = object
|
||||||
proof*: StorageWitness
|
storageProof*: TrieProof
|
||||||
|
accountProof*: TrieProof
|
||||||
blockHash*: BlockHash
|
blockHash*: BlockHash
|
||||||
|
|
||||||
ContractTrieNodeRetrieval* = object
|
ContractTrieNodeRetrieval* = object
|
||||||
node*: WitnessNode
|
node*: TrieNode
|
||||||
|
|
||||||
ContractCodeOffer* = object
|
ContractCodeOffer* = object
|
||||||
code*: ByteList
|
code*: Bytecode
|
||||||
accountProof*: StateWitness
|
accountProof*: TrieProof
|
||||||
blockHash*: BlockHash
|
blockHash*: BlockHash
|
||||||
|
|
||||||
ContractCodeRetrieval* = object
|
ContractCodeRetrieval* = object
|
||||||
code*: ByteList
|
code*: Bytecode
|
||||||
|
|
||||||
func encode*(contentKey: ContentKey): ByteList =
|
func encode*(contentKey: ContentKey): ByteList =
|
||||||
doAssert(contentKey.contentType != unused)
|
doAssert(contentKey.contentType != unused)
|
||||||
|
@ -125,3 +127,44 @@ func toContentId*(contentKey: ByteList): ContentId =
|
||||||
|
|
||||||
func toContentId*(contentKey: ContentKey): ContentId =
|
func toContentId*(contentKey: ContentKey): ContentId =
|
||||||
toContentId(encode(contentKey))
|
toContentId(encode(contentKey))
|
||||||
|
|
||||||
|
func packNibbles*(nibbles: seq[byte]): Nibbles =
|
||||||
|
doAssert(nibbles.len() <= MAX_UNPACKED_NIBBLES_LEN, "Can't pack more than 64 nibbles")
|
||||||
|
|
||||||
|
let
|
||||||
|
isOddLength = (nibbles.len() %% 2 == 1)
|
||||||
|
outputLength = (nibbles.len() + 1) div 2
|
||||||
|
|
||||||
|
var
|
||||||
|
output = newSeq[NibblePair]()
|
||||||
|
highNibble = not isOddLength
|
||||||
|
currentByte: byte = 0
|
||||||
|
|
||||||
|
for nibble in nibbles:
|
||||||
|
if highNibble:
|
||||||
|
currentByte = nibble shl 4
|
||||||
|
else:
|
||||||
|
output.add(NibblePair(currentByte or nibble))
|
||||||
|
currentByte = 0
|
||||||
|
highNibble = not highNibble
|
||||||
|
|
||||||
|
Nibbles(isOddLength: isOddLength, packedNibbles: Nibbles.packedNibbles.init(output))
|
||||||
|
|
||||||
|
func unpackNibbles*(nibbles: Nibbles): seq[byte] =
|
||||||
|
doAssert(nibbles.packedNibbles.len() <= MAX_PACKED_NIBBLES_LEN, "Can't unpack more than 32 nibbles")
|
||||||
|
|
||||||
|
var output = newSeq[byte]()
|
||||||
|
|
||||||
|
for pair in nibbles.packedNibbles:
|
||||||
|
let
|
||||||
|
first = (pair and 0xF0) shr 4
|
||||||
|
second = pair and 0x0F
|
||||||
|
|
||||||
|
output.add(first)
|
||||||
|
output.add(second)
|
||||||
|
|
||||||
|
if nibbles.isOddLength:
|
||||||
|
output.delete(0)
|
||||||
|
|
||||||
|
output
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Nimbus
|
# Nimbus
|
||||||
# Copyright (c) 2021-2023 Status Research & Development GmbH
|
# Copyright (c) 2021-2024 Status Research & Development GmbH
|
||||||
# Licensed under either of
|
# Licensed under either of
|
||||||
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
|
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
|
||||||
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
|
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
|
||||||
|
@ -9,7 +9,8 @@
|
||||||
|
|
||||||
import
|
import
|
||||||
./test_portal_wire_protocol,
|
./test_portal_wire_protocol,
|
||||||
./state_network_tests/test_state_content,
|
./state_network_tests/test_state_content_keys,
|
||||||
|
./state_network_tests/test_state_content_values,
|
||||||
./test_state_proof_verification,
|
./test_state_proof_verification,
|
||||||
./test_accumulator,
|
./test_accumulator,
|
||||||
./test_history_network,
|
./test_history_network,
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
# 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
|
||||||
|
../../network/state/state_content
|
||||||
|
|
||||||
|
type JsonBlockInfo* = object
|
||||||
|
number*: uint64
|
||||||
|
block_hash*: string
|
||||||
|
state_root*: string
|
||||||
|
|
||||||
|
type JsonAccount* = object
|
||||||
|
nonce*: string
|
||||||
|
balance*: string
|
||||||
|
storage_hash*: string
|
||||||
|
code_hash*: string
|
||||||
|
|
||||||
|
type JsonBlock* = object
|
||||||
|
`block`*: JsonBlockInfo
|
||||||
|
address*: string
|
||||||
|
account*: JsonAccount
|
||||||
|
storage_slot*: string
|
||||||
|
storage_value*: string
|
||||||
|
account_proof*: seq[string]
|
||||||
|
storage_proof*: seq[string]
|
||||||
|
bytecode*: string
|
||||||
|
|
||||||
|
type JsonAccountTrieNode* = object
|
||||||
|
content_key*: string
|
||||||
|
content_id*: string
|
||||||
|
content_value_offer*: string
|
||||||
|
content_value_retrieval*: string
|
||||||
|
|
||||||
|
type JsonContractStorageTtrieNode* = object
|
||||||
|
content_key*: string
|
||||||
|
content_id*: string
|
||||||
|
content_value_offer*: string
|
||||||
|
content_value_retrieval*: string
|
||||||
|
|
||||||
|
type JsonContractBytecode* = object
|
||||||
|
content_key*: string
|
||||||
|
content_id*: string
|
||||||
|
content_value_offer*: string
|
||||||
|
content_value_retrieval*: string
|
|
@ -1,239 +0,0 @@
|
||||||
# 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
|
|
||||||
testutils/unittests,
|
|
||||||
stew/[byteutils, io2],
|
|
||||||
eth/keys,
|
|
||||||
../../network/state/state_content
|
|
||||||
|
|
||||||
suite "State Content Keys":
|
|
||||||
const evenNibles = "0005000000123456789abc"
|
|
||||||
test "Encode/decode even nibbles":
|
|
||||||
const
|
|
||||||
packedNibbles = Nibbles.packedNibbles.init(@[NibblePair 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC])
|
|
||||||
isOddLength = false
|
|
||||||
|
|
||||||
let
|
|
||||||
nibbles = Nibbles(packedNibbles: packedNibbles, isOddLength: isOddLength)
|
|
||||||
encoded = SSZ.encode(nibbles)
|
|
||||||
check encoded.toHex() == evenNibles
|
|
||||||
# echo ">>>", encoded.toHex()
|
|
||||||
|
|
||||||
const oddNibbles = "0105000000123456789abc0d"
|
|
||||||
test "Encode/decode odd nibbles":
|
|
||||||
const
|
|
||||||
packedNibbles = Nibbles.packedNibbles.init(@[NibblePair 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0x0D])
|
|
||||||
isOddLength = true
|
|
||||||
|
|
||||||
let
|
|
||||||
nibbles = Nibbles(packedNibbles: packedNibbles, isOddLength: isOddLength)
|
|
||||||
encoded = SSZ.encode(nibbles)
|
|
||||||
check encoded.toHex() == oddNibbles
|
|
||||||
# echo ">>>", encoded.toHex()
|
|
||||||
|
|
||||||
const accountTrieNodeKeyEncoded = "2024000000c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4700005000000123456789abc"
|
|
||||||
test "Encode/decode AccountTrieNodeKey":
|
|
||||||
const
|
|
||||||
packedNibbles = Nibbles.packedNibbles.init(@[NibblePair 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC])
|
|
||||||
isOddLength = false
|
|
||||||
nodeHash = NodeHash.fromHex("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470")
|
|
||||||
|
|
||||||
let
|
|
||||||
nibbles = Nibbles(packedNibbles: packedNibbles, isOddLength: isOddLength)
|
|
||||||
accountTrieNodeKey = AccountTrieNodeKey(path: nibbles, nodeHash: nodeHash)
|
|
||||||
contentKey = ContentKey(contentType: accountTrieNode, accountTrieNodeKey: accountTrieNodeKey)
|
|
||||||
encoded = contentKey.encode()
|
|
||||||
# echo ">>>", $encoded
|
|
||||||
check $encoded == accountTrieNodeKeyEncoded
|
|
||||||
|
|
||||||
let decoded = encoded.decode().valueOr:
|
|
||||||
raiseAssert "Cannot decode AccountTrieNodeKey"
|
|
||||||
check:
|
|
||||||
decoded.contentType == accountTrieNode
|
|
||||||
decoded.accountTrieNodeKey == AccountTrieNodeKey(path: nibbles, nodeHash: nodeHash)
|
|
||||||
|
|
||||||
const contractTrieNodeKeyEncoded = "21000d836201318ec6899a6754069038278074328038000000c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4700005000000123456789abc"
|
|
||||||
test "Encode/decode ContractTrieNodeKey":
|
|
||||||
const
|
|
||||||
address = Address.fromHex("000d836201318ec6899a67540690382780743280")
|
|
||||||
packedNibbles = Nibbles.packedNibbles.init(@[NibblePair 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC])
|
|
||||||
isOddLength = false
|
|
||||||
nodeHash = NodeHash.fromHex("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470")
|
|
||||||
|
|
||||||
let
|
|
||||||
nibbles = Nibbles(packedNibbles: (packedNibbles), isOddLength: isOddLength)
|
|
||||||
contractTrieNodeKey = ContractTrieNodeKey(address: address, path: nibbles, nodeHash: nodeHash)
|
|
||||||
contentKey = ContentKey(contentType: contractTrieNode, contractTrieNodeKey: contractTrieNodeKey)
|
|
||||||
encoded = contentKey.encode()
|
|
||||||
# echo ">>>", $encoded
|
|
||||||
check $encoded == contractTrieNodeKeyEncoded
|
|
||||||
|
|
||||||
let decoded = encoded.decode().valueOr:
|
|
||||||
raiseAssert "Cannot decode ContractTrieNodeKey"
|
|
||||||
check:
|
|
||||||
decoded.contentType == contractTrieNode
|
|
||||||
decoded.contractTrieNodeKey == ContractTrieNodeKey(address: address, path: nibbles, nodeHash: nodeHash)
|
|
||||||
|
|
||||||
const contractCodeKeyEncoded = "22000d836201318ec6899a67540690382780743280c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"
|
|
||||||
test "Encode/decode ContractCodeKey":
|
|
||||||
const
|
|
||||||
address = Address.fromHex("000d836201318ec6899a67540690382780743280")
|
|
||||||
codeHash = CodeHash.fromHex("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470")
|
|
||||||
|
|
||||||
let
|
|
||||||
contractCodeKey = ContractCodeKey(address: address, codeHash: codeHash)
|
|
||||||
contentKey = ContentKey(contentType: contractCode, contractCodeKey: contractCodeKey)
|
|
||||||
encoded = contentKey.encode()
|
|
||||||
# echo ">>>", $encoded
|
|
||||||
check $encoded == contractCodeKeyEncoded
|
|
||||||
|
|
||||||
let decoded = encoded.decode().valueOr:
|
|
||||||
raiseAssert "Cannot decode ContractCodeKey"
|
|
||||||
check:
|
|
||||||
decoded.contentType == contractCode
|
|
||||||
decoded.contractCodeKey.address == address
|
|
||||||
decoded.contractCodeKey.codeHash == codeHash
|
|
||||||
|
|
||||||
test "Invalid prefix - 0 value":
|
|
||||||
let encoded = ByteList.init(@[byte 0x00])
|
|
||||||
let decoded = decode(encoded)
|
|
||||||
|
|
||||||
check decoded.isNone()
|
|
||||||
|
|
||||||
test "Invalid prefix - before valid range":
|
|
||||||
let encoded = ByteList.init(@[byte 0x01])
|
|
||||||
let decoded = decode(encoded)
|
|
||||||
|
|
||||||
check decoded.isNone()
|
|
||||||
|
|
||||||
test "Invalid prefix - after valid range":
|
|
||||||
let encoded = ByteList.init(@[byte 0x25])
|
|
||||||
let decoded = decode(encoded)
|
|
||||||
|
|
||||||
check decoded.isNone()
|
|
||||||
|
|
||||||
test "Invalid key - empty input":
|
|
||||||
let encoded = ByteList.init(@[])
|
|
||||||
let decoded = decode(encoded)
|
|
||||||
|
|
||||||
check decoded.isNone()
|
|
||||||
|
|
||||||
suite "State Content Values":
|
|
||||||
const accountTrieNodeOfferEncoded = "24000000d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa308000000130000000005000000123456789abc04000000010203040506"
|
|
||||||
test "Encode/decode AccountTrieNodeOffer":
|
|
||||||
let
|
|
||||||
blockHash = "d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3"
|
|
||||||
packedNibbles = @[NibblePair 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC]
|
|
||||||
isOddLength = false
|
|
||||||
key = Nibbles(packedNibbles: Nibbles.packedNibbles.init(packedNibbles), isOddLength: isOddLength)
|
|
||||||
witnessNode = WitnessNode(@[byte 0x01, 0x02, 0x03, 0x04, 0x05, 0x06])
|
|
||||||
proof = Witness(@[witnessNode])
|
|
||||||
|
|
||||||
accountTrieNodeOffer = AccountTrieNodeOffer(blockHash: BlockHash.fromHex(blockHash), proof: StateWitness(key: key, proof: proof))
|
|
||||||
encoded = SSZ.encode(accountTrieNodeOffer)
|
|
||||||
# echo ">>>", encoded.toHex()
|
|
||||||
check encoded.toHex() == accountTrieNodeOfferEncoded
|
|
||||||
|
|
||||||
let decoded = SSZ.decode(encoded, AccountTrieNodeOffer)
|
|
||||||
check:
|
|
||||||
decoded.blockHash == BlockHash.fromHex(blockHash)
|
|
||||||
decoded.proof == StateWitness(key: key, proof: proof)
|
|
||||||
|
|
||||||
const accountTrieNodeRetrievalEncoded = "04000000010203040506"
|
|
||||||
test "Encode/decode AccountTrieNodeRetrieval":
|
|
||||||
let
|
|
||||||
witnessNode = WitnessNode(@[byte 0x01, 0x02, 0x03, 0x04, 0x05, 0x06])
|
|
||||||
|
|
||||||
accountTrieNodeRetrieval = AccountTrieNodeRetrieval(node: witnessNode)
|
|
||||||
encoded = SSZ.encode(accountTrieNodeRetrieval)
|
|
||||||
# echo ">>>", encoded.toHex()
|
|
||||||
check encoded.toHex() == accountTrieNodeRetrievalEncoded
|
|
||||||
|
|
||||||
let decoded = SSZ.decode(encoded, AccountTrieNodeRetrieval)
|
|
||||||
check decoded.node == witnessNode
|
|
||||||
|
|
||||||
const contractTrieNodeOfferEncoded = "24000000d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa30c00000017000000220000000005000000123456789abc040000000102030405060708000000150000000005000000123456789abcdef104000000010203040506070809"
|
|
||||||
test "Encode/decode ContractTrieNodeOffer":
|
|
||||||
let
|
|
||||||
blockHash = "d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3"
|
|
||||||
contractWitnessKeyPackedNibbles = @[NibblePair 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC]
|
|
||||||
contractWitnessProof = Witness(@[WitnessNode(@[byte 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07])])
|
|
||||||
stateWitnessKeyPackedNibbles = @[NibblePair 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF1]
|
|
||||||
stateWitnessProof = Witness(@[WitnessNode(@[byte 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09])])
|
|
||||||
|
|
||||||
contractTrieNodeOffer = ContractTrieNodeOffer(
|
|
||||||
blockHash: BlockHash.fromHex(blockHash),
|
|
||||||
proof: StorageWitness(
|
|
||||||
key: Nibbles(packedNibbles: Nibbles.packedNibbles.init(contractWitnessKeyPackedNibbles), isOddLength: false),
|
|
||||||
proof: contractWitnessProof,
|
|
||||||
stateWitness: StateWitness(
|
|
||||||
key: Nibbles(packedNibbles: Nibbles.packedNibbles.init(stateWitnessKeyPackedNibbles), isOddLength: false),
|
|
||||||
proof: stateWitnessProof
|
|
||||||
)))
|
|
||||||
encoded = SSZ.encode(contractTrieNodeOffer)
|
|
||||||
# echo ">>>", encoded.toHex()
|
|
||||||
check encoded.toHex() == contractTrieNodeOfferEncoded
|
|
||||||
|
|
||||||
let decoded = SSZ.decode(encoded, ContractTrieNodeOffer)
|
|
||||||
check:
|
|
||||||
decoded.blockHash == BlockHash.fromHex(blockHash)
|
|
||||||
decoded.proof == StorageWitness(
|
|
||||||
key: Nibbles(packedNibbles: Nibbles.packedNibbles.init(contractWitnessKeyPackedNibbles), isOddLength: false),
|
|
||||||
proof: contractWitnessProof,
|
|
||||||
stateWitness: StateWitness(
|
|
||||||
key: Nibbles(packedNibbles: Nibbles.packedNibbles.init(stateWitnessKeyPackedNibbles), isOddLength: false),
|
|
||||||
proof: stateWitnessProof
|
|
||||||
))
|
|
||||||
|
|
||||||
const contractTrieNodeRetrievalEncoded = "04000000010203040506"
|
|
||||||
test "Encode/decode ContractTrieNodeRetrieval":
|
|
||||||
let
|
|
||||||
witnessNode = WitnessNode(@[byte 0x01, 0x02, 0x03, 0x04, 0x05, 0x06])
|
|
||||||
|
|
||||||
contractTrieNodeRetrieval = ContractTrieNodeRetrieval(node: witnessNode)
|
|
||||||
encoded = SSZ.encode(contractTrieNodeRetrieval)
|
|
||||||
# echo ">>>", encoded.toHex()
|
|
||||||
check encoded.toHex() == contractTrieNodeRetrievalEncoded
|
|
||||||
|
|
||||||
let decoded = SSZ.decode(encoded, ContractTrieNodeRetrieval)
|
|
||||||
check decoded.node == witnessNode
|
|
||||||
|
|
||||||
const contractCodeOfferEncoded = "2800000036000000d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3010203040506070809a0a1a2a3a408000000130000000005000000123456789abc04000000010203040506"
|
|
||||||
test "Encode/decode ContractCodeOffer":
|
|
||||||
let
|
|
||||||
code = @[byte 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4]
|
|
||||||
blockHash = "d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3"
|
|
||||||
accountProofKey = Nibbles(packedNibbles: Nibbles.packedNibbles.init(@[NibblePair 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC]), isOddLength: false)
|
|
||||||
accountProofWitness = Witness(@[WitnessNode(@[byte 0x01, 0x02, 0x03, 0x04, 0x05, 0x06])])
|
|
||||||
|
|
||||||
contractCodeOffer = ContractCodeOffer(
|
|
||||||
code: ByteList.init(code),
|
|
||||||
blockHash: BlockHash.fromHex(blockHash),
|
|
||||||
accountProof: StateWitness(key: accountProofKey, proof: accountProofWitness))
|
|
||||||
encoded = SSZ.encode(contractCodeOffer)
|
|
||||||
# echo ">>>", encoded.toHex()
|
|
||||||
check encoded.toHex() == contractCodeOfferEncoded
|
|
||||||
|
|
||||||
let decoded = SSZ.decode(encoded, ContractCodeOffer)
|
|
||||||
check:
|
|
||||||
decoded.code == ByteList.init(code)
|
|
||||||
decoded.blockHash == BlockHash.fromHex(blockHash)
|
|
||||||
decoded.accountProof == StateWitness(key: accountProofKey, proof: accountProofWitness)
|
|
||||||
|
|
||||||
const contractCodeRetrievalEncoded = "04000000010203040506070809a0a1a2a3a4"
|
|
||||||
test "Encode/decode ContractCodeRetrieval":
|
|
||||||
let
|
|
||||||
code = @[byte 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4]
|
|
||||||
|
|
||||||
contractCodeRetrieval = ContractCodeRetrieval(code: ByteList.init(code))
|
|
||||||
encoded = SSZ.encode(contractCodeRetrieval)
|
|
||||||
# echo ">>>", encoded.toHex()
|
|
||||||
check encoded.toHex() == contractCodeRetrievalEncoded
|
|
||||||
|
|
||||||
let decoded = SSZ.decode(encoded, ContractCodeRetrieval)
|
|
||||||
check decoded.code == ByteList.init(code)
|
|
|
@ -0,0 +1,123 @@
|
||||||
|
# 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
|
||||||
|
testutils/unittests,
|
||||||
|
stew/[byteutils, io2],
|
||||||
|
eth/keys,
|
||||||
|
../../network/state/state_content
|
||||||
|
|
||||||
|
|
||||||
|
suite "State Content Keys":
|
||||||
|
const evenNibles = "00050000008679e8ed"
|
||||||
|
test "Encode/decode even nibbles":
|
||||||
|
const
|
||||||
|
nibbles: seq[byte] = @[8, 6, 7, 9, 14, 8, 14, 13]
|
||||||
|
packedNibbles = packNibbles(nibbles)
|
||||||
|
unpackedNibbles = unpackNibbles(packedNibbles)
|
||||||
|
|
||||||
|
let
|
||||||
|
encoded = SSZ.encode(packedNibbles)
|
||||||
|
|
||||||
|
check encoded.toHex() == evenNibles
|
||||||
|
check unpackedNibbles == nibbles
|
||||||
|
|
||||||
|
const oddNibbles = "0105000000018679e8ed"
|
||||||
|
test "Encode/decode odd nibbles":
|
||||||
|
const
|
||||||
|
nibbles: seq[byte] = @[1, 8, 6, 7, 9, 14, 8, 14, 13]
|
||||||
|
packedNibbles = packNibbles(nibbles)
|
||||||
|
unpackedNibbles = unpackNibbles(packedNibbles)
|
||||||
|
|
||||||
|
let
|
||||||
|
encoded = SSZ.encode(packedNibbles)
|
||||||
|
|
||||||
|
check encoded.toHex() == oddNibbles
|
||||||
|
check unpackedNibbles == nibbles
|
||||||
|
|
||||||
|
const accountTrieNodeKeyEncoded = "20240000006225fcc63b22b80301d9f2582014e450e91f9b329b7cc87ad16894722fff529600050000008679e8ed"
|
||||||
|
test "Encode/decode AccountTrieNodeKey":
|
||||||
|
const
|
||||||
|
nibbles: seq[byte] = @[8, 6, 7, 9, 14, 8, 14, 13]
|
||||||
|
packedNibbles = packNibbles(nibbles)
|
||||||
|
nodeHash = NodeHash.fromHex("6225fcc63b22b80301d9f2582014e450e91f9b329b7cc87ad16894722fff5296")
|
||||||
|
|
||||||
|
let
|
||||||
|
accountTrieNodeKey = AccountTrieNodeKey(path: packedNibbles, nodeHash: nodeHash)
|
||||||
|
contentKey = ContentKey(contentType: accountTrieNode, accountTrieNodeKey: accountTrieNodeKey)
|
||||||
|
encoded = contentKey.encode()
|
||||||
|
check $encoded == accountTrieNodeKeyEncoded
|
||||||
|
|
||||||
|
let decoded = encoded.decode().valueOr:
|
||||||
|
raiseAssert "Cannot decode AccountTrieNodeKey"
|
||||||
|
check:
|
||||||
|
decoded.contentType == accountTrieNode
|
||||||
|
decoded.accountTrieNodeKey == AccountTrieNodeKey(path: packedNibbles, nodeHash: nodeHash)
|
||||||
|
|
||||||
|
const contractTrieNodeKeyEncoded = "21c02aaa39b223fe8d0a0e5c4f27ead9083c756cc238000000eb43d68008d216e753fef198cf51077f5a89f406d9c244119d1643f0f2b190110005000000405787"
|
||||||
|
test "Encode/decode ContractTrieNodeKey":
|
||||||
|
const
|
||||||
|
nibbles: seq[byte] = @[4, 0, 5, 7, 8, 7]
|
||||||
|
packedNibbles = packNibbles(nibbles)
|
||||||
|
address = Address.fromHex("c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2")
|
||||||
|
isOddLength = false
|
||||||
|
nodeHash = NodeHash.fromHex("eb43d68008d216e753fef198cf51077f5a89f406d9c244119d1643f0f2b19011")
|
||||||
|
|
||||||
|
let
|
||||||
|
contractTrieNodeKey = ContractTrieNodeKey(address: address, path: packedNibbles, nodeHash: nodeHash)
|
||||||
|
contentKey = ContentKey(contentType: contractTrieNode, contractTrieNodeKey: contractTrieNodeKey)
|
||||||
|
encoded = contentKey.encode()
|
||||||
|
check $encoded == contractTrieNodeKeyEncoded
|
||||||
|
|
||||||
|
let decoded = encoded.decode().valueOr:
|
||||||
|
raiseAssert "Cannot decode ContractTrieNodeKey"
|
||||||
|
check:
|
||||||
|
decoded.contentType == contractTrieNode
|
||||||
|
decoded.contractTrieNodeKey == ContractTrieNodeKey(address: address, path: packedNibbles, nodeHash: nodeHash)
|
||||||
|
|
||||||
|
const contractCodeKeyEncoded = "22c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2d0a06b12ac47863b5c7be4185c2deaad1c61557033f56c7d4ea74429cbb25e23"
|
||||||
|
test "Encode/decode ContractCodeKey":
|
||||||
|
const
|
||||||
|
address = Address.fromHex("c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2")
|
||||||
|
codeHash = CodeHash.fromHex("d0a06b12ac47863b5c7be4185c2deaad1c61557033f56c7d4ea74429cbb25e23")
|
||||||
|
|
||||||
|
let
|
||||||
|
contractCodeKey = ContractCodeKey(address: address, codeHash: codeHash)
|
||||||
|
contentKey = ContentKey(contentType: contractCode, contractCodeKey: contractCodeKey)
|
||||||
|
encoded = contentKey.encode()
|
||||||
|
check $encoded == contractCodeKeyEncoded
|
||||||
|
|
||||||
|
let decoded = encoded.decode().valueOr:
|
||||||
|
raiseAssert "Cannot decode ContractCodeKey"
|
||||||
|
check:
|
||||||
|
decoded.contentType == contractCode
|
||||||
|
decoded.contractCodeKey.address == address
|
||||||
|
decoded.contractCodeKey.codeHash == codeHash
|
||||||
|
|
||||||
|
test "Invalid prefix - 0 value":
|
||||||
|
let encoded = ByteList.init(@[byte 0x00])
|
||||||
|
let decoded = decode(encoded)
|
||||||
|
|
||||||
|
check decoded.isNone()
|
||||||
|
|
||||||
|
test "Invalid prefix - before valid range":
|
||||||
|
let encoded = ByteList.init(@[byte 0x01])
|
||||||
|
let decoded = decode(encoded)
|
||||||
|
|
||||||
|
check decoded.isNone()
|
||||||
|
|
||||||
|
test "Invalid prefix - after valid range":
|
||||||
|
let encoded = ByteList.init(@[byte 0x25])
|
||||||
|
let decoded = decode(encoded)
|
||||||
|
|
||||||
|
check decoded.isNone()
|
||||||
|
|
||||||
|
test "Invalid key - empty input":
|
||||||
|
let encoded = ByteList.init(@[])
|
||||||
|
let decoded = decode(encoded)
|
||||||
|
|
||||||
|
check decoded.isNone()
|
|
@ -0,0 +1,130 @@
|
||||||
|
# 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/[sugar, sequtils],
|
||||||
|
testutils/unittests,
|
||||||
|
stew/[byteutils, io2],
|
||||||
|
eth/keys,
|
||||||
|
./helpers,
|
||||||
|
../../network/state/state_content,
|
||||||
|
../../eth_data/history_data_json_store
|
||||||
|
|
||||||
|
const testVectorDir = "./vendor/portal-spec-tests/tests/mainnet/state/"
|
||||||
|
|
||||||
|
suite "State Content Values":
|
||||||
|
test "Encode/decode AccountTrieNodeOffer":
|
||||||
|
let
|
||||||
|
blockContent = readJsonType(testVectorDir & "block.json", JsonBlock).valueOr:
|
||||||
|
raiseAssert "Cannot read test vector: " & error
|
||||||
|
accountTrieNode = readJsonType(testVectorDir & "account_trie_node.json", JsonAccountTrieNode).valueOr:
|
||||||
|
raiseAssert "Cannot read test vector: " & error
|
||||||
|
blockHash = BlockHash.fromHex(blockContent.`block`.block_hash)
|
||||||
|
proof = TrieProof.init(blockContent.account_proof.map((hex) => TrieNode.init(hex.hexToSeqByte())))
|
||||||
|
accountTrieNodeOffer = AccountTrieNodeOffer(blockHash: blockHash, proof: proof)
|
||||||
|
|
||||||
|
encoded = SSZ.encode(accountTrieNodeOffer)
|
||||||
|
expected = accountTrieNode.content_value_offer.hexToSeqByte()
|
||||||
|
decoded = SSZ.decode(encoded, AccountTrieNodeOffer)
|
||||||
|
|
||||||
|
check encoded == expected
|
||||||
|
check decoded == accountTrieNodeOffer
|
||||||
|
|
||||||
|
test "Encode/decode AccountTrieNodeRetrieval":
|
||||||
|
let
|
||||||
|
blockContent = readJsonType(testVectorDir & "block.json", JsonBlock).valueOr:
|
||||||
|
raiseAssert "Cannot read test vector: " & error
|
||||||
|
accountTrieNode = readJsonType(testVectorDir & "account_trie_node.json", JsonAccountTrieNode).valueOr:
|
||||||
|
raiseAssert "Cannot read test vector: " & error
|
||||||
|
|
||||||
|
node = TrieNode.init(blockContent.account_proof[^1].hexToSeqByte())
|
||||||
|
accountTrieNodeRetrieval = AccountTrieNodeRetrieval(node: node)
|
||||||
|
|
||||||
|
encoded = SSZ.encode(accountTrieNodeRetrieval)
|
||||||
|
expected = accountTrieNode.content_value_retrieval.hexToSeqByte()
|
||||||
|
decoded = SSZ.decode(encoded, AccountTrieNodeRetrieval)
|
||||||
|
|
||||||
|
check encoded == expected
|
||||||
|
check decoded == accountTrieNodeRetrieval
|
||||||
|
|
||||||
|
test "Encode/decode ContractTrieNodeOffer":
|
||||||
|
let
|
||||||
|
blockContent = readJsonType(testVectorDir & "block.json", JsonBlock).valueOr:
|
||||||
|
raiseAssert "Cannot read test vector: " & error
|
||||||
|
contractStorageTrieNode = readJsonType(testVectorDir & "contract_storage_trie_node.json", JsonContractStorageTtrieNode).valueOr:
|
||||||
|
raiseAssert "Cannot read test vector: " & error
|
||||||
|
|
||||||
|
blockHash = BlockHash.fromHex(blockContent.`block`.block_hash)
|
||||||
|
storageProof = TrieProof.init(blockContent.storage_proof.map((hex) => TrieNode.init(hex.hexToSeqByte())))
|
||||||
|
accountProof = TrieProof.init(blockContent.account_proof.map((hex) => TrieNode.init(hex.hexToSeqByte())))
|
||||||
|
contractTrieNodeOffer = ContractTrieNodeOffer(
|
||||||
|
blockHash: blockHash,
|
||||||
|
storage_proof: storageProof,
|
||||||
|
account_proof: accountProof)
|
||||||
|
|
||||||
|
encoded = SSZ.encode(contractTrieNodeOffer)
|
||||||
|
expected = contractStorageTrieNode.content_value_offer.hexToSeqByte()
|
||||||
|
decoded = SSZ.decode(encoded, ContractTrieNodeOffer)
|
||||||
|
|
||||||
|
check encoded == expected
|
||||||
|
check decoded == contractTrieNodeOffer
|
||||||
|
|
||||||
|
test "Encode/decode ContractTrieNodeRetrieval":
|
||||||
|
let
|
||||||
|
blockContent = readJsonType(testVectorDir & "block.json", JsonBlock).valueOr:
|
||||||
|
raiseAssert "Cannot read test vector: " & error
|
||||||
|
contractStorageTrieNode = readJsonType(testVectorDir & "contract_storage_trie_node.json", JsonContractStorageTtrieNode).valueOr:
|
||||||
|
raiseAssert "Cannot read test vector: " & error
|
||||||
|
|
||||||
|
node = TrieNode.init(blockContent.storage_proof[^1].hexToSeqByte())
|
||||||
|
contractTrieNodeRetrieval = ContractTrieNodeRetrieval(node: node)
|
||||||
|
|
||||||
|
encoded = SSZ.encode(contractTrieNodeRetrieval)
|
||||||
|
expected = contractStorageTrieNode.content_value_retrieval.hexToSeqByte()
|
||||||
|
decoded = SSZ.decode(encoded, ContractTrieNodeRetrieval)
|
||||||
|
|
||||||
|
check encoded == expected
|
||||||
|
check decoded == contractTrieNodeRetrieval
|
||||||
|
|
||||||
|
test "Encode/decode ContractCodeOffer":
|
||||||
|
let
|
||||||
|
blockContent = readJsonType(testVectorDir & "block.json", JsonBlock).valueOr:
|
||||||
|
raiseAssert "Cannot read test vector: " & error
|
||||||
|
contractBytecode = readJsonType(testVectorDir & "contract_bytecode.json", JsonContractBytecode).valueOr:
|
||||||
|
raiseAssert "Cannot read test vector: " & error
|
||||||
|
|
||||||
|
code = Bytecode.init(blockContent.bytecode.hexToSeqByte())
|
||||||
|
blockHash = BlockHash.fromHex(blockContent.`block`.block_hash)
|
||||||
|
accountProof = TrieProof.init(blockContent.account_proof.map((hex) => TrieNode.init(hex.hexToSeqByte())))
|
||||||
|
contractCodeOffer = ContractCodeOffer(
|
||||||
|
code: code,
|
||||||
|
blockHash: blockHash,
|
||||||
|
accountProof: accountProof)
|
||||||
|
|
||||||
|
encoded = SSZ.encode(contractCodeOffer)
|
||||||
|
expected = contractBytecode.content_value_offer.hexToSeqByte()
|
||||||
|
decoded = SSZ.decode(encoded, ContractCodeOffer)
|
||||||
|
|
||||||
|
check encoded == expected
|
||||||
|
check decoded == contractCodeOffer
|
||||||
|
|
||||||
|
test "Encode/decode ContractCodeRetrieval":
|
||||||
|
let
|
||||||
|
blockContent = readJsonType(testVectorDir & "block.json", JsonBlock).valueOr:
|
||||||
|
raiseAssert "Cannot read test vector: " & error
|
||||||
|
contractBytecode = readJsonType(testVectorDir & "contract_bytecode.json", JsonContractBytecode).valueOr:
|
||||||
|
raiseAssert "Cannot read test vector: " & error
|
||||||
|
|
||||||
|
code = Bytecode.init(blockContent.bytecode.hexToSeqByte())
|
||||||
|
contractCodeRetrieval = ContractCodeRetrieval(code: code)
|
||||||
|
|
||||||
|
encoded = SSZ.encode(contractCodeRetrieval)
|
||||||
|
expected = contractBytecode.content_value_retrieval.hexToSeqByte()
|
||||||
|
decoded = SSZ.decode(encoded, ContractCodeRetrieval)
|
||||||
|
|
||||||
|
check encoded == expected
|
||||||
|
check decoded == contractCodeRetrieval
|
|
@ -1 +1 @@
|
||||||
Subproject commit c3f11b8713c3e12be7f517d75cbdbafb9753d1ff
|
Subproject commit e3928b0487ab92ed8323e631728ee3475629757d
|
Loading…
Reference in New Issue