@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.
- package/dest/attestation_pool/attestation_pool.d.ts +39 -0
- package/dest/attestation_pool/attestation_pool.d.ts.map +1 -0
- package/dest/attestation_pool/attestation_pool.js +2 -0
- package/dest/attestation_pool/index.d.ts +3 -0
- package/dest/attestation_pool/index.d.ts.map +1 -0
- package/dest/attestation_pool/index.js +3 -0
- package/dest/attestation_pool/memory_attestation_pool.d.ts +12 -0
- package/dest/attestation_pool/memory_attestation_pool.d.ts.map +1 -0
- package/dest/attestation_pool/memory_attestation_pool.js +56 -0
- package/dest/attestation_pool/mocks.d.ts +16 -0
- package/dest/attestation_pool/mocks.d.ts.map +1 -0
- package/dest/attestation_pool/mocks.js +29 -0
- package/dest/client/index.d.ts +2 -1
- package/dest/client/index.d.ts.map +1 -1
- package/dest/client/index.js +11 -5
- package/dest/client/p2p_client.d.ts +33 -2
- package/dest/client/p2p_client.d.ts.map +1 -1
- package/dest/client/p2p_client.js +20 -5
- package/dest/index.d.ts +1 -0
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +2 -1
- package/dest/service/discV5_service.d.ts.map +1 -1
- package/dest/service/discV5_service.js +4 -3
- package/dest/service/dummy_service.d.ts +10 -4
- package/dest/service/dummy_service.d.ts.map +1 -1
- package/dest/service/dummy_service.js +14 -4
- package/dest/service/libp2p_service.d.ts +25 -6
- package/dest/service/libp2p_service.d.ts.map +1 -1
- package/dest/service/libp2p_service.js +55 -10
- package/dest/service/reqresp/handlers.d.ts +3 -0
- package/dest/service/reqresp/handlers.d.ts.map +1 -0
- package/dest/service/reqresp/handlers.js +7 -0
- package/dest/service/reqresp/index.d.ts +6 -0
- package/dest/service/reqresp/index.d.ts.map +1 -0
- package/dest/service/reqresp/index.js +6 -0
- package/dest/service/reqresp/interface.d.ts +11 -0
- package/dest/service/reqresp/interface.d.ts.map +1 -0
- package/dest/service/reqresp/interface.js +10 -0
- package/dest/service/reqresp/reqresp.d.ts +48 -0
- package/dest/service/reqresp/reqresp.d.ts.map +1 -0
- package/dest/service/reqresp/reqresp.js +112 -0
- package/dest/service/service.d.ts +6 -3
- package/dest/service/service.d.ts.map +1 -1
- package/dest/util.d.ts +1 -1
- package/dest/util.d.ts.map +1 -1
- package/dest/util.js +31 -12
- package/package.json +8 -7
- package/src/attestation_pool/attestation_pool.ts +42 -0
- package/src/attestation_pool/index.ts +2 -0
- package/src/attestation_pool/memory_attestation_pool.ts +70 -0
- package/src/attestation_pool/mocks.ts +33 -0
- package/src/client/index.ts +12 -3
- package/src/client/p2p_client.ts +63 -3
- package/src/index.ts +1 -0
- package/src/service/discV5_service.ts +3 -2
- package/src/service/dummy_service.ts +17 -4
- package/src/service/libp2p_service.ts +74 -7
- package/src/service/reqresp/handlers.ts +7 -0
- package/src/service/reqresp/index.ts +4 -0
- package/src/service/reqresp/interface.ts +13 -0
- package/src/service/reqresp/reqresp.ts +130 -0
- package/src/service/service.ts +10 -3
- 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
|
+
}
|
package/src/service/service.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
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
|
|
30
|
+
* @param message - The message to be propagated.
|
|
31
31
|
*/
|
|
32
|
-
|
|
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
|
-
|
|
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
|
+
}
|