Add SSZ Unions through case objects (#882)

* Add SSZ Unions through case objects

* Add connection id content response test and improve other test vectors

* Implement content keys and ids for state network as per spec

Content keys case object is used so that it can be serialized and
deserialized as an SSZ Union.

* Let message Union in Portal wire protocol start at 0 as per new spec
This commit is contained in:
Kim De Mey 2021-11-17 17:11:17 +01:00 committed by GitHub
parent 414fdafab9
commit bdbd8e4c87
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 225 additions and 173 deletions

View File

@ -13,3 +13,4 @@ import
type
ByteList* = List[byte, 2048]
Bytes2* = array[2, byte]
Bytes32* = array[32, byte]

View File

@ -5,78 +5,124 @@
# * 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.
# https://github.com/ethereum/stateless-ethereum-specs/blob/master/state-network.md#content
# As per spec:
# https://github.com/ethereum/portal-network-specs/blob/master/state-network.md#content-keys-and-content-ids
{.push raises: [Defect].}
import
std/options,
nimcrypto/[sha2, hash], stew/objects, stint,
nimcrypto/[hash, sha2, keccak], stew/objects, stint,
ssz_serialization,
../../common/common_types
export ssz_serialization, common_types
type
ContentType* = enum
Account = 0x01
ContractStorage = 0x02
ContractBytecode = 0x03
NetworkId* = uint16
NodeHash* = MDigest[32 * 8] # keccak256
CodeHash* = MDigest[32 * 8] # keccak256
Address* = array[20, byte]
ContentKey* = object
networkId*: NetworkId
contentType*: ContentType
# TODO: How shall we deal with the different ContentKey structures?
# Lets start with just node hashes for now.
# address: Address
# triePath: ByteList
ContentType* = enum
accountTrieNode = 0x00
contractStorageTrieNode = 0x01
accountTrieProof = 0x02
contractStorageTrieProof = 0x03
contractBytecode = 0x04
AccountTrieNodeKey* = object
path*: ByteList
nodeHash*: NodeHash
stateRoot*: Bytes32
ContractStorageTrieNodeKey* = object
address*: Address
path*: ByteList
nodeHash*: NodeHash
stateRoot*: Bytes32
AccountTrieProofKey* = object
address*: Address
stateRoot*: Bytes32
ContractStorageTrieProofKey* = object
address*: Address
slot*: UInt256
stateRoot*: Bytes32
ContractBytecodeKey* = object
address*: Address
codeHash*: CodeHash
ContentKey* = object
case contentType*: ContentType
of accountTrieNode:
accountTrieNodeKey*: AccountTrieNodeKey
of contractStorageTrieNode:
contractStorageTrieNodeKey*: ContractStorageTrieNodeKey
of accountTrieProof:
accountTrieProofKey*: AccountTrieProofKey
of contractStorageTrieProof:
contractStorageTrieProofKey*: ContractStorageTrieProofKey
of contractBytecode:
contractBytecodeKey*: ContractBytecodeKey
ContentId* = Uint256
KeccakHash* = MDigest[32 * 8] # could also import from either eth common types or trie defs
template toSszType*(x: ContentType): uint8 =
uint8(x)
template toSszType*(x: auto): auto =
x
func fromSszBytes*(T: type ContentType, data: openArray[byte]):
T {.raises: [MalformedSszError, Defect].} =
if data.len != sizeof(uint8):
raiseIncorrectSize T
var contentType: T
if not checkedEnumAssign(contentType, data[0]):
raiseIncorrectSize T
contentType
func encode*(contentKey: ContentKey): ByteList =
ByteList.init(SSZ.encode(contentKey))
# TODO consider if more powerfull error handling is necessary here.
func decode*(contentKey: ByteList): Option[ContentKey] =
try:
some(SSZ.decode(contentKey.asSeq(), ContentKey))
except SszError:
return none[ContentKey]()
func toContentId*(contentKey: ByteList): ContentId =
# TODO: Hash function to be defined, sha256 used now, might be confusing
# with keccak256 that is used for the actual nodes:
# https://github.com/ethereum/stateless-ethereum-specs/blob/master/state-network.md#content
let idHash = sha2.sha_256.digest(contentKey.asSeq())
template computeContentId*(digestCtxType: type, body: untyped): ContentId =
var h {.inject.}: digestCtxType
init(h)
body
let idHash = finish(h)
readUintBE[256](idHash.data)
func toContentId*(contentKey: ContentKey): ContentId =
toContentId(encode(contentKey))
proc toContentId*(contentKey: ContentKey): ContentId =
case contentKey.contentType:
of accountTrieNode: # sha256(path | node_hash)
let key = contentKey.accountTrieNodeKey
computeContentId sha256:
h.update(key.path.asSeq())
h.update(key.nodeHash.data)
of contractStorageTrieNode: # sha256(address | path | node_hash)
let key = contentKey.contractStorageTrieNodeKey
computeContentId sha256:
h.update(key.address)
h.update(key.path.asSeq())
h.update(key.nodeHash.data)
of accountTrieProof: # keccak(address)
let key = contentKey.accountTrieProofKey
computeContentId keccak256:
h.update(key.address)
of contractStorageTrieProof: # (keccak(address) + keccak(slot)) % 2**256
# TODO: Why is keccak run on slot, when it can be used directly?
# Also, value to LE or BE? Not mentioned in specification.
let key = contentKey.contractStorageTrieProofKey
let n1 =
block: computeContentId keccak256:
h.update(key.address)
let n2 =
block: computeContentId keccak256:
h.update(toBytesLE(key.slot))
n1 + n2 # uint256 will wrap arround, practically applying the modulo 256
of contractBytecode: # sha256(address | code_hash)
let key = contentKey.contractBytecodeKey
computeContentId sha256:
h.update(key.address)
h.update(key.codeHash.data)
proc toContentId*(contentKey: ByteList): Option[ContentId] =
let key = decode(contentKey)
if key.isSome():
some(key.get().toContentId())
else:
none(ContentId)

View File

@ -24,17 +24,20 @@ type StateNetwork* = ref object
proc getHandler(contentDB: ContentDB): ContentHandler =
return (proc (contentKey: state_content.ByteList): ContentResult =
let contentId = toContentId(contentKey)
let maybeContent = contentDB.get(contentId)
if (maybeContent.isSome()):
ContentResult(kind: ContentFound, content: maybeContent.unsafeGet())
if contentId.isSome():
let maybeContent = contentDB.get(contentId.get())
if (maybeContent.isSome()):
ContentResult(kind: ContentFound, content: maybeContent.unsafeGet())
else:
ContentResult(kind: ContentMissing, contentId: contentId.get())
else:
ContentResult(kind: ContentMissing, contentId: contentId))
ContentResult(kind: ContentKeyValidationFailure, error: ""))
proc getContent*(n: StateNetwork, key: ContentKey):
Future[Option[seq[byte]]] {.async.} =
let
keyEncoded = encode(key)
contentId = toContentId(keyEncoded)
contentId = toContentId(key)
let nodeId = n.portalProtocol.localNode.id

View File

@ -30,16 +30,19 @@ type
dataRadius*: UInt256
MessageKind* = enum
unused = 0x00
ping = 0x00
pong = 0x01
findnode = 0x02
nodes = 0x03
findcontent = 0x04
content = 0x05
offer = 0x06
accept = 0x07
ping = 0x01
pong = 0x02
findnode = 0x03
nodes = 0x04
findcontent = 0x05
content = 0x06
offer = 0x07
accept = 0x08
ContentMessageType* = enum
connectionIdType = 0x00
contentType = 0x01
enrsType = 0x02
PingMessage* = object
enrSeq*: uint64
@ -60,11 +63,14 @@ type
FindContentMessage* = object
contentKey*: ByteList
# TODO: Must become an SSZ Union
ContentMessage* = object
connectionId*: Bytes2
content*: ByteList
enrs*: List[ByteList, 32]
case contentMessageType*: ContentMessageType
of connectionIdType:
connectionId*: Bytes2
of contentType:
content*: ByteList
of enrsType:
enrs*: List[ByteList, 32]
OfferMessage* = object
contentKeys*: ContentKeysList
@ -73,7 +79,6 @@ type
connectionId*: Bytes2
contentKeys*: ContentKeysBitList
# TODO: Needs to become an SSZ Union
Message* = object
case kind*: MessageKind
of ping:
@ -81,7 +86,7 @@ type
of pong:
pong*: PongMessage
of findnode:
findNode*: FindNodeMessage
findnode*: FindNodeMessage
of nodes:
nodes*: NodesMessage
of findcontent:
@ -92,8 +97,6 @@ type
offer*: OfferMessage
of accept:
accept*: AcceptMessage
else:
discard
SomeMessage* =
PingMessage or PongMessage or
@ -104,7 +107,7 @@ type
template messageKind*(T: typedesc[SomeMessage]): MessageKind =
when T is PingMessage: ping
elif T is PongMessage: pong
elif T is FindNodeMessage: findNode
elif T is FindNodeMessage: findnode
elif T is NodesMessage: nodes
elif T is FindContentMessage: findcontent
elif T is ContentMessage: content
@ -122,42 +125,24 @@ func fromSszBytes*(T: type UInt256, data: openArray[byte]):
T.fromBytesLE(data)
proc encodeMessage*[T: SomeMessage](m: T): seq[byte] =
ord(messageKind(T)).byte & SSZ.encode(m)
# TODO: Could/should be macro'd away,
# or we just use SSZ.encode(Message) directly
when T is PingMessage: SSZ.encode(Message(kind: ping, ping: m))
elif T is PongMessage: SSZ.encode(Message(kind: pong, pong: m))
elif T is FindNodeMessage: SSZ.encode(Message(kind: findnode, findnode: m))
elif T is NodesMessage: SSZ.encode(Message(kind: nodes, nodes: m))
elif T is FindContentMessage: SSZ.encode(Message(kind: findcontent, findcontent: m))
elif T is ContentMessage: SSZ.encode(Message(kind: content, content: m))
elif T is OfferMessage: SSZ.encode(Message(kind: offer, offer: m))
elif T is AcceptMessage: SSZ.encode(Message(kind: accept, accept: m))
proc decodeMessage*(body: openarray[byte]): Result[Message, cstring] =
# Decodes to the specific `Message` type.
if body.len < 1:
return err("No message data, peer might not support this talk protocol")
var kind: MessageKind
if not checkedEnumAssign(kind, body[0]):
return err("Invalid message type")
var message = Message(kind: kind)
try:
case kind
of unused: return err("Invalid message type")
of ping:
message.ping = SSZ.decode(body.toOpenArray(1, body.high), PingMessage)
of pong:
message.pong = SSZ.decode(body.toOpenArray(1, body.high), PongMessage)
of findNode:
message.findNode = SSZ.decode(body.toOpenArray(1, body.high), FindNodeMessage)
of nodes:
message.nodes = SSZ.decode(body.toOpenArray(1, body.high), NodesMessage)
of findcontent:
message.findcontent = SSZ.decode(body.toOpenArray(1, body.high), FindContentMessage)
of content:
message.content = SSZ.decode(body.toOpenArray(1, body.high), ContentMessage)
of offer:
message.offer = SSZ.decode(body.toOpenArray(1, body.high), OfferMessage)
of accept:
message.accept = SSZ.decode(body.toOpenArray(1, body.high), AcceptMessage)
if body.len < 1: # TODO: This check should probably move a layer down
return err("No message data, peer might not support this talk protocol")
ok(SSZ.decode(body, Message))
except SszError:
return err("Invalid message encoding")
ok(message)
err("Invalid message encoding")
template innerMessage[T: SomeMessage](message: Message, expected: MessageKind): Option[T] =
if (message.kind == expected):

View File

@ -137,26 +137,25 @@ proc handleFindContent(p: PortalProtocol, fc: FindContentMessage): seq[byte] =
# TODO: Need to provide uTP connectionId when content is too large for a
# single response.
let content = contentHandlingResult.content
let enrs = List[ByteList, 32](@[]) # Empty enrs when payload is send
encodeMessage(ContentMessage(
enrs: enrs, content: ByteList(content)))
contentMessageType: contentType, content: ByteList(content)))
of ContentMissing:
let
contentId = contentHandlingResult.contentId
closestNodes = p.routingTable.neighbours(
NodeId(contentId), seenOnly = true)
content = ByteList(@[]) # Empty payload when enrs are send
enrs =
closestNodes.map(proc(x: Node): ByteList = ByteList(x.record.raw))
encodeMessage(ContentMessage(
enrs: List[ByteList, 32](List(enrs)), content: content))
contentMessageType: enrsType, enrs: List[ByteList, 32](List(enrs))))
of ContentKeyValidationFailure:
# Return empty response when content key validation fails
# Return empty content response when content key validation fails
# TODO: Better would be to return no message at all, or we need to add a
# None type or so.
let content = ByteList(@[])
let enrs = List[ByteList, 32](@[]) # Empty enrs when payload is send
encodeMessage(ContentMessage(
enrs: enrs, content: content))
contentMessageType: contentType, content: content))
proc handleOffer(p: PortalProtocol, a: OfferMessage): seq[byte] =
let
@ -203,8 +202,9 @@ proc messageHandler*(protocol: TalkProtocol, request: seq[byte],
of MessageKind.offer:
p.handleOffer(message.offer)
else:
# This shouldn't occur as the 0 case is already covered in `decodedMessage`
debug "Packet decoding error: Invalid message type"
# This would mean a that Portal wire response message is being send over a
# discv5 talkreq message.
debug "Invalid Portal wire message type over talkreq", kind = message.kind
@[]
else:
debug "Packet decoding error", error = decoded.error, srcId, srcUdpAddress
@ -388,7 +388,14 @@ proc lookup*(p: PortalProtocol, target: NodeId): Future[seq[Node]] {.async.} =
proc handleFoundContentMessage(p: PortalProtocol, m: ContentMessage,
dst: Node, nodes: var seq[Node]): LookupResult =
if (m.enrs.len() != 0 and m.content.len() == 0):
case m.contentMessageType:
of connectionIdType:
# TODO: We'd have to get the data through uTP, or wrap some proc around
# this call that does that.
LookupResult(kind: Content)
of contentType:
LookupResult(kind: Content, content: m.content)
of enrsType:
let records = recordsFromBytes(m.enrs)
let verifiedNodes = verifyNodesRecords(records, dst, EnrsResultLimit)
nodes.add(verifiedNodes)
@ -397,16 +404,7 @@ proc handleFoundContentMessage(p: PortalProtocol, m: ContentMessage,
# Attempt to add all nodes discovered
discard p.routingTable.addNode(n)
return LookupResult(kind: Nodes, nodes: nodes)
elif (m.content.len() != 0 and m.enrs.len() == 0):
return LookupResult(kind: Content, content: m.content)
elif ((m.content.len() != 0 and m.enrs.len() != 0)):
# Both content and enrs are filled, which means protocol breach. For now
# just logging offending node to quickly identify it
warn "Invalid foundcontent response form node ", uri = toURI(dst.record)
return LookupResult(kind: Nodes, nodes: nodes)
else:
return LookupResult(kind: Nodes, nodes: nodes)
LookupResult(kind: Nodes, nodes: nodes)
proc contentLookupWorker(p: PortalProtocol, destNode: Node, target: ByteList):
Future[LookupResult] {.async.} =

View File

@ -13,8 +13,8 @@ import
suite "Portal Wire Protocol Message Encodings":
test "Ping Request":
var dataRadius: UInt256
let
dataRadius = UInt256.high() - 1 # Full radius - 1
enrSeq = 1'u64
# Can be any custom payload, testing with just dataRadius here.
customPayload = ByteList(SSZ.encode(CustomPayload(dataRadius: dataRadius)))
@ -22,7 +22,7 @@ suite "Portal Wire Protocol Message Encodings":
let encoded = encodeMessage(p)
check encoded.toHex ==
"0101000000000000000c0000000000000000000000000000000000000000000000000000000000000000000000"
"0001000000000000000c000000feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
let decoded = decodeMessage(encoded)
check decoded.isOk()
@ -33,8 +33,8 @@ suite "Portal Wire Protocol Message Encodings":
message.ping.customPayload == customPayload
test "Pong Response":
var dataRadius: UInt256
let
dataRadius = UInt256.high() div 2.stuint(256) # Radius of half the UInt256
enrSeq = 1'u64
# Can be any custom payload, testing with just dataRadius here.
customPayload = ByteList(SSZ.encode(CustomPayload(dataRadius: dataRadius)))
@ -42,7 +42,7 @@ suite "Portal Wire Protocol Message Encodings":
let encoded = encodeMessage(p)
check encoded.toHex ==
"0201000000000000000c0000000000000000000000000000000000000000000000000000000000000000000000"
"0101000000000000000c000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f"
let decoded = decodeMessage(encoded)
check decoded.isOk()
@ -54,11 +54,11 @@ suite "Portal Wire Protocol Message Encodings":
test "FindNode Request":
let
distances = List[uint16, 256](@[0x0100'u16])
distances = List[uint16, 256](@[0x0100'u16, 0x00ff'u16])
fn = FindNodeMessage(distances: distances)
let encoded = encodeMessage(fn)
check encoded.toHex == "03040000000001"
check encoded.toHex == "02040000000001ff00"
let decoded = decodeMessage(encoded)
check decoded.isOk()
@ -68,13 +68,13 @@ suite "Portal Wire Protocol Message Encodings":
message.kind == findnode
message.findnode.distances == distances
test "Nodes Response - empty":
test "Nodes Response - empty enr list":
let
total = 0x1'u8
n = NodesMessage(total: total)
let encoded = encodeMessage(n)
check encoded.toHex == "040105000000"
check encoded.toHex == "030105000000"
let decoded = decodeMessage(encoded)
check decoded.isOk()
@ -85,7 +85,7 @@ suite "Portal Wire Protocol Message Encodings":
message.nodes.total == total
message.nodes.enrs.len() == 0
test "Nodes Response - enr":
test "Nodes Response - enrs":
var e1, e2: Record
check:
e1.fromURI("enr:-HW4QBzimRxkmT18hMKaAL3IcZF1UcfTMPyi3Q1pxwZZbcZVRI8DC5infUAB_UauARLOJtYTxaagKoGmIjzQxO2qUygBgmlkgnY0iXNlY3AyNTZrMaEDymNMrg1JrLQB2KTGtv6MVbcNEVv0AHacwUAPMljNMTg")
@ -96,7 +96,7 @@ suite "Portal Wire Protocol Message Encodings":
n = NodesMessage(total: total, enrs: List[ByteList, 32](@[ByteList(e1.raw), ByteList(e2.raw)]))
let encoded = encodeMessage(n)
check encoded.toHex == "040105000000080000007f000000f875b8401ce2991c64993d7c84c29a00bdc871917551c7d330fca2dd0d69c706596dc655448f030b98a77d4001fd46ae0112ce26d613c5a6a02a81a6223cd0c4edaa53280182696482763489736563703235366b31a103ca634cae0d49acb401d8a4c6b6fe8c55b70d115bf400769cc1400f3258cd3138f875b840d7f1c39e376297f81d7297758c64cb37dcc5c3beea9f57f7ce9695d7d5a67553417d719539d6ae4b445946de4d99e680eb8063f29485b555d45b7df16a1850130182696482763489736563703235366b31a1030e2cb74241c0c4fc8e8166f1a79a05d5b0dd95813a74b094529f317d5c39d235"
check encoded.toHex == "030105000000080000007f000000f875b8401ce2991c64993d7c84c29a00bdc871917551c7d330fca2dd0d69c706596dc655448f030b98a77d4001fd46ae0112ce26d613c5a6a02a81a6223cd0c4edaa53280182696482763489736563703235366b31a103ca634cae0d49acb401d8a4c6b6fe8c55b70d115bf400769cc1400f3258cd3138f875b840d7f1c39e376297f81d7297758c64cb37dcc5c3beea9f57f7ce9695d7d5a67553417d719539d6ae4b445946de4d99e680eb8063f29485b555d45b7df16a1850130182696482763489736563703235366b31a1030e2cb74241c0c4fc8e8166f1a79a05d5b0dd95813a74b094529f317d5c39d235"
let decoded = decodeMessage(encoded)
check decoded.isOk()
@ -110,12 +110,13 @@ suite "Portal Wire Protocol Message Encodings":
message.nodes.enrs[1] == ByteList(e2.raw)
test "FindContent Request":
const contentKeyString = "0x706f7274616c"
let
contentEncoded = ByteList.init(@[1'u8])
fn = FindContentMessage(contentKey: contentEncoded)
contentKey = ByteList.init(hexToSeqByte(contentKeyString))
fc = FindContentMessage(contentKey: contentKey)
let encoded = encodeMessage(fn)
check encoded.toHex == "050400000001"
let encoded = encodeMessage(fc)
check encoded.toHex == "0404000000706f7274616c"
let decoded = decodeMessage(encoded)
check decoded.isOk()
@ -123,16 +124,16 @@ suite "Portal Wire Protocol Message Encodings":
let message = decoded.get()
check:
message.kind == findcontent
message.findcontent.contentKey == contentEncoded
message.findcontent.contentKey == contentKey
test "Content Response - payload":
test "Content Response - connection id":
let
enrs = List[ByteList, 32](@[])
content = ByteList(@[byte 0x01, 0x02, 0x03])
n = ContentMessage(enrs: enrs, content: content)
connectionId = Bytes2([byte 0x01, 0x02])
c = ContentMessage(
contentMessageType: connectionIdType, connectionId: connectionId)
let encoded = encodeMessage(n)
check encoded.toHex == "0600000a0000000d000000010203"
let encoded = encodeMessage(c)
check encoded.toHex == "05000102"
let decoded = decodeMessage(encoded)
check decoded.isOk()
@ -140,7 +141,25 @@ suite "Portal Wire Protocol Message Encodings":
let message = decoded.get()
check:
message.kind == MessageKind.content
message.content.enrs.len() == 0
message.content.contentMessageType == connectionIdType
message.content.connectionId == connectionId
test "Content Response - content payload":
const contentString = "0x7468652063616b652069732061206c6965"
let
content = ByteList(hexToSeqByte(contentString))
c = ContentMessage(contentMessageType: contentType, content: content)
let encoded = encodeMessage(c)
check encoded.toHex == "05017468652063616b652069732061206c6965"
let decoded = decodeMessage(encoded)
check decoded.isOk()
let message = decoded.get()
check:
message.kind == MessageKind.content
message.content.contentMessageType == contentType
message.content.content == content
test "Content Response - enrs":
@ -151,11 +170,10 @@ suite "Portal Wire Protocol Message Encodings":
let
enrs = List[ByteList, 32](@[ByteList(e1.raw), ByteList(e2.raw)])
content = ByteList(@[])
n = ContentMessage(enrs: enrs, content: content)
c = ContentMessage(contentMessageType: enrsType, enrs: enrs)
let encoded = encodeMessage(n)
check encoded.toHex == "0600000a0000000a000000080000007f000000f875b8401ce2991c64993d7c84c29a00bdc871917551c7d330fca2dd0d69c706596dc655448f030b98a77d4001fd46ae0112ce26d613c5a6a02a81a6223cd0c4edaa53280182696482763489736563703235366b31a103ca634cae0d49acb401d8a4c6b6fe8c55b70d115bf400769cc1400f3258cd3138f875b840d7f1c39e376297f81d7297758c64cb37dcc5c3beea9f57f7ce9695d7d5a67553417d719539d6ae4b445946de4d99e680eb8063f29485b555d45b7df16a1850130182696482763489736563703235366b31a1030e2cb74241c0c4fc8e8166f1a79a05d5b0dd95813a74b094529f317d5c39d235"
let encoded = encodeMessage(c)
check encoded.toHex == "0502080000007f000000f875b8401ce2991c64993d7c84c29a00bdc871917551c7d330fca2dd0d69c706596dc655448f030b98a77d4001fd46ae0112ce26d613c5a6a02a81a6223cd0c4edaa53280182696482763489736563703235366b31a103ca634cae0d49acb401d8a4c6b6fe8c55b70d115bf400769cc1400f3258cd3138f875b840d7f1c39e376297f81d7297758c64cb37dcc5c3beea9f57f7ce9695d7d5a67553417d719539d6ae4b445946de4d99e680eb8063f29485b555d45b7df16a1850130182696482763489736563703235366b31a1030e2cb74241c0c4fc8e8166f1a79a05d5b0dd95813a74b094529f317d5c39d235"
let decoded = decodeMessage(encoded)
check decoded.isOk()
@ -163,18 +181,18 @@ suite "Portal Wire Protocol Message Encodings":
let message = decoded.get()
check:
message.kind == MessageKind.content
message.content.contentMessageType == enrsType
message.content.enrs.len() == 2
message.content.enrs[0] == ByteList(e1.raw)
message.content.enrs[1] == ByteList(e2.raw)
message.content.content == content
test "Offer Request":
let
contentKeys = ContentKeysList(List(@[ByteList(@[byte 0x01, 0x02, 0x03])]))
am = OfferMessage(contentKeys: contentKeys)
o = OfferMessage(contentKeys: contentKeys)
let encoded = encodeMessage(am)
check encoded.toHex == "070400000004000000010203"
let encoded = encodeMessage(o)
check encoded.toHex == "060400000004000000010203"
let decoded = decodeMessage(encoded)
check decoded.isOk()
@ -185,14 +203,14 @@ suite "Portal Wire Protocol Message Encodings":
message.offer.contentKeys == contentKeys
test "Accept Response":
var contentKeys = ContentKeysBitList.init(8)
contentKeys.setBit(0)
let
connectionId = Bytes2([byte 0x01, 0x02])
contentKeys = ContentKeysBitList.init(8)
n = AcceptMessage(connectionId: connectionId,
contentKeys: contentKeys)
a = AcceptMessage(connectionId: connectionId, contentKeys: contentKeys)
let encoded = encodeMessage(n)
check encoded.toHex == "080102060000000001"
let encoded = encodeMessage(a)
check encoded.toHex == "070102060000000101"
let decoded = decodeMessage(encoded)
check decoded.isOk()

View File

@ -133,7 +133,6 @@ procSuite "Portal Wire Protocol Tests":
check:
content.isOk()
content.get().enrs.len() == 1
content.get().content.len() == 0
await test.stopTest()

View File

@ -59,10 +59,10 @@ procSuite "State Content Network":
copyMem(nodeHash.data.addr, unsafeAddr k[0], sizeof(nodeHash.data))
let
# TODO: add stateRoot, and path eventually
accountTrieNodeKey = AccountTrieNodeKey(nodeHash: nodeHash)
contentKey = ContentKey(
networkId: 0'u16,
contentType: state_content.ContentType.Account,
nodeHash: nodeHash)
contentType: accountTrieNode, accountTrieNodeKey: accountTrieNodeKey)
contentId = toContentId(contentKey)
proto1.contentDB.put(contentId, v)
@ -72,10 +72,10 @@ procSuite "State Content Network":
copyMem(nodeHash.data.addr, unsafeAddr key[0], sizeof(nodeHash.data))
let
accountTrieNodeKey = AccountTrieNodeKey(nodeHash: nodeHash)
contentKey = ContentKey(
networkId: 0'u16,
contentType: state_content.ContentType.Account,
nodeHash: nodeHash)
contentType: accountTrieNode, accountTrieNodeKey: accountTrieNodeKey)
contentId = toContentId(contentKey)
# Note: GetContent and thus the lookup here is not really needed, as we
# only have to request data to one node.
@ -102,12 +102,10 @@ procSuite "State Content Network":
node3 = initDiscoveryNode(
rng, PrivateKey.random(rng[]), localAddress(20304))
proto1 = StateNetwork.new(node1, ContentDB.new("", inMemory = true))
proto2 = StateNetwork.new(node2, ContentDB.new("", inMemory = true))
proto3 = StateNetwork.new(node3, ContentDB.new("", inMemory = true))
# Node1 knows about Node2, and Node2 knows about Node3 which hold all content
check proto1.portalProtocol.addNode(node2.localNode) == Added
check proto2.portalProtocol.addNode(node3.localNode) == Added
@ -122,10 +120,9 @@ procSuite "State Content Network":
copyMem(nodeHash.data.addr, unsafeAddr k[0], sizeof(nodeHash.data))
let
accountTrieNodeKey = AccountTrieNodeKey(nodeHash: nodeHash)
contentKey = ContentKey(
networkId: 0'u16,
contentType: state_content.ContentType.Account,
nodeHash: nodeHash)
contentType: accountTrieNode, accountTrieNodeKey: accountTrieNodeKey)
contentId = toContentId(contentKey)
proto2.contentDB.put(contentId, v)
@ -138,10 +135,10 @@ procSuite "State Content Network":
let firstKey = keys[0]
copyMem(nodeHash.data.addr, unsafeAddr firstKey[0], sizeof(nodeHash.data))
let contentKey = ContentKey(
networkId: 0'u16,
contentType: state_content.ContentType.Account,
nodeHash: nodeHash)
let
accountTrieNodeKey = AccountTrieNodeKey(nodeHash: nodeHash)
contentKey = ContentKey(
contentType: accountTrieNode, accountTrieNodeKey: accountTrieNodeKey)
let foundContent = await proto1.getContent(contentKey)

View File

@ -162,7 +162,12 @@ proc testHandler(contentKey: state_content.ByteList): ContentResult =
# Note: We don't incorperate storage in this tool so we always return
# missing content. For now we are using the state network derivation but it
# could be selective based on the network the tool is used for.
ContentResult(kind: ContentMissing, contentId: toContentId(contentKey))
let contentId = toContentId(contentKey)
if contentId.isSome():
ContentResult(kind: ContentMissing, contentId: contentId.get())
else:
ContentResult(kind: ContentKeyValidationFailure,
error: "Failed decoding content key")
proc run(config: DiscoveryConf) =
let

@ -1 +1 @@
Subproject commit 5d65b20d6b56265902e5c9b6a2be4d1c2fd6427e
Subproject commit 1f07d6500aa708321aefd1a209aaba05b9ea80a8