@aztec/p2p 0.65.2 → 0.67.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/dest/bootstrap/bootstrap.d.ts +7 -2
  2. package/dest/bootstrap/bootstrap.d.ts.map +1 -1
  3. package/dest/bootstrap/bootstrap.js +25 -12
  4. package/dest/client/index.d.ts.map +1 -1
  5. package/dest/client/index.js +11 -7
  6. package/dest/client/p2p_client.d.ts +11 -16
  7. package/dest/client/p2p_client.d.ts.map +1 -1
  8. package/dest/client/p2p_client.js +32 -8
  9. package/dest/config.d.ts +40 -2
  10. package/dest/config.d.ts.map +1 -1
  11. package/dest/config.js +10 -2
  12. package/dest/mem_pools/attestation_pool/attestation_pool.d.ts +8 -0
  13. package/dest/mem_pools/attestation_pool/attestation_pool.d.ts.map +1 -1
  14. package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts +1 -0
  15. package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts.map +1 -1
  16. package/dest/mem_pools/attestation_pool/memory_attestation_pool.js +22 -3
  17. package/dest/mem_pools/instrumentation.d.ts +2 -7
  18. package/dest/mem_pools/instrumentation.d.ts.map +1 -1
  19. package/dest/mem_pools/instrumentation.js +4 -25
  20. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts.map +1 -1
  21. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.js +5 -7
  22. package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts.map +1 -1
  23. package/dest/mem_pools/tx_pool/memory_tx_pool.js +4 -4
  24. package/dest/mocks/index.d.ts.map +1 -1
  25. package/dest/mocks/index.js +12 -6
  26. package/dest/service/discV5_service.d.ts +2 -0
  27. package/dest/service/discV5_service.d.ts.map +1 -1
  28. package/dest/service/discV5_service.js +14 -11
  29. package/dest/service/dummy_service.d.ts +3 -1
  30. package/dest/service/dummy_service.d.ts.map +1 -1
  31. package/dest/service/dummy_service.js +5 -1
  32. package/dest/service/encoding.d.ts +26 -0
  33. package/dest/service/encoding.d.ts.map +1 -0
  34. package/dest/service/encoding.js +49 -0
  35. package/dest/service/libp2p_service.d.ts +2 -7
  36. package/dest/service/libp2p_service.d.ts.map +1 -1
  37. package/dest/service/libp2p_service.js +24 -31
  38. package/dest/service/peer_manager.d.ts +3 -0
  39. package/dest/service/peer_manager.d.ts.map +1 -1
  40. package/dest/service/peer_manager.js +59 -21
  41. package/dest/service/peer_scoring.d.ts +4 -1
  42. package/dest/service/peer_scoring.d.ts.map +1 -1
  43. package/dest/service/peer_scoring.js +6 -1
  44. package/dest/service/reqresp/handlers.d.ts +4 -2
  45. package/dest/service/reqresp/handlers.d.ts.map +1 -1
  46. package/dest/service/reqresp/handlers.js +3 -3
  47. package/dest/service/reqresp/interface.d.ts +1 -1
  48. package/dest/service/reqresp/interface.d.ts.map +1 -1
  49. package/dest/service/reqresp/interface.js +2 -2
  50. package/dest/service/reqresp/reqresp.d.ts +3 -0
  51. package/dest/service/reqresp/reqresp.d.ts.map +1 -1
  52. package/dest/service/reqresp/reqresp.js +14 -9
  53. package/dest/service/service.d.ts +2 -1
  54. package/dest/service/service.d.ts.map +1 -1
  55. package/dest/tx_validator/data_validator.js +3 -3
  56. package/dest/tx_validator/double_spend_validator.js +3 -3
  57. package/dest/tx_validator/metadata_validator.js +3 -3
  58. package/dest/tx_validator/tx_proof_validator.js +3 -3
  59. package/dest/util.d.ts +20 -2
  60. package/dest/util.d.ts.map +1 -1
  61. package/dest/util.js +39 -3
  62. package/package.json +14 -9
  63. package/src/bootstrap/bootstrap.ts +33 -13
  64. package/src/client/index.ts +10 -6
  65. package/src/client/p2p_client.ts +47 -24
  66. package/src/config.ts +17 -2
  67. package/src/mem_pools/attestation_pool/attestation_pool.ts +9 -0
  68. package/src/mem_pools/attestation_pool/memory_attestation_pool.ts +23 -2
  69. package/src/mem_pools/instrumentation.ts +4 -26
  70. package/src/mem_pools/tx_pool/aztec_kv_tx_pool.ts +4 -6
  71. package/src/mem_pools/tx_pool/memory_tx_pool.ts +3 -3
  72. package/src/mocks/index.ts +11 -5
  73. package/src/service/discV5_service.ts +17 -12
  74. package/src/service/dummy_service.ts +6 -1
  75. package/src/service/encoding.ts +61 -0
  76. package/src/service/libp2p_service.ts +26 -32
  77. package/src/service/peer_manager.ts +68 -22
  78. package/src/service/peer_scoring.ts +8 -1
  79. package/src/service/reqresp/handlers.ts +4 -4
  80. package/src/service/reqresp/interface.ts +3 -3
  81. package/src/service/reqresp/reqresp.ts +13 -8
  82. package/src/service/service.ts +3 -1
  83. package/src/tx_validator/data_validator.ts +2 -2
  84. package/src/tx_validator/double_spend_validator.ts +2 -2
  85. package/src/tx_validator/metadata_validator.ts +2 -2
  86. package/src/tx_validator/tx_proof_validator.ts +2 -2
  87. package/src/util.ts +48 -2
@@ -1,8 +1,10 @@
1
- import { createDebugLogger } from '@aztec/foundation/log';
1
+ import { type PeerInfo } from '@aztec/circuit-types';
2
+ import { createLogger } from '@aztec/foundation/log';
2
3
 
3
4
  import { type ENR } from '@chainsafe/enr';
4
5
  import { type PeerId } from '@libp2p/interface';
5
6
  import { type Multiaddr } from '@multiformats/multiaddr';
7
+ import { inspect } from 'util';
6
8
 
7
9
  import { type P2PConfig } from '../config.js';
8
10
  import { type PubSubLibp2p } from '../util.js';
@@ -22,21 +24,22 @@ type CachedPeer = {
22
24
  export class PeerManager {
23
25
  private cachedPeers: Map<string, CachedPeer> = new Map();
24
26
  private peerScoring: PeerScoring;
27
+ private heartbeatCounter: number = 0;
25
28
 
26
29
  constructor(
27
30
  private libP2PNode: PubSubLibp2p,
28
31
  private peerDiscoveryService: PeerDiscoveryService,
29
32
  private config: P2PConfig,
30
- private logger = createDebugLogger('aztec:p2p:peer_manager'),
33
+ private logger = createLogger('p2p:peer-manager'),
31
34
  ) {
32
35
  this.peerScoring = new PeerScoring(config);
33
36
  // Handle new established connections
34
37
  this.libP2PNode.addEventListener('peer:connect', evt => {
35
38
  const peerId = evt.detail;
36
39
  if (this.peerDiscoveryService.isBootstrapPeer(peerId)) {
37
- this.logger.debug(`Connected to bootstrap peer ${peerId.toString()}`);
40
+ this.logger.verbose(`Connected to bootstrap peer ${peerId.toString()}`);
38
41
  } else {
39
- this.logger.debug(`Connected to transaction peer ${peerId.toString()}`);
42
+ this.logger.verbose(`Connected to transaction peer ${peerId.toString()}`);
40
43
  }
41
44
  });
42
45
 
@@ -44,9 +47,9 @@ export class PeerManager {
44
47
  this.libP2PNode.addEventListener('peer:disconnect', evt => {
45
48
  const peerId = evt.detail;
46
49
  if (this.peerDiscoveryService.isBootstrapPeer(peerId)) {
47
- this.logger.debug(`Disconnected from bootstrap peer ${peerId.toString()}`);
50
+ this.logger.verbose(`Disconnected from bootstrap peer ${peerId.toString()}`);
48
51
  } else {
49
- this.logger.debug(`Disconnected from transaction peer ${peerId.toString()}`);
52
+ this.logger.verbose(`Disconnected from transaction peer ${peerId.toString()}`);
50
53
  }
51
54
  });
52
55
 
@@ -57,6 +60,7 @@ export class PeerManager {
57
60
  }
58
61
 
59
62
  public heartbeat() {
63
+ this.heartbeatCounter++;
60
64
  this.discover();
61
65
  this.peerScoring.decayAllScores();
62
66
  }
@@ -64,13 +68,47 @@ export class PeerManager {
64
68
  public penalizePeer(peerId: PeerId, penalty: PeerErrorSeverity) {
65
69
  const id = peerId.toString();
66
70
  const penaltyValue = this.peerScoring.peerPenalties[penalty];
67
- this.peerScoring.updateScore(id, -penaltyValue);
71
+ const newScore = this.peerScoring.updateScore(id, -penaltyValue);
72
+ this.logger.verbose(`Penalizing peer ${id} with ${penalty} (new score is ${newScore})`);
68
73
  }
69
74
 
70
75
  public getPeerScore(peerId: string): number {
71
76
  return this.peerScoring.getScore(peerId);
72
77
  }
73
78
 
79
+ public getPeers(includePending = false): PeerInfo[] {
80
+ const connected = this.libP2PNode
81
+ .getPeers()
82
+ .map(peer => ({ id: peer.toString(), score: this.getPeerScore(peer.toString()), status: 'connected' as const }));
83
+
84
+ if (!includePending) {
85
+ return connected;
86
+ }
87
+
88
+ const dialQueue = this.libP2PNode
89
+ .getDialQueue()
90
+ .filter(peer => !!peer.peerId)
91
+ .map(peer => ({
92
+ id: peer.peerId!.toString(),
93
+ status: 'dialing' as const,
94
+ dialStatus: peer.status,
95
+ addresses: peer.multiaddrs.map(m => m.toString()),
96
+ }));
97
+
98
+ const cachedPeers = Array.from(this.cachedPeers.values())
99
+ .filter(peer => !dialQueue.some(dialPeer => dialPeer.id && peer.peerId.toString() === dialPeer.id.toString()))
100
+ .filter(peer => !connected.some(connPeer => connPeer.id.toString() === peer.peerId.toString()))
101
+ .map(peer => ({
102
+ status: 'cached' as const,
103
+ id: peer.peerId.toString(),
104
+ addresses: [peer.multiaddrTcp.toString()],
105
+ dialAttempts: peer.dialAttempts,
106
+ enr: peer.enr.encodeTxt(),
107
+ }));
108
+
109
+ return [...connected, ...dialQueue, ...cachedPeers];
110
+ }
111
+
74
112
  /**
75
113
  * Discovers peers.
76
114
  */
@@ -81,9 +119,13 @@ export class PeerManager {
81
119
  // Calculate how many connections we're looking to make
82
120
  const peersToConnect = this.config.maxPeerCount - connections.length;
83
121
 
84
- this.logger.debug(
85
- `Connections: ${connections.length}, Peers to connect: ${peersToConnect}, maxPeerCount: ${this.config.maxPeerCount}, cachedPeers: ${this.cachedPeers.size}`,
86
- );
122
+ const logLevel = this.heartbeatCounter % 60 === 0 ? 'info' : 'debug';
123
+ this.logger[logLevel](`Connected to ${connections.length} peers`, {
124
+ connections: connections.length,
125
+ maxPeerCount: this.config.maxPeerCount,
126
+ cachedPeers: this.cachedPeers.size,
127
+ ...this.peerScoring.getStats(),
128
+ });
87
129
 
88
130
  // Exit if no peers to connect
89
131
  if (peersToConnect <= 0) {
@@ -119,7 +161,7 @@ export class PeerManager {
119
161
 
120
162
  // if we need more peers, start randomNodesQuery
121
163
  if (peersToConnect > 0) {
122
- this.logger.debug('Running random nodes query');
164
+ this.logger.trace(`Running random nodes query to connect to ${peersToConnect} peers`);
123
165
  void this.peerDiscoveryService.runRandomNodesQuery();
124
166
  }
125
167
  }
@@ -134,23 +176,25 @@ export class PeerManager {
134
176
  // check if peer is already connected
135
177
  const [peerId, multiaddrTcp] = await Promise.all([enr.peerId(), enr.getFullMultiaddr('tcp')]);
136
178
 
137
- this.logger.debug(`Handling discovered peer ${peerId.toString()}, ${multiaddrTcp?.toString()}`);
179
+ this.logger.trace(
180
+ `Handling discovered peer ${peerId.toString()} at ${multiaddrTcp?.toString() ?? 'undefined address'}`,
181
+ );
138
182
 
139
183
  // throw if no tcp addr in multiaddr
140
184
  if (!multiaddrTcp) {
141
- this.logger.debug(`No TCP address in discovered node's multiaddr: ${enr.toString()}`);
185
+ this.logger.debug(`No TCP address in discovered node's multiaddr ${enr.encodeTxt()}`);
142
186
  return;
143
187
  }
144
188
  const connections = this.libP2PNode.getConnections();
145
189
  if (connections.some(conn => conn.remotePeer.equals(peerId))) {
146
- this.logger.debug(`Already connected to peer ${peerId.toString()}`);
190
+ this.logger.trace(`Already connected to peer ${peerId.toString()}`);
147
191
  return;
148
192
  }
149
193
 
150
194
  // check if peer is already in cache
151
195
  const id = peerId.toString();
152
196
  if (this.cachedPeers.has(id)) {
153
- this.logger.debug(`Already in cache ${id}`);
197
+ this.logger.trace(`Peer already in cache ${id}`);
154
198
  return;
155
199
  }
156
200
 
@@ -164,10 +208,9 @@ export class PeerManager {
164
208
 
165
209
  // Determine if we should dial immediately or not
166
210
  if (this.shouldDialPeer()) {
167
- this.logger.debug(`Dialing peer ${id}`);
168
211
  void this.dialPeer(cachedPeer);
169
212
  } else {
170
- this.logger.debug(`Caching peer ${id}`);
213
+ this.logger.trace(`Caching peer ${id}`);
171
214
  this.cachedPeers.set(id, cachedPeer);
172
215
  // Prune set of cached peers
173
216
  this.pruneCachedPeers();
@@ -178,15 +221,16 @@ export class PeerManager {
178
221
  const id = peer.peerId.toString();
179
222
  await this.libP2PNode.peerStore.merge(peer.peerId, { multiaddrs: [peer.multiaddrTcp] });
180
223
 
181
- this.logger.debug(`Dialing peer ${id}`);
224
+ this.logger.trace(`Dialing peer ${id}`);
182
225
  try {
183
226
  await this.libP2PNode.dial(peer.multiaddrTcp);
184
- } catch {
185
- this.logger.debug(`Failed to dial peer ${id}`);
227
+ } catch (error) {
186
228
  peer.dialAttempts++;
187
229
  if (peer.dialAttempts < MAX_DIAL_ATTEMPTS) {
230
+ this.logger.trace(`Failed to dial peer ${id} (attempt ${peer.dialAttempts})`, { error: inspect(error) });
188
231
  this.cachedPeers.set(id, peer);
189
232
  } else {
233
+ this.logger.debug(`Failed to dial peer ${id} (dropping)`, { error: inspect(error) });
190
234
  this.cachedPeers.delete(id);
191
235
  }
192
236
  }
@@ -194,9 +238,10 @@ export class PeerManager {
194
238
 
195
239
  private shouldDialPeer(): boolean {
196
240
  const connections = this.libP2PNode.getConnections().length;
197
- this.logger.debug(`Connections: ${connections}, maxPeerCount: ${this.config.maxPeerCount}`);
198
241
  if (connections >= this.config.maxPeerCount) {
199
- this.logger.debug('Not dialing peer, maxPeerCount reached');
242
+ this.logger.trace(
243
+ `Not dialing peer due to max peer count of ${this.config.maxPeerCount} reached (${connections} current connections)`,
244
+ );
200
245
  return false;
201
246
  }
202
247
  return true;
@@ -211,6 +256,7 @@ export class PeerManager {
211
256
  // Remove the oldest peers
212
257
  for (const key of this.cachedPeers.keys()) {
213
258
  this.cachedPeers.delete(key);
259
+ this.logger.trace(`Pruning peer ${key} from cache`);
214
260
  peersToDelete--;
215
261
  if (peersToDelete <= 0) {
216
262
  break;
@@ -1,3 +1,5 @@
1
+ import { median } from '@aztec/foundation/collection';
2
+
1
3
  import { type P2PConfig } from '../config.js';
2
4
 
3
5
  export enum PeerErrorSeverity {
@@ -43,7 +45,7 @@ export class PeerScoring {
43
45
  };
44
46
  }
45
47
 
46
- updateScore(peerId: string, scoreDelta: number): void {
48
+ updateScore(peerId: string, scoreDelta: number): number {
47
49
  const currentTime = Date.now();
48
50
  const lastUpdate = this.lastUpdateTime.get(peerId) || currentTime;
49
51
  const timePassed = currentTime - lastUpdate;
@@ -59,6 +61,7 @@ export class PeerScoring {
59
61
 
60
62
  this.scores.set(peerId, currentScore);
61
63
  this.lastUpdateTime.set(peerId, currentTime);
64
+ return currentScore;
62
65
  }
63
66
 
64
67
  decayAllScores(): void {
@@ -78,4 +81,8 @@ export class PeerScoring {
78
81
  getScore(peerId: string): number {
79
82
  return this.scores.get(peerId) || 0;
80
83
  }
84
+
85
+ getStats(): { medianScore: number } {
86
+ return { medianScore: median(Array.from(this.scores.values())) ?? 0 };
87
+ }
81
88
  }
@@ -3,8 +3,8 @@
3
3
  * @param _msg - The ping request message.
4
4
  * @returns A resolved promise with the pong response.
5
5
  */
6
- export function pingHandler(_msg: any): Promise<Uint8Array> {
7
- return Promise.resolve(Uint8Array.from(Buffer.from('pong')));
6
+ export function pingHandler(_msg: any): Promise<Buffer> {
7
+ return Promise.resolve(Buffer.from('pong'));
8
8
  }
9
9
 
10
10
  /**
@@ -12,6 +12,6 @@ export function pingHandler(_msg: any): Promise<Uint8Array> {
12
12
  * @param _msg - The status request message.
13
13
  * @returns A resolved promise with the ok response.
14
14
  */
15
- export function statusHandler(_msg: any): Promise<Uint8Array> {
16
- return Promise.resolve(Uint8Array.from(Buffer.from('ok')));
15
+ export function statusHandler(_msg: any): Promise<Buffer> {
16
+ return Promise.resolve(Buffer.from('ok'));
17
17
  }
@@ -16,7 +16,7 @@ export type ReqRespSubProtocol = typeof PING_PROTOCOL | typeof STATUS_PROTOCOL |
16
16
  * A handler for a sub protocol
17
17
  * The message will arrive as a buffer, and the handler must return a buffer
18
18
  */
19
- export type ReqRespSubProtocolHandler = (msg: Buffer) => Promise<Uint8Array>;
19
+ export type ReqRespSubProtocolHandler = (msg: Buffer) => Promise<Buffer>;
20
20
 
21
21
  /**
22
22
  * A type mapping from supprotocol to it's rate limits
@@ -83,8 +83,8 @@ export type SubProtocolMap = {
83
83
  * Default handler for unimplemented sub protocols, this SHOULD be overwritten
84
84
  * by the service, but is provided as a fallback
85
85
  */
86
- const defaultHandler = (_msg: any): Promise<Uint8Array> => {
87
- return Promise.resolve(Uint8Array.from(Buffer.from('unimplemented')));
86
+ const defaultHandler = (_msg: any): Promise<Buffer> => {
87
+ return Promise.resolve(Buffer.from('unimplemented'));
88
88
  };
89
89
 
90
90
  /**
@@ -1,10 +1,11 @@
1
1
  // @attribution: lodestar impl for inspiration
2
- import { type Logger, createDebugLogger } from '@aztec/foundation/log';
2
+ import { type Logger, createLogger } from '@aztec/foundation/log';
3
3
  import { executeTimeoutWithCustomError } from '@aztec/foundation/timer';
4
4
 
5
5
  import { type IncomingStreamData, type PeerId, type Stream } from '@libp2p/interface';
6
6
  import { pipe } from 'it-pipe';
7
7
  import { type Libp2p } from 'libp2p';
8
+ import { compressSync, uncompressSync } from 'snappy';
8
9
  import { type Uint8ArrayList } from 'uint8arraylist';
9
10
 
10
11
  import { CollectiveReqRespTimeoutError, IndiviualReqRespTimeoutError } from '../../errors/reqresp.error.js';
@@ -31,6 +32,9 @@ import { RequestResponseRateLimiter } from './rate_limiter/rate_limiter.js';
31
32
  * This service implements the request response sub protocol, it is heavily inspired from
32
33
  * ethereum implementations of the same name.
33
34
  *
35
+ * Note, responses get compressed in streamHandler
36
+ * so they get decompressed in readMessage
37
+ *
34
38
  * see: https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/p2p-interface.md#the-reqresp-domain
35
39
  */
36
40
  export class ReqResp {
@@ -46,7 +50,7 @@ export class ReqResp {
46
50
  private rateLimiter: RequestResponseRateLimiter;
47
51
 
48
52
  constructor(config: P2PReqRespConfig, protected readonly libp2p: Libp2p, private peerManager: PeerManager) {
49
- this.logger = createDebugLogger('aztec:p2p:reqresp');
53
+ this.logger = createLogger('p2p:reqresp');
50
54
 
51
55
  this.overallRequestTimeoutMs = config.overallRequestTimeoutMs;
52
56
  this.individualRequestTimeoutMs = config.individualRequestTimeoutMs;
@@ -192,7 +196,7 @@ export class ReqResp {
192
196
  let stream: Stream | undefined;
193
197
  try {
194
198
  stream = await this.libp2p.dialProtocol(peerId, subProtocol);
195
- this.logger.debug(`Stream opened with ${peerId.toString()} for ${subProtocol}`);
199
+ this.logger.trace(`Stream opened with ${peerId.toString()} for ${subProtocol}`);
196
200
 
197
201
  // Open the stream with a timeout
198
202
  const result = await executeTimeoutWithCustomError<Buffer>(
@@ -202,17 +206,17 @@ export class ReqResp {
202
206
  );
203
207
 
204
208
  await stream.close();
205
- this.logger.debug(`Stream closed with ${peerId.toString()} for ${subProtocol}`);
209
+ this.logger.trace(`Stream closed with ${peerId.toString()} for ${subProtocol}`);
206
210
 
207
211
  return result;
208
212
  } catch (e: any) {
209
- this.logger.error(`${e.message} | peerId: ${peerId.toString()} | subProtocol: ${subProtocol}`);
213
+ this.logger.error(`Error sending request to peer`, e, { peerId: peerId.toString(), subProtocol });
210
214
  this.peerManager.penalizePeer(peerId, PeerErrorSeverity.HighToleranceError);
211
215
  } finally {
212
216
  if (stream) {
213
217
  try {
214
218
  await stream.close();
215
- this.logger.debug(`Stream closed with ${peerId.toString()} for ${subProtocol}`);
219
+ this.logger.trace(`Stream closed with ${peerId.toString()} for ${subProtocol}`);
216
220
  } catch (closeError) {
217
221
  this.logger.error(
218
222
  `Error closing stream: ${closeError instanceof Error ? closeError.message : 'Unknown error'}`,
@@ -232,7 +236,7 @@ export class ReqResp {
232
236
  chunks.push(chunk.subarray());
233
237
  }
234
238
  const messageData = chunks.concat();
235
- return Buffer.concat(messageData);
239
+ return uncompressSync(Buffer.concat(messageData), { asBuffer: true }) as Buffer;
236
240
  }
237
241
 
238
242
  /**
@@ -269,7 +273,8 @@ export class ReqResp {
269
273
  async function* (source: any) {
270
274
  for await (const chunkList of source) {
271
275
  const msg = Buffer.from(chunkList.subarray());
272
- yield handler(msg);
276
+ const response = await handler(msg);
277
+ yield new Uint8Array(compressSync(response));
273
278
  }
274
279
  },
275
280
  stream,
@@ -1,4 +1,4 @@
1
- import type { BlockAttestation, BlockProposal, Gossipable } from '@aztec/circuit-types';
1
+ import type { BlockAttestation, BlockProposal, Gossipable, PeerInfo } from '@aztec/circuit-types';
2
2
 
3
3
  import type { ENR } from '@chainsafe/enr';
4
4
  import type { PeerId } from '@libp2p/interface';
@@ -49,6 +49,8 @@ export interface P2PService {
49
49
  registerBlockReceivedCallback(callback: (block: BlockProposal) => Promise<BlockAttestation | undefined>): void;
50
50
 
51
51
  getEnr(): ENR | undefined;
52
+
53
+ getPeers(includePending?: boolean): PeerInfo[];
52
54
  }
53
55
 
54
56
  /**
@@ -1,8 +1,8 @@
1
1
  import { Tx, type TxValidator } from '@aztec/circuit-types';
2
- import { createDebugLogger } from '@aztec/foundation/log';
2
+ import { createLogger } from '@aztec/foundation/log';
3
3
 
4
4
  export class DataTxValidator implements TxValidator<Tx> {
5
- #log = createDebugLogger('aztec:sequencer:tx_validator:tx_data');
5
+ #log = createLogger('p2p:tx_validator:tx_data');
6
6
 
7
7
  validateTxs(txs: Tx[]): Promise<[validTxs: Tx[], invalidTxs: Tx[]]> {
8
8
  const validTxs: Tx[] = [];
@@ -1,13 +1,13 @@
1
1
  import { type AnyTx, Tx, type TxValidator } from '@aztec/circuit-types';
2
2
  import { Fr } from '@aztec/circuits.js';
3
- import { createDebugLogger } from '@aztec/foundation/log';
3
+ import { createLogger } from '@aztec/foundation/log';
4
4
 
5
5
  export interface NullifierSource {
6
6
  getNullifierIndex: (nullifier: Fr) => Promise<bigint | undefined>;
7
7
  }
8
8
 
9
9
  export class DoubleSpendTxValidator<T extends AnyTx> implements TxValidator<T> {
10
- #log = createDebugLogger('aztec:sequencer:tx_validator:tx_double_spend');
10
+ #log = createLogger('p2p:tx_validator:tx_double_spend');
11
11
  #nullifierSource: NullifierSource;
12
12
 
13
13
  constructor(nullifierSource: NullifierSource, private readonly isValidatingBlock: boolean = true) {
@@ -1,9 +1,9 @@
1
1
  import { type AnyTx, Tx, type TxValidator } from '@aztec/circuit-types';
2
2
  import { type Fr } from '@aztec/circuits.js';
3
- import { createDebugLogger } from '@aztec/foundation/log';
3
+ import { createLogger } from '@aztec/foundation/log';
4
4
 
5
5
  export class MetadataTxValidator<T extends AnyTx> implements TxValidator<T> {
6
- #log = createDebugLogger('aztec:sequencer:tx_validator:tx_metadata');
6
+ #log = createLogger('p2p:tx_validator:tx_metadata');
7
7
 
8
8
  constructor(private chainId: Fr, private blockNumber: Fr) {}
9
9
 
@@ -1,8 +1,8 @@
1
1
  import { type ClientProtocolCircuitVerifier, Tx, type TxValidator } from '@aztec/circuit-types';
2
- import { createDebugLogger } from '@aztec/foundation/log';
2
+ import { createLogger } from '@aztec/foundation/log';
3
3
 
4
4
  export class TxProofValidator implements TxValidator<Tx> {
5
- #log = createDebugLogger('aztec:sequencer:tx_validator:private_proof');
5
+ #log = createLogger('p2p:tx_validator:private_proof');
6
6
 
7
7
  constructor(private verifier: ClientProtocolCircuitVerifier) {}
8
8
 
package/src/util.ts CHANGED
@@ -1,6 +1,10 @@
1
+ import { type AztecKVStore, type AztecSingleton } from '@aztec/kv-store';
1
2
  import { type DataStoreConfig } from '@aztec/kv-store/config';
2
3
 
3
4
  import type { GossipSub } from '@chainsafe/libp2p-gossipsub';
5
+ import { generateKeyPair, marshalPrivateKey, unmarshalPrivateKey } from '@libp2p/crypto/keys';
6
+ import { type PeerId, type PrivateKey } from '@libp2p/interface';
7
+ import { createFromPrivKey } from '@libp2p/peer-id-factory';
4
8
  import { resolve } from 'dns/promises';
5
9
  import type { Libp2p } from 'libp2p';
6
10
 
@@ -19,8 +23,7 @@ export interface PubSubLibp2p extends Libp2p {
19
23
  * const udpAddr = '[2001:db8::1]:8080' -> /ip6/2001:db8::1/udp/8080
20
24
  * @param address - The address string to convert. Has to be in the format <addr>:<port>.
21
25
  * @param protocol - The protocol to use in the multiaddr string.
22
- * @returns A multiaddr compliant string.
23
- */
26
+ * @returns A multiaddr compliant string. */
24
27
  export function convertToMultiaddr(address: string, protocol: 'tcp' | 'udp'): string {
25
28
  const [addr, port] = splitAddressPort(address, false);
26
29
 
@@ -141,3 +144,46 @@ export async function configureP2PClientAddresses(
141
144
 
142
145
  return config;
143
146
  }
147
+
148
+ /**
149
+ * Get the peer id private key
150
+ *
151
+ * 1. Check if we have a peer id private key in the config
152
+ * 2. If not, check we have a peer id private key persisted in the node
153
+ * 3. If not, create a new one, then persist it in the node
154
+ *
155
+ */
156
+ export async function getPeerIdPrivateKey(config: { peerIdPrivateKey?: string }, store: AztecKVStore): Promise<string> {
157
+ const peerIdPrivateKeySingleton: AztecSingleton<string> = store.openSingleton('peerIdPrivateKey');
158
+ if (config.peerIdPrivateKey) {
159
+ await peerIdPrivateKeySingleton.set(config.peerIdPrivateKey);
160
+ return config.peerIdPrivateKey;
161
+ }
162
+
163
+ const storedPeerIdPrivateKey = peerIdPrivateKeySingleton.get();
164
+ if (storedPeerIdPrivateKey) {
165
+ return storedPeerIdPrivateKey;
166
+ }
167
+
168
+ const newPeerIdPrivateKey = await generateKeyPair('secp256k1');
169
+ const privateKeyString = Buffer.from(marshalPrivateKey(newPeerIdPrivateKey)).toString('hex');
170
+
171
+ await peerIdPrivateKeySingleton.set(privateKeyString);
172
+ return privateKeyString;
173
+ }
174
+
175
+ /**
176
+ * Create a libp2p peer ID from the private key.
177
+ * @param privateKey - peer ID private key as hex string
178
+ * @returns The peer ID.
179
+ */
180
+ export async function createLibP2PPeerIdFromPrivateKey(privateKey: string): Promise<PeerId> {
181
+ if (!privateKey?.length) {
182
+ throw new Error('No peer private key provided');
183
+ }
184
+
185
+ const asLibp2pPrivateKey: PrivateKey<'secp256k1'> = await unmarshalPrivateKey(
186
+ new Uint8Array(Buffer.from(privateKey, 'hex')),
187
+ );
188
+ return await createFromPrivKey(asLibp2pPrivateKey);
189
+ }