From 523cc1c70c1e08165285fe09953c560a0a059927 Mon Sep 17 00:00:00 2001 From: kdeme <7857583+kdeme@users.noreply.github.com> Date: Fri, 17 Jan 2025 18:04:15 +0100 Subject: [PATCH 1/2] Minimal implementation of Portal ping payload extensions spec --- fluffy/network/beacon/beacon_network.nim | 7 +- fluffy/network/history/history_network.nim | 5 +- fluffy/network/state/state_network.nim | 7 +- fluffy/network/wire/messages.nim | 6 +- fluffy/network/wire/ping_extensions.nim | 89 ++++++++ fluffy/network/wire/portal_protocol.nim | 118 ++++++++--- fluffy/rpc/rpc_portal_common_api.nim | 14 +- .../all_wire_protocol_tests.nim | 7 +- .../test_ping_extensions_encoding.nim | 194 ++++++++++++++++++ .../test_portal_wire_encoding.nim | 20 +- .../test_portal_wire_protocol.nim | 22 +- 11 files changed, 415 insertions(+), 74 deletions(-) create mode 100644 fluffy/network/wire/ping_extensions.nim create mode 100644 fluffy/tests/wire_protocol_tests/test_ping_extensions_encoding.nim diff --git a/fluffy/network/beacon/beacon_network.nim b/fluffy/network/beacon/beacon_network.nim index 9ee4de945a..4191293f52 100644 --- a/fluffy/network/beacon/beacon_network.nim +++ b/fluffy/network/beacon/beacon_network.nim @@ -1,5 +1,5 @@ # fluffy -# Copyright (c) 2022-2024 Status Research & Development GmbH +# Copyright (c) 2022-2025 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). @@ -14,7 +14,7 @@ import eth/p2p/discoveryv5/[protocol, enr], beacon_chain/spec/forks, beacon_chain/gossip_processing/light_client_processor, - ../wire/[portal_protocol, portal_stream, portal_protocol_config], + ../wire/[portal_protocol, portal_stream, portal_protocol_config, ping_extensions], "."/[beacon_content, beacon_db, beacon_validation, beacon_chain_historical_summaries] export beacon_content, beacon_db @@ -22,6 +22,8 @@ export beacon_content, beacon_db logScope: topics = "portal_beacon" +const pingExtensionCapabilities = {CapabilitiesType, BasicRadiusType} + type BeaconNetwork* = ref object portalProtocol*: PortalProtocol beaconDb*: BeaconDb @@ -213,6 +215,7 @@ proc new*( stream, bootstrapRecords, config = portalConfig, + pingExtensionCapabilities = pingExtensionCapabilities, ) let beaconBlockRoot = diff --git a/fluffy/network/history/history_network.nim b/fluffy/network/history/history_network.nim index 8a362e3f89..18546667db 100644 --- a/fluffy/network/history/history_network.nim +++ b/fluffy/network/history/history_network.nim @@ -17,7 +17,7 @@ import ../../common/common_types, ../../database/content_db, ../../network_metadata, - ../wire/[portal_protocol, portal_stream, portal_protocol_config], + ../wire/[portal_protocol, portal_stream, portal_protocol_config, ping_extensions], "."/[history_content, history_validation, history_type_conversions], ../beacon/beacon_chain_historical_roots, ./content/content_deprecated @@ -30,6 +30,8 @@ logScope: export blocks_rlp +const pingExtensionCapabilities = {CapabilitiesType, HistoryRadiusType} + type HistoryNetwork* = ref object portalProtocol*: PortalProtocol @@ -352,6 +354,7 @@ proc new*( stream, bootstrapRecords, config = portalConfig, + pingExtensionCapabilities = pingExtensionCapabilities, ) HistoryNetwork( diff --git a/fluffy/network/state/state_network.nim b/fluffy/network/state/state_network.nim index fe4f82e403..6871b7130e 100644 --- a/fluffy/network/state/state_network.nim +++ b/fluffy/network/state/state_network.nim @@ -1,5 +1,5 @@ # Fluffy -# Copyright (c) 2021-2024 Status Research & Development GmbH +# Copyright (c) 2021-2025 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). @@ -16,7 +16,7 @@ import eth/p2p/discoveryv5/[protocol, enr], ../../database/content_db, ../history/history_network, - ../wire/[portal_protocol, portal_stream, portal_protocol_config], + ../wire/[portal_protocol, portal_stream, portal_protocol_config, ping_extensions], ./state_content, ./state_validation, ./state_gossip @@ -31,6 +31,8 @@ declareCounter state_network_offers_success, declareCounter state_network_offers_failed, "Portal state network offers which failed validation", labels = ["protocol_id"] +const pingExtensionCapabilities = {CapabilitiesType, BasicRadiusType} + type StateNetwork* = ref object portalProtocol*: PortalProtocol contentQueue*: AsyncQueue[(Opt[NodeId], ContentKeysList, seq[seq[byte]])] @@ -69,6 +71,7 @@ proc new*( s, bootstrapRecords, config = portalConfig, + pingExtensionCapabilities = pingExtensionCapabilities, ) StateNetwork( diff --git a/fluffy/network/wire/messages.nim b/fluffy/network/wire/messages.nim index 1f6515cfbc..90373c94ef 100644 --- a/fluffy/network/wire/messages.nim +++ b/fluffy/network/wire/messages.nim @@ -1,5 +1,5 @@ # Nimbus - Portal Network- Message types -# Copyright (c) 2021-2024 Status Research & Development GmbH +# Copyright (c) 2021-2025 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). @@ -29,10 +29,6 @@ type ContentKeysList* = List[ContentKeyByteList, contentKeysLimit] ContentKeysBitList* = BitList[contentKeysLimit] - # TODO: should become part of the specific networks, considering it is custom. - CustomPayload* = object - dataRadius*: UInt256 - MessageKind* = enum ping = 0x00 pong = 0x01 diff --git a/fluffy/network/wire/ping_extensions.nim b/fluffy/network/wire/ping_extensions.nim new file mode 100644 index 0000000000..c108b491c0 --- /dev/null +++ b/fluffy/network/wire/ping_extensions.nim @@ -0,0 +1,89 @@ +# Nimbus +# Copyright (c) 2025 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. + +{.push raises: [].} + +import ssz_serialization + +type CustomPayloadExtensionsFormat* = object + `type`*: uint16 + payload*: ByteList[1100] + +const + # Extension types + CapabilitiesType* = 0'u16 + BasicRadiusType* = 1'u16 + HistoryRadiusType* = 2'u16 + ErrorType* = 65535'u16 + + # Limits + MAX_CLIENT_INFO_BYTE_LENGTH* = 200 + MAX_CAPABILITIES_LENGTH* = 400 + MAX_ERROR_BYTE_LENGTH* = 300 + +# Different ping extension payloads, TODO: could be moved to each their own file? +type + CapabilitiesPayload* = object + client_info*: ByteList[MAX_CLIENT_INFO_BYTE_LENGTH] + data_radius*: UInt256 + capabilities*: List[uint16, MAX_CAPABILITIES_LENGTH] + + BasicRadiusPayload* = object + data_radius*: UInt256 + + HistoryRadiusPayload* = object + data_radius*: UInt256 + ephemeral_header_count*: uint16 + + ErrorPayload* = object + error_code*: uint16 + message*: ByteList[MAX_ERROR_BYTE_LENGTH] + + ErrorCode* = enum + ExtensionNotSupported = 0 + RequestedDataNotFound = 1 + FailedToDecodePayload = 2 + SystemError = 3 + +func encodeCustomPayload*(payload: CapabilitiesPayload): ByteList[2048] = + let + encodedPayload = SSZ.encode(payload) + customPayload = CustomPayloadExtensionsFormat( + `type`: CapabilitiesType, payload: ByteList[1100](encodedPayload) + ) + ByteList[2048](SSZ.encode(customPayload)) + +func encodeCustomPayload*(payload: BasicRadiusPayload): ByteList[2048] = + let + encodedPayload = SSZ.encode(payload) + customPayload = CustomPayloadExtensionsFormat( + `type`: BasicRadiusType, payload: ByteList[1100](encodedPayload) + ) + return ByteList[2048](SSZ.encode(customPayload)) + +func encodeCustomPayload*(payload: HistoryRadiusPayload): ByteList[2048] = + let + encodedPayload = SSZ.encode(payload) + customPayload = CustomPayloadExtensionsFormat( + `type`: HistoryRadiusType, payload: ByteList[1100](encodedPayload) + ) + return ByteList[2048](SSZ.encode(customPayload)) + +func encodeCustomPayload*(payload: ErrorPayload): ByteList[2048] = + let + encodedPayload = SSZ.encode(payload) + customPayload = CustomPayloadExtensionsFormat( + `type`: ErrorType, payload: ByteList[1100](encodedPayload) + ) + return ByteList[2048](SSZ.encode(customPayload)) + +func encodeErrorPayload*(code: ErrorCode): ByteList[2048] = + encodeCustomPayload( + ErrorPayload( + error_code: uint16(ord(code)), message: ByteList[MAX_ERROR_BYTE_LENGTH].init(@[]) + ) + ) diff --git a/fluffy/network/wire/portal_protocol.nim b/fluffy/network/wire/portal_protocol.nim index f7304ca334..3697017cbf 100644 --- a/fluffy/network/wire/portal_protocol.nim +++ b/fluffy/network/wire/portal_protocol.nim @@ -24,7 +24,7 @@ import minilru, eth/rlp, eth/p2p/discoveryv5/[protocol, node, enr, routing_table, random2, nodes_verification], - "."/[portal_stream, portal_protocol_config], + "."/[portal_stream, portal_protocol_config, ping_extensions], ./messages from std/times import epochTime # For system timestamp in traceContentLookup @@ -186,6 +186,7 @@ type offerWorkers: seq[Future[void]] pingTimings: Table[NodeId, chronos.Moment] config*: PortalProtocolConfig + pingExtensionCapabilities*: set[uint16] PortalResult*[T] = Result[T, string] @@ -334,26 +335,63 @@ func truncateEnrs( enrs +proc handlePingExtension( + p: PortalProtocol, encodedCustomPayload: ByteList[2048], srcId: NodeId +): ByteList[2048] = + let customPayload = decodeSsz( + encodedCustomPayload.asSeq(), CustomPayloadExtensionsFormat + ).valueOr: + # invalid custom payload format, send back FailedToDecodePayload + return encodeErrorPayload(ErrorCode.FailedToDecodePayload) + + if customPayload.`type` notin p.pingExtensionCapabilities: + return encodeErrorPayload(ErrorCode.ExtensionNotSupported) + + case customPayload.`type` + of CapabilitiesType: + let payload = decodeSsz(customPayload.payload.asSeq(), CapabilitiesPayload).valueOr: + return encodeErrorPayload(ErrorCode.FailedToDecodePayload) + + p.radiusCache.put(srcId, payload.data_radius) + + encodeCustomPayload( + CapabilitiesPayload( + client_info: ByteList[MAX_CLIENT_INFO_BYTE_LENGTH].init(@[]), + data_radius: p.dataRadius(), + capabilities: List[uint16, MAX_CAPABILITIES_LENGTH].init( + p.pingExtensionCapabilities.toSeq() + ), + ) + ) + of BasicRadiusType: + let payload = decodeSsz(customPayload.payload.asSeq(), BasicRadiusPayload).valueOr: + return encodeErrorPayload(ErrorCode.FailedToDecodePayload) + + p.radiusCache.put(srcId, payload.data_radius) + + encodeCustomPayload(HistoryRadiusPayload(data_radius: p.dataRadius())) + of HistoryRadiusType: + let payload = decodeSsz(customPayload.payload.asSeq(), HistoryRadiusPayload).valueOr: + return encodeErrorPayload(ErrorCode.FailedToDecodePayload) + + p.radiusCache.put(srcId, payload.data_radius) + + encodeCustomPayload( + HistoryRadiusPayload(data_radius: p.dataRadius(), ephemeral_header_count: 0) + ) + else: + encodeErrorPayload(ErrorCode.ExtensionNotSupported) + proc handlePing(p: PortalProtocol, ping: PingMessage, srcId: NodeId): seq[byte] = - # TODO: This should become custom per Portal Network # TODO: Need to think about the effect of malicious actor sending lots of # pings from different nodes to clear the LRU. - let customPayloadDecoded = - try: - SSZ.decode(ping.customPayload.asSeq(), CustomPayload) - except SerializationError: - # invalid custom payload, send empty back - return @[] - p.radiusCache.put(srcId, customPayloadDecoded.dataRadius) - - let customPayload = CustomPayload(dataRadius: p.dataRadius()) - let p = PongMessage( - enrSeq: p.localNode.record.seqNum, - customPayload: ByteList[2048](SSZ.encode(customPayload)), + encodeMessage( + PongMessage( + enrSeq: p.localNode.record.seqNum, + customPayload: handlePingExtension(p, ping.customPayload, srcId), + ) ) - encodeMessage(p) - proc handleFindNodes(p: PortalProtocol, fn: FindNodesMessage): seq[byte] = if fn.distances.len == 0: let enrs = List[ByteList[2048], 32](@[]) @@ -573,6 +611,7 @@ proc new*( bootstrapRecords: openArray[Record] = [], distanceCalculator: DistanceCalculator = XorDistanceCalculator, config: PortalProtocolConfig = defaultPortalProtocolConfig, + pingExtensionCapabilities: set[uint16] = {CapabilitiesType}, ): T = let proto = PortalProtocol( protocolHandler: messageHandler, @@ -595,6 +634,7 @@ proc new*( offerQueue: newAsyncQueue[OfferRequest](config.maxConcurrentOffers), pingTimings: Table[NodeId, chronos.Moment](), config: config, + pingExtensionCapabilities: pingExtensionCapabilities, ) proto.baseProtocol.registerTalkProtocol(@(proto.protocolId), proto).expect( @@ -657,12 +697,18 @@ proc reqResponse[Request: SomeMessage, Response: SomeMessage]( proc pingImpl*( p: PortalProtocol, dst: Node ): Future[PortalResult[PongMessage]] {.async: (raises: [CancelledError]).} = - let customPayload = CustomPayload(dataRadius: p.dataRadius()) - let ping = PingMessage( - enrSeq: p.localNode.record.seqNum, - customPayload: ByteList[2048](SSZ.encode(customPayload)), + let pingCustomPayload = encodeCustomPayload( + CapabilitiesPayload( + client_info: ByteList[MAX_CLIENT_INFO_BYTE_LENGTH].init(@[]), + data_radius: p.dataRadius(), + capabilities: + List[uint16, MAX_CAPABILITIES_LENGTH].init(p.pingExtensionCapabilities.toSeq()), + ) ) + let ping = + PingMessage(enrSeq: p.localNode.record.seqNum, customPayload: pingCustomPayload) + return await reqResponse[PingMessage, PongMessage](p, dst, ping) proc findNodesImpl*( @@ -701,7 +747,9 @@ proc recordsFromBytes(rawRecords: List[ByteList[2048], 32]): PortalResult[seq[Re proc ping*( p: PortalProtocol, dst: Node -): Future[PortalResult[PongMessage]] {.async: (raises: [CancelledError]).} = +): Future[PortalResult[(uint64, CapabilitiesPayload)]] {. + async: (raises: [CancelledError]) +.} = let pongResponse = await p.pingImpl(dst) if pongResponse.isOk(): @@ -709,17 +757,23 @@ proc ping*( p.pingTimings[dst.id] = now(chronos.Moment) let pong = pongResponse.get() - # TODO: This should become custom per Portal Network - let customPayloadDecoded = - try: - SSZ.decode(pong.customPayload.asSeq(), CustomPayload) - except SerializationError: - # invalid custom payload - return err("Pong message contains invalid custom payload") - p.radiusCache.put(dst.id, customPayloadDecoded.dataRadius) + let customPayload = decodeSsz( + pong.customPayload.asSeq(), CustomPayloadExtensionsFormat + ).valueOr: + return err("Pong message contains invalid custom payload") + + if customPayload.`type` != CapabilitiesType: + return err("Pong message contains invalid custom payload") + + let payload = decodeSsz(customPayload.payload.asSeq(), CapabilitiesPayload).valueOr: + return err("Pong message contains invalid CapabilitiesPayload") - return pongResponse + p.radiusCache.put(dst.id, payload.data_radius) + + ok((pong.enrSeq, payload)) + else: + err(pongResponse.error) proc findNodes*( p: PortalProtocol, dst: Node, distances: seq[uint16] @@ -1691,8 +1745,8 @@ proc revalidateNode*(p: PortalProtocol, n: Node) {.async: (raises: [CancelledErr let pong = await p.ping(n) if pong.isOk(): - let res = pong.get() - if res.enrSeq > n.record.seqNum: + let (enrSeq, _) = pong.get() + if enrSeq > n.record.seqNum: # Request new ENR let nodesMessage = await p.findNodes(n, @[0'u16]) if nodesMessage.isOk(): diff --git a/fluffy/rpc/rpc_portal_common_api.nim b/fluffy/rpc/rpc_portal_common_api.nim index 013719e799..4b311d3a82 100644 --- a/fluffy/rpc/rpc_portal_common_api.nim +++ b/fluffy/rpc/rpc_portal_common_api.nim @@ -1,5 +1,5 @@ # fluffy -# Copyright (c) 2021-2024 Status Research & Development GmbH +# Copyright (c) 2021-2025 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). @@ -83,16 +83,8 @@ proc installPortalCommonApiHandlers*( if pong.isErr(): raise newException(ValueError, $pong.error) else: - let - p = pong.get() - # Note: the SSZ.decode cannot fail here as it has already been verified - # in the ping call. - decodedPayload = - try: - SSZ.decode(p.customPayload.asSeq(), CustomPayload) - except MalformedSszError, SszSizeMismatchError: - raiseAssert("Already verified") - return (p.enrSeq, decodedPayload.dataRadius) + let (enrSeq, pongPayload) = pong.get() + return (enrSeq, pongPayload.data_radius) rpcServer.rpc("portal_" & networkStr & "FindNodes") do( enr: Record, distances: seq[uint16] diff --git a/fluffy/tests/wire_protocol_tests/all_wire_protocol_tests.nim b/fluffy/tests/wire_protocol_tests/all_wire_protocol_tests.nim index 856aa70929..ae47106f63 100644 --- a/fluffy/tests/wire_protocol_tests/all_wire_protocol_tests.nim +++ b/fluffy/tests/wire_protocol_tests/all_wire_protocol_tests.nim @@ -1,5 +1,5 @@ # Nimbus -# Copyright (c) 2024 Status Research & Development GmbH +# Copyright (c) 2025 Status Research & Development GmbH # Licensed under either of # * 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) @@ -7,4 +7,7 @@ {.warning[UnusedImport]: off.} -import ./test_portal_wire_encoding, ./test_portal_wire_protocol +import + ./test_portal_wire_encoding, + ./test_portal_wire_protocol, + ./test_ping_extensions_encoding diff --git a/fluffy/tests/wire_protocol_tests/test_ping_extensions_encoding.nim b/fluffy/tests/wire_protocol_tests/test_ping_extensions_encoding.nim new file mode 100644 index 0000000000..b2f199003f --- /dev/null +++ b/fluffy/tests/wire_protocol_tests/test_ping_extensions_encoding.nim @@ -0,0 +1,194 @@ +# Nimbus +# Copyright (c) 2025 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. + +{.used.} + +import + unittest2, + stint, + stew/byteutils, + results, + ../../network/wire/[messages, ping_extensions] + +suite "Portal Wire Ping Extension Encodings - Type 0x00": + test "SSZ encoded Ping request - with client info": + let + enr_seq = 1'u64 + data_radius = UInt256.high() - 1 # Full radius - 1 + client_info = "trin/v0.1.1-b61fdc5c/linux-x86_64/rustc1.81.0" + capabilities = @[uint16 0, 1, 65535] + + payload = CapabilitiesPayload( + client_info: ByteList[MAX_CLIENT_INFO_BYTE_LENGTH](client_info.toBytes()), + data_radius: data_radius, + capabilities: List[uint16, MAX_CAPABILITIES_LENGTH].init(capabilities), + ) + customPayload = encodeCustomPayload(payload) + ping = PingMessage(enrSeq: enr_seq, customPayload: customPayload) + + let encoded = encodeMessage(ping) + check encoded.to0xHex == + "0x0001000000000000000c00000000000600000028000000feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff550000007472696e2f76302e312e312d62363166646335632f6c696e75782d7838365f36342f7275737463312e38312e3000000100ffff" + + let decoded = decodeMessage(encoded) + check decoded.isOk() + let message = decoded.value() + check: + message.kind == MessageKind.ping + message.ping.enrSeq == enr_seq + message.ping.customPayload == customPayload + + let decodedCustomPayload = + decodeSsz(message.ping.customPayload.asSeq(), CustomPayloadExtensionsFormat) + check: + decodedCustomPayload.isOk() + decodedCustomPayload.value().type == CapabilitiesType + + let decodedPayload = + decodeSsz(decodedCustomPayload.value.payload.asSeq(), CapabilitiesPayload) + check: + decodedPayload.isOk() + decodedPayload.value().client_info.asSeq() == client_info.toBytes() + decodedPayload.value().data_radius == data_radius + decodedPayload.value().capabilities.asSeq() == capabilities + + test "SSZ encoded Ping request - with empty client info": + let + enr_seq = 1'u64 + data_radius = UInt256.high() - 1 # Full radius - 1 + client_info = "" + capabilities = @[uint16 0, 1, 65535] + + payload = CapabilitiesPayload( + client_info: ByteList[MAX_CLIENT_INFO_BYTE_LENGTH](client_info.toBytes()), + data_radius: data_radius, + capabilities: List[uint16, MAX_CAPABILITIES_LENGTH].init(capabilities), + ) + customPayload = encodeCustomPayload(payload) + ping = PingMessage(enrSeq: enr_seq, customPayload: customPayload) + + let encoded = encodeMessage(ping) + check encoded.to0xHex == + "0x0001000000000000000c00000000000600000028000000feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2800000000000100ffff" + let decoded = decodeMessage(encoded) + check decoded.isOk() + + test "SSZ encoded Pong response - with client info": + let + enr_seq = 1'u64 + data_radius = UInt256.high() - 1 # Full radius - 1 + client_info = "trin/v0.1.1-b61fdc5c/linux-x86_64/rustc1.81.0" + capabilities = @[uint16 0, 1, 65535] + + payload = CapabilitiesPayload( + client_info: ByteList[MAX_CLIENT_INFO_BYTE_LENGTH](client_info.toBytes()), + data_radius: data_radius, + capabilities: List[uint16, MAX_CAPABILITIES_LENGTH].init(capabilities), + ) + customPayload = encodeCustomPayload(payload) + pong = PongMessage(enrSeq: enr_seq, customPayload: customPayload) + + let encoded = encodeMessage(pong) + check encoded.to0xHex == + "0x0101000000000000000c00000000000600000028000000feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff550000007472696e2f76302e312e312d62363166646335632f6c696e75782d7838365f36342f7275737463312e38312e3000000100ffff" + + test "SSZ encoded Pong response - with empty client info": + let + enr_seq = 1'u64 + data_radius = UInt256.high() - 1 # Full radius - 1 + client_info = "" + capabilities = @[uint16 0, 1, 65535] + + payload = CapabilitiesPayload( + client_info: ByteList[MAX_CLIENT_INFO_BYTE_LENGTH](client_info.toBytes()), + data_radius: data_radius, + capabilities: List[uint16, MAX_CAPABILITIES_LENGTH].init(capabilities), + ) + customPayload = encodeCustomPayload(payload) + pong = PongMessage(enrSeq: enr_seq, customPayload: customPayload) + + let encoded = encodeMessage(pong) + check encoded.to0xHex == + "0x0101000000000000000c00000000000600000028000000feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2800000000000100ffff" + +suite "Portal Wire Ping Extension Encodings - Type 0x01": + test "SSZ encoded Ping request": + let + enr_seq = 1'u64 + data_radius = UInt256.high() - 1 # Full radius - 1 + + payload = BasicRadiusPayload(data_radius: data_radius) + customPayload = encodeCustomPayload(payload) + ping = PingMessage(enrSeq: enr_seq, customPayload: customPayload) + + let encoded = encodeMessage(ping) + check encoded.to0xHex == + "0x0001000000000000000c000000010006000000feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + + test "SSZ encoded Pong response": + let + enr_seq = 1'u64 + data_radius = UInt256.high() - 1 # Full radius - 1 + + payload = BasicRadiusPayload(data_radius: data_radius) + customPayload = encodeCustomPayload(payload) + pong = PongMessage(enrSeq: enr_seq, customPayload: customPayload) + + let encoded = encodeMessage(pong) + check encoded.to0xHex == + "0x0101000000000000000c000000010006000000feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + +suite "Portal Wire Ping Extension Encodings - Type 0x02": + test "SSZ encoded Ping request": + let + enr_seq = 1'u64 + data_radius = UInt256.high() - 1 # Full radius - 1 + ephemeral_header_count = 4242'u16 + + payload = HistoryRadiusPayload( + data_radius: data_radius, ephemeral_header_count: ephemeral_header_count + ) + customPayload = encodeCustomPayload(payload) + ping = PingMessage(enrSeq: enr_seq, customPayload: customPayload) + + let encoded = encodeMessage(ping) + check encoded.to0xHex == + "0x0001000000000000000c000000020006000000feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9210" + + test "SSZ encoded Pong response": + let + enr_seq = 1'u64 + data_radius = UInt256.high() - 1 # Full radius - 1 + ephemeral_header_count = 4242'u16 + + payload = HistoryRadiusPayload( + data_radius: data_radius, ephemeral_header_count: ephemeral_header_count + ) + customPayload = encodeCustomPayload(payload) + pong = PongMessage(enrSeq: enr_seq, customPayload: customPayload) + + let encoded = encodeMessage(pong) + check encoded.to0xHex == + "0x0101000000000000000c000000020006000000feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9210" + +suite "Portal Wire Ping Extension Encodings - Type 0x03": + test "SSZ encoded Pong response": + let + enr_seq = 1'u64 + error_code = 2'u16 + message = "hello world" + + payload = ErrorPayload( + error_code: error_code, + message: ByteList[MAX_ERROR_BYTE_LENGTH].init(message.toBytes()), + ) + customPayload = encodeCustomPayload(payload) + pong = PongMessage(enrSeq: enr_seq, customPayload: customPayload) + + let encoded = encodeMessage(pong) + check encoded.to0xHex == + "0x0101000000000000000c000000ffff0600000002000600000068656c6c6f20776f726c64" diff --git a/fluffy/tests/wire_protocol_tests/test_portal_wire_encoding.nim b/fluffy/tests/wire_protocol_tests/test_portal_wire_encoding.nim index 3a9e939fbc..cbb43591b9 100644 --- a/fluffy/tests/wire_protocol_tests/test_portal_wire_encoding.nim +++ b/fluffy/tests/wire_protocol_tests/test_portal_wire_encoding.nim @@ -1,5 +1,5 @@ -# Fluffy -# Copyright (c) 2021-2024 Status Research & Development GmbH +# Nimbus +# Copyright (c) 2021-2025 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). @@ -21,15 +21,13 @@ import suite "Portal Wire Protocol Message Encodings": test "Ping Request": let - dataRadius = UInt256.high() - 1 # Full radius - 1 enrSeq = 1'u64 - # Can be any custom payload, testing with just dataRadius here. - customPayload = ByteList[2048](SSZ.encode(CustomPayload(dataRadius: dataRadius))) + # Can be any custom payload, testing with meaningless string of bytes. + customPayload = ByteList[2048].init(@[byte 0x01, 0x02, 0x03, 0x04]) p = PingMessage(enrSeq: enrSeq, customPayload: customPayload) let encoded = encodeMessage(p) - check encoded.toHex == - "0001000000000000000c000000feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + check encoded.toHex == "0001000000000000000c00000001020304" let decoded = decodeMessage(encoded) check decoded.isOk() @@ -41,15 +39,13 @@ suite "Portal Wire Protocol Message Encodings": test "Pong Response": 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[2048](SSZ.encode(CustomPayload(dataRadius: dataRadius))) + # Can be any custom payload, testing with meaningless string of bytes. + customPayload = ByteList[2048].init(@[byte 0x01, 0x02, 0x03, 0x04]) p = PongMessage(enrSeq: enrSeq, customPayload: customPayload) let encoded = encodeMessage(p) - check encoded.toHex == - "0101000000000000000c000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f" + check encoded.toHex == "0101000000000000000c00000001020304" let decoded = decodeMessage(encoded) check decoded.isOk() diff --git a/fluffy/tests/wire_protocol_tests/test_portal_wire_protocol.nim b/fluffy/tests/wire_protocol_tests/test_portal_wire_protocol.nim index 41b734401f..93c982cb99 100644 --- a/fluffy/tests/wire_protocol_tests/test_portal_wire_protocol.nim +++ b/fluffy/tests/wire_protocol_tests/test_portal_wire_protocol.nim @@ -1,5 +1,5 @@ # Fluffy -# Copyright (c) 2021-2024 Status Research & Development GmbH +# Copyright (c) 2021-2025 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). @@ -16,7 +16,8 @@ import eth/p2p/discoveryv5/routing_table, nimcrypto/[hash, sha2], eth/p2p/discoveryv5/protocol as discv5_protocol, - ../../network/wire/[portal_protocol, portal_stream, portal_protocol_config], + ../../network/wire/ + [portal_protocol, portal_stream, portal_protocol_config, ping_extensions], ../../database/content_db, ../test_helpers @@ -77,13 +78,20 @@ procSuite "Portal Wire Protocol Tests": let pong = await proto1.ping(proto2.localNode) - let customPayload = - ByteList[2048](SSZ.encode(CustomPayload(dataRadius: UInt256.high()))) + let customPayload = CapabilitiesPayload( + client_info: ByteList[MAX_CLIENT_INFO_BYTE_LENGTH].init(@[]), + data_radius: UInt256.high(), + capabilities: List[uint16, MAX_CAPABILITIES_LENGTH].init( + proto1.pingExtensionCapabilities.toSeq() + ), + ) + + check pong.isOk() + let (enrSeq, payload) = pong.value() check: - pong.isOk() - pong.get().enrSeq == 1'u64 - pong.get().customPayload == customPayload + enrSeq == 1'u64 + payload == customPayload await proto1.stopPortalProtocol() await proto2.stopPortalProtocol() From b82cf652e982bd7f3b55d277700daca619f66d1a Mon Sep 17 00:00:00 2001 From: kdeme <7857583+kdeme@users.noreply.github.com> Date: Mon, 20 Jan 2025 15:04:29 +0100 Subject: [PATCH 2/2] Remove serialization layer for CustomPayload (spec change) --- fluffy/network/wire/messages.nim | 6 +- fluffy/network/wire/ping_extensions.nim | 56 ++++--------- fluffy/network/wire/portal_protocol.nim | 79 +++++++++--------- .../test_ping_extensions_encoding.nim | 83 +++++++++++-------- .../test_portal_wire_encoding.nim | 18 ++-- 5 files changed, 118 insertions(+), 124 deletions(-) diff --git a/fluffy/network/wire/messages.nim b/fluffy/network/wire/messages.nim index 90373c94ef..10b15f28fa 100644 --- a/fluffy/network/wire/messages.nim +++ b/fluffy/network/wire/messages.nim @@ -46,11 +46,13 @@ type PingMessage* = object enrSeq*: uint64 - customPayload*: ByteList[2048] + payload_type*: uint16 + payload*: ByteList[1100] PongMessage* = object enrSeq*: uint64 - customPayload*: ByteList[2048] + payload_type*: uint16 + payload*: ByteList[1100] FindNodesMessage* = object distances*: List[uint16, 256] diff --git a/fluffy/network/wire/ping_extensions.nim b/fluffy/network/wire/ping_extensions.nim index c108b491c0..9e4dc278da 100644 --- a/fluffy/network/wire/ping_extensions.nim +++ b/fluffy/network/wire/ping_extensions.nim @@ -9,10 +9,6 @@ import ssz_serialization -type CustomPayloadExtensionsFormat* = object - `type`*: uint16 - payload*: ByteList[1100] - const # Extension types CapabilitiesType* = 0'u16 @@ -43,47 +39,25 @@ type error_code*: uint16 message*: ByteList[MAX_ERROR_BYTE_LENGTH] + CustomPayload* = + CapabilitiesPayload | BasicRadiusPayload | HistoryRadiusPayload | ErrorPayload + ErrorCode* = enum ExtensionNotSupported = 0 RequestedDataNotFound = 1 FailedToDecodePayload = 2 SystemError = 3 -func encodeCustomPayload*(payload: CapabilitiesPayload): ByteList[2048] = - let - encodedPayload = SSZ.encode(payload) - customPayload = CustomPayloadExtensionsFormat( - `type`: CapabilitiesType, payload: ByteList[1100](encodedPayload) - ) - ByteList[2048](SSZ.encode(customPayload)) - -func encodeCustomPayload*(payload: BasicRadiusPayload): ByteList[2048] = - let - encodedPayload = SSZ.encode(payload) - customPayload = CustomPayloadExtensionsFormat( - `type`: BasicRadiusType, payload: ByteList[1100](encodedPayload) - ) - return ByteList[2048](SSZ.encode(customPayload)) - -func encodeCustomPayload*(payload: HistoryRadiusPayload): ByteList[2048] = - let - encodedPayload = SSZ.encode(payload) - customPayload = CustomPayloadExtensionsFormat( - `type`: HistoryRadiusType, payload: ByteList[1100](encodedPayload) - ) - return ByteList[2048](SSZ.encode(customPayload)) - -func encodeCustomPayload*(payload: ErrorPayload): ByteList[2048] = - let - encodedPayload = SSZ.encode(payload) - customPayload = CustomPayloadExtensionsFormat( - `type`: ErrorType, payload: ByteList[1100](encodedPayload) - ) - return ByteList[2048](SSZ.encode(customPayload)) - -func encodeErrorPayload*(code: ErrorCode): ByteList[2048] = - encodeCustomPayload( - ErrorPayload( - error_code: uint16(ord(code)), message: ByteList[MAX_ERROR_BYTE_LENGTH].init(@[]) - ) +func encodePayload*(payload: CustomPayload): ByteList[1100] = + ByteList[1100].init(SSZ.encode(payload)) + +func encodeErrorPayload*(code: ErrorCode): (uint16, ByteList[1100]) = + ( + ErrorType, + encodePayload( + ErrorPayload( + error_code: uint16(ord(code)), + message: ByteList[MAX_ERROR_BYTE_LENGTH].init(@[]), + ) + ), ) diff --git a/fluffy/network/wire/portal_protocol.nim b/fluffy/network/wire/portal_protocol.nim index 3697017cbf..b6a778fe40 100644 --- a/fluffy/network/wire/portal_protocol.nim +++ b/fluffy/network/wire/portal_protocol.nim @@ -336,48 +336,51 @@ func truncateEnrs( enrs proc handlePingExtension( - p: PortalProtocol, encodedCustomPayload: ByteList[2048], srcId: NodeId -): ByteList[2048] = - let customPayload = decodeSsz( - encodedCustomPayload.asSeq(), CustomPayloadExtensionsFormat - ).valueOr: - # invalid custom payload format, send back FailedToDecodePayload - return encodeErrorPayload(ErrorCode.FailedToDecodePayload) - - if customPayload.`type` notin p.pingExtensionCapabilities: + p: PortalProtocol, + payloadType: uint16, + encodedPayload: ByteList[1100], + srcId: NodeId, +): (uint16, ByteList[1100]) = + if payloadType notin p.pingExtensionCapabilities: return encodeErrorPayload(ErrorCode.ExtensionNotSupported) - case customPayload.`type` + case payloadType of CapabilitiesType: - let payload = decodeSsz(customPayload.payload.asSeq(), CapabilitiesPayload).valueOr: + let payload = decodeSsz(encodedPayload.asSeq(), CapabilitiesPayload).valueOr: return encodeErrorPayload(ErrorCode.FailedToDecodePayload) p.radiusCache.put(srcId, payload.data_radius) - encodeCustomPayload( - CapabilitiesPayload( - client_info: ByteList[MAX_CLIENT_INFO_BYTE_LENGTH].init(@[]), - data_radius: p.dataRadius(), - capabilities: List[uint16, MAX_CAPABILITIES_LENGTH].init( - p.pingExtensionCapabilities.toSeq() - ), - ) + ( + payloadType, + encodePayload( + CapabilitiesPayload( + client_info: ByteList[MAX_CLIENT_INFO_BYTE_LENGTH].init(@[]), + data_radius: p.dataRadius(), + capabilities: List[uint16, MAX_CAPABILITIES_LENGTH].init( + p.pingExtensionCapabilities.toSeq() + ), + ) + ), ) of BasicRadiusType: - let payload = decodeSsz(customPayload.payload.asSeq(), BasicRadiusPayload).valueOr: + let payload = decodeSsz(encodedPayload.asSeq(), BasicRadiusPayload).valueOr: return encodeErrorPayload(ErrorCode.FailedToDecodePayload) p.radiusCache.put(srcId, payload.data_radius) - encodeCustomPayload(HistoryRadiusPayload(data_radius: p.dataRadius())) + (payloadType, encodePayload(HistoryRadiusPayload(data_radius: p.dataRadius()))) of HistoryRadiusType: - let payload = decodeSsz(customPayload.payload.asSeq(), HistoryRadiusPayload).valueOr: + let payload = decodeSsz(encodedPayload.asSeq(), HistoryRadiusPayload).valueOr: return encodeErrorPayload(ErrorCode.FailedToDecodePayload) p.radiusCache.put(srcId, payload.data_radius) - encodeCustomPayload( - HistoryRadiusPayload(data_radius: p.dataRadius(), ephemeral_header_count: 0) + ( + payloadType, + encodePayload( + HistoryRadiusPayload(data_radius: p.dataRadius(), ephemeral_header_count: 0) + ), ) else: encodeErrorPayload(ErrorCode.ExtensionNotSupported) @@ -385,10 +388,12 @@ proc handlePingExtension( proc handlePing(p: PortalProtocol, ping: PingMessage, srcId: NodeId): seq[byte] = # TODO: Need to think about the effect of malicious actor sending lots of # pings from different nodes to clear the LRU. + let (payloadType, payload) = + handlePingExtension(p, ping.payload_type, ping.payload, srcId) + encodeMessage( PongMessage( - enrSeq: p.localNode.record.seqNum, - customPayload: handlePingExtension(p, ping.customPayload, srcId), + enrSeq: p.localNode.record.seqNum, payload_type: payloadType, payload: payload ) ) @@ -697,7 +702,7 @@ proc reqResponse[Request: SomeMessage, Response: SomeMessage]( proc pingImpl*( p: PortalProtocol, dst: Node ): Future[PortalResult[PongMessage]] {.async: (raises: [CancelledError]).} = - let pingCustomPayload = encodeCustomPayload( + let pingPayload = encodePayload( CapabilitiesPayload( client_info: ByteList[MAX_CLIENT_INFO_BYTE_LENGTH].init(@[]), data_radius: p.dataRadius(), @@ -706,8 +711,11 @@ proc pingImpl*( ) ) - let ping = - PingMessage(enrSeq: p.localNode.record.seqNum, customPayload: pingCustomPayload) + let ping = PingMessage( + enrSeq: p.localNode.record.seqNum, + payload_type: CapabilitiesType, + payload: pingPayload, + ) return await reqResponse[PingMessage, PongMessage](p, dst, ping) @@ -758,15 +766,12 @@ proc ping*( let pong = pongResponse.get() - let customPayload = decodeSsz( - pong.customPayload.asSeq(), CustomPayloadExtensionsFormat - ).valueOr: - return err("Pong message contains invalid custom payload") - - if customPayload.`type` != CapabilitiesType: - return err("Pong message contains invalid custom payload") + # Note: currently only decoding as capabilities payload as this is the only + # one that we support sending. + if pong.payload_type != CapabilitiesType: + return err("Pong message contains invalid or error payload") - let payload = decodeSsz(customPayload.payload.asSeq(), CapabilitiesPayload).valueOr: + let payload = decodeSsz(pong.payload.asSeq(), CapabilitiesPayload).valueOr: return err("Pong message contains invalid CapabilitiesPayload") p.radiusCache.put(dst.id, payload.data_radius) diff --git a/fluffy/tests/wire_protocol_tests/test_ping_extensions_encoding.nim b/fluffy/tests/wire_protocol_tests/test_ping_extensions_encoding.nim index b2f199003f..20a5828bec 100644 --- a/fluffy/tests/wire_protocol_tests/test_ping_extensions_encoding.nim +++ b/fluffy/tests/wire_protocol_tests/test_ping_extensions_encoding.nim @@ -27,12 +27,14 @@ suite "Portal Wire Ping Extension Encodings - Type 0x00": data_radius: data_radius, capabilities: List[uint16, MAX_CAPABILITIES_LENGTH].init(capabilities), ) - customPayload = encodeCustomPayload(payload) - ping = PingMessage(enrSeq: enr_seq, customPayload: customPayload) + customPayload = encodePayload(payload) + ping = PingMessage( + enrSeq: enr_seq, payload_type: CapabilitiesType, payload: customPayload + ) let encoded = encodeMessage(ping) check encoded.to0xHex == - "0x0001000000000000000c00000000000600000028000000feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff550000007472696e2f76302e312e312d62363166646335632f6c696e75782d7838365f36342f7275737463312e38312e3000000100ffff" + "0x00010000000000000000000e00000028000000feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff550000007472696e2f76302e312e312d62363166646335632f6c696e75782d7838365f36342f7275737463312e38312e3000000100ffff" let decoded = decodeMessage(encoded) check decoded.isOk() @@ -40,16 +42,10 @@ suite "Portal Wire Ping Extension Encodings - Type 0x00": check: message.kind == MessageKind.ping message.ping.enrSeq == enr_seq - message.ping.customPayload == customPayload - - let decodedCustomPayload = - decodeSsz(message.ping.customPayload.asSeq(), CustomPayloadExtensionsFormat) - check: - decodedCustomPayload.isOk() - decodedCustomPayload.value().type == CapabilitiesType + message.ping.payload_type == CapabilitiesType + message.ping.payload == customPayload - let decodedPayload = - decodeSsz(decodedCustomPayload.value.payload.asSeq(), CapabilitiesPayload) + let decodedPayload = decodeSsz(message.ping.payload.asSeq(), CapabilitiesPayload) check: decodedPayload.isOk() decodedPayload.value().client_info.asSeq() == client_info.toBytes() @@ -68,12 +64,14 @@ suite "Portal Wire Ping Extension Encodings - Type 0x00": data_radius: data_radius, capabilities: List[uint16, MAX_CAPABILITIES_LENGTH].init(capabilities), ) - customPayload = encodeCustomPayload(payload) - ping = PingMessage(enrSeq: enr_seq, customPayload: customPayload) + customPayload = encodePayload(payload) + ping = PingMessage( + enrSeq: enr_seq, payload_type: CapabilitiesType, payload: customPayload + ) let encoded = encodeMessage(ping) check encoded.to0xHex == - "0x0001000000000000000c00000000000600000028000000feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2800000000000100ffff" + "0x00010000000000000000000e00000028000000feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2800000000000100ffff" let decoded = decodeMessage(encoded) check decoded.isOk() @@ -89,12 +87,14 @@ suite "Portal Wire Ping Extension Encodings - Type 0x00": data_radius: data_radius, capabilities: List[uint16, MAX_CAPABILITIES_LENGTH].init(capabilities), ) - customPayload = encodeCustomPayload(payload) - pong = PongMessage(enrSeq: enr_seq, customPayload: customPayload) + customPayload = encodePayload(payload) + pong = PongMessage( + enrSeq: enr_seq, payload_type: CapabilitiesType, payload: customPayload + ) let encoded = encodeMessage(pong) check encoded.to0xHex == - "0x0101000000000000000c00000000000600000028000000feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff550000007472696e2f76302e312e312d62363166646335632f6c696e75782d7838365f36342f7275737463312e38312e3000000100ffff" + "0x01010000000000000000000e00000028000000feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff550000007472696e2f76302e312e312d62363166646335632f6c696e75782d7838365f36342f7275737463312e38312e3000000100ffff" test "SSZ encoded Pong response - with empty client info": let @@ -108,12 +108,14 @@ suite "Portal Wire Ping Extension Encodings - Type 0x00": data_radius: data_radius, capabilities: List[uint16, MAX_CAPABILITIES_LENGTH].init(capabilities), ) - customPayload = encodeCustomPayload(payload) - pong = PongMessage(enrSeq: enr_seq, customPayload: customPayload) + customPayload = encodePayload(payload) + pong = PongMessage( + enrSeq: enr_seq, payload_type: CapabilitiesType, payload: customPayload + ) let encoded = encodeMessage(pong) check encoded.to0xHex == - "0x0101000000000000000c00000000000600000028000000feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2800000000000100ffff" + "0x01010000000000000000000e00000028000000feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2800000000000100ffff" suite "Portal Wire Ping Extension Encodings - Type 0x01": test "SSZ encoded Ping request": @@ -122,12 +124,14 @@ suite "Portal Wire Ping Extension Encodings - Type 0x01": data_radius = UInt256.high() - 1 # Full radius - 1 payload = BasicRadiusPayload(data_radius: data_radius) - customPayload = encodeCustomPayload(payload) - ping = PingMessage(enrSeq: enr_seq, customPayload: customPayload) + customPayload = encodePayload(payload) + ping = PingMessage( + enrSeq: enr_seq, payload_type: BasicRadiusType, payload: customPayload + ) let encoded = encodeMessage(ping) check encoded.to0xHex == - "0x0001000000000000000c000000010006000000feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + "0x00010000000000000001000e000000feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" test "SSZ encoded Pong response": let @@ -135,12 +139,14 @@ suite "Portal Wire Ping Extension Encodings - Type 0x01": data_radius = UInt256.high() - 1 # Full radius - 1 payload = BasicRadiusPayload(data_radius: data_radius) - customPayload = encodeCustomPayload(payload) - pong = PongMessage(enrSeq: enr_seq, customPayload: customPayload) + customPayload = encodePayload(payload) + pong = PongMessage( + enrSeq: enr_seq, payload_type: BasicRadiusType, payload: customPayload + ) let encoded = encodeMessage(pong) check encoded.to0xHex == - "0x0101000000000000000c000000010006000000feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + "0x01010000000000000001000e000000feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" suite "Portal Wire Ping Extension Encodings - Type 0x02": test "SSZ encoded Ping request": @@ -152,12 +158,14 @@ suite "Portal Wire Ping Extension Encodings - Type 0x02": payload = HistoryRadiusPayload( data_radius: data_radius, ephemeral_header_count: ephemeral_header_count ) - customPayload = encodeCustomPayload(payload) - ping = PingMessage(enrSeq: enr_seq, customPayload: customPayload) + customPayload = encodePayload(payload) + ping = PingMessage( + enrSeq: enr_seq, payload_type: HistoryRadiusType, payload: customPayload + ) let encoded = encodeMessage(ping) check encoded.to0xHex == - "0x0001000000000000000c000000020006000000feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9210" + "0x00010000000000000002000e000000feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9210" test "SSZ encoded Pong response": let @@ -168,12 +176,14 @@ suite "Portal Wire Ping Extension Encodings - Type 0x02": payload = HistoryRadiusPayload( data_radius: data_radius, ephemeral_header_count: ephemeral_header_count ) - customPayload = encodeCustomPayload(payload) - pong = PongMessage(enrSeq: enr_seq, customPayload: customPayload) + customPayload = encodePayload(payload) + pong = PongMessage( + enrSeq: enr_seq, payload_type: HistoryRadiusType, payload: customPayload + ) let encoded = encodeMessage(pong) check encoded.to0xHex == - "0x0101000000000000000c000000020006000000feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9210" + "0x01010000000000000002000e000000feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9210" suite "Portal Wire Ping Extension Encodings - Type 0x03": test "SSZ encoded Pong response": @@ -186,9 +196,10 @@ suite "Portal Wire Ping Extension Encodings - Type 0x03": error_code: error_code, message: ByteList[MAX_ERROR_BYTE_LENGTH].init(message.toBytes()), ) - customPayload = encodeCustomPayload(payload) - pong = PongMessage(enrSeq: enr_seq, customPayload: customPayload) + customPayload = encodePayload(payload) + pong = + PongMessage(enrSeq: enr_seq, payload_type: ErrorType, payload: customPayload) let encoded = encodeMessage(pong) check encoded.to0xHex == - "0x0101000000000000000c000000ffff0600000002000600000068656c6c6f20776f726c64" + "0x010100000000000000ffff0e00000002000600000068656c6c6f20776f726c64" diff --git a/fluffy/tests/wire_protocol_tests/test_portal_wire_encoding.nim b/fluffy/tests/wire_protocol_tests/test_portal_wire_encoding.nim index cbb43591b9..e55c381ac5 100644 --- a/fluffy/tests/wire_protocol_tests/test_portal_wire_encoding.nim +++ b/fluffy/tests/wire_protocol_tests/test_portal_wire_encoding.nim @@ -23,11 +23,11 @@ suite "Portal Wire Protocol Message Encodings": let enrSeq = 1'u64 # Can be any custom payload, testing with meaningless string of bytes. - customPayload = ByteList[2048].init(@[byte 0x01, 0x02, 0x03, 0x04]) - p = PingMessage(enrSeq: enrSeq, customPayload: customPayload) + customPayload = ByteList[1100].init(@[byte 0x01, 0x02, 0x03, 0x04]) + p = PingMessage(enrSeq: enrSeq, payload_type: 42'u16, payload: customPayload) let encoded = encodeMessage(p) - check encoded.toHex == "0001000000000000000c00000001020304" + check encoded.toHex == "0001000000000000002a000e00000001020304" let decoded = decodeMessage(encoded) check decoded.isOk() @@ -35,17 +35,18 @@ suite "Portal Wire Protocol Message Encodings": check: message.kind == ping message.ping.enrSeq == enrSeq - message.ping.customPayload == customPayload + message.ping.payload_type == 42'u16 + message.ping.payload == customPayload test "Pong Response": let enrSeq = 1'u64 # Can be any custom payload, testing with meaningless string of bytes. - customPayload = ByteList[2048].init(@[byte 0x01, 0x02, 0x03, 0x04]) - p = PongMessage(enrSeq: enrSeq, customPayload: customPayload) + customPayload = ByteList[1100].init(@[byte 0x01, 0x02, 0x03, 0x04]) + p = PongMessage(enrSeq: enrSeq, payload_type: 42'u16, payload: customPayload) let encoded = encodeMessage(p) - check encoded.toHex == "0101000000000000000c00000001020304" + check encoded.toHex == "0101000000000000002a000e00000001020304" let decoded = decodeMessage(encoded) check decoded.isOk() @@ -53,7 +54,8 @@ suite "Portal Wire Protocol Message Encodings": check: message.kind == pong message.pong.enrSeq == enrSeq - message.pong.customPayload == customPayload + message.pong.payload_type == 42'u16 + message.pong.payload == customPayload test "FindNodes Request": let