mirror of
https://github.com/status-im/nimbus-eth1.git
synced 2025-01-11 21:04:11 +00:00
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:
parent
414fdafab9
commit
bdbd8e4c87
@ -13,3 +13,4 @@ import
|
||||
type
|
||||
ByteList* = List[byte, 2048]
|
||||
Bytes2* = array[2, byte]
|
||||
Bytes32* = array[32, byte]
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
||||
|
@ -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):
|
||||
|
@ -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.} =
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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
|
||||
|
2
vendor/nim-ssz-serialization
vendored
2
vendor/nim-ssz-serialization
vendored
@ -1 +1 @@
|
||||
Subproject commit 5d65b20d6b56265902e5c9b6a2be4d1c2fd6427e
|
||||
Subproject commit 1f07d6500aa708321aefd1a209aaba05b9ea80a8
|
Loading…
x
Reference in New Issue
Block a user