@aztec/p2p 0.38.0 → 0.40.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 (36) hide show
  1. package/dest/bootstrap/bootstrap.d.ts.map +1 -1
  2. package/dest/bootstrap/bootstrap.js +3 -1
  3. package/dest/config.d.ts +5 -0
  4. package/dest/config.d.ts.map +1 -1
  5. package/dest/config.js +4 -2
  6. package/dest/service/data_store.d.ts +27 -0
  7. package/dest/service/data_store.d.ts.map +1 -0
  8. package/dest/service/data_store.js +188 -0
  9. package/dest/service/discV5_service.d.ts +8 -6
  10. package/dest/service/discV5_service.d.ts.map +1 -1
  11. package/dest/service/discV5_service.js +35 -21
  12. package/dest/service/dummy_service.d.ts +3 -1
  13. package/dest/service/dummy_service.d.ts.map +1 -1
  14. package/dest/service/dummy_service.js +11 -1
  15. package/dest/service/libp2p_service.d.ts +28 -17
  16. package/dest/service/libp2p_service.d.ts.map +1 -1
  17. package/dest/service/libp2p_service.js +101 -174
  18. package/dest/service/peer_manager.d.ts +12 -0
  19. package/dest/service/peer_manager.d.ts.map +1 -0
  20. package/dest/service/peer_manager.js +22 -0
  21. package/dest/service/service.d.ts +5 -0
  22. package/dest/service/service.d.ts.map +1 -1
  23. package/dest/service/service.js +6 -2
  24. package/dest/service/tx_messages.d.ts +11 -57
  25. package/dest/service/tx_messages.d.ts.map +1 -1
  26. package/dest/service/tx_messages.js +14 -89
  27. package/package.json +29 -21
  28. package/src/bootstrap/bootstrap.ts +2 -0
  29. package/src/config.ts +9 -0
  30. package/src/service/data_store.ts +235 -0
  31. package/src/service/discV5_service.ts +37 -20
  32. package/src/service/dummy_service.ts +8 -1
  33. package/src/service/libp2p_service.ts +130 -194
  34. package/src/service/peer_manager.ts +26 -0
  35. package/src/service/service.ts +7 -0
  36. package/src/service/tx_messages.ts +18 -93
@@ -2,43 +2,43 @@ import { type Tx, type TxHash } from '@aztec/circuit-types';
2
2
  import { SerialQueue } from '@aztec/foundation/fifo';
3
3
  import { createDebugLogger } from '@aztec/foundation/log';
4
4
  import { type AztecKVStore } from '@aztec/kv-store';
5
+ import { AztecLmdbStore } from '@aztec/kv-store/lmdb';
5
6
 
6
7
  import { ENR } from '@chainsafe/enr';
8
+ import { type GossipsubEvents, gossipsub } from '@chainsafe/libp2p-gossipsub';
7
9
  import { noise } from '@chainsafe/libp2p-noise';
8
10
  import { yamux } from '@chainsafe/libp2p-yamux';
9
11
  import { identify } from '@libp2p/identify';
10
- import type { IncomingStreamData, PeerId, Stream } from '@libp2p/interface';
11
- import type { ServiceMap } from '@libp2p/interface-libp2p';
12
+ import type { IncomingStreamData, PeerId, PubSub, Stream } from '@libp2p/interface';
12
13
  import '@libp2p/kad-dht';
13
14
  import { mplex } from '@libp2p/mplex';
14
15
  import { peerIdFromString } from '@libp2p/peer-id';
15
- import { createFromJSON, createSecp256k1PeerId, exportToProtobuf } from '@libp2p/peer-id-factory';
16
+ import { createFromJSON, createSecp256k1PeerId } from '@libp2p/peer-id-factory';
16
17
  import { tcp } from '@libp2p/tcp';
17
18
  import { pipe } from 'it-pipe';
18
- import { type Libp2p, type Libp2pOptions, type ServiceFactoryMap, createLibp2p } from 'libp2p';
19
+ import { type Libp2p, createLibp2p } from 'libp2p';
19
20
 
20
21
  import { type P2PConfig } from '../config.js';
21
22
  import { type TxPool } from '../tx_pool/index.js';
23
+ import { AztecDatastore } from './data_store.js';
22
24
  import { KnownTxLookup } from './known_txs.js';
25
+ import { PeerManager } from './peer_manager.js';
23
26
  import { AztecPeerDb, type AztecPeerStore } from './peer_store.js';
24
27
  import type { P2PService, PeerDiscoveryService } from './service.js';
25
- import {
26
- Messages,
27
- createGetTransactionsRequestMessage,
28
- createTransactionHashesMessage,
29
- createTransactionsMessage,
30
- decodeGetTransactionsRequestMessage,
31
- decodeTransactionHashesMessage,
32
- decodeTransactionsMessage,
33
- getEncodedMessage,
34
- } from './tx_messages.js';
28
+ import { AztecTxMessageCreator, fromTxMessage } from './tx_messages.js';
29
+
30
+ export interface PubSubLibp2p extends Libp2p {
31
+ services: {
32
+ pubsub: PubSub<GossipsubEvents>;
33
+ };
34
+ }
35
35
 
36
36
  /**
37
37
  * Create a libp2p peer ID from the private key if provided, otherwise creates a new random ID.
38
38
  * @param privateKey - Optional peer ID private key as hex string
39
39
  * @returns The peer ID.
40
40
  */
41
- export async function createLibP2PPeerId(privateKey?: string) {
41
+ export async function createLibP2PPeerId(privateKey?: string): Promise<PeerId> {
42
42
  if (!privateKey?.length) {
43
43
  return await createSecp256k1PeerId();
44
44
  }
@@ -49,31 +49,27 @@ export async function createLibP2PPeerId(privateKey?: string) {
49
49
  });
50
50
  }
51
51
 
52
- /**
53
- * Exports a given peer id to a string representation.
54
- * @param peerId - The peerId instance to be converted.
55
- * @returns The peer id as a string.
56
- */
57
- export function exportLibP2PPeerIdToString(peerId: PeerId) {
58
- return Buffer.from(exportToProtobuf(peerId)).toString('hex');
59
- }
60
-
61
52
  /**
62
53
  * Lib P2P implementation of the P2PService interface.
63
54
  */
64
55
  export class LibP2PService implements P2PService {
65
56
  private jobQueue: SerialQueue = new SerialQueue();
66
57
  private knownTxLookup: KnownTxLookup = new KnownTxLookup();
58
+ private messageCreator: AztecTxMessageCreator;
59
+ private peerManager: PeerManager;
67
60
  constructor(
68
61
  private config: P2PConfig,
69
- private node: Libp2p,
62
+ private node: PubSubLibp2p,
70
63
  private peerDiscoveryService: PeerDiscoveryService,
71
64
  private peerStore: AztecPeerStore,
72
65
  private protocolId: string,
73
66
  private txPool: TxPool,
74
67
  private bootstrapPeerIds: PeerId[] = [],
75
68
  private logger = createDebugLogger('aztec:libp2p_service'),
76
- ) {}
69
+ ) {
70
+ this.messageCreator = new AztecTxMessageCreator(config.txGossipVersion);
71
+ this.peerManager = new PeerManager(node, peerDiscoveryService, config, logger);
72
+ }
77
73
 
78
74
  /**
79
75
  * Starts the LibP2P service.
@@ -97,24 +93,18 @@ export class LibP2PService implements P2PService {
97
93
  await this.addPeer(enr);
98
94
  });
99
95
 
100
- this.node.addEventListener('peer:discovery', evt => {
101
- const peerId = evt.detail.id;
102
- if (this.isBootstrapPeer(peerId)) {
103
- this.logger.verbose(`Discovered bootstrap peer ${peerId.toString()}`);
104
- }
105
- });
106
-
107
- this.node.addEventListener('peer:connect', evt => {
96
+ this.node.addEventListener('peer:connect', async evt => {
108
97
  const peerId = evt.detail;
109
- this.handleNewConnection(peerId);
98
+ await this.handleNewConnection(peerId as PeerId);
110
99
  });
111
100
 
112
- this.node.addEventListener('peer:disconnect', evt => {
101
+ this.node.addEventListener('peer:disconnect', async evt => {
113
102
  const peerId = evt.detail;
114
103
  if (this.isBootstrapPeer(peerId)) {
115
104
  this.logger.verbose(`Disconnect from bootstrap peer ${peerId.toString()}`);
116
105
  } else {
117
106
  this.logger.verbose(`Disconnected from transaction peer ${peerId.toString()}`);
107
+ await this.peerManager.updateDiscoveryService();
118
108
  }
119
109
  });
120
110
 
@@ -125,6 +115,17 @@ export class LibP2PService implements P2PService {
125
115
  this.jobQueue.put(() => Promise.resolve(this.handleProtocolDial(incoming))),
126
116
  );
127
117
  this.logger.info(`Started P2P client with Peer ID ${this.node.peerId.toString()}`);
118
+
119
+ // Subscribe to standard topics by default
120
+ this.subscribeToTopic(this.messageCreator.getTopic());
121
+
122
+ // add gossipsub listener
123
+ this.node.services.pubsub.addEventListener('gossipsub:message', async e => {
124
+ const { msg } = e.detail;
125
+ this.logger.debug(`Received PUBSUB message.`);
126
+
127
+ await this.handleNewGossipMessage(msg.topic, msg.data);
128
+ });
128
129
  }
129
130
 
130
131
  /**
@@ -152,27 +153,15 @@ export class LibP2PService implements P2PService {
152
153
  txPool: TxPool,
153
154
  store: AztecKVStore,
154
155
  ) {
155
- const { tcpListenIp, tcpListenPort, minPeerCount, maxPeerCount } = config;
156
- const opts: Libp2pOptions<ServiceMap> = {
157
- start: false,
158
- peerId,
159
- addresses: {
160
- listen: [`/ip4/${tcpListenIp}/tcp/${tcpListenPort}`],
161
- },
162
- transports: [tcp()],
163
- streamMuxers: [yamux(), mplex()],
164
- connectionEncryption: [noise()],
165
- connectionManager: {
166
- minConnections: minPeerCount,
167
- maxConnections: maxPeerCount,
168
- },
169
- };
170
-
171
- const services: ServiceFactoryMap = {
172
- identify: identify({
173
- protocolPrefix: 'aztec',
174
- }),
175
- };
156
+ const {
157
+ tcpListenIp,
158
+ tcpListenPort,
159
+ minPeerCount,
160
+ maxPeerCount,
161
+ dataDirectory,
162
+ transactionProtocol: protocolId,
163
+ } = config;
164
+ const bindAddrTcp = `/ip4/${tcpListenIp}/tcp/${tcpListenPort}`;
176
165
 
177
166
  // The autonat service seems quite problematic in that using it seems to cause a lot of attempts
178
167
  // to dial ephemeral ports. I suspect that it works better if you can get the uPNPnat service to
@@ -188,11 +177,41 @@ export class LibP2PService implements P2PService {
188
177
  // services.uPnPNAT = uPnPNATService();
189
178
  // }
190
179
 
180
+ const datastore = new AztecDatastore(AztecLmdbStore.open(dataDirectory));
181
+
191
182
  const node = await createLibp2p({
192
- ...opts,
193
- services,
183
+ start: false,
184
+ peerId,
185
+ addresses: {
186
+ listen: [bindAddrTcp],
187
+ },
188
+ transports: [
189
+ tcp({
190
+ maxConnections: config.maxPeerCount,
191
+ }),
192
+ ],
193
+ datastore,
194
+ streamMuxers: [yamux(), mplex()],
195
+ connectionEncryption: [noise()],
196
+ connectionManager: {
197
+ minConnections: minPeerCount,
198
+ maxConnections: maxPeerCount,
199
+ },
200
+ services: {
201
+ identify: identify({
202
+ protocolPrefix: 'aztec',
203
+ }),
204
+ pubsub: gossipsub({
205
+ allowPublishToZeroTopicPeers: true,
206
+ D: 6,
207
+ Dlo: 4,
208
+ Dhi: 12,
209
+ heartbeatInterval: 1_000,
210
+ mcacheLength: 5,
211
+ mcacheGossip: 3,
212
+ }),
213
+ },
194
214
  });
195
- const protocolId = config.transactionProtocol;
196
215
 
197
216
  // Create an LMDB peer store
198
217
  const peerDb = new AztecPeerDb(store);
@@ -208,6 +227,47 @@ export class LibP2PService implements P2PService {
208
227
  return new LibP2PService(config, node, peerDiscoveryService, peerDb, protocolId, txPool, bootstrapPeerIds);
209
228
  }
210
229
 
230
+ /**
231
+ * Subscribes to a topic.
232
+ * @param topic - The topic to subscribe to.
233
+ */
234
+ private subscribeToTopic(topic: string) {
235
+ if (!this.node.services.pubsub) {
236
+ throw new Error('Pubsub service not available.');
237
+ }
238
+ void this.node.services.pubsub.subscribe(topic);
239
+ }
240
+
241
+ /**
242
+ * Publishes data to a topic.
243
+ * @param topic - The topic to publish to.
244
+ * @param data - The data to publish.
245
+ * @returns The number of recipients the data was sent to.
246
+ */
247
+ private async publishToTopic(topic: string, data: Uint8Array) {
248
+ if (!this.node.services.pubsub) {
249
+ throw new Error('Pubsub service not available.');
250
+ }
251
+ const result = await this.node.services.pubsub.publish(topic, data);
252
+
253
+ return result.recipients.length;
254
+ }
255
+
256
+ /**
257
+ * Handles a new gossip message that was received by the client.
258
+ * @param topic - The message's topic.
259
+ * @param data - The message data
260
+ */
261
+ private async handleNewGossipMessage(topic: string, data: Uint8Array) {
262
+ if (topic !== this.messageCreator.getTopic()) {
263
+ // Invalid TX Topic, ignore
264
+ return;
265
+ }
266
+
267
+ const tx = fromTxMessage(Buffer.from(data));
268
+ await this.processTxFromPeer(tx);
269
+ }
270
+
211
271
  /**
212
272
  * Propagates the provided transaction to peers.
213
273
  * @param tx - The transaction to propagate.
@@ -243,7 +303,7 @@ export class LibP2PService implements P2PService {
243
303
 
244
304
  // add to peer store if not already known
245
305
  if (!hasPeer) {
246
- this.logger.info(`Discovered peer ${enr.peerId().toString()}. Adding to libp2p peer list`);
306
+ this.logger.info(`Discovered peer ${peerIdStr}. Adding to libp2p peer list`);
247
307
  let stream: Stream | undefined;
248
308
  try {
249
309
  stream = await this.node.dialProtocol(peerMultiAddr, this.protocolId);
@@ -268,7 +328,7 @@ export class LibP2PService implements P2PService {
268
328
  if (!message.length) {
269
329
  this.logger.verbose(`Ignoring 0 byte message from peer${peer.toString()}`);
270
330
  }
271
- await this.processMessage(message, peer);
331
+ // await this.processTransactionMessage(message, peer);
272
332
  } catch (err) {
273
333
  this.logger.error(
274
334
  `Failed to handle received message from peer ${incomingStreamData.connection.remotePeer.toString()}`,
@@ -289,151 +349,27 @@ export class LibP2PService implements P2PService {
289
349
  return { message: buffer, peer: incomingStreamData.connection.remotePeer };
290
350
  }
291
351
 
292
- private handleNewConnection(peerId: PeerId) {
352
+ private async handleNewConnection(peerId: PeerId) {
293
353
  if (this.isBootstrapPeer(peerId)) {
294
354
  this.logger.verbose(`Connected to bootstrap peer ${peerId.toString()}`);
295
355
  } else {
296
356
  this.logger.verbose(`Connected to transaction peer ${peerId.toString()}`);
297
- // send the peer our current pooled transaction hashes
298
- void this.jobQueue.put(async () => {
299
- await this.sendTxHashesMessageToPeer(peerId);
300
- });
301
- }
302
- }
303
-
304
- private async processMessage(message: Buffer, peerId: PeerId) {
305
- const type = message.readUInt32BE(0);
306
- const encodedMessage = getEncodedMessage(message);
307
- switch (type) {
308
- case Messages.POOLED_TRANSACTIONS:
309
- await this.processReceivedTxs(encodedMessage, peerId);
310
- return;
311
- case Messages.POOLED_TRANSACTION_HASHES:
312
- await this.processReceivedTxHashes(encodedMessage, peerId);
313
- return;
314
- case Messages.GET_TRANSACTIONS:
315
- await this.processReceivedGetTransactionsRequest(encodedMessage, peerId);
316
- return;
317
- }
318
- throw new Error(`Unknown message type ${type}`);
319
- }
320
-
321
- private async processReceivedTxHashes(encodedMessage: Buffer, peerId: PeerId) {
322
- try {
323
- const txHashes = decodeTransactionHashesMessage(encodedMessage);
324
- this.logger.debug(`Received tx hash messages from ${peerId.toString()}`);
325
- // we send a message requesting the transactions that we don't have from the set of received hashes
326
- const requiredHashes = txHashes.filter(hash => !this.txPool.hasTx(hash));
327
- if (!requiredHashes.length) {
328
- return;
329
- }
330
- await this.sendGetTransactionsMessageToPeer(txHashes, peerId);
331
- } catch (err) {
332
- this.logger.error(`Failed to process received tx hashes`, err);
333
- }
334
- }
335
-
336
- private async processReceivedGetTransactionsRequest(encodedMessage: Buffer, peerId: PeerId) {
337
- try {
338
- this.logger.debug(`Received get txs messages from ${peerId.toString()}`);
339
- // get the transactions in the list that we have and return them
340
- const removeUndefined = <S>(value: S | undefined): value is S => value != undefined;
341
- const txHashes = decodeGetTransactionsRequestMessage(encodedMessage);
342
- const txs = txHashes.map(x => this.txPool.getTxByHash(x)).filter(removeUndefined);
343
- if (!txs.length) {
344
- return;
345
- }
346
- await this.sendTransactionsMessageToPeer(txs, peerId);
347
- } catch (err) {
348
- this.logger.error(`Failed to process get txs request`, err);
349
- }
350
- }
351
-
352
- private async processReceivedTxs(encodedMessage: Buffer, peerId: PeerId) {
353
- try {
354
- const txs = decodeTransactionsMessage(encodedMessage);
355
- // Could optimize here and process all txs at once
356
- // Propagation would need to filter and send custom tx set per peer
357
- for (const tx of txs) {
358
- await this.processTxFromPeer(tx, peerId);
359
- }
360
- } catch (err) {
361
- this.logger.error(`Failed to process pooled transactions message`, err);
357
+ await this.peerManager.updateDiscoveryService();
362
358
  }
363
359
  }
364
360
 
365
- private async processTxFromPeer(tx: Tx, peerId: PeerId): Promise<void> {
361
+ private async processTxFromPeer(tx: Tx): Promise<void> {
366
362
  const txHash = tx.getTxHash();
367
363
  const txHashString = txHash.toString();
368
- this.knownTxLookup.addPeerForTx(peerId, txHashString);
369
- this.logger.debug(`Received tx ${txHashString} from peer ${peerId.toString()}`);
364
+ this.logger.debug(`Received tx ${txHashString} from external peer.`);
370
365
  await this.txPool.addTxs([tx]);
371
- this.propagateTx(tx);
372
366
  }
373
367
 
374
368
  private async sendTxToPeers(tx: Tx) {
375
- const txs = createTransactionsMessage([tx]);
376
- const payload = new Uint8Array(txs);
377
- const peers = this.getTxPeers();
378
- const txHash = tx.getTxHash();
379
- const txHashString = txHash.toString();
380
- for (const peer of peers) {
381
- try {
382
- if (this.knownTxLookup.hasPeerSeenTx(peer, txHashString)) {
383
- this.logger.debug(`Not sending tx ${txHashString} to peer ${peer.toString()} as they have already seen it`);
384
- continue;
385
- }
386
- this.logger.debug(`Sending tx ${txHashString} to peer ${peer.toString()}`);
387
- await this.sendRawMessageToPeer(payload, peer);
388
- this.knownTxLookup.addPeerForTx(peer, txHashString);
389
- } catch (err) {
390
- this.logger.error(`Failed to send txs to peer ${peer.toString()}`, err);
391
- continue;
392
- }
393
- }
394
- }
395
-
396
- private async sendTxHashesMessageToPeer(peer: PeerId) {
397
- try {
398
- const hashes = this.txPool.getAllTxHashes();
399
- if (!hashes.length) {
400
- return;
401
- }
402
- const message = createTransactionHashesMessage(hashes);
403
- await this.sendRawMessageToPeer(new Uint8Array(message), peer);
404
- } catch (err) {
405
- this.logger.error(`Failed to send tx hashes to peer ${peer.toString()}`, err);
406
- }
407
- }
408
-
409
- private async sendGetTransactionsMessageToPeer(hashes: TxHash[], peer: PeerId) {
410
- try {
411
- const message = createGetTransactionsRequestMessage(hashes);
412
- await this.sendRawMessageToPeer(new Uint8Array(message), peer);
413
- } catch (err) {
414
- this.logger.error(`Failed to send tx request to peer ${peer.toString()}`, err);
415
- }
416
- }
417
-
418
- private async sendTransactionsMessageToPeer(txs: Tx[], peer: PeerId) {
419
- // don't filter out any transactions based on what we think the peer has seen,
420
- // we have been explicitly asked for these transactions
421
- const message = createTransactionsMessage(txs);
422
- await this.sendRawMessageToPeer(message, peer);
423
- for (const tx of txs) {
424
- const hash = tx.getTxHash();
425
- this.knownTxLookup.addPeerForTx(peer, hash.toString());
426
- }
427
- }
428
-
429
- private async sendRawMessageToPeer(message: Uint8Array, peer: PeerId) {
430
- const stream = await this.node.dialProtocol(peer, this.protocolId);
431
- await pipe([message], stream);
432
- await stream.close();
433
- }
434
-
435
- private getTxPeers() {
436
- return this.node.getPeers().filter(peer => !this.isBootstrapPeer(peer));
369
+ const { data: txData } = this.messageCreator.createTxMessage(tx);
370
+ this.logger.debug(`Sending tx ${tx.getTxHash().toString()} to peers`);
371
+ const recipientsNum = await this.publishToTopic(this.messageCreator.getTopic(), txData);
372
+ this.logger.debug(`Sent tx ${tx.getTxHash().toString()} to ${recipientsNum} peers`);
437
373
  }
438
374
 
439
375
  private isBootstrapPeer(peer: PeerId) {
@@ -0,0 +1,26 @@
1
+ import { createDebugLogger } from '@aztec/foundation/log';
2
+
3
+ import { type Libp2p } from 'libp2p';
4
+
5
+ import { type P2PConfig } from '../config.js';
6
+ import { type PeerDiscoveryService, PeerDiscoveryState } from './service.js';
7
+
8
+ export class PeerManager {
9
+ constructor(
10
+ private libP2PNode: Libp2p,
11
+ private discV5Node: PeerDiscoveryService,
12
+ private config: P2PConfig,
13
+ private logger = createDebugLogger('aztec:p2p:peer_manager'),
14
+ ) {}
15
+
16
+ async updateDiscoveryService() {
17
+ const peerCount = this.libP2PNode.getPeers().length;
18
+ if (peerCount >= this.config.maxPeerCount && this.discV5Node.getStatus() === PeerDiscoveryState.RUNNING) {
19
+ this.logger.debug('Max peer count reached, stopping discovery service');
20
+ await this.discV5Node.stop();
21
+ } else if (peerCount <= this.config.minPeerCount && this.discV5Node.getStatus() === PeerDiscoveryState.STOPPED) {
22
+ this.logger.debug('Min peer count reached, starting discovery service');
23
+ await this.discV5Node.start();
24
+ }
25
+ }
26
+ }
@@ -3,6 +3,11 @@ import type { Tx, TxHash } from '@aztec/circuit-types';
3
3
  import type { ENR } from '@chainsafe/enr';
4
4
  import type EventEmitter from 'events';
5
5
 
6
+ export enum PeerDiscoveryState {
7
+ RUNNING = 'running',
8
+ STOPPED = 'stopped',
9
+ }
10
+
6
11
  /**
7
12
  * The interface for a P2P service implementation.
8
13
  */
@@ -57,4 +62,6 @@ export interface PeerDiscoveryService extends EventEmitter {
57
62
  */
58
63
  on(event: 'peer:discovered', listener: (enr: ENR) => void): this;
59
64
  emit(event: 'peer:discovered', enr: ENR): boolean;
65
+
66
+ getStatus(): PeerDiscoveryState;
60
67
  }
@@ -1,34 +1,26 @@
1
- import { EncryptedTxL2Logs, Tx, TxHash, UnencryptedTxL2Logs } from '@aztec/circuit-types';
1
+ import { EncryptedTxL2Logs, Tx, UnencryptedTxL2Logs } from '@aztec/circuit-types';
2
2
  import { PrivateKernelTailCircuitPublicInputs, Proof, PublicCallRequest } from '@aztec/circuits.js';
3
3
  import { numToUInt32BE } from '@aztec/foundation/serialize';
4
4
 
5
- /**
6
- * Enumeration of P2P message types.
7
- */
8
- export enum Messages {
9
- POOLED_TRANSACTIONS = 1,
10
- POOLED_TRANSACTION_HASHES = 2,
11
- GET_TRANSACTIONS = 3,
12
- }
5
+ import { type SemVer } from 'semver';
13
6
 
14
- /**
15
- * Create a P2P message from the message type and message data.
16
- * @param type - The type of the message.
17
- * @param messageData - The binary message data.
18
- * @returns The encoded message.
19
- */
20
- export function createMessage(type: Messages, messageData: Buffer) {
21
- return Buffer.concat([numToUInt32BE(type), messageData]);
22
- }
7
+ export const TX_MESSAGE_TOPIC = '';
23
8
 
24
- /**
25
- * Create a POOLED_TRANSACTIONS message from an array of transactions.
26
- * @param txs - The transactions to encoded into a message.
27
- * @returns The encoded message.
28
- */
29
- export function createTransactionsMessage(txs: Tx[]) {
30
- const messageData = txs.map(toTxMessage);
31
- return createMessage(Messages.POOLED_TRANSACTIONS, Buffer.concat(messageData));
9
+ export class AztecTxMessageCreator {
10
+ private readonly topic: string;
11
+ constructor(version: SemVer) {
12
+ this.topic = `/aztec/tx/${version.toString()}`;
13
+ }
14
+
15
+ createTxMessage(tx: Tx) {
16
+ const messageData = toTxMessage(tx);
17
+
18
+ return { topic: this.topic, data: messageData };
19
+ }
20
+
21
+ getTopic() {
22
+ return this.topic;
23
+ }
32
24
  }
33
25
 
34
26
  /**
@@ -49,73 +41,6 @@ export function decodeTransactionsMessage(message: Buffer) {
49
41
  return txs;
50
42
  }
51
43
 
52
- /**
53
- * Create a POOLED_TRANSACTION_HASHES message.
54
- * @param hashes - The transaction hashes to be sent.
55
- * @returns The encoded message.
56
- */
57
- export function createTransactionHashesMessage(hashes: TxHash[]) {
58
- const messageData = hashes.map(x => x.buffer);
59
- return createMessage(Messages.POOLED_TRANSACTION_HASHES, Buffer.concat(messageData));
60
- }
61
-
62
- /**
63
- * Decode a POOLED_TRANSACTION_HASHESs message ito the original transaction hash objects.
64
- * @param message - The binary message to be decoded.
65
- * @returns - The array of transaction hashes originally encoded into the message.
66
- */
67
- export function decodeTransactionHashesMessage(message: Buffer) {
68
- let offset = 0;
69
- const txHashes: TxHash[] = [];
70
- while (offset < message.length) {
71
- const slice = message.subarray(offset, offset + TxHash.SIZE);
72
- if (slice.length < TxHash.SIZE) {
73
- throw new Error(`Invalid message size when processing transaction hashes message`);
74
- }
75
- txHashes.push(new TxHash(slice));
76
- offset += TxHash.SIZE;
77
- }
78
- return txHashes;
79
- }
80
-
81
- /**
82
- * Create a GET_TRANSACTIONS message from an array of transaction hashes.
83
- * @param hashes - The hashes of the transactions to be requested.
84
- * @returns The encoded message.
85
- */
86
- export function createGetTransactionsRequestMessage(hashes: TxHash[]) {
87
- const messageData = hashes.map(x => x.buffer);
88
- return createMessage(Messages.GET_TRANSACTIONS, Buffer.concat(messageData));
89
- }
90
-
91
- /**
92
- * Decode a GET_TRANSACTIONS message into the original transaction hash objects.
93
- * @param message - The binary message to be decoded.
94
- * @returns - The array of transaction hashes originally encoded into the message.
95
- */
96
- export function decodeGetTransactionsRequestMessage(message: Buffer) {
97
- // for the time being this payload is effectively the same as the POOLED_TRANSACTION_HASHES message
98
- return decodeTransactionHashesMessage(message);
99
- }
100
-
101
- /**
102
- * Decode the message type from a received message.
103
- * @param message - The received message.
104
- * @returns The decoded MessageType.
105
- */
106
- export function decodeMessageType(message: Buffer) {
107
- return message.readUInt32BE(0);
108
- }
109
-
110
- /**
111
- * Return the encoded message (minus the header) from received message buffer.
112
- * @param message - The complete received message.
113
- * @returns The encoded message, without the header.
114
- */
115
- export function getEncodedMessage(message: Buffer) {
116
- return message.subarray(4);
117
- }
118
-
119
44
  /**
120
45
  * Creates a tx 'message' for sending to a peer.
121
46
  * @param tx - The transaction to convert to a message.