Skip to content

Commit

Permalink
update extensions types
Browse files Browse the repository at this point in the history
  • Loading branch information
ScottyPoi committed Jan 18, 2025
1 parent 065084d commit 58bd756
Show file tree
Hide file tree
Showing 4 changed files with 254 additions and 77 deletions.
93 changes: 42 additions & 51 deletions packages/portalnetwork/src/networks/network.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ import {
BasicRadius,
ClientInfoAndCapabilities,
ContentMessageType,
CustomPayloadExtensionsFormat,
ErrorPayload,
HistoryRadius,
MAX_PACKET_SIZE,
Expand Down Expand Up @@ -304,15 +303,12 @@ export abstract class BaseNetwork extends EventEmitter {
return undefined
}, 3000)
try {
const customPayload = CustomPayloadExtensionsFormat.serialize({
type: extensionType,
payload: this.pingPongPayload(extensionType),
})
const pingMsg = PortalWireMessageType.serialize({
selector: MessageCodes.PING,
value: {
enrSeq: this.enr.seq,
customPayload,
payloadType: extensionType,
customPayload: this.pingPongPayload(extensionType),
},
})
this.logger.extend(`PING`)(`Sent to ${shortId(enr)}`)
Expand All @@ -323,31 +319,29 @@ export abstract class BaseNetwork extends EventEmitter {
const pongMessage = decoded.value as PongMessage
// Received a PONG message so node is reachable, add to routing table
this.updateRoutingTable(enr)
const { type, payload } = CustomPayloadExtensionsFormat.deserialize(
pongMessage.customPayload,
)
switch (type) {
switch (pongMessage.payloadType) {
case PingPongPayloadExtensions.CLIENT_INFO_RADIUS_AND_CAPABILITIES: {
const { ClientInfo, Capabilities, DataRadius } =
ClientInfoAndCapabilities.deserialize(payload)
const { ClientInfo, Capabilities, DataRadius } = ClientInfoAndCapabilities.deserialize(
pongMessage.customPayload,
)
this.logger.extend('PONG')(
`Client ${shortId(enr.nodeId)} is ${decodeClientInfo(ClientInfo).clientName} node with capabilities: ${Capabilities}`,
)
this.routingTable.updateRadius(enr.nodeId, DataRadius)
break
}
case PingPongPayloadExtensions.BASIC_RADIUS_PAYLOAD: {
const { dataRadius } = BasicRadius.deserialize(payload)
const { dataRadius } = BasicRadius.deserialize(pongMessage.customPayload)
this.routingTable.updateRadius(enr.nodeId, dataRadius)
break
}
case PingPongPayloadExtensions.HISTORY_RADIUS_PAYLOAD: {
const { dataRadius } = HistoryRadius.deserialize(payload)
const { dataRadius } = HistoryRadius.deserialize(pongMessage.customPayload)
this.routingTable.updateRadius(enr.nodeId, dataRadius)
break
}
case PingPongPayloadExtensions.ERROR_RESPONSE: {
const { errorCode, message } = ErrorPayload.deserialize(payload)
const { errorCode, message } = ErrorPayload.deserialize(pongMessage.customPayload)
this.logger.extend('PONG')(
`Received error response from ${shortId(enr.nodeId)}: ${errorCode} - ${message}`,
)
Expand All @@ -372,21 +366,19 @@ export abstract class BaseNetwork extends EventEmitter {
}

handlePing = async (src: INodeAddress, id: bigint, pingMessage: PingMessage) => {
const { type, payload } = CustomPayloadExtensionsFormat.deserialize(pingMessage.customPayload)
if (!this.routingTable.getWithPending(src.nodeId)?.value) {
if (type !== PingPongPayloadExtensions.CLIENT_INFO_RADIUS_AND_CAPABILITIES) {
const customPayload = CustomPayloadExtensionsFormat.serialize({
type: PingPongPayloadExtensions.ERROR_RESPONSE,
payload: ErrorPayload.serialize({
errorCode: PingPongErrorCodes.EXTENSION_NOT_SUPPORTED,
message: hexToBytes(
fromAscii(
`First PING message must be type 0: CLIENT_INFO_RADIUS_AND_CAPABILITIES. Received type ${type}`,
),
if (
pingMessage.payloadType !== PingPongPayloadExtensions.CLIENT_INFO_RADIUS_AND_CAPABILITIES
) {
const customPayload = ErrorPayload.serialize({
errorCode: PingPongErrorCodes.EXTENSION_NOT_SUPPORTED,
message: hexToBytes(
fromAscii(
`First PING message must be type 0: CLIENT_INFO_RADIUS_AND_CAPABILITIES. Received type ${pingMessage.payloadType}`,
),
}),
),
})
return this.sendPong(src, id, customPayload)
return this.sendPong(src, id, customPayload, PingPongPayloadExtensions.ERROR_RESPONSE)
}
// Check to see if node is already in corresponding network routing table and add if not
const enr = this.findEnr(src.nodeId)
Expand All @@ -395,31 +387,33 @@ export abstract class BaseNetwork extends EventEmitter {
}
}
let pongPayload: Uint8Array
if (this.capabilities.includes(type)) {
switch (type) {
if (this.capabilities.includes(pingMessage.payloadType)) {
switch (pingMessage.payloadType) {
case PingPongPayloadExtensions.CLIENT_INFO_RADIUS_AND_CAPABILITIES: {
const { DataRadius } = ClientInfoAndCapabilities.deserialize(payload)
const { DataRadius } = ClientInfoAndCapabilities.deserialize(pingMessage.customPayload)
this.routingTable.updateRadius(src.nodeId, DataRadius)
pongPayload = this.pingPongPayload(type)
pongPayload = this.pingPongPayload(pingMessage.payloadType)
break
}
case PingPongPayloadExtensions.BASIC_RADIUS_PAYLOAD: {
const { dataRadius } = BasicRadius.deserialize(payload)
const { dataRadius } = BasicRadius.deserialize(pingMessage.customPayload)
this.routingTable.updateRadius(src.nodeId, dataRadius)
pongPayload = this.pingPongPayload(type)
pongPayload = this.pingPongPayload(pingMessage.payloadType)
break
}
case PingPongPayloadExtensions.HISTORY_RADIUS_PAYLOAD: {
const { dataRadius } = HistoryRadius.deserialize(payload)
const { dataRadius } = HistoryRadius.deserialize(pingMessage.customPayload)
this.routingTable.updateRadius(src.nodeId, dataRadius)
pongPayload = this.pingPongPayload(type)
pongPayload = this.pingPongPayload(pingMessage.payloadType)
break
}
default: {
pongPayload = ErrorPayload.serialize({
errorCode: 0,
message: hexToBytes(
fromAscii(`${this.constructor.name} does not support PING extension type: ${type}`),
fromAscii(
`${this.constructor.name} does not support PING extension type: ${pingMessage.payloadType}`,
),
),
})
}
Expand All @@ -428,28 +422,25 @@ export abstract class BaseNetwork extends EventEmitter {
pongPayload = ErrorPayload.serialize({
errorCode: PingPongErrorCodes.EXTENSION_NOT_SUPPORTED,
message: hexToBytes(
fromAscii(`${this.constructor.name} does not support PING extension type: ${type}`),
fromAscii(
`${this.constructor.name} does not support PING extension type: ${pingMessage.payloadType}`,
),
),
})
return this.sendPong(
src,
id,
CustomPayloadExtensionsFormat.serialize({
type: PingPongPayloadExtensions.ERROR_RESPONSE,
payload: pongPayload,
}),
)
return this.sendPong(src, id, pongPayload, PingPongPayloadExtensions.ERROR_RESPONSE)
}
const customPayload = CustomPayloadExtensionsFormat.serialize({
type,
payload: pongPayload,
})
return this.sendPong(src, id, customPayload)
return this.sendPong(src, id, pongPayload, pingMessage.payloadType)
}

sendPong = async (src: INodeAddress, requestId: bigint, customPayload: Uint8Array) => {
sendPong = async (
src: INodeAddress,
requestId: bigint,
customPayload: Uint8Array,
payloadType: number,
) => {
const payload = {
enrSeq: this.enr.seq,
payloadType,
customPayload,
}
const pongMsg = PortalWireMessageType.serialize({
Expand Down
23 changes: 6 additions & 17 deletions packages/portalnetwork/src/wire/payloadExtensions.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,9 @@
import { ByteListType, ContainerType, ListBasicType, UintBigintType, UintNumberType } from "@chainsafe/ssz";
import { bytesToHex, fromAscii, hexToBytes, toAscii } from "@ethereumjs/util";
import { PingPongPayloadType } from "./types.js";


/**
* Numeric identifier which tells clients how the payload field should be decoded.
*/
export const PingPongPayloadType = new UintNumberType(2)

/**
* SSZ encoded extension payload
*/
export const PingPongPayload = new ByteListType(1100)

/**
* All payloads used in the Ping custom_payload MUST follow the Ping Custom Payload Extensions format.
*/
export const CustomPayloadExtensionsFormat = new ContainerType({
type: PingPongPayloadType,
payload: PingPongPayload
})


/**
Expand Down Expand Up @@ -53,13 +38,16 @@ export interface IClientInfo {

export const MAX_CLIENT_INFO_BYTE_LENGTH = 200

export function clientInfoStringToBytes(clientInfo: string): Uint8Array {
return hexToBytes(fromAscii(clientInfo))
}
/**
* Encode Client info as ASCII hex encoded string.
* @param clientInfo
* @returns
*/
export function encodeClientInfo(clientInfo: IClientInfo): Uint8Array {
const clientInfoBytes = hexToBytes(fromAscii(Object.values(clientInfo).join("/")))
const clientInfoBytes = clientInfoStringToBytes(Object.values(clientInfo).join("/"))
if (clientInfoBytes.length > MAX_CLIENT_INFO_BYTE_LENGTH) {
throw new Error(`Client info is too long: ${clientInfoBytes.length} > ${MAX_CLIENT_INFO_BYTE_LENGTH}`)
}
Expand All @@ -76,6 +64,7 @@ export function decodeClientInfo(clientInfo: Uint8Array): IClientInfo {
};
}


export const ClientInfo = new ByteListType(MAX_CLIENT_INFO_BYTE_LENGTH)


Expand Down
17 changes: 15 additions & 2 deletions packages/portalnetwork/src/wire/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,24 +36,37 @@ export enum MessageCodes {
export const ByteList = new ByteListType(2048)
export const Bytes2 = new ByteVectorType(2)
export const ENRs = new ListCompositeType(ByteList, 32)
/**
* Numeric identifier which tells clients how the payload field should be decoded.
*/
export const PingPongPayloadType = new UintNumberType(2)

/**
* SSZ encoded extension payload
*/
export const PingPongPayload = new ByteListType(1100)
export type PingMessage = {
enrSeq: bigint
payloadType: number
customPayload: PingPongCustomData
}

export type PongMessage = {
enrSeq: bigint
payloadType: number
customPayload: PingPongCustomData
}

export const PingMessageType = new ContainerType({
enrSeq: new UintBigintType(8),
customPayload: ByteList,
payloadType: PingPongPayloadType,
customPayload: PingPongPayload,
})

export const PongMessageType = new ContainerType({
enrSeq: new UintBigintType(8),
customPayload: ByteList,
payloadType: PingPongPayloadType,
customPayload: PingPongPayload,
})

export type FindNodesMessage = {
Expand Down
Loading

0 comments on commit 58bd756

Please sign in to comment.