@aztec/p2p 0.75.0 → 0.76.1
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/bootstrap/bootstrap.d.ts.map +1 -1
- package/dest/bootstrap/bootstrap.js +9 -4
- package/dest/client/factory.d.ts +4 -2
- package/dest/client/factory.d.ts.map +1 -1
- package/dest/client/factory.js +4 -4
- package/dest/config.d.ts +30 -14
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +30 -14
- package/dest/msg_validators/attestation_validator/attestation_validator.d.ts +2 -2
- package/dest/msg_validators/attestation_validator/attestation_validator.d.ts.map +1 -1
- package/dest/msg_validators/attestation_validator/attestation_validator.js +1 -1
- package/dest/msg_validators/block_proposal_validator/block_proposal_validator.d.ts +2 -2
- package/dest/msg_validators/block_proposal_validator/block_proposal_validator.d.ts.map +1 -1
- package/dest/msg_validators/block_proposal_validator/block_proposal_validator.js +1 -1
- package/dest/msg_validators/epoch_proof_quote_validator/epoch_proof_quote_validator.d.ts +2 -2
- package/dest/msg_validators/epoch_proof_quote_validator/epoch_proof_quote_validator.d.ts.map +1 -1
- package/dest/msg_validators/epoch_proof_quote_validator/epoch_proof_quote_validator.js +1 -1
- package/dest/services/discv5/discV5_service.d.ts +5 -1
- package/dest/services/discv5/discV5_service.d.ts.map +1 -1
- package/dest/services/discv5/discV5_service.js +65 -18
- package/dest/services/dummy_service.d.ts +1 -0
- package/dest/services/dummy_service.d.ts.map +1 -1
- package/dest/services/dummy_service.js +2 -1
- package/dest/services/libp2p/libp2p_logger.d.ts +7 -0
- package/dest/services/libp2p/libp2p_logger.d.ts.map +1 -0
- package/dest/services/libp2p/libp2p_logger.js +67 -0
- package/dest/services/libp2p/libp2p_service.d.ts +3 -3
- package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
- package/dest/services/libp2p/libp2p_service.js +42 -10
- package/dest/services/reqresp/interface.d.ts +9 -0
- package/dest/services/reqresp/interface.d.ts.map +1 -1
- package/dest/services/reqresp/interface.js +1 -1
- package/dest/services/reqresp/protocols/goodbye.js +2 -2
- package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts.map +1 -1
- package/dest/services/reqresp/rate-limiter/rate_limiter.js +4 -2
- package/dest/services/reqresp/rate-limiter/rate_limits.js +3 -3
- package/dest/services/reqresp/reqresp.d.ts +7 -2
- package/dest/services/reqresp/reqresp.d.ts.map +1 -1
- package/dest/services/reqresp/reqresp.js +90 -21
- package/dest/services/reqresp/status.d.ts +31 -0
- package/dest/services/reqresp/status.d.ts.map +1 -0
- package/dest/services/reqresp/status.js +52 -0
- package/dest/services/service.d.ts +1 -0
- package/dest/services/service.d.ts.map +1 -1
- package/dest/services/types.d.ts +1 -7
- package/dest/services/types.d.ts.map +1 -1
- package/dest/services/types.js +2 -10
- package/dest/test-helpers/generate-peer-id-private-keys.d.ts +7 -0
- package/dest/test-helpers/generate-peer-id-private-keys.d.ts.map +1 -0
- package/dest/test-helpers/generate-peer-id-private-keys.js +15 -0
- package/dest/test-helpers/get-ports.d.ts +7 -0
- package/dest/test-helpers/get-ports.d.ts.map +1 -0
- package/dest/test-helpers/get-ports.js +8 -0
- package/dest/test-helpers/index.d.ts +6 -0
- package/dest/test-helpers/index.d.ts.map +1 -0
- package/dest/test-helpers/index.js +6 -0
- package/dest/test-helpers/make-enrs.d.ts +16 -0
- package/dest/test-helpers/make-enrs.d.ts.map +1 -0
- package/dest/test-helpers/make-enrs.js +35 -0
- package/dest/test-helpers/make-test-p2p-clients.d.ts +37 -0
- package/dest/test-helpers/make-test-p2p-clients.d.ts.map +1 -0
- package/dest/test-helpers/make-test-p2p-clients.js +71 -0
- package/dest/{mocks/index.d.ts → test-helpers/reqresp-nodes.d.ts} +6 -5
- package/dest/test-helpers/reqresp-nodes.d.ts.map +1 -0
- package/dest/test-helpers/reqresp-nodes.js +183 -0
- package/dest/testbench/p2p_client_testbench_worker.d.ts +2 -0
- package/dest/testbench/p2p_client_testbench_worker.d.ts.map +1 -0
- package/dest/testbench/p2p_client_testbench_worker.js +125 -0
- package/dest/versioning.d.ts +12 -0
- package/dest/versioning.d.ts.map +1 -0
- package/dest/versioning.js +38 -0
- package/package.json +10 -8
- package/src/bootstrap/bootstrap.ts +9 -3
- package/src/client/factory.ts +12 -5
- package/src/config.ts +56 -29
- package/src/msg_validators/attestation_validator/attestation_validator.ts +3 -3
- package/src/msg_validators/block_proposal_validator/block_proposal_validator.ts +3 -3
- package/src/msg_validators/epoch_proof_quote_validator/epoch_proof_quote_validator.ts +3 -3
- package/src/services/discv5/discV5_service.ts +67 -18
- package/src/services/dummy_service.ts +2 -0
- package/src/services/libp2p/libp2p_logger.ts +78 -0
- package/src/services/libp2p/libp2p_service.ts +47 -10
- package/src/services/reqresp/interface.ts +11 -0
- package/src/services/reqresp/protocols/goodbye.ts +1 -1
- package/src/services/reqresp/rate-limiter/rate_limiter.ts +3 -1
- package/src/services/reqresp/rate-limiter/rate_limits.ts +2 -2
- package/src/services/reqresp/reqresp.ts +120 -25
- package/src/services/reqresp/status.ts +59 -0
- package/src/services/service.ts +2 -0
- package/src/services/types.ts +2 -10
- package/src/test-helpers/generate-peer-id-private-keys.ts +15 -0
- package/src/test-helpers/get-ports.ts +8 -0
- package/src/test-helpers/index.ts +5 -0
- package/src/test-helpers/make-enrs.ts +44 -0
- package/src/test-helpers/make-test-p2p-clients.ts +124 -0
- package/src/{mocks/index.ts → test-helpers/reqresp-nodes.ts} +10 -5
- package/src/testbench/README.md +20 -0
- package/src/testbench/p2p_client_testbench_worker.ts +156 -0
- package/src/testbench/scripts/run_testbench.sh +7 -0
- package/src/versioning.ts +50 -0
- package/dest/mocks/index.d.ts.map +0 -1
- package/dest/mocks/index.js +0 -181
package/src/config.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type ChainConfig, chainConfigMappings } from '@aztec/circuit-types/config';
|
|
1
2
|
import {
|
|
2
3
|
type ConfigMappingsType,
|
|
3
4
|
booleanConfigHelper,
|
|
@@ -13,7 +14,7 @@ import { type P2PReqRespConfig, p2pReqRespConfigMappings } from './services/reqr
|
|
|
13
14
|
/**
|
|
14
15
|
* P2P client configuration values.
|
|
15
16
|
*/
|
|
16
|
-
export interface P2PConfig extends P2PReqRespConfig {
|
|
17
|
+
export interface P2PConfig extends P2PReqRespConfig, ChainConfig {
|
|
17
18
|
/**
|
|
18
19
|
* A flag dictating whether the P2P subsystem should be enabled.
|
|
19
20
|
*/
|
|
@@ -29,6 +30,16 @@ export interface P2PConfig extends P2PReqRespConfig {
|
|
|
29
30
|
*/
|
|
30
31
|
blockRequestBatchSize: number;
|
|
31
32
|
|
|
33
|
+
/**
|
|
34
|
+
* DEBUG: Disable message validation - for testing purposes only
|
|
35
|
+
*/
|
|
36
|
+
debugDisableMessageValidation: boolean;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* DEBUG: Disable colocation penalty - for testing purposes only
|
|
40
|
+
*/
|
|
41
|
+
debugDisableColocationPenalty: boolean;
|
|
42
|
+
|
|
32
43
|
/**
|
|
33
44
|
* The frequency in which to check for new peers.
|
|
34
45
|
*/
|
|
@@ -69,16 +80,14 @@ export interface P2PConfig extends P2PReqRespConfig {
|
|
|
69
80
|
*/
|
|
70
81
|
bootstrapNodes: string[];
|
|
71
82
|
|
|
83
|
+
/** Whether to execute the version check in the bootstrap node ENR. */
|
|
84
|
+
bootstrapNodeEnrVersionCheck: boolean;
|
|
85
|
+
|
|
72
86
|
/**
|
|
73
87
|
* Protocol identifier for transaction gossiping.
|
|
74
88
|
*/
|
|
75
89
|
transactionProtocol: string;
|
|
76
90
|
|
|
77
|
-
/**
|
|
78
|
-
* The minimum number of peers (a peer count below this will cause the node to look for more peers)
|
|
79
|
-
*/
|
|
80
|
-
minPeerCount: number;
|
|
81
|
-
|
|
82
91
|
/**
|
|
83
92
|
* The maximum number of peers (a peer count above this will cause the node to refuse connection attempts)
|
|
84
93
|
*/
|
|
@@ -115,6 +124,16 @@ export interface P2PConfig extends P2PReqRespConfig {
|
|
|
115
124
|
*/
|
|
116
125
|
gossipsubDhi: number;
|
|
117
126
|
|
|
127
|
+
/**
|
|
128
|
+
* The Dlazy parameter for the gossipsub protocol.
|
|
129
|
+
*/
|
|
130
|
+
gossipsubDLazy: number;
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Whether to flood publish messages. - For testing purposes only
|
|
134
|
+
*/
|
|
135
|
+
gossipsubFloodPublish: boolean;
|
|
136
|
+
|
|
118
137
|
/**
|
|
119
138
|
* The number of gossipsub interval message cache windows to keep.
|
|
120
139
|
*/
|
|
@@ -150,11 +169,6 @@ export interface P2PConfig extends P2PReqRespConfig {
|
|
|
150
169
|
*/
|
|
151
170
|
peerPenaltyValues: number[];
|
|
152
171
|
|
|
153
|
-
/**
|
|
154
|
-
* The chain id of the L1 chain.
|
|
155
|
-
*/
|
|
156
|
-
l1ChainId: number;
|
|
157
|
-
|
|
158
172
|
/** Limit of transactions to archive in the tx pool. Once the archived tx limit is reached, the oldest archived txs will be purged. */
|
|
159
173
|
archivedTxLimit: number;
|
|
160
174
|
}
|
|
@@ -170,6 +184,16 @@ export const p2pConfigMappings: ConfigMappingsType<P2PConfig> = {
|
|
|
170
184
|
description: 'The frequency in which to check for new L2 blocks.',
|
|
171
185
|
...numberConfigHelper(100),
|
|
172
186
|
},
|
|
187
|
+
debugDisableMessageValidation: {
|
|
188
|
+
env: 'DEBUG_P2P_DISABLE_MESSAGE_VALIDATION',
|
|
189
|
+
description: 'DEBUG: Disable message validation - NEVER set to true in production',
|
|
190
|
+
...booleanConfigHelper(false),
|
|
191
|
+
},
|
|
192
|
+
debugDisableColocationPenalty: {
|
|
193
|
+
env: 'DEBUG_P2P_DISABLE_COLOCATION_PENALTY',
|
|
194
|
+
description: 'DEBUG: Disable colocation penalty - NEVER set to true in production',
|
|
195
|
+
...booleanConfigHelper(false),
|
|
196
|
+
},
|
|
173
197
|
peerCheckIntervalMS: {
|
|
174
198
|
env: 'P2P_PEER_CHECK_INTERVAL_MS',
|
|
175
199
|
description: 'The frequency in which to check for new peers.',
|
|
@@ -209,16 +233,16 @@ export const p2pConfigMappings: ConfigMappingsType<P2PConfig> = {
|
|
|
209
233
|
parseEnv: (val: string) => val.split(','),
|
|
210
234
|
description: 'A list of bootstrap peer ENRs to connect to. Separated by commas.',
|
|
211
235
|
},
|
|
236
|
+
bootstrapNodeEnrVersionCheck: {
|
|
237
|
+
env: 'P2P_BOOTSTRAP_NODE_ENR_VERSION_CHECK',
|
|
238
|
+
description: 'Whether to check the version of the bootstrap node ENR.',
|
|
239
|
+
...booleanConfigHelper(),
|
|
240
|
+
},
|
|
212
241
|
transactionProtocol: {
|
|
213
242
|
env: 'P2P_TX_PROTOCOL',
|
|
214
243
|
description: 'Protocol identifier for transaction gossiping.',
|
|
215
244
|
defaultValue: '/aztec/0.1.0',
|
|
216
245
|
},
|
|
217
|
-
minPeerCount: {
|
|
218
|
-
env: 'P2P_MIN_PEERS',
|
|
219
|
-
description: 'The minimum number of peers to connect to.',
|
|
220
|
-
...numberConfigHelper(10),
|
|
221
|
-
},
|
|
222
246
|
maxPeerCount: {
|
|
223
247
|
env: 'P2P_MAX_PEERS',
|
|
224
248
|
description: 'The maximum number of peers to connect to.',
|
|
@@ -244,7 +268,7 @@ export const p2pConfigMappings: ConfigMappingsType<P2PConfig> = {
|
|
|
244
268
|
gossipsubInterval: {
|
|
245
269
|
env: 'P2P_GOSSIPSUB_INTERVAL_MS',
|
|
246
270
|
description: 'The interval of the gossipsub heartbeat to perform maintenance tasks.',
|
|
247
|
-
...numberConfigHelper(
|
|
271
|
+
...numberConfigHelper(700),
|
|
248
272
|
},
|
|
249
273
|
gossipsubD: {
|
|
250
274
|
env: 'P2P_GOSSIPSUB_D',
|
|
@@ -261,10 +285,20 @@ export const p2pConfigMappings: ConfigMappingsType<P2PConfig> = {
|
|
|
261
285
|
description: 'The Dhi parameter for the gossipsub protocol.',
|
|
262
286
|
...numberConfigHelper(12),
|
|
263
287
|
},
|
|
288
|
+
gossipsubDLazy: {
|
|
289
|
+
env: 'P2P_GOSSIPSUB_DLAZY',
|
|
290
|
+
description: 'The Dlazy parameter for the gossipsub protocol.',
|
|
291
|
+
...numberConfigHelper(6),
|
|
292
|
+
},
|
|
293
|
+
gossipsubFloodPublish: {
|
|
294
|
+
env: 'P2P_GOSSIPSUB_FLOOD_PUBLISH',
|
|
295
|
+
description: 'Whether to flood publish messages. - For testing purposes only',
|
|
296
|
+
...booleanConfigHelper(true),
|
|
297
|
+
},
|
|
264
298
|
gossipsubMcacheLength: {
|
|
265
299
|
env: 'P2P_GOSSIPSUB_MCACHE_LENGTH',
|
|
266
300
|
description: 'The number of gossipsub interval message cache windows to keep.',
|
|
267
|
-
...numberConfigHelper(
|
|
301
|
+
...numberConfigHelper(6),
|
|
268
302
|
},
|
|
269
303
|
gossipsubMcacheGossip: {
|
|
270
304
|
env: 'P2P_GOSSIPSUB_MCACHE_GOSSIP',
|
|
@@ -298,11 +332,6 @@ export const p2pConfigMappings: ConfigMappingsType<P2PConfig> = {
|
|
|
298
332
|
description: 'The "age" (in L2 blocks) of a tx after which we heavily penalize a peer for sending it.',
|
|
299
333
|
...numberConfigHelper(30),
|
|
300
334
|
},
|
|
301
|
-
l1ChainId: {
|
|
302
|
-
env: 'L1_CHAIN_ID',
|
|
303
|
-
description: 'The chain id of the L1 chain.',
|
|
304
|
-
...numberConfigHelper(31337),
|
|
305
|
-
},
|
|
306
335
|
blockRequestBatchSize: {
|
|
307
336
|
env: 'P2P_BLOCK_REQUEST_BATCH_SIZE',
|
|
308
337
|
description: 'The number of blocks to fetch in a single batch.',
|
|
@@ -315,6 +344,7 @@ export const p2pConfigMappings: ConfigMappingsType<P2PConfig> = {
|
|
|
315
344
|
...numberConfigHelper(0),
|
|
316
345
|
},
|
|
317
346
|
...p2pReqRespConfigMappings,
|
|
347
|
+
...chainConfigMappings,
|
|
318
348
|
};
|
|
319
349
|
|
|
320
350
|
/**
|
|
@@ -332,17 +362,14 @@ export function getP2PDefaultConfig(): P2PConfig {
|
|
|
332
362
|
/**
|
|
333
363
|
* Required P2P config values for a bootstrap node.
|
|
334
364
|
*/
|
|
335
|
-
export type BootnodeConfig = Pick<
|
|
336
|
-
P2PConfig,
|
|
337
|
-
'udpAnnounceAddress' | 'peerIdPrivateKey' | 'minPeerCount' | 'maxPeerCount'
|
|
338
|
-
> &
|
|
365
|
+
export type BootnodeConfig = Pick<P2PConfig, 'udpAnnounceAddress' | 'peerIdPrivateKey' | 'maxPeerCount'> &
|
|
339
366
|
Required<Pick<P2PConfig, 'udpListenAddress'>> &
|
|
340
|
-
Pick<DataStoreConfig, 'dataDirectory' | 'dataStoreMapSizeKB'
|
|
367
|
+
Pick<DataStoreConfig, 'dataDirectory' | 'dataStoreMapSizeKB'> &
|
|
368
|
+
ChainConfig;
|
|
341
369
|
|
|
342
370
|
const bootnodeConfigKeys: (keyof BootnodeConfig)[] = [
|
|
343
371
|
'udpAnnounceAddress',
|
|
344
372
|
'peerIdPrivateKey',
|
|
345
|
-
'minPeerCount',
|
|
346
373
|
'maxPeerCount',
|
|
347
374
|
'udpListenAddress',
|
|
348
375
|
'dataDirectory',
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { type BlockAttestation, type P2PValidator, PeerErrorSeverity } from '@aztec/circuit-types';
|
|
2
|
-
import { type
|
|
2
|
+
import { type EpochCacheInterface } from '@aztec/epoch-cache';
|
|
3
3
|
|
|
4
4
|
export class AttestationValidator implements P2PValidator<BlockAttestation> {
|
|
5
|
-
private epochCache:
|
|
5
|
+
private epochCache: EpochCacheInterface;
|
|
6
6
|
|
|
7
|
-
constructor(epochCache:
|
|
7
|
+
constructor(epochCache: EpochCacheInterface) {
|
|
8
8
|
this.epochCache = epochCache;
|
|
9
9
|
}
|
|
10
10
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { type BlockProposal, type P2PValidator, PeerErrorSeverity } from '@aztec/circuit-types';
|
|
2
|
-
import { type
|
|
2
|
+
import { type EpochCacheInterface } from '@aztec/epoch-cache';
|
|
3
3
|
|
|
4
4
|
export class BlockProposalValidator implements P2PValidator<BlockProposal> {
|
|
5
|
-
private epochCache:
|
|
5
|
+
private epochCache: EpochCacheInterface;
|
|
6
6
|
|
|
7
|
-
constructor(epochCache:
|
|
7
|
+
constructor(epochCache: EpochCacheInterface) {
|
|
8
8
|
this.epochCache = epochCache;
|
|
9
9
|
}
|
|
10
10
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { type EpochProofQuote, type P2PValidator, PeerErrorSeverity } from '@aztec/circuit-types';
|
|
2
|
-
import { type
|
|
2
|
+
import { type EpochCacheInterface } from '@aztec/epoch-cache';
|
|
3
3
|
|
|
4
4
|
export class EpochProofQuoteValidator implements P2PValidator<EpochProofQuote> {
|
|
5
|
-
private epochCache:
|
|
5
|
+
private epochCache: EpochCacheInterface;
|
|
6
6
|
|
|
7
|
-
constructor(epochCache:
|
|
7
|
+
constructor(epochCache: EpochCacheInterface) {
|
|
8
8
|
this.epochCache = epochCache;
|
|
9
9
|
}
|
|
10
10
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type ComponentsVersions, checkCompressedComponentVersion } from '@aztec/circuit-types';
|
|
1
2
|
import { createLogger } from '@aztec/foundation/log';
|
|
2
3
|
import { sleep } from '@aztec/foundation/sleep';
|
|
3
4
|
import { OtelMetricsAdapter, type TelemetryClient, getTelemetryClient } from '@aztec/telemetry-client';
|
|
@@ -10,8 +11,9 @@ import EventEmitter from 'events';
|
|
|
10
11
|
|
|
11
12
|
import type { P2PConfig } from '../../config.js';
|
|
12
13
|
import { convertToMultiaddr } from '../../util.js';
|
|
14
|
+
import { setAztecEnrKey } from '../../versioning.js';
|
|
13
15
|
import { type PeerDiscoveryService, PeerDiscoveryState } from '../service.js';
|
|
14
|
-
import { AZTEC_ENR_KEY,
|
|
16
|
+
import { AZTEC_ENR_KEY, Discv5Event, PeerEvent } from '../types.js';
|
|
15
17
|
|
|
16
18
|
const delayBeforeStart = 2000; // 2sec
|
|
17
19
|
|
|
@@ -25,29 +27,32 @@ export class DiscV5Service extends EventEmitter implements PeerDiscoveryService
|
|
|
25
27
|
/** This instance's ENR */
|
|
26
28
|
private enr: SignableENR;
|
|
27
29
|
|
|
30
|
+
/** Version identifiers. */
|
|
31
|
+
private versions: ComponentsVersions;
|
|
32
|
+
|
|
28
33
|
/** UDP listen addr */
|
|
29
34
|
private listenMultiAddrUdp: Multiaddr;
|
|
30
35
|
|
|
31
36
|
private currentState = PeerDiscoveryState.STOPPED;
|
|
32
37
|
|
|
33
|
-
|
|
38
|
+
public readonly bootstrapNodes: string[] = [];
|
|
34
39
|
private bootstrapNodePeerIds: PeerId[] = [];
|
|
35
40
|
|
|
36
41
|
private startTime = 0;
|
|
37
42
|
|
|
38
43
|
constructor(
|
|
39
44
|
private peerId: PeerId,
|
|
40
|
-
config: P2PConfig,
|
|
45
|
+
private config: P2PConfig,
|
|
41
46
|
telemetry: TelemetryClient = getTelemetryClient(),
|
|
42
47
|
private logger = createLogger('p2p:discv5_service'),
|
|
43
48
|
) {
|
|
44
49
|
super();
|
|
45
50
|
const { tcpAnnounceAddress, udpAnnounceAddress, udpListenAddress, bootstrapNodes } = config;
|
|
46
|
-
this.bootstrapNodes = bootstrapNodes;
|
|
51
|
+
this.bootstrapNodes = bootstrapNodes ?? [];
|
|
47
52
|
// create ENR from PeerId
|
|
48
53
|
this.enr = SignableENR.createFromPeerId(peerId);
|
|
49
54
|
// Add aztec identification to ENR
|
|
50
|
-
this.enr
|
|
55
|
+
this.versions = setAztecEnrKey(this.enr, config);
|
|
51
56
|
|
|
52
57
|
if (!tcpAnnounceAddress) {
|
|
53
58
|
throw new Error('You need to provide at least a TCP announce address.');
|
|
@@ -78,6 +83,20 @@ export class DiscV5Service extends EventEmitter implements PeerDiscoveryService
|
|
|
78
83
|
metricsRegistry,
|
|
79
84
|
});
|
|
80
85
|
|
|
86
|
+
// Hook onto the onEstablished method to check the peer's version from the ENR,
|
|
87
|
+
// so we don't add it to our dht if it doesn't have the correct version.
|
|
88
|
+
// In addition, we'll hook onto onDiscovered to to repeat the same check there,
|
|
89
|
+
// just in case. Note that not adding the peer to the dht could lead to it
|
|
90
|
+
// being "readded" constantly, we'll need to keep an eye on whether this
|
|
91
|
+
// turns out to be a problem or not.
|
|
92
|
+
const origOnEstablished = this.discv5.onEstablished.bind(this.discv5);
|
|
93
|
+
this.discv5.onEstablished = (...args: unknown[]) => {
|
|
94
|
+
const enr = args[1] as ENR;
|
|
95
|
+
if (this.validateEnr(enr)) {
|
|
96
|
+
return origOnEstablished(...args);
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
|
|
81
100
|
this.discv5.on(Discv5Event.DISCOVERED, this.onDiscovered.bind(this));
|
|
82
101
|
this.discv5.on(Discv5Event.ENR_ADDED, this.onEnrAdded.bind(this));
|
|
83
102
|
}
|
|
@@ -95,20 +114,29 @@ export class DiscV5Service extends EventEmitter implements PeerDiscoveryService
|
|
|
95
114
|
peerId: this.peerId,
|
|
96
115
|
enrUdp: await this.enr.getFullMultiaddr('udp'),
|
|
97
116
|
enrTcp: await this.enr.getFullMultiaddr('tcp'),
|
|
117
|
+
versions: this.versions,
|
|
98
118
|
});
|
|
99
119
|
this.currentState = PeerDiscoveryState.RUNNING;
|
|
100
120
|
|
|
101
121
|
// Add bootnode ENR if provided
|
|
102
122
|
if (this.bootstrapNodes?.length) {
|
|
103
123
|
// Do this conversion once since it involves an async function call
|
|
104
|
-
|
|
105
|
-
this.
|
|
106
|
-
|
|
107
|
-
|
|
124
|
+
const bootstrapNodesEnrs = this.bootstrapNodes.map(enr => ENR.decodeTxt(enr));
|
|
125
|
+
this.bootstrapNodePeerIds = await Promise.all(bootstrapNodesEnrs.map(enr => enr.peerId()));
|
|
126
|
+
this.logger.info(`Adding ${this.bootstrapNodes} bootstrap nodes ENRs: ${this.bootstrapNodes.join(', ')}`);
|
|
127
|
+
for (const enr of bootstrapNodesEnrs) {
|
|
128
|
+
try {
|
|
129
|
+
if (this.config.bootstrapNodeEnrVersionCheck) {
|
|
130
|
+
const value = enr.kvs.get(AZTEC_ENR_KEY);
|
|
131
|
+
if (!value) {
|
|
132
|
+
throw new Error('ENR does not contain aztec key');
|
|
133
|
+
}
|
|
134
|
+
checkCompressedComponentVersion(Buffer.from(value).toString(), this.versions);
|
|
135
|
+
}
|
|
108
136
|
this.discv5.addEnr(enr);
|
|
109
|
-
})
|
|
110
|
-
|
|
111
|
-
|
|
137
|
+
} catch (e) {
|
|
138
|
+
this.logger.error(`Error adding bootratrap node ${enr.encodeTxt()}`, e);
|
|
139
|
+
}
|
|
112
140
|
}
|
|
113
141
|
}
|
|
114
142
|
}
|
|
@@ -169,14 +197,35 @@ export class DiscV5Service extends EventEmitter implements PeerDiscoveryService
|
|
|
169
197
|
}
|
|
170
198
|
|
|
171
199
|
private onDiscovered(enr: ENR) {
|
|
172
|
-
|
|
200
|
+
if (this.validateEnr(enr)) {
|
|
201
|
+
this.emit(PeerEvent.DISCOVERED, enr);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
private validateEnr(enr: ENR): boolean {
|
|
206
|
+
// Check the peer is an aztec peer
|
|
173
207
|
const value = enr.kvs.get(AZTEC_ENR_KEY);
|
|
174
|
-
if (value) {
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
208
|
+
if (!value) {
|
|
209
|
+
this.logger.warn(`Peer ${enr.nodeId} does not have aztec key in ENR`);
|
|
210
|
+
return false;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
let compressedVersion;
|
|
214
|
+
try {
|
|
215
|
+
// And check it has the correct version
|
|
216
|
+
compressedVersion = Buffer.from(value).toString();
|
|
217
|
+
checkCompressedComponentVersion(compressedVersion, this.versions);
|
|
218
|
+
return true;
|
|
219
|
+
} catch (err: any) {
|
|
220
|
+
if (err.name === 'ComponentsVersionsError') {
|
|
221
|
+
this.logger.warn(`Peer ${enr.nodeId} has incorrect version: ${err.message}`, {
|
|
222
|
+
compressedVersion,
|
|
223
|
+
expected: this.versions,
|
|
224
|
+
});
|
|
225
|
+
} else {
|
|
226
|
+
this.logger.error(`Error checking peer version`, err);
|
|
179
227
|
}
|
|
180
228
|
}
|
|
229
|
+
return false;
|
|
181
230
|
}
|
|
182
231
|
}
|
|
@@ -88,6 +88,8 @@ export class DummyP2PService implements P2PService {
|
|
|
88
88
|
*/
|
|
89
89
|
export class DummyPeerDiscoveryService extends EventEmitter implements PeerDiscoveryService {
|
|
90
90
|
private currentState = PeerDiscoveryState.STOPPED;
|
|
91
|
+
public bootstrapNodes: string[] = [];
|
|
92
|
+
|
|
91
93
|
/**
|
|
92
94
|
* Starts the dummy implementation.
|
|
93
95
|
* @returns A resolved promise.
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { createLogger } from '@aztec/foundation/log';
|
|
2
|
+
|
|
3
|
+
import { type ComponentLogger, type Logger } from '@libp2p/interface';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Creates a libp2p compatible logger that wraps our pino logger.
|
|
7
|
+
* This adapter implements the ComponentLogger interface required by libp2p.
|
|
8
|
+
*/
|
|
9
|
+
export function createLibp2pComponentLogger(namespace: string, fixedTerms = {}): ComponentLogger {
|
|
10
|
+
return {
|
|
11
|
+
forComponent: (component: string) => createLibp2pLogger(`${namespace}:${component}`, fixedTerms),
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function createLibp2pLogger(component: string, fixedTerms = {}): Logger {
|
|
16
|
+
const logger = createLogger(component, fixedTerms);
|
|
17
|
+
|
|
18
|
+
// Default log level is trace as this is super super noisy
|
|
19
|
+
const logFn = (formatter: any, ...args: any[]) => {
|
|
20
|
+
// Handle %p format specifier by manually replacing with args
|
|
21
|
+
if (typeof formatter === 'string' && args.length > 0) {
|
|
22
|
+
// Handle %p, %a, %s and %d format specifiers
|
|
23
|
+
const parts = formatter.split(/(%p|%a|%s|%d)/);
|
|
24
|
+
let result = parts[0];
|
|
25
|
+
let argIndex = 0;
|
|
26
|
+
|
|
27
|
+
for (let i = 1; i < parts.length; i += 2) {
|
|
28
|
+
if (argIndex < args.length) {
|
|
29
|
+
result += String(args[argIndex]) + (parts[i + 1] || '');
|
|
30
|
+
argIndex++;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
formatter = result;
|
|
35
|
+
// Only keep non-format args as data
|
|
36
|
+
args = args.slice(argIndex);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Handle object args by spreading them, but only if they weren't used in formatting
|
|
40
|
+
if (args.length === 1 && typeof args[0] === 'object') {
|
|
41
|
+
logger.trace(formatter, args[0]);
|
|
42
|
+
} else if (args.length > 0) {
|
|
43
|
+
// If we have remaining args after formatting, pass them as data
|
|
44
|
+
logger.trace(formatter, { _args: args });
|
|
45
|
+
} else {
|
|
46
|
+
logger.trace(formatter);
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
return Object.assign(logFn, {
|
|
51
|
+
enabled: logger.isLevelEnabled('debug'),
|
|
52
|
+
|
|
53
|
+
error(...args: any[]) {
|
|
54
|
+
const [msg, ...rest] = args;
|
|
55
|
+
logger.error(msg as string, ...rest);
|
|
56
|
+
},
|
|
57
|
+
|
|
58
|
+
debug(...args: any[]) {
|
|
59
|
+
const [msg, ...rest] = args;
|
|
60
|
+
logger.debug(msg as string, ...rest);
|
|
61
|
+
},
|
|
62
|
+
|
|
63
|
+
info(...args: any[]) {
|
|
64
|
+
const [msg, ...rest] = args;
|
|
65
|
+
logger.info(msg as string, ...rest);
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
warn(...args: any[]) {
|
|
69
|
+
const [msg, ...rest] = args;
|
|
70
|
+
logger.warn(msg as string, ...rest);
|
|
71
|
+
},
|
|
72
|
+
|
|
73
|
+
trace(...args: any[]) {
|
|
74
|
+
const [msg, ...rest] = args;
|
|
75
|
+
logger.trace(msg as string, ...rest);
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
}
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
metricsTopicStrToLabels,
|
|
20
20
|
} from '@aztec/circuit-types';
|
|
21
21
|
import { Fr } from '@aztec/circuits.js';
|
|
22
|
-
import { type
|
|
22
|
+
import { type EpochCacheInterface } from '@aztec/epoch-cache';
|
|
23
23
|
import { createLogger } from '@aztec/foundation/log';
|
|
24
24
|
import { SerialQueue } from '@aztec/foundation/queue';
|
|
25
25
|
import { RunningPromise } from '@aztec/foundation/running-promise';
|
|
@@ -34,8 +34,10 @@ import {
|
|
|
34
34
|
gossipsub,
|
|
35
35
|
} from '@chainsafe/libp2p-gossipsub';
|
|
36
36
|
import { createPeerScoreParams, createTopicScoreParams } from '@chainsafe/libp2p-gossipsub/score';
|
|
37
|
+
import { SignaturePolicy } from '@chainsafe/libp2p-gossipsub/types';
|
|
37
38
|
import { noise } from '@chainsafe/libp2p-noise';
|
|
38
39
|
import { yamux } from '@chainsafe/libp2p-yamux';
|
|
40
|
+
import { bootstrap } from '@libp2p/bootstrap';
|
|
39
41
|
import { identify } from '@libp2p/identify';
|
|
40
42
|
import { type Message, type PeerId, TopicValidatorResult } from '@libp2p/interface';
|
|
41
43
|
import { type ConnectionManager } from '@libp2p/interface-internal';
|
|
@@ -65,6 +67,7 @@ import { pingHandler, reqRespBlockHandler, reqRespTxHandler, statusHandler } fro
|
|
|
65
67
|
import { ReqResp } from '../reqresp/reqresp.js';
|
|
66
68
|
import type { P2PService, PeerDiscoveryService } from '../service.js';
|
|
67
69
|
import { GossipSubEvent } from '../types.js';
|
|
70
|
+
import { createLibp2pComponentLogger } from './libp2p_logger.js';
|
|
68
71
|
|
|
69
72
|
interface MessageValidator {
|
|
70
73
|
validator: {
|
|
@@ -111,7 +114,7 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
|
|
|
111
114
|
private peerDiscoveryService: PeerDiscoveryService,
|
|
112
115
|
private mempools: MemPools<T>,
|
|
113
116
|
private l2BlockSource: L2BlockSource,
|
|
114
|
-
epochCache:
|
|
117
|
+
epochCache: EpochCacheInterface,
|
|
115
118
|
private proofVerifier: ClientProtocolCircuitVerifier,
|
|
116
119
|
private worldStateSynchronizer: WorldStateSynchronizer,
|
|
117
120
|
telemetry: TelemetryClient,
|
|
@@ -127,7 +130,7 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
|
|
|
127
130
|
peerDiscoveryService,
|
|
128
131
|
config,
|
|
129
132
|
telemetry,
|
|
130
|
-
logger,
|
|
133
|
+
createLogger(`${logger.module}:peer_manager`),
|
|
131
134
|
peerScoring,
|
|
132
135
|
this.reqresp,
|
|
133
136
|
);
|
|
@@ -164,13 +167,14 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
|
|
|
164
167
|
peerId: PeerId,
|
|
165
168
|
mempools: MemPools<T>,
|
|
166
169
|
l2BlockSource: L2BlockSource,
|
|
167
|
-
epochCache:
|
|
170
|
+
epochCache: EpochCacheInterface,
|
|
168
171
|
proofVerifier: ClientProtocolCircuitVerifier,
|
|
169
172
|
worldStateSynchronizer: WorldStateSynchronizer,
|
|
170
173
|
store: AztecAsyncKVStore,
|
|
171
174
|
telemetry: TelemetryClient,
|
|
175
|
+
logger = createLogger('p2p:libp2p_service'),
|
|
172
176
|
) {
|
|
173
|
-
const { tcpListenAddress, tcpAnnounceAddress,
|
|
177
|
+
const { tcpListenAddress, tcpAnnounceAddress, maxPeerCount } = config;
|
|
174
178
|
const bindAddrTcp = convertToMultiaddr(tcpListenAddress, 'tcp');
|
|
175
179
|
// We know tcpAnnounceAddress cannot be null here because we set it or throw when setting up the service.
|
|
176
180
|
const announceAddrTcp = convertToMultiaddr(tcpAnnounceAddress!, 'tcp');
|
|
@@ -179,6 +183,12 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
|
|
|
179
183
|
|
|
180
184
|
const otelMetricsAdapter = new OtelMetricsAdapter(telemetry);
|
|
181
185
|
|
|
186
|
+
// If bootstrap nodes are provided, also provide them to the p2p service
|
|
187
|
+
const peerDiscovery = [];
|
|
188
|
+
if (peerDiscoveryService.bootstrapNodes.length > 0) {
|
|
189
|
+
peerDiscovery.push(bootstrap({ list: peerDiscoveryService.bootstrapNodes }));
|
|
190
|
+
}
|
|
191
|
+
|
|
182
192
|
const node = await createLibp2p({
|
|
183
193
|
start: false,
|
|
184
194
|
peerId,
|
|
@@ -200,24 +210,35 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
|
|
|
200
210
|
}),
|
|
201
211
|
],
|
|
202
212
|
datastore,
|
|
203
|
-
|
|
213
|
+
peerDiscovery,
|
|
214
|
+
streamMuxers: [mplex(), yamux()],
|
|
204
215
|
connectionEncryption: [noise()],
|
|
205
216
|
connectionManager: {
|
|
206
|
-
minConnections:
|
|
217
|
+
minConnections: 0,
|
|
207
218
|
maxConnections: maxPeerCount,
|
|
219
|
+
|
|
220
|
+
maxParallelDials: 100,
|
|
221
|
+
maxPeerAddrsToDial: 5,
|
|
222
|
+
maxIncomingPendingConnections: 5,
|
|
208
223
|
},
|
|
209
224
|
services: {
|
|
210
225
|
identify: identify({
|
|
211
226
|
protocolPrefix: 'aztec',
|
|
212
227
|
}),
|
|
213
228
|
pubsub: gossipsub({
|
|
229
|
+
debugName: 'gossipsub',
|
|
230
|
+
globalSignaturePolicy: SignaturePolicy.StrictNoSign,
|
|
214
231
|
allowPublishToZeroTopicPeers: true,
|
|
232
|
+
floodPublish: config.gossipsubFloodPublish,
|
|
215
233
|
D: config.gossipsubD,
|
|
216
234
|
Dlo: config.gossipsubDlo,
|
|
217
235
|
Dhi: config.gossipsubDhi,
|
|
236
|
+
Dlazy: config.gossipsubDLazy,
|
|
218
237
|
heartbeatInterval: config.gossipsubInterval,
|
|
219
238
|
mcacheLength: config.gossipsubMcacheLength,
|
|
220
239
|
mcacheGossip: config.gossipsubMcacheGossip,
|
|
240
|
+
// Increased from default 3s to give time for input lag: configuration and rationale from lodestar
|
|
241
|
+
gossipsubIWantFollowupMs: 12 * 1000,
|
|
221
242
|
msgIdFn: getMsgIdFn,
|
|
222
243
|
msgIdToStrFn: msgIdToStrFn,
|
|
223
244
|
fastMsgIdFn: fastMsgIdFn,
|
|
@@ -226,6 +247,8 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
|
|
|
226
247
|
metricsTopicStrToLabel: metricsTopicStrToLabels(),
|
|
227
248
|
asyncValidation: true,
|
|
228
249
|
scoreParams: createPeerScoreParams({
|
|
250
|
+
// IPColocation factor can be disabled for local testing - default to -5
|
|
251
|
+
IPColocationFactorWeight: config.debugDisableColocationPenalty ? 0 : -5.0,
|
|
229
252
|
topics: {
|
|
230
253
|
[Tx.p2pTopic]: createTopicScoreParams({
|
|
231
254
|
topicWeight: 1,
|
|
@@ -254,6 +277,8 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
|
|
|
254
277
|
connectionManager: components.connectionManager,
|
|
255
278
|
}),
|
|
256
279
|
},
|
|
280
|
+
// Fix the peer id in libp2p logs so we can see the source of the log
|
|
281
|
+
logger: createLibp2pComponentLogger(logger.module, { sourcePeerId: peerId }),
|
|
257
282
|
});
|
|
258
283
|
|
|
259
284
|
return new LibP2PService(
|
|
@@ -267,6 +292,7 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
|
|
|
267
292
|
proofVerifier,
|
|
268
293
|
worldStateSynchronizer,
|
|
269
294
|
telemetry,
|
|
295
|
+
logger,
|
|
270
296
|
);
|
|
271
297
|
}
|
|
272
298
|
|
|
@@ -319,8 +345,16 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
|
|
|
319
345
|
[BlockProposal.p2pTopic]: this.validatePropagatedBlockFromMessage.bind(this),
|
|
320
346
|
[EpochProofQuote.p2pTopic]: this.validatePropagatedEpochProofQuoteFromMessage.bind(this),
|
|
321
347
|
};
|
|
322
|
-
|
|
323
|
-
|
|
348
|
+
// When running bandwidth benchmarks, we use send blobs of data we do not want to validate
|
|
349
|
+
// NEVER switch this off in production
|
|
350
|
+
if (!this.config.debugDisableMessageValidation) {
|
|
351
|
+
for (const [topic, validator] of Object.entries(topicValidators)) {
|
|
352
|
+
this.node.services.pubsub.topicValidators.set(topic, validator);
|
|
353
|
+
}
|
|
354
|
+
} else {
|
|
355
|
+
this.logger.warn(
|
|
356
|
+
'MESSAGE VALIDATION DISABLED - IF YOU SEE THIS LOG AND ARE NOT DEBUGGING AND ARE RUNNING IN A PRODUCTION ENVIRONMENT, PLEASE RE-ENABLE MESSAGE VALIDATION',
|
|
357
|
+
);
|
|
324
358
|
}
|
|
325
359
|
|
|
326
360
|
// add GossipSub listener
|
|
@@ -904,7 +938,10 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
|
|
|
904
938
|
this.logger.trace(`Sending message ${identifier}`, { p2pMessageIdentifier: identifier });
|
|
905
939
|
|
|
906
940
|
const recipientsNum = await this.publishToTopic(parent.p2pTopic, message.toBuffer());
|
|
907
|
-
this.logger.debug(`Sent message ${identifier} to ${recipientsNum} peers`, {
|
|
941
|
+
this.logger.debug(`Sent message ${identifier} to ${recipientsNum} peers`, {
|
|
942
|
+
p2pMessageIdentifier: identifier,
|
|
943
|
+
sourcePeer: this.node.peerId.toString(),
|
|
944
|
+
});
|
|
908
945
|
}
|
|
909
946
|
|
|
910
947
|
// Libp2p seems to hang sometimes if new peers are initiating connections.
|
|
@@ -3,6 +3,8 @@ import { Fr } from '@aztec/foundation/fields';
|
|
|
3
3
|
|
|
4
4
|
import { type PeerId } from '@libp2p/interface';
|
|
5
5
|
|
|
6
|
+
import { type ReqRespStatus } from './status.js';
|
|
7
|
+
|
|
6
8
|
/*
|
|
7
9
|
* Request Response Sub Protocols
|
|
8
10
|
*/
|
|
@@ -31,6 +33,15 @@ export type ReqRespSubProtocolHandler = (peerId: PeerId, msg: Buffer) => Promise
|
|
|
31
33
|
*/
|
|
32
34
|
export type ReqRespSubProtocolRateLimits = Record<ReqRespSubProtocol, ProtocolRateLimitQuota>;
|
|
33
35
|
|
|
36
|
+
/**
|
|
37
|
+
* The response from the ReqResp protocol
|
|
38
|
+
* Consists of a status (Error code) and data
|
|
39
|
+
*/
|
|
40
|
+
export interface ReqRespResponse {
|
|
41
|
+
status: ReqRespStatus;
|
|
42
|
+
data: Buffer;
|
|
43
|
+
}
|
|
44
|
+
|
|
34
45
|
/**
|
|
35
46
|
* A rate limit quota
|
|
36
47
|
*/
|
|
@@ -95,7 +95,7 @@ export function reqGoodbyeHandler(peerManager: PeerManager): ReqRespSubProtocolH
|
|
|
95
95
|
|
|
96
96
|
peerManager.goodbyeReceived(peerId, reason);
|
|
97
97
|
|
|
98
|
-
// Return a buffer of length 1 as an acknowledgement
|
|
98
|
+
// Return a buffer of length 1 as an acknowledgement: this is allowed to fail
|
|
99
99
|
return Promise.resolve(Buffer.from([0x0]));
|
|
100
100
|
};
|
|
101
101
|
}
|