Skip to content

Commit 4264c8c

Browse files
varex83natebeauregardMaddiaa0
authored
feat(p2p): add private peers (#12585)
Closes #12444 --------- Co-authored-by: Nate Beauregard <[email protected]> Co-authored-by: Maddiaa <[email protected]> Co-authored-by: Nate Beauregard <[email protected]>
1 parent 60e73f9 commit 4264c8c

File tree

7 files changed

+374
-84
lines changed

7 files changed

+374
-84
lines changed

yarn-project/foundation/src/config/env_var.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,8 @@ export type EnvVar =
116116
| 'P2P_TX_POOL_KEEP_PROVEN_FOR'
117117
| 'P2P_ATTESTATION_POOL_KEEP_FOR'
118118
| 'P2P_ARCHIVED_TX_LIMIT'
119+
| 'P2P_TRUSTED_PEERS'
120+
| 'P2P_PRIVATE_PEERS'
119121
| 'P2P_MAX_TX_POOL_SIZE'
120122
| 'PEER_ID_PRIVATE_KEY'
121123
| 'PEER_ID_PRIVATE_KEY_PATH'
@@ -218,5 +220,4 @@ export type EnvVar =
218220
| 'K8S_POD_UID'
219221
| 'K8S_NAMESPACE_NAME'
220222
| 'CUSTOM_FORWARDER_CONTRACT_ADDRESS'
221-
| 'P2P_TRUSTED_PEERS'
222223
| 'FEE_ASSET_HANDLER_CONTRACT_ADDRESS';

yarn-project/p2p/src/config.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,11 @@ export interface P2PConfig extends P2PReqRespConfig, ChainConfig {
175175
*/
176176
trustedPeers: string[];
177177

178+
/**
179+
* A list of private peers.
180+
*/
181+
privatePeers: string[];
182+
178183
/**
179184
* The maximum possible size of the P2P DB in KB. Overwrites the general dataStoreMapSizeKB.
180185
*/
@@ -357,7 +362,14 @@ export const p2pConfigMappings: ConfigMappingsType<P2PConfig> = {
357362
trustedPeers: {
358363
env: 'P2P_TRUSTED_PEERS',
359364
parseEnv: (val: string) => val.split(','),
360-
description: 'A list of trusted peers ENRs. Separated by commas.',
365+
description: 'A list of trusted peer ENRs that will always be persisted. Separated by commas.',
366+
defaultValue: [],
367+
},
368+
privatePeers: {
369+
env: 'P2P_PRIVATE_PEERS',
370+
parseEnv: (val: string) => val.split(','),
371+
description:
372+
'A list of private peer ENRs that will always be persisted and not be used for discovery. Separated by commas.',
361373
defaultValue: [],
362374
},
363375
p2pStoreMapSizeKb: {

yarn-project/p2p/src/services/discv5/discV5_service.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ export class DiscV5Service extends EventEmitter implements PeerDiscoveryService
3434

3535
private bootstrapNodePeerIds: PeerId[] = [];
3636
public bootstrapNodeEnrs: ENR[] = [];
37+
private trustedPeerEnrs: ENR[] = [];
3738

3839
private startTime = 0;
3940

@@ -51,8 +52,10 @@ export class DiscV5Service extends EventEmitter implements PeerDiscoveryService
5152
configOverrides: Partial<IDiscv5CreateOptions> = {},
5253
) {
5354
super();
54-
const { p2pIp, p2pPort, bootstrapNodes } = config;
55+
const { p2pIp, p2pPort, bootstrapNodes, trustedPeers, privatePeers } = config;
5556
this.bootstrapNodeEnrs = bootstrapNodes.map(x => ENR.decodeTxt(x));
57+
const privatePeerEnrs = new Set(privatePeers);
58+
this.trustedPeerEnrs = trustedPeers.filter(x => !privatePeerEnrs.has(x)).map(x => ENR.decodeTxt(x));
5659
// create ENR from PeerId
5760
this.enr = SignableENR.createFromPeerId(peerId);
5861
// Add aztec identification to ENR
@@ -159,6 +162,18 @@ export class DiscV5Service extends EventEmitter implements PeerDiscoveryService
159162
}
160163
}
161164
}
165+
166+
// Add trusted peer ENRs if provided
167+
if (this.trustedPeerEnrs?.length) {
168+
this.logger.info(
169+
`Adding ${this.trustedPeerEnrs.length} trusted peer ENRs: ${this.trustedPeerEnrs
170+
.map(enr => enr.encodeTxt())
171+
.join(', ')}`,
172+
);
173+
for (const enr of this.trustedPeerEnrs) {
174+
this.discv5.addEnr(enr);
175+
}
176+
}
162177
}
163178

164179
public async runRandomNodesQuery(): Promise<void> {

yarn-project/p2p/src/services/discv5/discv5_service.test.ts

Lines changed: 109 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,114 @@ describe('Discv5Service', () => {
226226
await node2.stop();
227227
});
228228

229-
const createNode = async (overrides: Partial<P2PConfig & IDiscv5CreateOptions> = {}) => {
229+
it('should use trusted peers for discovery', async () => {
230+
const node1 = await createNode({}, false);
231+
const trustedNode = await createNode({}, false);
232+
const trustedEnr = trustedNode.getEnr().encodeTxt();
233+
234+
const node2 = await createNode(
235+
{
236+
trustedPeers: [trustedEnr],
237+
privatePeers: [],
238+
},
239+
false,
240+
);
241+
const node3 = await createNode(
242+
{
243+
trustedPeers: [trustedEnr],
244+
privatePeers: [],
245+
},
246+
false,
247+
);
248+
249+
await startNodes(node1, node2, node3, trustedNode);
250+
251+
expect(node1.getAllPeers()).toHaveLength(0);
252+
expect(trustedNode.getAllPeers()).toHaveLength(0);
253+
254+
// Verify node2 and node3 are connected to the trusted peer
255+
expect(node2.getAllPeers().length).toBe(1);
256+
expect(node3.getAllPeers().length).toBe(1);
257+
expect(await getPeers(node2)).toContain(trustedNode.getPeerId().toString());
258+
expect(await getPeers(node3)).toContain(trustedNode.getPeerId().toString());
259+
260+
await Promise.all([
261+
waitForPeers(node2, 2),
262+
waitForPeers(node3, 2),
263+
(async () => {
264+
await sleep(2000); // wait for peer discovery to be able to start
265+
for (let i = 0; i < 5; i++) {
266+
await node1.runRandomNodesQuery();
267+
await node2.runRandomNodesQuery();
268+
await node3.runRandomNodesQuery();
269+
await trustedNode.runRandomNodesQuery();
270+
await sleep(100);
271+
}
272+
})(),
273+
]);
274+
275+
expect(node1.getAllPeers()).toHaveLength(0);
276+
277+
// Verify node2 and node3 discovered each other through the trusted peer
278+
const node2Peers = await getPeers(node2);
279+
expect(node2Peers).toHaveLength(2);
280+
expect(node2Peers).toContain(node3.getPeerId().toString());
281+
const node3Peers = await getPeers(node3);
282+
expect(node3Peers).toHaveLength(2);
283+
expect(node3Peers).toContain(node2.getPeerId().toString());
284+
const trustedNodePeers = await getPeers(trustedNode);
285+
expect(trustedNodePeers).toHaveLength(2);
286+
expect(trustedNodePeers).toContain(node2.getPeerId().toString());
287+
expect(trustedNodePeers).toContain(node3.getPeerId().toString());
288+
289+
await stopNodes(node1, node2, node3, trustedNode);
290+
});
291+
292+
it('should not use private peers or peers marked as both trusted and private for discovery', async () => {
293+
const node1 = await createNode({}, false);
294+
const privateNode = await createNode({}, false);
295+
const privateEnr = privateNode.getEnr().encodeTxt();
296+
297+
const node2 = await createNode(
298+
{
299+
trustedPeers: [],
300+
privatePeers: [privateEnr],
301+
},
302+
false,
303+
);
304+
const node3 = await createNode(
305+
{
306+
trustedPeers: [privateEnr],
307+
privatePeers: [privateEnr],
308+
},
309+
false,
310+
);
311+
312+
await startNodes(node1, node2, node3, privateNode);
313+
314+
expect(node1.getAllPeers()).toHaveLength(0);
315+
expect(node2.getAllPeers()).toHaveLength(0);
316+
expect(node3.getAllPeers()).toHaveLength(0);
317+
expect(privateNode.getAllPeers()).toHaveLength(0);
318+
319+
await sleep(2000); // wait for peer discovery to be able to start
320+
for (let i = 0; i < 3; i++) {
321+
await node1.runRandomNodesQuery();
322+
await node2.runRandomNodesQuery();
323+
await node3.runRandomNodesQuery();
324+
await privateNode.runRandomNodesQuery();
325+
await sleep(100);
326+
}
327+
328+
expect(node1.getAllPeers()).toHaveLength(0);
329+
expect(node2.getAllPeers()).toHaveLength(0);
330+
expect(node3.getAllPeers()).toHaveLength(0);
331+
expect(privateNode.getAllPeers()).toHaveLength(0);
332+
333+
await stopNodes(node1, node2, node3, privateNode);
334+
}, 30_000);
335+
336+
const createNode = async (overrides: Partial<P2PConfig & IDiscv5CreateOptions> = {}, useBootnode = true) => {
230337
const port = ++basePort;
231338
const bootnodeAddr = bootNode.getENR().encodeTxt();
232339
const peerId = await createSecp256k1PeerId();
@@ -235,7 +342,7 @@ describe('Discv5Service', () => {
235342
...baseConfig,
236343
p2pIp: `127.0.0.1`,
237344
p2pPort: port,
238-
bootstrapNodes: [bootnodeAddr],
345+
bootstrapNodes: useBootnode ? [bootnodeAddr] : [],
239346
blockCheckIntervalMS: 50,
240347
peerCheckIntervalMS: 50,
241348
p2pEnabled: true,

yarn-project/p2p/src/services/libp2p/libp2p_service.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
318318
// Start job queue, peer discovery service and libp2p node
319319
this.jobQueue.start();
320320

321-
await this.peerManager.initializeTrustedPeers();
321+
await this.peerManager.initializePeers();
322322
await this.peerDiscoveryService.start();
323323
await this.node.start();
324324

0 commit comments

Comments
 (0)