@aztec/p2p 0.49.2 → 0.51.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 (63) hide show
  1. package/dest/attestation_pool/attestation_pool.d.ts +39 -0
  2. package/dest/attestation_pool/attestation_pool.d.ts.map +1 -0
  3. package/dest/attestation_pool/attestation_pool.js +2 -0
  4. package/dest/attestation_pool/index.d.ts +3 -0
  5. package/dest/attestation_pool/index.d.ts.map +1 -0
  6. package/dest/attestation_pool/index.js +3 -0
  7. package/dest/attestation_pool/memory_attestation_pool.d.ts +12 -0
  8. package/dest/attestation_pool/memory_attestation_pool.d.ts.map +1 -0
  9. package/dest/attestation_pool/memory_attestation_pool.js +56 -0
  10. package/dest/attestation_pool/mocks.d.ts +16 -0
  11. package/dest/attestation_pool/mocks.d.ts.map +1 -0
  12. package/dest/attestation_pool/mocks.js +29 -0
  13. package/dest/client/index.d.ts +2 -1
  14. package/dest/client/index.d.ts.map +1 -1
  15. package/dest/client/index.js +11 -5
  16. package/dest/client/p2p_client.d.ts +33 -2
  17. package/dest/client/p2p_client.d.ts.map +1 -1
  18. package/dest/client/p2p_client.js +20 -5
  19. package/dest/index.d.ts +1 -0
  20. package/dest/index.d.ts.map +1 -1
  21. package/dest/index.js +2 -1
  22. package/dest/service/discV5_service.d.ts.map +1 -1
  23. package/dest/service/discV5_service.js +4 -3
  24. package/dest/service/dummy_service.d.ts +10 -4
  25. package/dest/service/dummy_service.d.ts.map +1 -1
  26. package/dest/service/dummy_service.js +14 -4
  27. package/dest/service/libp2p_service.d.ts +25 -6
  28. package/dest/service/libp2p_service.d.ts.map +1 -1
  29. package/dest/service/libp2p_service.js +55 -10
  30. package/dest/service/reqresp/handlers.d.ts +3 -0
  31. package/dest/service/reqresp/handlers.d.ts.map +1 -0
  32. package/dest/service/reqresp/handlers.js +7 -0
  33. package/dest/service/reqresp/index.d.ts +6 -0
  34. package/dest/service/reqresp/index.d.ts.map +1 -0
  35. package/dest/service/reqresp/index.js +6 -0
  36. package/dest/service/reqresp/interface.d.ts +11 -0
  37. package/dest/service/reqresp/interface.d.ts.map +1 -0
  38. package/dest/service/reqresp/interface.js +10 -0
  39. package/dest/service/reqresp/reqresp.d.ts +48 -0
  40. package/dest/service/reqresp/reqresp.d.ts.map +1 -0
  41. package/dest/service/reqresp/reqresp.js +112 -0
  42. package/dest/service/service.d.ts +6 -3
  43. package/dest/service/service.d.ts.map +1 -1
  44. package/dest/util.d.ts +1 -1
  45. package/dest/util.d.ts.map +1 -1
  46. package/dest/util.js +31 -12
  47. package/package.json +8 -7
  48. package/src/attestation_pool/attestation_pool.ts +42 -0
  49. package/src/attestation_pool/index.ts +2 -0
  50. package/src/attestation_pool/memory_attestation_pool.ts +70 -0
  51. package/src/attestation_pool/mocks.ts +33 -0
  52. package/src/client/index.ts +12 -3
  53. package/src/client/p2p_client.ts +63 -3
  54. package/src/index.ts +1 -0
  55. package/src/service/discV5_service.ts +3 -2
  56. package/src/service/dummy_service.ts +17 -4
  57. package/src/service/libp2p_service.ts +74 -7
  58. package/src/service/reqresp/handlers.ts +7 -0
  59. package/src/service/reqresp/index.ts +4 -0
  60. package/src/service/reqresp/interface.ts +13 -0
  61. package/src/service/reqresp/reqresp.ts +130 -0
  62. package/src/service/service.ts +10 -3
  63. package/src/util.ts +30 -10
@@ -0,0 +1,130 @@
1
+ // @attribution: lodestar impl for inspiration
2
+ import { type Logger, createDebugLogger } from '@aztec/foundation/log';
3
+
4
+ import { type IncomingStreamData, type PeerId } from '@libp2p/interface';
5
+ import { pipe } from 'it-pipe';
6
+ import { type Libp2p } from 'libp2p';
7
+ import { type Uint8ArrayList } from 'uint8arraylist';
8
+
9
+ import { pingHandler, statusHandler } from './handlers.js';
10
+ import { PING_PROTOCOL, STATUS_PROTOCOL, type SubProtocol, type SubProtocolHandler } from './interface.js';
11
+
12
+ /**
13
+ * A mapping from a protocol to a handler function
14
+ */
15
+ const SUB_PROTOCOL_HANDLERS: Record<SubProtocol, SubProtocolHandler> = {
16
+ [PING_PROTOCOL]: pingHandler,
17
+ [STATUS_PROTOCOL]: statusHandler,
18
+ };
19
+
20
+ export class ReqResp {
21
+ protected readonly logger: Logger;
22
+
23
+ private abortController: AbortController = new AbortController();
24
+
25
+ constructor(protected readonly libp2p: Libp2p) {
26
+ this.logger = createDebugLogger('aztec:p2p:reqresp');
27
+ }
28
+
29
+ /**
30
+ * Start the reqresp service
31
+ */
32
+ async start() {
33
+ // Register all protocol handlers
34
+ for (const subProtocol of Object.keys(SUB_PROTOCOL_HANDLERS)) {
35
+ await this.libp2p.handle(subProtocol, this.streamHandler.bind(this, subProtocol as SubProtocol));
36
+ }
37
+ }
38
+
39
+ /**
40
+ * Stop the reqresp service
41
+ */
42
+ async stop() {
43
+ // Unregister all handlers
44
+ for (const protocol of Object.keys(SUB_PROTOCOL_HANDLERS)) {
45
+ await this.libp2p.unhandle(protocol);
46
+ }
47
+ await this.libp2p.stop();
48
+ this.abortController.abort();
49
+ }
50
+
51
+ /**
52
+ * Send a request to peers, returns the first response
53
+ *
54
+ * @param subProtocol - The protocol being requested
55
+ * @param payload - The payload to send
56
+ * @returns - The response from the peer, otherwise undefined
57
+ */
58
+ async sendRequest(subProtocol: SubProtocol, payload: Buffer): Promise<Buffer | undefined> {
59
+ // Get active peers
60
+ const peers = this.libp2p.getPeers();
61
+
62
+ // Attempt to ask all of our peers
63
+ for (const peer of peers) {
64
+ const response = await this.sendRequestToPeer(peer, subProtocol, payload);
65
+
66
+ // If we get a response, return it, otherwise we iterate onto the next peer
67
+ if (response) {
68
+ return response;
69
+ }
70
+ }
71
+ return undefined;
72
+ }
73
+
74
+ /**
75
+ * Sends a request to a specific peer
76
+ *
77
+ * @param peerId - The peer to send the request to
78
+ * @param subProtocol - The protocol to use to request
79
+ * @param payload - The payload to send
80
+ * @returns If the request is successful, the response is returned, otherwise undefined
81
+ */
82
+ async sendRequestToPeer(peerId: PeerId, subProtocol: SubProtocol, payload: Buffer): Promise<Buffer | undefined> {
83
+ try {
84
+ const stream = await this.libp2p.dialProtocol(peerId, subProtocol);
85
+
86
+ const result = await pipe([payload], stream, this.readMessage);
87
+ return result;
88
+ } catch (e) {
89
+ this.logger.warn(`Failed to send request to peer ${peerId.publicKey}`);
90
+ return undefined;
91
+ }
92
+ }
93
+
94
+ /**
95
+ * Read a message returned from a stream into a single buffer
96
+ */
97
+ private async readMessage(source: AsyncIterable<Uint8ArrayList>): Promise<Buffer> {
98
+ const chunks: Uint8Array[] = [];
99
+ for await (const chunk of source) {
100
+ chunks.push(chunk.subarray());
101
+ }
102
+ const messageData = chunks.concat();
103
+ return Buffer.concat(messageData);
104
+ }
105
+
106
+ /**
107
+ * Stream Handler
108
+ * Reads the incoming stream, determines the protocol, then triggers the appropriate handler
109
+ *
110
+ * @param param0 - The incoming stream data
111
+ */
112
+ private async streamHandler(protocol: SubProtocol, { stream }: IncomingStreamData) {
113
+ try {
114
+ await pipe(
115
+ stream,
116
+ async function* (source) {
117
+ for await (const chunkList of source) {
118
+ const msg = Buffer.from(chunkList.subarray()).toString();
119
+ yield SUB_PROTOCOL_HANDLERS[protocol](msg);
120
+ }
121
+ },
122
+ stream,
123
+ );
124
+ } catch (e: any) {
125
+ this.logger.warn(e);
126
+ } finally {
127
+ await stream.close();
128
+ }
129
+ }
130
+ }
@@ -1,4 +1,4 @@
1
- import type { Tx } from '@aztec/circuit-types';
1
+ import type { BlockAttestation, BlockProposal, Gossipable } from '@aztec/circuit-types';
2
2
 
3
3
  import type { ENR } from '@chainsafe/enr';
4
4
  import type { PeerId } from '@libp2p/interface';
@@ -27,9 +27,14 @@ export interface P2PService {
27
27
 
28
28
  /**
29
29
  * Called to have the given transaction propagated through the P2P network.
30
- * @param tx - The transaction to be propagated.
30
+ * @param message - The message to be propagated.
31
31
  */
32
- propagateTx(tx: Tx): void;
32
+ propagate<T extends Gossipable>(message: T): void;
33
+
34
+ // Leaky abstraction: fix https://github.com/AztecProtocol/aztec-packages/issues/7963
35
+ registerBlockReceivedCallback(callback: (block: BlockProposal) => Promise<BlockAttestation>): void;
36
+
37
+ getEnr(): ENR | undefined;
33
38
  }
34
39
 
35
40
  /**
@@ -71,4 +76,6 @@ export interface PeerDiscoveryService extends EventEmitter {
71
76
  emit(event: 'peer:discovered', enr: ENR): boolean;
72
77
 
73
78
  getStatus(): PeerDiscoveryState;
79
+
80
+ getEnr(): ENR | undefined;
74
81
  }
package/src/util.ts CHANGED
@@ -1,9 +1,10 @@
1
+ import { resolve } from 'dns/promises';
2
+
1
3
  /**
2
4
  * Converts an address string to a multiaddr string.
3
5
  * Example usage:
4
6
  * const tcpAddr = '123.456.7.8:80' -> /ip4/123.456.7.8/tcp/80
5
7
  * const udpAddr = '[2001:db8::1]:8080' -> /ip6/2001:db8::1/udp/8080
6
- * const dnsAddr = 'example.com:443' -> /dns4/example.com/tcp/443
7
8
  * @param address - The address string to convert. Has to be in the format <addr>:<port>.
8
9
  * @param protocol - The protocol to use in the multiaddr string.
9
10
  * @returns A multiaddr compliant string.
@@ -11,15 +12,8 @@
11
12
  export function convertToMultiaddr(address: string, protocol: 'tcp' | 'udp'): string {
12
13
  const [addr, port] = splitAddressPort(address, false);
13
14
 
14
- let multiaddrPrefix: string;
15
-
16
- if (addr.includes(':')) {
17
- // IPv6 address
18
- multiaddrPrefix = 'ip6';
19
- } else if (addr.match(/^[\d.]+$/)) {
20
- // IPv4 address
21
- multiaddrPrefix = 'ip4';
22
- } else {
15
+ const multiaddrPrefix = addressToMultiAddressType(addr);
16
+ if (multiaddrPrefix === 'dns') {
23
17
  throw new Error('Invalid address format. Expected an IPv4 or IPv6 address.');
24
18
  }
25
19
 
@@ -60,3 +54,29 @@ export async function getPublicIp(): Promise<string> {
60
54
  const text = await resp.text();
61
55
  return text.trim();
62
56
  }
57
+
58
+ export async function resolveAddressIfNecessary(address: string): Promise<string> {
59
+ const [addr, port] = splitAddressPort(address, false);
60
+ const multiaddrPrefix = addressToMultiAddressType(addr);
61
+ if (multiaddrPrefix === 'dns') {
62
+ const resolvedAddresses = await resolve(addr);
63
+ if (resolvedAddresses.length === 0) {
64
+ throw new Error(`Could not resolve address: ${addr}`);
65
+ }
66
+ return `${resolvedAddresses[0]}:${port}`;
67
+ } else {
68
+ return address;
69
+ }
70
+ }
71
+
72
+ // Not public because it is not used outside of this file.
73
+ // Plus, it relies on `splitAddressPort` being called on the address first.
74
+ function addressToMultiAddressType(address: string): 'ip4' | 'ip6' | 'dns' {
75
+ if (address.includes(':')) {
76
+ return 'ip6';
77
+ } else if (address.match(/^[\d.]+$/)) {
78
+ return 'ip4';
79
+ } else {
80
+ return 'dns';
81
+ }
82
+ }