Update wire protocol of state network spec (#829)

* Update wire protocol of state network spec

* BytesN should be SSZ Vector not List

* Add specific lists and bitlists for content keys
This commit is contained in:
Kim De Mey 2021-09-22 11:28:04 +02:00 committed by GitHub
parent 908dc21478
commit 11c120e400
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 77 additions and 47 deletions

View File

@ -17,8 +17,15 @@ import
export ssz_serialization, stint
const
contentKeysLimit = 64
type
ByteList* = List[byte, 2048]
Bytes2* = array[2, byte]
ContentKeysList* = List[ByteList, contentKeysLimit]
ContentKeysBitList* = BitList[contentKeysLimit]
MessageKind* = enum
unused = 0x00
@ -29,8 +36,8 @@ type
nodes = 0x04
findcontent = 0x05
foundcontent = 0x06
advertise = 0x07
requestproofs = 0x08
offer = 0x07
accept = 0x08
PingMessage* = object
enrSeq*: uint64
@ -55,15 +62,12 @@ type
enrs*: List[ByteList, 32]
payload*: ByteList
AdvertiseMessage* = List[ByteList, 32] # No container, heh...
OfferMessage* = object
contentKeys*: ContentKeysList
# This would be more consistent with the other messages
# AdvertiseMessage* = object
# contentKeys*: List[ByteList, 32]
RequestProofsMessage* = object
connectionId*: List[byte, 4]
contentKeys*: List[ByteList, 32]
AcceptMessage* = object
connectionId*: Bytes2
contentKeys*: ContentKeysBitList
Message* = object
case kind*: MessageKind
@ -79,10 +83,10 @@ type
findcontent*: FindContentMessage
of foundcontent:
foundcontent*: FoundContentMessage
of advertise:
advertise*: AdvertiseMessage
of requestproofs:
requestproofs*: RequestProofsMessage
of offer:
offer*: OfferMessage
of accept:
accept*: AcceptMessage
else:
discard
@ -90,7 +94,7 @@ type
PingMessage or PongMessage or
FindNodeMessage or NodesMessage or
FindContentMessage or FoundContentMessage or
AdvertiseMessage or RequestProofsMessage
OfferMessage or AcceptMessage
template messageKind*(T: typedesc[SomeMessage]): MessageKind =
when T is PingMessage: ping
@ -99,8 +103,8 @@ template messageKind*(T: typedesc[SomeMessage]): MessageKind =
elif T is NodesMessage: nodes
elif T is FindContentMessage: findcontent
elif T is FoundContentMessage: foundcontent
elif T is AdvertiseMessage: advertise
elif T is RequestProofsMessage: requestproofs
elif T is OfferMessage: offer
elif T is AcceptMessage: accept
template toSszType*(x: UInt256): array[32, byte] =
toBytesLE(x)
@ -144,10 +148,10 @@ proc decodeMessage*(body: openarray[byte]): Result[Message, cstring] =
message.findcontent = SSZ.decode(body.toOpenArray(1, body.high), FindContentMessage)
of foundcontent:
message.foundcontent = SSZ.decode(body.toOpenArray(1, body.high), FoundContentMessage)
of advertise:
message.advertise = SSZ.decode(body.toOpenArray(1, body.high), AdvertiseMessage)
of requestproofs:
message.requestproofs = SSZ.decode(body.toOpenArray(1, body.high), RequestProofsMessage)
of offer:
message.offer = SSZ.decode(body.toOpenArray(1, body.high), OfferMessage)
of accept:
message.accept = SSZ.decode(body.toOpenArray(1, body.high), AcceptMessage)
except SszError:
return err("Invalid message encoding")

View File

@ -143,13 +143,17 @@ proc handleFindContent(p: PortalProtocol, fc: FindContentMessage): seq[byte] =
encodeMessage(FoundContentMessage(
enrs: enrs, payload: content))
proc handleAdvertise(p: PortalProtocol, a: AdvertiseMessage): seq[byte] =
# TODO: Not implemented
proc handleOffer(p: PortalProtocol, a: OfferMessage): seq[byte] =
let
connectionId = List[byte, 4](@[])
contentKeys = List[ByteList, 32](@[])
encodeMessage(RequestProofsMessage(connectionId: connectionId,
contentKeys: contentKeys))
# TODO: Random ID that needs to be stored together with some buffer that
# gets shared with uTP session that needs to be set up (start listening)
connectionId = Bytes2([byte 0x01, 0x02])
# TODO: Not implemented: Based on the content radius and the content that is
# already stored, interest in provided content keys needs to be indicated
# by setting bits in this BitList
contentKeys = ContentKeysBitList.init(a.contentKeys.len)
encodeMessage(
AcceptMessage(connectionId: connectionId, contentKeys: contentKeys))
proc messageHandler*(protocol: TalkProtocol, request: seq[byte],
srcId: NodeId, srcUdpAddress: Address): seq[byte] =
@ -168,8 +172,8 @@ proc messageHandler*(protocol: TalkProtocol, request: seq[byte],
p.handleFindNode(message.findNode)
of MessageKind.findcontent:
p.handleFindContent(message.findcontent)
of MessageKind.advertise:
p.handleAdvertise(message.advertise)
of MessageKind.offer:
p.handleOffer(message.offer)
else:
@[]
else:
@ -242,6 +246,19 @@ proc findContent*(p: PortalProtocol, dst: Node, contentKey: ByteList):
return await reqResponse[FindContentMessage, FoundContentMessage](
p, dst, PortalProtocolId, fc)
proc offer*(p: PortalProtocol, dst: Node, contentKeys: ContentKeysList):
Future[PortalResult[AcceptMessage]] {.async.} =
let offer = OfferMessage(contentKeys: contentKeys)
trace "Send message request", dstId = dst.id, kind = MessageKind.offer
return await reqResponse[OfferMessage, AcceptMessage](
p, dst, PortalProtocolId, offer)
# TODO: Actually have to parse the offer message and get the uTP connection
# id, and initiate an uTP stream with given uTP connection id to get the data
# out.
proc recordsFromBytes(rawRecords: List[ByteList, 32]): seq[Record] =
var records: seq[Record]
for r in rawRecords.asSeq():

View File

@ -185,3 +185,16 @@ procSuite "Portal Tests":
await test.stopTest()
asyncTest "Portal Offer/Accept":
let test = defaultTestCase(rng)
let contentKeys = ContentKeysList(List(@[ByteList(@[byte 0x01, 0x02, 0x03])]))
let accept = await test.proto1.offer(
test.proto2.baseProtocol.localNode, contentKeys)
check:
accept.isOk()
accept.get().connectionId.len == 2
accept.get().contentKeys.len == contentKeys.len
await test.stopTest()

View File

@ -165,41 +165,37 @@ suite "Portal Protocol Message Encodings":
message.foundcontent.enrs[1] == ByteList(e2.raw)
message.foundcontent.payload == payload
test "Advertise Request":
test "Offer Request":
let
contentKeys = List[ByteList, 32](List(@[ByteList(@[byte 0x01, 0x02, 0x03])]))
am = AdvertiseMessage(contentKeys)
# am = AdvertiseMessage(contentKeys: contentKeys)
contentKeys = ContentKeysList(List(@[ByteList(@[byte 0x01, 0x02, 0x03])]))
am = OfferMessage(contentKeys: contentKeys)
let encoded = encodeMessage(am)
check encoded.toHex == "0704000000010203"
# "070400000004000000010203"
check encoded.toHex == "070400000004000000010203"
let decoded = decodeMessage(encoded)
check decoded.isOk()
let message = decoded.get()
check:
message.kind == advertise
message.advertise == contentKeys
# message.advertise.contentKeys == contentKeys
message.kind == offer
message.offer.contentKeys == contentKeys
test "RequestProofs Response": # That sounds weird
test "Accept Response":
let
connectionId = List[byte, 4](@[byte 0x01, 0x02, 0x03, 0x04])
contentKeys =
List[ByteList, 32](List(@[ByteList(@[byte 0x01, 0x02, 0x03])]))
n = RequestProofsMessage(connectionId: connectionId,
connectionId = Bytes2([byte 0x01, 0x02])
contentKeys = ContentKeysBitList.init(8)
n = AcceptMessage(connectionId: connectionId,
contentKeys: contentKeys)
let encoded = encodeMessage(n)
check encoded.toHex == "08080000000c0000000102030404000000010203"
check encoded.toHex == "080102060000000001"
let decoded = decodeMessage(encoded)
check decoded.isOk()
let message = decoded.get()
check:
message.kind == requestproofs
message.requestproofs.connectionId == connectionId
message.requestproofs.contentKeys == contentKeys
message.kind == MessageKind.accept
message.accept.connectionId == connectionId
message.accept.contentKeys == contentKeys