diff --git a/fluffy/network/state/messages.nim b/fluffy/network/state/messages.nim index 6a1445b95..856bcf1f7 100644 --- a/fluffy/network/state/messages.nim +++ b/fluffy/network/state/messages.nim @@ -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") diff --git a/fluffy/network/state/portal_protocol.nim b/fluffy/network/state/portal_protocol.nim index 75f8c314b..a104cba0d 100644 --- a/fluffy/network/state/portal_protocol.nim +++ b/fluffy/network/state/portal_protocol.nim @@ -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(): diff --git a/fluffy/tests/test_portal.nim b/fluffy/tests/test_portal.nim index 614e0d715..2a596811a 100644 --- a/fluffy/tests/test_portal.nim +++ b/fluffy/tests/test_portal.nim @@ -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() diff --git a/fluffy/tests/test_portal_encoding.nim b/fluffy/tests/test_portal_encoding.nim index 67389099d..b7f8f2c0d 100644 --- a/fluffy/tests/test_portal_encoding.nim +++ b/fluffy/tests/test_portal_encoding.nim @@ -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