From 959d15e80832e14c5661d3b94f4e48d1a1bcfd6e Mon Sep 17 00:00:00 2001 From: acolytec3 <17355484+acolytec3@users.noreply.github.com> Date: Wed, 7 Aug 2024 15:44:20 -0400 Subject: [PATCH 1/4] add initial implementation of admin_peers --- packages/client/src/rpc/modules/admin.ts | 31 +++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/packages/client/src/rpc/modules/admin.ts b/packages/client/src/rpc/modules/admin.ts index 49a5c31234..08a22d7f25 100644 --- a/packages/client/src/rpc/modules/admin.ts +++ b/packages/client/src/rpc/modules/admin.ts @@ -6,6 +6,7 @@ import { middleware } from '../validation.js' import type { Chain } from '../../blockchain/index.js' import type { EthereumClient } from '../../client.js' +import type { RlpxPeer } from '../../net/peer/rlpxpeer.js' import type { Service } from '../../service/index.js' /** @@ -28,14 +29,14 @@ export class Admin { this._rpcDebug = rpcDebug this.nodeInfo = middleware(callWithStackTrace(this.nodeInfo.bind(this), this._rpcDebug), 0, []) + this.peers = middleware(callWithStackTrace(this.peers.bind(this), this._rpcDebug), 0, []) } /** * Returns information about the currently running node. - * see for reference: https://geth.ethereum.org/docs/rpc/ns-admin#admin_nodeinfo - * @param params An empty array + * see for reference: https://geth.ethereum.org/docs/interacting-with-geth/rpc/ns-admin#admin_peers */ - async nodeInfo(_params: []) { + async nodeInfo() { const rlpxInfo = this._client.config.server!.getRlpxInfo() const { enode, id, ip, listenAddr, ports } = rlpxInfo const { discovery, listener } = ports @@ -68,4 +69,28 @@ export class Admin { } return nodeInfo } + + /** + * Returns information about currently connected peers + * @returns an array of objects containing information about peers (including id, eth protocol versions supported, client name, etc.) + */ + async peers() { + const peers = this._client.service('eth')?.pool.peers as RlpxPeer[] + + return peers?.map((peer) => { + return { + id: peer.id, + // Typescript complains about the typing of `_hello` if we make rlpxPeer possibly null + name: (peer.rlpxPeer as any)['_hello'].clientId ?? null, + protocols: { + eth: { + head: peer.eth?.updatedBestHeader + ? bytesToHex(peer.eth.updatedBestHeader?.hash()) + : bytesToHex(peer.eth?.status.bestHash), + }, + }, + caps: peer.eth?.['versions'].map((ver) => 'eth/' + ver), + } + }) + } } From cbc974294ad7219858a215614b2ec90c8b8fade1 Mon Sep 17 00:00:00 2001 From: acolytec3 <17355484+acolytec3@users.noreply.github.com> Date: Wed, 7 Aug 2024 15:48:28 -0400 Subject: [PATCH 2/4] add more fields --- packages/client/src/rpc/modules/admin.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/client/src/rpc/modules/admin.ts b/packages/client/src/rpc/modules/admin.ts index 08a22d7f25..42db35e093 100644 --- a/packages/client/src/rpc/modules/admin.ts +++ b/packages/client/src/rpc/modules/admin.ts @@ -87,9 +87,14 @@ export class Admin { head: peer.eth?.updatedBestHeader ? bytesToHex(peer.eth.updatedBestHeader?.hash()) : bytesToHex(peer.eth?.status.bestHash), + difficulty: peer.eth?.status.td.toString(10), + version: peer.eth?.['versions'][-1] ?? null, }, }, caps: peer.eth?.['versions'].map((ver) => 'eth/' + ver), + network: { + remoteAddress: peer.address, + }, } }) } From 2484722da26e4d91a0edfcb94a3a6260a2365ffb Mon Sep 17 00:00:00 2001 From: acolytec3 <17355484+acolytec3@users.noreply.github.com> Date: Wed, 7 Aug 2024 15:49:59 -0400 Subject: [PATCH 3/4] fix versions --- packages/client/src/rpc/modules/admin.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/client/src/rpc/modules/admin.ts b/packages/client/src/rpc/modules/admin.ts index 42db35e093..f967676dd3 100644 --- a/packages/client/src/rpc/modules/admin.ts +++ b/packages/client/src/rpc/modules/admin.ts @@ -88,7 +88,7 @@ export class Admin { ? bytesToHex(peer.eth.updatedBestHeader?.hash()) : bytesToHex(peer.eth?.status.bestHash), difficulty: peer.eth?.status.td.toString(10), - version: peer.eth?.['versions'][-1] ?? null, + version: peer.eth?.['versions'].slice(-1)[0] ?? null, }, }, caps: peer.eth?.['versions'].map((ver) => 'eth/' + ver), From 2759af03e493ce8f5df45bc4abf1b1c2b1abf1d2 Mon Sep 17 00:00:00 2001 From: acolytec3 <17355484+acolytec3@users.noreply.github.com> Date: Wed, 7 Aug 2024 17:56:06 -0400 Subject: [PATCH 4/4] add test --- packages/client/src/rpc/modules/admin.ts | 3 +- packages/client/test/rpc/admin/peers.spec.ts | 38 ++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 packages/client/test/rpc/admin/peers.spec.ts diff --git a/packages/client/src/rpc/modules/admin.ts b/packages/client/src/rpc/modules/admin.ts index f967676dd3..5b94d3b658 100644 --- a/packages/client/src/rpc/modules/admin.ts +++ b/packages/client/src/rpc/modules/admin.ts @@ -75,7 +75,8 @@ export class Admin { * @returns an array of objects containing information about peers (including id, eth protocol versions supported, client name, etc.) */ async peers() { - const peers = this._client.service('eth')?.pool.peers as RlpxPeer[] + const peers = this._client.services.filter((serv) => serv.name === 'eth')[0]?.pool + .peers as RlpxPeer[] return peers?.map((peer) => { return { diff --git a/packages/client/test/rpc/admin/peers.spec.ts b/packages/client/test/rpc/admin/peers.spec.ts new file mode 100644 index 0000000000..c7bf6f40f8 --- /dev/null +++ b/packages/client/test/rpc/admin/peers.spec.ts @@ -0,0 +1,38 @@ +import { randomBytes } from 'crypto' +import { assert, describe, it } from 'vitest' + +import { createClient, createManager, getRpcClient, startRPC } from '../helpers.js' + +const method = 'admin_peers' + +describe(method, () => { + it('works', async () => { + const manager = createManager(await createClient({ opened: true, noPeers: true })) + const rpc = getRpcClient(startRPC(manager.getMethods())) + + console.log(manager['_client'].services[0].pool) + //@ts-ignore + manager['_client'].services[0].pool.peers = [ + { + id: 'abcd', + eth: { + versions: ['68'], + status: { + td: 1n, + bestHash: randomBytes(32), + }, + }, + rlpxPeer: { + _hello: { + clientId: 'fakeClient', + }, + }, + address: '127.0.0.1:8545', + }, + ] + const res = await rpc.request(method, []) + const { result } = res + console.log(res) + assert.notEqual(result, undefined, 'admin_peers returns a value') + }) +})