@aztec/p2p 0.0.1-commit.2f68f620 → 0.0.1-commit.321f6a9
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/README.md +7 -6
- package/dest/bootstrap/bootstrap.d.ts +1 -1
- package/dest/bootstrap/bootstrap.d.ts.map +1 -1
- package/dest/bootstrap/bootstrap.js +20 -12
- package/dest/client/factory.d.ts +2 -2
- package/dest/client/factory.d.ts.map +1 -1
- package/dest/client/factory.js +10 -5
- package/dest/client/interface.d.ts +36 -8
- package/dest/client/interface.d.ts.map +1 -1
- package/dest/client/p2p_client.d.ts +23 -12
- package/dest/client/p2p_client.d.ts.map +1 -1
- package/dest/client/p2p_client.js +38 -35
- package/dest/config.d.ts +19 -13
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +27 -26
- package/dest/errors/reqresp.error.d.ts +13 -1
- package/dest/errors/reqresp.error.d.ts.map +1 -1
- package/dest/errors/reqresp.error.js +14 -0
- package/dest/mem_pools/attestation_pool/attestation_pool.d.ts +4 -2
- package/dest/mem_pools/attestation_pool/attestation_pool.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/attestation_pool.js +9 -2
- package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.d.ts +1 -1
- package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.js +43 -0
- package/dest/mem_pools/instrumentation.d.ts +9 -4
- package/dest/mem_pools/instrumentation.d.ts.map +1 -1
- package/dest/mem_pools/instrumentation.js +11 -8
- package/dest/mem_pools/tx_pool_v2/deleted_pool.d.ts +3 -3
- package/dest/mem_pools/tx_pool_v2/deleted_pool.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/deleted_pool.js +6 -6
- package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.js +1 -1
- package/dest/mem_pools/tx_pool_v2/interfaces.d.ts +30 -5
- package/dest/mem_pools/tx_pool_v2/interfaces.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/interfaces.js +2 -1
- package/dest/mem_pools/tx_pool_v2/tx_pool_indices.d.ts +15 -1
- package/dest/mem_pools/tx_pool_v2/tx_pool_indices.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/tx_pool_indices.js +31 -0
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts +9 -3
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2.js +19 -8
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts +17 -4
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.js +133 -34
- package/dest/msg_validators/attestation_validator/attestation_validator.d.ts +6 -5
- package/dest/msg_validators/attestation_validator/attestation_validator.d.ts.map +1 -1
- package/dest/msg_validators/attestation_validator/attestation_validator.js +24 -26
- package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts +4 -4
- package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts.map +1 -1
- package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.js +2 -2
- package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts +4 -3
- package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts.map +1 -1
- package/dest/msg_validators/proposal_validator/block_proposal_validator.js +2 -2
- package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts +4 -3
- package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts.map +1 -1
- package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.js +8 -2
- package/dest/msg_validators/proposal_validator/proposal_validator.d.ts +19 -5
- package/dest/msg_validators/proposal_validator/proposal_validator.d.ts.map +1 -1
- package/dest/msg_validators/proposal_validator/proposal_validator.js +66 -30
- package/dest/msg_validators/tx_validator/factory.d.ts +9 -11
- package/dest/msg_validators/tx_validator/factory.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/factory.js +15 -6
- package/dest/msg_validators/tx_validator/gas_validator.d.ts +12 -7
- package/dest/msg_validators/tx_validator/gas_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/gas_validator.js +15 -15
- package/dest/msg_validators/tx_validator/phases_validator.js +2 -2
- package/dest/services/discv5/discV5_service.d.ts +12 -2
- package/dest/services/discv5/discV5_service.d.ts.map +1 -1
- package/dest/services/discv5/discV5_service.js +84 -15
- package/dest/services/discv5/persisted_enr_store.d.ts +38 -0
- package/dest/services/discv5/persisted_enr_store.d.ts.map +1 -0
- package/dest/services/discv5/persisted_enr_store.js +145 -0
- package/dest/services/dummy_service.d.ts +6 -2
- package/dest/services/dummy_service.d.ts.map +1 -1
- package/dest/services/dummy_service.js +3 -0
- package/dest/services/encoding.d.ts +19 -6
- package/dest/services/encoding.d.ts.map +1 -1
- package/dest/services/encoding.js +25 -15
- package/dest/services/gossipsub/topic_score_params.d.ts +6 -23
- package/dest/services/gossipsub/topic_score_params.d.ts.map +1 -1
- package/dest/services/gossipsub/topic_score_params.js +4 -31
- package/dest/services/libp2p/libp2p_service.d.ts +11 -3
- package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
- package/dest/services/libp2p/libp2p_service.js +135 -53
- package/dest/services/peer-manager/peer_manager.d.ts +15 -2
- package/dest/services/peer-manager/peer_manager.d.ts.map +1 -1
- package/dest/services/peer-manager/peer_manager.js +46 -18
- package/dest/services/peer-manager/peer_scoring.d.ts +28 -1
- package/dest/services/peer-manager/peer_scoring.d.ts.map +1 -1
- package/dest/services/peer-manager/peer_scoring.js +70 -3
- package/dest/services/reqresp/config.d.ts +13 -1
- package/dest/services/reqresp/config.d.ts.map +1 -1
- package/dest/services/reqresp/config.js +11 -0
- package/dest/services/reqresp/rate-limiter/rate_limits.js +3 -3
- package/dest/services/reqresp/reqresp.d.ts +1 -1
- package/dest/services/reqresp/reqresp.d.ts.map +1 -1
- package/dest/services/reqresp/reqresp.js +34 -3
- package/dest/services/service.d.ts +17 -1
- package/dest/services/service.d.ts.map +1 -1
- package/dest/services/tx_collection/tx_source.d.ts +1 -1
- package/dest/services/tx_collection/tx_source.d.ts.map +1 -1
- package/dest/services/tx_collection/tx_source.js +4 -1
- package/dest/test-helpers/testbench-utils.d.ts +4 -1
- package/dest/test-helpers/testbench-utils.d.ts.map +1 -1
- package/dest/test-helpers/testbench-utils.js +9 -0
- package/dest/testbench/p2p_client_testbench_worker.d.ts +1 -1
- package/dest/testbench/p2p_client_testbench_worker.d.ts.map +1 -1
- package/dest/testbench/p2p_client_testbench_worker.js +19 -2
- package/package.json +16 -17
- package/src/bootstrap/bootstrap.ts +15 -9
- package/src/client/factory.ts +9 -5
- package/src/client/interface.ts +29 -6
- package/src/client/p2p_client.ts +46 -48
- package/src/config.ts +50 -38
- package/src/errors/reqresp.error.ts +19 -0
- package/src/mem_pools/attestation_pool/attestation_pool.ts +12 -2
- package/src/mem_pools/attestation_pool/attestation_pool_test_suite.ts +40 -1
- package/src/mem_pools/instrumentation.ts +13 -11
- package/src/mem_pools/tx_pool_v2/deleted_pool.ts +7 -7
- package/src/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.ts +1 -1
- package/src/mem_pools/tx_pool_v2/interfaces.ts +28 -4
- package/src/mem_pools/tx_pool_v2/tx_pool_indices.ts +35 -0
- package/src/mem_pools/tx_pool_v2/tx_pool_v2.ts +22 -8
- package/src/mem_pools/tx_pool_v2/tx_pool_v2_impl.ts +158 -33
- package/src/msg_validators/attestation_validator/attestation_validator.ts +26 -26
- package/src/msg_validators/attestation_validator/fisherman_attestation_validator.ts +4 -3
- package/src/msg_validators/proposal_validator/block_proposal_validator.ts +4 -2
- package/src/msg_validators/proposal_validator/checkpoint_proposal_validator.ts +10 -2
- package/src/msg_validators/proposal_validator/proposal_validator.ts +69 -30
- package/src/msg_validators/tx_validator/README.md +2 -0
- package/src/msg_validators/tx_validator/factory.ts +19 -13
- package/src/msg_validators/tx_validator/gas_validator.ts +16 -20
- package/src/msg_validators/tx_validator/phases_validator.ts +2 -2
- package/src/services/discv5/discV5_service.ts +88 -9
- package/src/services/discv5/persisted_enr_store.ts +158 -0
- package/src/services/dummy_service.ts +6 -0
- package/src/services/encoding.ts +28 -20
- package/src/services/gossipsub/README.md +33 -11
- package/src/services/gossipsub/topic_score_params.ts +9 -50
- package/src/services/libp2p/libp2p_service.ts +159 -56
- package/src/services/peer-manager/peer_manager.ts +48 -17
- package/src/services/peer-manager/peer_scoring.ts +75 -3
- package/src/services/reqresp/README.md +2 -23
- package/src/services/reqresp/config.ts +17 -0
- package/src/services/reqresp/rate-limiter/rate_limits.ts +3 -3
- package/src/services/reqresp/reqresp.ts +42 -2
- package/src/services/service.ts +19 -0
- package/src/services/tx_collection/tx_source.ts +2 -1
- package/src/test-helpers/testbench-utils.ts +12 -0
- package/src/testbench/p2p_client_testbench_worker.ts +22 -2
- package/dest/msg_validators/clock_tolerance.d.ts +0 -32
- package/dest/msg_validators/clock_tolerance.d.ts.map +0 -1
- package/dest/msg_validators/clock_tolerance.js +0 -90
- package/src/msg_validators/clock_tolerance.ts +0 -121
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import type { EpochCacheInterface } from '@aztec/epoch-cache';
|
|
2
2
|
import { BlockNumber, type SlotNumber } from '@aztec/foundation/branded-types';
|
|
3
|
-
import { maxBy, merge } from '@aztec/foundation/collection';
|
|
3
|
+
import { compactArray, maxBy, merge } from '@aztec/foundation/collection';
|
|
4
4
|
import { type Logger, createLibp2pComponentLogger, createLogger } from '@aztec/foundation/log';
|
|
5
5
|
import { RunningPromise } from '@aztec/foundation/running-promise';
|
|
6
6
|
import { Timer } from '@aztec/foundation/timer';
|
|
7
7
|
import type { AztecAsyncKVStore } from '@aztec/kv-store';
|
|
8
8
|
import { protocolContractsHash } from '@aztec/protocol-contracts';
|
|
9
9
|
import type { EthAddress, L2BlockSource } from '@aztec/stdlib/block';
|
|
10
|
+
import { DEFAULT_MAX_BLOCKS_PER_CHECKPOINT } from '@aztec/stdlib/config';
|
|
10
11
|
import type { ContractDataSource } from '@aztec/stdlib/contract';
|
|
11
|
-
import { type BlockMinFeesProvider, GasFees } from '@aztec/stdlib/gas';
|
|
12
|
+
import { type BlockMinFeesProvider, GasFees, getNetworkTxGasLimits } from '@aztec/stdlib/gas';
|
|
12
13
|
import type { ClientProtocolCircuitVerifier, PeerInfo, WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
|
|
13
14
|
import {
|
|
14
15
|
BlockProposal,
|
|
@@ -24,6 +25,7 @@ import {
|
|
|
24
25
|
getTopicsForConfig,
|
|
25
26
|
metricsTopicStrToLabels,
|
|
26
27
|
} from '@aztec/stdlib/p2p';
|
|
28
|
+
import { ConsensusTimetable, getDefaultCheckpointProposalSyncGrace } from '@aztec/stdlib/timetable';
|
|
27
29
|
import { MerkleTreeId } from '@aztec/stdlib/trees';
|
|
28
30
|
import { Tx, type TxValidationResult } from '@aztec/stdlib/tx';
|
|
29
31
|
import type { UInt64 } from '@aztec/stdlib/types';
|
|
@@ -81,14 +83,14 @@ import { type PubSubLibp2p, convertToMultiaddr } from '../../util.js';
|
|
|
81
83
|
import { getVersions } from '../../versioning.js';
|
|
82
84
|
import { AztecDatastore } from '../data_store.js';
|
|
83
85
|
import { DiscV5Service } from '../discv5/discV5_service.js';
|
|
84
|
-
import { SnappyTransform,
|
|
86
|
+
import { SnappyTransform, getMsgIdFn, msgIdToStrFn } from '../encoding.js';
|
|
85
87
|
import { APP_SPECIFIC_WEIGHT, gossipScoreThresholds } from '../gossipsub/scoring.js';
|
|
86
88
|
import { createAllTopicScoreParams } from '../gossipsub/topic_score_params.js';
|
|
87
89
|
import type { PeerManagerInterface } from '../peer-manager/interface.js';
|
|
88
90
|
import { PeerManager } from '../peer-manager/peer_manager.js';
|
|
89
91
|
import { PeerScoring } from '../peer-manager/peer_scoring.js';
|
|
90
92
|
import type { BatchTxRequesterLibP2PService } from '../reqresp/batch-tx-requester/interface.js';
|
|
91
|
-
import type
|
|
93
|
+
import { type P2PReqRespConfig, YAMUX_MAX_MESSAGE_SIZE_BYTES } from '../reqresp/config.js';
|
|
92
94
|
import {
|
|
93
95
|
AuthRequest,
|
|
94
96
|
BlockTxsRequest,
|
|
@@ -112,11 +114,30 @@ import type {
|
|
|
112
114
|
P2PCheckpointAttestationCallback,
|
|
113
115
|
P2PCheckpointReceivedCallback,
|
|
114
116
|
P2PDuplicateAttestationCallback,
|
|
117
|
+
P2POversizedProposalCallback,
|
|
115
118
|
P2PService,
|
|
116
119
|
PeerDiscoveryService,
|
|
117
120
|
} from '../service.js';
|
|
118
121
|
import { P2PInstrumentation } from './instrumentation.js';
|
|
119
122
|
|
|
123
|
+
/**
|
|
124
|
+
* Builds the {@link ConsensusTimetable} shared by the gossip validators for proposal/attestation receive-window
|
|
125
|
+
* bounds. Derived purely from protocol slot-timing constants plus the block sub-slot duration and the consensus
|
|
126
|
+
* materialization grace, so every node agrees on these bounds without depending on proposer operational budgets.
|
|
127
|
+
*/
|
|
128
|
+
function buildConsensusTimetable(
|
|
129
|
+
config: P2PConfig,
|
|
130
|
+
l1Constants: ReturnType<EpochCacheInterface['getL1Constants']>,
|
|
131
|
+
): ConsensusTimetable {
|
|
132
|
+
const blockDuration = config.blockDurationMs / 1000;
|
|
133
|
+
return new ConsensusTimetable({
|
|
134
|
+
l1Constants,
|
|
135
|
+
blockDuration,
|
|
136
|
+
checkpointProposalSyncGrace:
|
|
137
|
+
config.checkpointProposalSyncGraceSeconds ?? getDefaultCheckpointProposalSyncGrace(blockDuration),
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
|
|
120
141
|
interface ValidationResult {
|
|
121
142
|
name: string;
|
|
122
143
|
isValid: TxValidationResult;
|
|
@@ -152,6 +173,9 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
152
173
|
type: 'checkpoint' | 'block';
|
|
153
174
|
}) => void;
|
|
154
175
|
|
|
176
|
+
/** Callback invoked when an oversized block proposal is stored as slashing evidence (triggers slashing). */
|
|
177
|
+
private oversizedProposalCallback?: P2POversizedProposalCallback;
|
|
178
|
+
|
|
155
179
|
/** Callback invoked when a duplicate attestation is detected (triggers slashing). */
|
|
156
180
|
private duplicateAttestationCallback?: P2PDuplicateAttestationCallback;
|
|
157
181
|
|
|
@@ -233,28 +257,39 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
233
257
|
this.protocolVersion,
|
|
234
258
|
);
|
|
235
259
|
|
|
236
|
-
|
|
260
|
+
// Build the consensus timetable once from protocol slot-timing constants and inject it into every
|
|
261
|
+
// validator so they share one set of receive-window bounds, independent of proposer operational budgets.
|
|
262
|
+
const consensusTimetable = buildConsensusTimetable(config, epochCache.getL1Constants());
|
|
237
263
|
const proposalValidatorOpts = {
|
|
238
264
|
txsPermitted: !config.disableTransactions,
|
|
239
265
|
maxTxsPerBlock: config.validateMaxTxsPerBlock ?? config.validateMaxTxsPerCheckpoint,
|
|
240
266
|
maxBlocksPerCheckpoint: config.maxBlocksPerCheckpoint,
|
|
241
|
-
p2pPropagationTime,
|
|
242
267
|
skipSlotValidation: config.skipProposalSlotValidation,
|
|
243
268
|
signatureContext: {
|
|
244
269
|
chainId: config.l1ChainId,
|
|
245
270
|
rollupAddress: config.rollupAddress,
|
|
246
271
|
},
|
|
272
|
+
clockDisparityMs: config.maxGossipClockDisparityMs,
|
|
247
273
|
};
|
|
248
|
-
this.blockProposalValidator = new BlockProposalValidator(epochCache, proposalValidatorOpts);
|
|
249
|
-
this.checkpointProposalValidator = new CheckpointProposalValidator(
|
|
274
|
+
this.blockProposalValidator = new BlockProposalValidator(epochCache, consensusTimetable, proposalValidatorOpts);
|
|
275
|
+
this.checkpointProposalValidator = new CheckpointProposalValidator(
|
|
276
|
+
epochCache,
|
|
277
|
+
consensusTimetable,
|
|
278
|
+
proposalValidatorOpts,
|
|
279
|
+
);
|
|
250
280
|
const attestationValidatorOpts = {
|
|
251
|
-
l1PublishingTime: config.l1PublishingTime,
|
|
252
|
-
p2pPropagationTime,
|
|
253
281
|
signatureContext: proposalValidatorOpts.signatureContext,
|
|
282
|
+
clockDisparityMs: config.maxGossipClockDisparityMs,
|
|
254
283
|
};
|
|
255
284
|
this.checkpointAttestationValidator = config.fishermanMode
|
|
256
|
-
? new FishermanAttestationValidator(
|
|
257
|
-
|
|
285
|
+
? new FishermanAttestationValidator(
|
|
286
|
+
epochCache,
|
|
287
|
+
consensusTimetable,
|
|
288
|
+
mempools.attestationPool,
|
|
289
|
+
telemetry,
|
|
290
|
+
attestationValidatorOpts,
|
|
291
|
+
)
|
|
292
|
+
: new CheckpointAttestationValidator(epochCache, consensusTimetable, attestationValidatorOpts);
|
|
258
293
|
|
|
259
294
|
this.gossipSubEventHandler = this.handleGossipSubEvent.bind(this);
|
|
260
295
|
|
|
@@ -333,6 +368,7 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
333
368
|
packageVersion,
|
|
334
369
|
telemetry,
|
|
335
370
|
createLogger(`${logger.module}:discv5_service`, logger.getBindings()),
|
|
371
|
+
peerStore,
|
|
336
372
|
);
|
|
337
373
|
|
|
338
374
|
// Seed libp2p's bootstrap discovery with private and trusted peers
|
|
@@ -347,37 +383,49 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
347
383
|
const protocolVersion = compressComponentVersions(versions);
|
|
348
384
|
|
|
349
385
|
const preferredPeersEnrs: ENR[] = config.preferredPeers.map(enr => ENR.decodeTxt(enr));
|
|
350
|
-
const directPeers = (
|
|
386
|
+
const directPeers = compactArray(
|
|
351
387
|
await Promise.all(
|
|
352
388
|
preferredPeersEnrs.map(async enr => {
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
389
|
+
try {
|
|
390
|
+
const peerId = await enr.peerId();
|
|
391
|
+
const address = enr.getLocationMultiaddr('tcp');
|
|
392
|
+
if (address === undefined) {
|
|
393
|
+
throw new Error(`Direct peer ${peerId.toString()} has no TCP address, ENR: ${enr.encodeTxt()}`);
|
|
394
|
+
}
|
|
395
|
+
return {
|
|
396
|
+
id: peerId,
|
|
397
|
+
addrs: [address],
|
|
398
|
+
};
|
|
399
|
+
} catch (err) {
|
|
400
|
+
// A malformed configured ENR shouldn't abort node setup — skip it and log.
|
|
401
|
+
logger.warn(`Skipping preferred peer with invalid ENR`, { err });
|
|
402
|
+
return undefined;
|
|
357
403
|
}
|
|
358
|
-
return {
|
|
359
|
-
id: peerId,
|
|
360
|
-
addrs: [address],
|
|
361
|
-
};
|
|
362
404
|
}),
|
|
363
|
-
)
|
|
364
|
-
)
|
|
405
|
+
),
|
|
406
|
+
);
|
|
365
407
|
|
|
366
408
|
const announceTcpMultiaddr = config.p2pIp ? [convertToMultiaddr(config.p2pIp, p2pPort, 'tcp')] : [];
|
|
367
409
|
|
|
368
|
-
// Create dynamic topic score params based on network configuration
|
|
410
|
+
// Create dynamic topic score params based on network configuration. Scoring uses the network-wide
|
|
411
|
+
// max-blocks-per-checkpoint config value directly to size expected per-slot message rates; these are
|
|
412
|
+
// peer-rate thresholds, not consensus deadlines, so they need no proposer operational budgets.
|
|
369
413
|
const l1Constants = epochCache.getL1Constants();
|
|
370
414
|
const topicScoreParams = createAllTopicScoreParams(protocolVersion, {
|
|
371
415
|
slotDurationMs: l1Constants.slotDuration * 1000,
|
|
372
|
-
ethereumSlotDuration: l1Constants.ethereumSlotDuration,
|
|
373
416
|
heartbeatIntervalMs: config.gossipsubInterval,
|
|
374
417
|
targetCommitteeSize: l1Constants.targetCommitteeSize,
|
|
375
|
-
|
|
376
|
-
l1PublishingTime: config.l1PublishingTime,
|
|
377
|
-
p2pPropagationTime: config.attestationPropagationTime,
|
|
418
|
+
maxBlocksPerCheckpoint: config.maxBlocksPerCheckpoint ?? DEFAULT_MAX_BLOCKS_PER_CHECKPOINT,
|
|
378
419
|
expectedBlockProposalsPerSlot: config.expectedBlockProposalsPerSlot,
|
|
379
420
|
});
|
|
380
421
|
|
|
422
|
+
// Restrict gossipsub to exactly the topics we subscribe to. Without this, an arbitrary-topic
|
|
423
|
+
// message is transformed, msg-id'd and inserted into the seenCache before the subscription check,
|
|
424
|
+
// so a crafted topic colliding on msg id can suppress a real message as a duplicate.
|
|
425
|
+
const allowedTopics = getTopicsForConfig(config.disableTransactions).map(topic =>
|
|
426
|
+
createTopicString(topic, protocolVersion),
|
|
427
|
+
);
|
|
428
|
+
|
|
381
429
|
const node = await createLibp2p({
|
|
382
430
|
start: false,
|
|
383
431
|
peerId,
|
|
@@ -409,7 +457,8 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
409
457
|
],
|
|
410
458
|
datastore,
|
|
411
459
|
peerDiscovery,
|
|
412
|
-
|
|
460
|
+
// Pin the yamux frame size: MAX_REQRESP_REQUEST_SIZE_BYTES relies on a reqresp request fitting in one frame.
|
|
461
|
+
streamMuxers: [yamux({ maxMessageSize: YAMUX_MAX_MESSAGE_SIZE_BYTES }), mplex()],
|
|
413
462
|
connectionEncryption: [noise()],
|
|
414
463
|
connectionManager: {
|
|
415
464
|
minConnections: 0, // Disable libp2p peer dialing, we do it manually
|
|
@@ -423,7 +472,7 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
423
472
|
},
|
|
424
473
|
connectionGater: {
|
|
425
474
|
denyInboundConnection: (maConn: MultiaddrConnection) => {
|
|
426
|
-
const allowed = peerManager.
|
|
475
|
+
const allowed = peerManager.isAddressAllowedToConnect(maConn.remoteAddr.nodeAddress().address);
|
|
427
476
|
if (allowed) {
|
|
428
477
|
return false;
|
|
429
478
|
}
|
|
@@ -434,7 +483,7 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
434
483
|
denyInboundEncryptedConnection: (peerId: PeerId, _maConn: MultiaddrConnection) => {
|
|
435
484
|
//NOTE: it is not necessary to check address here because this was already done by
|
|
436
485
|
// denyInboundConnection
|
|
437
|
-
const allowed = peerManager.
|
|
486
|
+
const allowed = peerManager.isPeerAllowedToConnect(peerId);
|
|
438
487
|
if (allowed) {
|
|
439
488
|
return false;
|
|
440
489
|
}
|
|
@@ -462,9 +511,13 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
462
511
|
mcacheLength: config.gossipsubMcacheLength,
|
|
463
512
|
mcacheGossip: config.gossipsubMcacheGossip,
|
|
464
513
|
seenTTL: config.gossipsubSeenTTL,
|
|
514
|
+
allowedTopics,
|
|
515
|
+
// No fastMsgIdFn: the fast-path dedup cache keys on a non-cryptographic 64-bit hash of the
|
|
516
|
+
// raw data only (no topic), so a collision — accidental or engineered via a weak seed — drops
|
|
517
|
+
// a different message with no fallback to the full id. Dedup instead rests solely on the
|
|
518
|
+
// cryptographic, topic-framed msgIdFn below.
|
|
465
519
|
msgIdFn: getMsgIdFn,
|
|
466
520
|
msgIdToStrFn: msgIdToStrFn,
|
|
467
|
-
fastMsgIdFn: fastMsgIdFn,
|
|
468
521
|
dataTransform: new SnappyTransform(),
|
|
469
522
|
metricsRegister: otelMetricsAdapter,
|
|
470
523
|
metricsTopicStrToLabel: metricsTopicStrToLabels(protocolVersion),
|
|
@@ -732,6 +785,13 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
732
785
|
this.duplicateProposalCallback = callback;
|
|
733
786
|
}
|
|
734
787
|
|
|
788
|
+
/**
|
|
789
|
+
* Registers a callback to be invoked when an oversized block proposal is stored as slashing evidence.
|
|
790
|
+
*/
|
|
791
|
+
public registerOversizedProposalCallback(callback: P2POversizedProposalCallback): void {
|
|
792
|
+
this.oversizedProposalCallback = callback;
|
|
793
|
+
}
|
|
794
|
+
|
|
735
795
|
/**
|
|
736
796
|
* Registers a callback to be invoked when a duplicate attestation is detected.
|
|
737
797
|
* A validator signing attestations for different proposals at the same slot.
|
|
@@ -1213,16 +1273,17 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1213
1273
|
const {
|
|
1214
1274
|
result,
|
|
1215
1275
|
obj: block,
|
|
1216
|
-
metadata: { isEquivocated } = {},
|
|
1217
|
-
} = await this.validateReceivedMessage<BlockProposal, { isEquivocated: boolean }>(
|
|
1276
|
+
metadata: { isEquivocated, isOversized } = {},
|
|
1277
|
+
} = await this.validateReceivedMessage<BlockProposal, { isEquivocated: boolean; isOversized: boolean }>(
|
|
1218
1278
|
() => this.validateAndStoreBlockProposal(source, BlockProposal.fromBuffer(payloadData)),
|
|
1219
1279
|
msgId,
|
|
1220
1280
|
source,
|
|
1221
1281
|
TopicType.block_proposal,
|
|
1222
1282
|
);
|
|
1223
1283
|
|
|
1224
|
-
// If not accepted or
|
|
1225
|
-
|
|
1284
|
+
// If not accepted, equivocated, or oversized, return. Oversized proposals are re-broadcast as
|
|
1285
|
+
// slashing evidence but never attested or processed.
|
|
1286
|
+
if (result !== TopicValidatorResult.Accept || !block || isEquivocated || isOversized) {
|
|
1226
1287
|
return;
|
|
1227
1288
|
}
|
|
1228
1289
|
|
|
@@ -1237,7 +1298,7 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1237
1298
|
protected async validateAndStoreBlockProposal(
|
|
1238
1299
|
peerId: PeerId,
|
|
1239
1300
|
block: BlockProposal,
|
|
1240
|
-
): Promise<ReceivedMessageValidationResult<BlockProposal, { isEquivocated: boolean }>> {
|
|
1301
|
+
): Promise<ReceivedMessageValidationResult<BlockProposal, { isEquivocated: boolean; isOversized: boolean }>> {
|
|
1241
1302
|
const validationResult = await this.blockProposalValidator.validate(block);
|
|
1242
1303
|
|
|
1243
1304
|
if (validationResult.result === 'reject') {
|
|
@@ -1252,6 +1313,12 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1252
1313
|
// Try to add the proposal: this handles existence check, cap check, and adding in one call
|
|
1253
1314
|
const { added, alreadyExists, count } = await this.mempools.attestationPool.tryAddBlockProposal(block);
|
|
1254
1315
|
const isEquivocated = count !== undefined && count > 1;
|
|
1316
|
+
// An oversized proposal (index at or beyond the consensus per-checkpoint limit) is structurally valid
|
|
1317
|
+
// proposer misbehavior: it is stored and re-broadcast as slashing evidence but never processed or
|
|
1318
|
+
// attested to. No-ops when maxBlocksPerCheckpoint is unset (local/test).
|
|
1319
|
+
const isOversized =
|
|
1320
|
+
this.config.maxBlocksPerCheckpoint !== undefined &&
|
|
1321
|
+
block.indexWithinCheckpoint >= this.config.maxBlocksPerCheckpoint;
|
|
1255
1322
|
|
|
1256
1323
|
// Duplicate proposal received, no need to re-broadcast
|
|
1257
1324
|
if (alreadyExists) {
|
|
@@ -1261,7 +1328,7 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1261
1328
|
proposer: block.getSender()?.toString(),
|
|
1262
1329
|
source: peerId.toString(),
|
|
1263
1330
|
});
|
|
1264
|
-
return { result: TopicValidatorResult.Ignore, obj: block, metadata: { isEquivocated } };
|
|
1331
|
+
return { result: TopicValidatorResult.Ignore, obj: block, metadata: { isEquivocated, isOversized } };
|
|
1265
1332
|
}
|
|
1266
1333
|
|
|
1267
1334
|
// Too many blocks received for this slot and index, penalize peer and do not re-broadcast
|
|
@@ -1275,11 +1342,27 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1275
1342
|
});
|
|
1276
1343
|
return {
|
|
1277
1344
|
result: TopicValidatorResult.Reject,
|
|
1278
|
-
metadata: { isEquivocated },
|
|
1345
|
+
metadata: { isEquivocated, isOversized },
|
|
1279
1346
|
severity: PeerErrorSeverity.HighToleranceError,
|
|
1280
1347
|
};
|
|
1281
1348
|
}
|
|
1282
1349
|
|
|
1350
|
+
// The proposal was stored: if oversized, invoke the oversized callback so the proposer can be
|
|
1351
|
+
// slashed. Fired alongside (not instead of) equivocation detection below.
|
|
1352
|
+
if (isOversized) {
|
|
1353
|
+
const proposer = block.getSender();
|
|
1354
|
+
if (proposer) {
|
|
1355
|
+
this.logger.warn(`Detected oversized block proposal at slot ${block.slotNumber}`, {
|
|
1356
|
+
...block.toBlockInfo(),
|
|
1357
|
+
indexWithinCheckpoint: block.indexWithinCheckpoint,
|
|
1358
|
+
maxBlocksPerCheckpoint: this.config.maxBlocksPerCheckpoint,
|
|
1359
|
+
source: peerId.toString(),
|
|
1360
|
+
proposer: proposer.toString(),
|
|
1361
|
+
});
|
|
1362
|
+
this.oversizedProposalCallback?.({ slot: block.slotNumber, proposer });
|
|
1363
|
+
}
|
|
1364
|
+
}
|
|
1365
|
+
|
|
1283
1366
|
// If this was a duplicate proposal, do not process it, but do invoke the duplicate callback,
|
|
1284
1367
|
// and do re-broadcast it so other nodes in the network know to slash the proposer
|
|
1285
1368
|
if (isEquivocated) {
|
|
@@ -1293,11 +1376,11 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1293
1376
|
if (proposer && count === 2) {
|
|
1294
1377
|
this.duplicateProposalCallback?.({ slot: block.slotNumber, proposer, type: 'block' });
|
|
1295
1378
|
}
|
|
1296
|
-
return { result: TopicValidatorResult.Accept, obj: block, metadata: { isEquivocated } };
|
|
1379
|
+
return { result: TopicValidatorResult.Accept, obj: block, metadata: { isEquivocated, isOversized } };
|
|
1297
1380
|
}
|
|
1298
1381
|
|
|
1299
1382
|
// Otherwise, we're good to go!
|
|
1300
|
-
return { result: TopicValidatorResult.Accept, obj: block };
|
|
1383
|
+
return { result: TopicValidatorResult.Accept, obj: block, metadata: { isEquivocated: false, isOversized } };
|
|
1301
1384
|
}
|
|
1302
1385
|
|
|
1303
1386
|
// REFACTOR(palla): This method should be moved to the p2p_client or to a separate component,
|
|
@@ -1323,6 +1406,9 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1323
1406
|
const isValid = await this.blockReceivedCallback(block, sender);
|
|
1324
1407
|
if (!isValid) {
|
|
1325
1408
|
this.logger.info(`Block proposal validation failed for block ${block.blockNumber}`, block.toBlockInfo());
|
|
1409
|
+
// Release the protections this proposal created so its txs return to pending. Only entries still
|
|
1410
|
+
// keyed to this slot are cleared, so a tx referenced by a live proposal at another slot stays protected.
|
|
1411
|
+
await this.mempools.txPool.unprotectTxs(block.txHashes, slot);
|
|
1326
1412
|
}
|
|
1327
1413
|
}
|
|
1328
1414
|
|
|
@@ -1334,17 +1420,21 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1334
1420
|
const {
|
|
1335
1421
|
result,
|
|
1336
1422
|
obj: checkpoint,
|
|
1337
|
-
metadata: { isEquivocated, processBlock } = {},
|
|
1338
|
-
} = await this.validateReceivedMessage<
|
|
1423
|
+
metadata: { isEquivocated, processBlock, isOversized } = {},
|
|
1424
|
+
} = await this.validateReceivedMessage<
|
|
1425
|
+
CheckpointProposal,
|
|
1426
|
+
{ isEquivocated: boolean; processBlock: boolean; isOversized: boolean }
|
|
1427
|
+
>(
|
|
1339
1428
|
() => this.validateAndStoreCheckpointProposal(source, CheckpointProposal.fromBuffer(payloadData)),
|
|
1340
1429
|
msgId,
|
|
1341
1430
|
source,
|
|
1342
1431
|
TopicType.checkpoint_proposal,
|
|
1343
1432
|
);
|
|
1344
1433
|
|
|
1345
|
-
//
|
|
1434
|
+
// An oversized checkpoint is re-broadcast as slashing evidence but never attested or processed.
|
|
1435
|
+
// Process checkpoint proposal if valid and neither equivocated nor oversized.
|
|
1346
1436
|
const processCheckpointFn = () =>
|
|
1347
|
-
result === TopicValidatorResult.Accept && checkpoint && !isEquivocated
|
|
1437
|
+
result === TopicValidatorResult.Accept && checkpoint && !isEquivocated && !isOversized
|
|
1348
1438
|
? this.processValidCheckpointProposal(checkpoint.toCore(), source)
|
|
1349
1439
|
: Promise.resolve();
|
|
1350
1440
|
|
|
@@ -1381,7 +1471,12 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1381
1471
|
protected async validateAndStoreCheckpointProposal(
|
|
1382
1472
|
peerId: PeerId,
|
|
1383
1473
|
checkpoint: CheckpointProposal,
|
|
1384
|
-
): Promise<
|
|
1474
|
+
): Promise<
|
|
1475
|
+
ReceivedMessageValidationResult<
|
|
1476
|
+
CheckpointProposal,
|
|
1477
|
+
{ isEquivocated: boolean; processBlock: boolean; isOversized: boolean }
|
|
1478
|
+
>
|
|
1479
|
+
> {
|
|
1385
1480
|
const validationResult = await this.checkpointProposalValidator.validate(checkpoint);
|
|
1386
1481
|
|
|
1387
1482
|
if (validationResult.result === 'reject') {
|
|
@@ -1396,13 +1491,16 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1396
1491
|
// Extract and try to add the block proposal first if present
|
|
1397
1492
|
const blockProposal = checkpoint.getBlockProposal();
|
|
1398
1493
|
let processBlock = false;
|
|
1494
|
+
let isOversized = false;
|
|
1399
1495
|
if (blockProposal) {
|
|
1400
1496
|
this.logger.debug(`Validating block proposal from propagated checkpoint`, {
|
|
1401
1497
|
[Attributes.SLOT_NUMBER]: checkpoint.slotNumber.toString(),
|
|
1402
1498
|
[Attributes.P2P_ID]: peerId.toString(),
|
|
1403
1499
|
});
|
|
1404
1500
|
const blockProposalResult = await this.validateAndStoreBlockProposal(peerId, blockProposal);
|
|
1405
|
-
const { obj, metadata: { isEquivocated } = {} } = blockProposalResult;
|
|
1501
|
+
const { obj, metadata: { isEquivocated, isOversized: blockIsOversized } = {} } = blockProposalResult;
|
|
1502
|
+
isOversized = blockIsOversized ?? false;
|
|
1503
|
+
|
|
1406
1504
|
if (blockProposalResult.result === TopicValidatorResult.Reject || !obj || isEquivocated) {
|
|
1407
1505
|
this.logger.debug(`Rejecting checkpoint due to invalid last block proposal`, {
|
|
1408
1506
|
[Attributes.SLOT_NUMBER]: checkpoint.slotNumber.toString(),
|
|
@@ -1415,7 +1513,8 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1415
1513
|
severity:
|
|
1416
1514
|
'severity' in blockProposalResult ? blockProposalResult.severity : PeerErrorSeverity.MidToleranceError,
|
|
1417
1515
|
};
|
|
1418
|
-
} else if (blockProposalResult.result === TopicValidatorResult.Accept && obj && !isEquivocated) {
|
|
1516
|
+
} else if (blockProposalResult.result === TopicValidatorResult.Accept && obj && !isEquivocated && !isOversized) {
|
|
1517
|
+
// An oversized terminal block is re-broadcast as slashing evidence but never processed.
|
|
1419
1518
|
processBlock = true;
|
|
1420
1519
|
}
|
|
1421
1520
|
}
|
|
@@ -1435,11 +1534,11 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1435
1534
|
return {
|
|
1436
1535
|
result: TopicValidatorResult.Ignore,
|
|
1437
1536
|
obj: checkpoint,
|
|
1438
|
-
metadata: { isEquivocated, processBlock },
|
|
1537
|
+
metadata: { isEquivocated, processBlock, isOversized },
|
|
1439
1538
|
};
|
|
1440
1539
|
}
|
|
1441
1540
|
|
|
1442
|
-
// Too many checkpoint proposals received for this slot, penalize peer and do not re-broadcast
|
|
1541
|
+
// Too many checkpoint proposals received for this slot, penalize peer and do not re-broadcast.
|
|
1443
1542
|
// Note: We still return the checkpoint obj so the lastBlock can be processed if valid
|
|
1444
1543
|
if (!added) {
|
|
1445
1544
|
this.logger.warn(`Penalizing peer for checkpoint proposal exceeding per-slot cap`, {
|
|
@@ -1450,7 +1549,7 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1450
1549
|
return {
|
|
1451
1550
|
result: TopicValidatorResult.Reject,
|
|
1452
1551
|
obj: checkpoint,
|
|
1453
|
-
metadata: { isEquivocated, processBlock },
|
|
1552
|
+
metadata: { isEquivocated, processBlock, isOversized },
|
|
1454
1553
|
severity: PeerErrorSeverity.HighToleranceError,
|
|
1455
1554
|
};
|
|
1456
1555
|
}
|
|
@@ -1471,12 +1570,16 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1471
1570
|
return {
|
|
1472
1571
|
result: TopicValidatorResult.Accept,
|
|
1473
1572
|
obj: checkpoint,
|
|
1474
|
-
metadata: { isEquivocated, processBlock },
|
|
1573
|
+
metadata: { isEquivocated, processBlock, isOversized },
|
|
1475
1574
|
};
|
|
1476
1575
|
}
|
|
1477
1576
|
|
|
1478
1577
|
// Otherwise, we're good to go!
|
|
1479
|
-
return {
|
|
1578
|
+
return {
|
|
1579
|
+
result: TopicValidatorResult.Accept,
|
|
1580
|
+
obj: checkpoint,
|
|
1581
|
+
metadata: { processBlock, isEquivocated, isOversized },
|
|
1582
|
+
};
|
|
1480
1583
|
}
|
|
1481
1584
|
|
|
1482
1585
|
/**
|
|
@@ -1670,6 +1773,7 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1670
1773
|
];
|
|
1671
1774
|
const blockNumber = BlockNumber(currentBlockNumber + 1);
|
|
1672
1775
|
const l1Constants = await this.archiver.getL1Constants();
|
|
1776
|
+
const networkTxGasLimits = getNetworkTxGasLimits(this.config, l1Constants);
|
|
1673
1777
|
|
|
1674
1778
|
return createFirstStageTxValidationsForGossipedTransactions(
|
|
1675
1779
|
nextSlotTimestamp,
|
|
@@ -1684,9 +1788,8 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1684
1788
|
allowedInSetup,
|
|
1685
1789
|
this.logger.getBindings(),
|
|
1686
1790
|
{
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
maxBlockDAGas: this.config.validateMaxDABlockGas,
|
|
1791
|
+
maxTxL2Gas: networkTxGasLimits.l2Gas,
|
|
1792
|
+
maxTxDAGas: networkTxGasLimits.daGas,
|
|
1690
1793
|
},
|
|
1691
1794
|
);
|
|
1692
1795
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { EpochCacheInterface } from '@aztec/epoch-cache';
|
|
2
|
+
import { compactArray } from '@aztec/foundation/collection';
|
|
2
3
|
import { makeEthSignDigest, tryRecoverAddress } from '@aztec/foundation/crypto/secp256k1-signer';
|
|
3
4
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
4
5
|
import type { EthAddress } from '@aztec/foundation/eth-address';
|
|
@@ -164,6 +165,7 @@ export class PeerManager implements PeerManagerInterface {
|
|
|
164
165
|
public async heartbeat() {
|
|
165
166
|
this.heartbeatCounter++;
|
|
166
167
|
this.peerScoring.decayAllScores();
|
|
168
|
+
this.peerScoring.pruneExpiredBans();
|
|
167
169
|
this.cleanupExpiredTimeouts();
|
|
168
170
|
|
|
169
171
|
await this.setupDirectPeersIfValidator();
|
|
@@ -198,21 +200,27 @@ export class PeerManager implements PeerManagerInterface {
|
|
|
198
200
|
.then(peerIds => peerIds.forEach(peerId => this.preferredPeers.add(peerId.toString())))
|
|
199
201
|
.catch(e => this.logger.error('Error initializing preferred peers', e));
|
|
200
202
|
|
|
201
|
-
const directPeers = (
|
|
203
|
+
const directPeers = compactArray(
|
|
202
204
|
await Promise.all(
|
|
203
205
|
preferredPeersEnrs.map(async enr => {
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
206
|
+
try {
|
|
207
|
+
const peerId = await enr.peerId();
|
|
208
|
+
const address = enr.getLocationMultiaddr('tcp');
|
|
209
|
+
if (address === undefined) {
|
|
210
|
+
throw new Error(`Direct peer ${peerId.toString()} has no TCP address, ENR: ${enr.encodeTxt()}`);
|
|
211
|
+
}
|
|
212
|
+
return {
|
|
213
|
+
id: peerId,
|
|
214
|
+
addrs: [address],
|
|
215
|
+
};
|
|
216
|
+
} catch (err) {
|
|
217
|
+
// A malformed configured ENR shouldn't abort preferred-peer setup — skip it and log.
|
|
218
|
+
this.logger.warn(`Skipping preferred peer with invalid ENR`, { err });
|
|
219
|
+
return undefined;
|
|
208
220
|
}
|
|
209
|
-
return {
|
|
210
|
-
id: peerId,
|
|
211
|
-
addrs: [address],
|
|
212
|
-
};
|
|
213
221
|
}),
|
|
214
|
-
)
|
|
215
|
-
)
|
|
222
|
+
),
|
|
223
|
+
);
|
|
216
224
|
|
|
217
225
|
await Promise.all(
|
|
218
226
|
directPeers.map(peer => {
|
|
@@ -494,15 +502,38 @@ export class PeerManager implements PeerManagerInterface {
|
|
|
494
502
|
*
|
|
495
503
|
* @returns: True if node is allowed to connect, otherwise false
|
|
496
504
|
* */
|
|
497
|
-
|
|
498
|
-
|
|
505
|
+
/**
|
|
506
|
+
* Whether a peer is allowed to connect, given its peer id. Rejects peers serving an active ban and
|
|
507
|
+
* peers that have exceeded the failed auth-handshake limit. Use this once the peer id is known —
|
|
508
|
+
* i.e. for the encrypted-inbound gater and when dialing.
|
|
509
|
+
*/
|
|
510
|
+
public isPeerAllowedToConnect(peerId: string | PeerId): boolean {
|
|
511
|
+
const id = peerId.toString();
|
|
512
|
+
if (this.peerScoring.getScoreState(id) === PeerScoreState.Banned) {
|
|
513
|
+
return false;
|
|
514
|
+
}
|
|
515
|
+
return this.isWithinFailedAuthLimit(id);
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
/**
|
|
519
|
+
* Whether a connection from an address is allowed. Bans are keyed by peer id, which isn't known at
|
|
520
|
+
* the raw-inbound layer, so only the failed auth-handshake limit (also tracked per address) is
|
|
521
|
+
* enforced here; the ban is applied once the peer id is known via {@link isPeerAllowedToConnect}.
|
|
522
|
+
*/
|
|
523
|
+
public isAddressAllowedToConnect(address: string): boolean {
|
|
524
|
+
return this.isWithinFailedAuthLimit(address);
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
/** Whether the failed auth-handshake count for a peer id or address is below the configured limit. */
|
|
528
|
+
private isWithinFailedAuthLimit(key: string): boolean {
|
|
529
|
+
const entry = this.failedAuthHandshakes.get(key);
|
|
499
530
|
if (!entry) {
|
|
500
531
|
return true;
|
|
501
532
|
}
|
|
502
533
|
|
|
503
534
|
// In case entry is too old, remove it and allow connection
|
|
504
535
|
if (this.dateProvider.now() - entry.lastFailureTimestamp > FAILED_AUTH_HANDSHAKE_EXPIRY_MS) {
|
|
505
|
-
this.failedAuthHandshakes.delete(
|
|
536
|
+
this.failedAuthHandshakes.delete(key);
|
|
506
537
|
return true;
|
|
507
538
|
}
|
|
508
539
|
|
|
@@ -729,9 +760,9 @@ export class PeerManager implements PeerManagerInterface {
|
|
|
729
760
|
return;
|
|
730
761
|
}
|
|
731
762
|
|
|
732
|
-
// Don't dial peers that have exceeded the auth failure threshold
|
|
733
|
-
if (!this.
|
|
734
|
-
this.logger.trace(`Skipping peer ${peerId} due to failed auth handshake attempts`);
|
|
763
|
+
// Don't dial banned peers or those that have exceeded the auth failure threshold
|
|
764
|
+
if (!this.isPeerAllowedToConnect(peerId)) {
|
|
765
|
+
this.logger.trace(`Skipping peer ${peerId} due to ban or failed auth handshake attempts`);
|
|
735
766
|
return;
|
|
736
767
|
}
|
|
737
768
|
|