@aztec/p2p 0.0.1-commit.f5d02921e → 0.0.1-commit.f7ea82942
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/client/factory.d.ts +3 -2
- package/dest/client/factory.d.ts.map +1 -1
- package/dest/client/factory.js +16 -15
- package/dest/client/p2p_client.d.ts +1 -1
- package/dest/client/p2p_client.d.ts.map +1 -1
- package/dest/client/p2p_client.js +9 -2
- package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.js +4 -1
- package/dest/config.d.ts +103 -99
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +11 -6
- 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 +5 -3
- package/dest/mem_pools/tx_pool_v2/eviction/index.d.ts +2 -1
- package/dest/mem_pools/tx_pool_v2/eviction/index.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/index.js +1 -0
- package/dest/mem_pools/tx_pool_v2/eviction/insufficient_fee_per_gas_eviction_rule.d.ts +16 -0
- package/dest/mem_pools/tx_pool_v2/eviction/insufficient_fee_per_gas_eviction_rule.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/eviction/insufficient_fee_per_gas_eviction_rule.js +62 -0
- package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.js +2 -2
- package/dest/mem_pools/tx_pool_v2/interfaces.d.ts +4 -1
- package/dest/mem_pools/tx_pool_v2/interfaces.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts +5 -2
- package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/tx_metadata.js +8 -5
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts +1 -1
- 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 +2 -1
- package/dest/msg_validators/attestation_validator/attestation_validator.d.ts +5 -2
- package/dest/msg_validators/attestation_validator/attestation_validator.d.ts.map +1 -1
- package/dest/msg_validators/attestation_validator/attestation_validator.js +17 -9
- package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts +4 -2
- 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/clock_tolerance.d.ts +12 -1
- package/dest/msg_validators/clock_tolerance.d.ts.map +1 -1
- package/dest/msg_validators/clock_tolerance.js +50 -0
- package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts +2 -1
- package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts.map +1 -1
- package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts +2 -1
- package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts.map +1 -1
- package/dest/msg_validators/proposal_validator/proposal_validator.d.ts +3 -1
- package/dest/msg_validators/proposal_validator/proposal_validator.d.ts.map +1 -1
- package/dest/msg_validators/proposal_validator/proposal_validator.js +16 -8
- package/dest/msg_validators/tx_validator/archive_cache.js +1 -1
- package/dest/msg_validators/tx_validator/factory.d.ts +2 -2
- package/dest/msg_validators/tx_validator/factory.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/factory.js +3 -3
- package/dest/msg_validators/tx_validator/gas_validator.d.ts +36 -4
- package/dest/msg_validators/tx_validator/gas_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/gas_validator.js +50 -33
- package/dest/services/data_store.d.ts +1 -1
- package/dest/services/data_store.d.ts.map +1 -1
- package/dest/services/data_store.js +5 -5
- package/dest/services/dummy_service.d.ts +2 -1
- package/dest/services/dummy_service.d.ts.map +1 -1
- package/dest/services/dummy_service.js +1 -0
- package/dest/services/gossipsub/topic_score_params.d.ts +13 -2
- package/dest/services/gossipsub/topic_score_params.d.ts.map +1 -1
- package/dest/services/gossipsub/topic_score_params.js +21 -4
- package/dest/services/libp2p/instrumentation.d.ts +3 -1
- package/dest/services/libp2p/instrumentation.d.ts.map +1 -1
- package/dest/services/libp2p/instrumentation.js +14 -0
- package/dest/services/libp2p/libp2p_service.d.ts +6 -17
- package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
- package/dest/services/libp2p/libp2p_service.js +37 -73
- package/dest/services/peer-manager/peer_manager.d.ts +1 -1
- package/dest/services/peer-manager/peer_manager.d.ts.map +1 -1
- package/dest/services/peer-manager/peer_manager.js +15 -2
- package/dest/services/peer-manager/peer_scoring.d.ts +3 -1
- package/dest/services/peer-manager/peer_scoring.d.ts.map +1 -1
- package/dest/services/peer-manager/peer_scoring.js +4 -0
- package/dest/services/reqresp/config.d.ts +3 -3
- package/dest/services/reqresp/config.d.ts.map +1 -1
- package/dest/services/reqresp/interface.d.ts +14 -9
- package/dest/services/reqresp/interface.d.ts.map +1 -1
- package/dest/services/reqresp/interface.js +10 -11
- package/dest/services/reqresp/metrics.d.ts +1 -1
- package/dest/services/reqresp/metrics.d.ts.map +1 -1
- package/dest/services/reqresp/metrics.js +0 -1
- package/dest/services/reqresp/protocols/index.d.ts +1 -2
- package/dest/services/reqresp/protocols/index.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/index.js +0 -1
- package/dest/services/reqresp/protocols/tx.d.ts +1 -1
- package/dest/services/reqresp/protocols/tx.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/tx.js +1 -3
- package/dest/services/reqresp/rate-limiter/rate_limits.d.ts +1 -1
- package/dest/services/reqresp/rate-limiter/rate_limits.d.ts.map +1 -1
- package/dest/services/reqresp/rate-limiter/rate_limits.js +0 -10
- package/dest/services/reqresp/reqresp.d.ts +4 -2
- package/dest/services/reqresp/reqresp.d.ts.map +1 -1
- package/dest/services/reqresp/reqresp.js +11 -2
- package/dest/test-helpers/make-test-p2p-clients.d.ts +1 -1
- package/dest/test-helpers/make-test-p2p-clients.d.ts.map +1 -1
- package/dest/test-helpers/make-test-p2p-clients.js +4 -1
- package/dest/test-helpers/mock-pubsub.d.ts +11 -3
- package/dest/test-helpers/mock-pubsub.d.ts.map +1 -1
- package/dest/test-helpers/mock-pubsub.js +36 -11
- package/dest/test-helpers/reqresp-nodes.d.ts +1 -1
- package/dest/test-helpers/reqresp-nodes.d.ts.map +1 -1
- package/dest/test-helpers/reqresp-nodes.js +5 -3
- package/dest/test-helpers/testbench-utils.d.ts +1 -1
- package/dest/test-helpers/testbench-utils.d.ts.map +1 -1
- package/dest/test-helpers/testbench-utils.js +1 -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 +29 -2
- package/dest/testbench/worker_client_manager.d.ts +8 -1
- package/dest/testbench/worker_client_manager.d.ts.map +1 -1
- package/dest/testbench/worker_client_manager.js +49 -0
- package/package.json +14 -14
- package/src/client/factory.ts +23 -18
- package/src/client/p2p_client.ts +11 -3
- package/src/client/test/tx_proposal_collector/proposal_tx_collector_worker.ts +2 -0
- package/src/config.ts +19 -7
- package/src/mem_pools/attestation_pool/attestation_pool.ts +5 -3
- package/src/mem_pools/tx_pool_v2/eviction/index.ts +1 -0
- package/src/mem_pools/tx_pool_v2/eviction/insufficient_fee_per_gas_eviction_rule.ts +65 -0
- package/src/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.ts +3 -3
- package/src/mem_pools/tx_pool_v2/interfaces.ts +3 -0
- package/src/mem_pools/tx_pool_v2/tx_metadata.ts +13 -7
- package/src/mem_pools/tx_pool_v2/tx_pool_v2_impl.ts +2 -0
- package/src/msg_validators/attestation_validator/attestation_validator.ts +18 -7
- package/src/msg_validators/attestation_validator/fisherman_attestation_validator.ts +4 -1
- package/src/msg_validators/clock_tolerance.ts +68 -0
- package/src/msg_validators/proposal_validator/block_proposal_validator.ts +4 -1
- package/src/msg_validators/proposal_validator/checkpoint_proposal_validator.ts +4 -1
- package/src/msg_validators/proposal_validator/proposal_validator.ts +13 -7
- package/src/msg_validators/tx_validator/README.md +11 -3
- package/src/msg_validators/tx_validator/archive_cache.ts +1 -1
- package/src/msg_validators/tx_validator/factory.ts +3 -1
- package/src/msg_validators/tx_validator/gas_validator.ts +82 -33
- package/src/services/data_store.ts +5 -13
- package/src/services/dummy_service.ts +1 -0
- package/src/services/gossipsub/topic_score_params.ts +36 -4
- package/src/services/libp2p/instrumentation.ts +14 -0
- package/src/services/libp2p/libp2p_service.ts +32 -68
- package/src/services/peer-manager/peer_manager.ts +17 -2
- package/src/services/peer-manager/peer_scoring.ts +6 -0
- package/src/services/reqresp/config.ts +2 -2
- package/src/services/reqresp/interface.ts +21 -11
- package/src/services/reqresp/metrics.ts +0 -1
- package/src/services/reqresp/protocols/index.ts +0 -1
- package/src/services/reqresp/protocols/tx.ts +1 -3
- package/src/services/reqresp/rate-limiter/rate_limits.ts +0 -10
- package/src/services/reqresp/reqresp.ts +18 -1
- package/src/test-helpers/make-test-p2p-clients.ts +2 -0
- package/src/test-helpers/mock-pubsub.ts +34 -5
- package/src/test-helpers/reqresp-nodes.ts +4 -2
- package/src/test-helpers/testbench-utils.ts +1 -0
- package/src/testbench/p2p_client_testbench_worker.ts +30 -0
- package/src/testbench/worker_client_manager.ts +55 -0
- package/dest/services/reqresp/protocols/block.d.ts +0 -9
- package/dest/services/reqresp/protocols/block.d.ts.map +0 -1
- package/dest/services/reqresp/protocols/block.js +0 -32
- package/src/services/reqresp/protocols/block.ts +0 -37
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
import type { EpochCacheInterface } from '@aztec/epoch-cache';
|
|
2
2
|
import { BlockNumber, type SlotNumber } from '@aztec/foundation/branded-types';
|
|
3
3
|
import { maxBy } from '@aztec/foundation/collection';
|
|
4
|
-
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
5
4
|
import { type Logger, createLibp2pComponentLogger, createLogger } from '@aztec/foundation/log';
|
|
6
5
|
import { RunningPromise } from '@aztec/foundation/running-promise';
|
|
7
6
|
import { Timer } from '@aztec/foundation/timer';
|
|
8
7
|
import type { AztecAsyncKVStore } from '@aztec/kv-store';
|
|
9
8
|
import { protocolContractsHash } from '@aztec/protocol-contracts';
|
|
10
|
-
import type { EthAddress,
|
|
9
|
+
import type { EthAddress, L2BlockSource } from '@aztec/stdlib/block';
|
|
11
10
|
import type { ContractDataSource } from '@aztec/stdlib/contract';
|
|
12
|
-
import { GasFees } from '@aztec/stdlib/gas';
|
|
11
|
+
import { type BlockMinFeesProvider, GasFees } from '@aztec/stdlib/gas';
|
|
13
12
|
import type { ClientProtocolCircuitVerifier, PeerInfo, WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
|
|
14
13
|
import {
|
|
15
14
|
BlockProposal,
|
|
@@ -105,7 +104,6 @@ import {
|
|
|
105
104
|
ValidationError,
|
|
106
105
|
pingHandler,
|
|
107
106
|
reqGoodbyeHandler,
|
|
108
|
-
reqRespBlockHandler,
|
|
109
107
|
reqRespBlockTxsHandler,
|
|
110
108
|
reqRespStatusHandler,
|
|
111
109
|
reqRespTxHandler,
|
|
@@ -148,8 +146,6 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
148
146
|
private protocolVersion = '';
|
|
149
147
|
private topicStrings: Record<TopicType, string> = {} as Record<TopicType, string>;
|
|
150
148
|
|
|
151
|
-
private feesCache: { blockNumber: BlockNumber; gasFees: GasFees } | undefined;
|
|
152
|
-
|
|
153
149
|
/** Callback invoked when a duplicate proposal is detected (triggers slashing). */
|
|
154
150
|
private duplicateProposalCallback?: (info: {
|
|
155
151
|
slot: SlotNumber;
|
|
@@ -199,6 +195,7 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
199
195
|
private epochCache: EpochCacheInterface,
|
|
200
196
|
private proofVerifier: ClientProtocolCircuitVerifier,
|
|
201
197
|
private worldStateSynchronizer: WorldStateSynchronizer,
|
|
198
|
+
private blockMinFeesProvider: BlockMinFeesProvider,
|
|
202
199
|
telemetry: TelemetryClient,
|
|
203
200
|
logger: Logger = createLogger('p2p:libp2p_service'),
|
|
204
201
|
) {
|
|
@@ -230,15 +227,19 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
230
227
|
this.protocolVersion,
|
|
231
228
|
);
|
|
232
229
|
|
|
230
|
+
const p2pPropagationTime = config.attestationPropagationTime;
|
|
233
231
|
const proposalValidatorOpts = {
|
|
234
232
|
txsPermitted: !config.disableTransactions,
|
|
235
233
|
maxTxsPerBlock: config.validateMaxTxsPerBlock ?? config.validateMaxTxsPerCheckpoint,
|
|
234
|
+
p2pPropagationTime,
|
|
236
235
|
};
|
|
237
236
|
this.blockProposalValidator = new BlockProposalValidator(epochCache, proposalValidatorOpts);
|
|
238
237
|
this.checkpointProposalValidator = new CheckpointProposalValidator(epochCache, proposalValidatorOpts);
|
|
239
238
|
this.checkpointAttestationValidator = config.fishermanMode
|
|
240
|
-
? new FishermanAttestationValidator(epochCache, mempools.attestationPool, telemetry
|
|
241
|
-
|
|
239
|
+
? new FishermanAttestationValidator(epochCache, mempools.attestationPool, telemetry, {
|
|
240
|
+
l1PublishingTime: config.l1PublishingTime,
|
|
241
|
+
})
|
|
242
|
+
: new CheckpointAttestationValidator(epochCache, { l1PublishingTime: config.l1PublishingTime });
|
|
242
243
|
|
|
243
244
|
this.gossipSubEventHandler = this.handleGossipSubEvent.bind(this);
|
|
244
245
|
|
|
@@ -283,6 +284,7 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
283
284
|
proofVerifier: ClientProtocolCircuitVerifier;
|
|
284
285
|
worldStateSynchronizer: WorldStateSynchronizer;
|
|
285
286
|
peerStore: AztecAsyncKVStore;
|
|
287
|
+
blockMinFeesProvider: BlockMinFeesProvider;
|
|
286
288
|
telemetry: TelemetryClient;
|
|
287
289
|
logger: Logger;
|
|
288
290
|
packageVersion: string;
|
|
@@ -295,6 +297,7 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
295
297
|
mempools,
|
|
296
298
|
proofVerifier,
|
|
297
299
|
peerStore,
|
|
300
|
+
blockMinFeesProvider,
|
|
298
301
|
telemetry,
|
|
299
302
|
logger,
|
|
300
303
|
packageVersion,
|
|
@@ -348,9 +351,12 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
348
351
|
const l1Constants = epochCache.getL1Constants();
|
|
349
352
|
const topicScoreParams = createAllTopicScoreParams(protocolVersion, {
|
|
350
353
|
slotDurationMs: l1Constants.slotDuration * 1000,
|
|
354
|
+
ethereumSlotDuration: l1Constants.ethereumSlotDuration,
|
|
351
355
|
heartbeatIntervalMs: config.gossipsubInterval,
|
|
352
356
|
targetCommitteeSize: l1Constants.targetCommitteeSize,
|
|
353
357
|
blockDurationMs: config.blockDurationMs,
|
|
358
|
+
l1PublishingTime: config.l1PublishingTime,
|
|
359
|
+
p2pPropagationTime: config.attestationPropagationTime,
|
|
354
360
|
expectedBlockProposalsPerSlot: config.expectedBlockProposalsPerSlot,
|
|
355
361
|
});
|
|
356
362
|
|
|
@@ -475,6 +481,9 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
475
481
|
epochCache,
|
|
476
482
|
);
|
|
477
483
|
|
|
484
|
+
// Gate req/resp data protocols for unauthenticated peers when p2pAllowOnlyValidators is enabled
|
|
485
|
+
reqresp.setShouldRejectPeer(peerId => peerManager.shouldDisableP2PGossip(peerId));
|
|
486
|
+
|
|
478
487
|
// Configure application-specific scoring for gossipsub.
|
|
479
488
|
// The weight scales app score to align with gossipsub thresholds:
|
|
480
489
|
// - Disconnect (-50) × 10 = -500 = gossipThreshold (stops receiving gossip)
|
|
@@ -495,6 +504,7 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
495
504
|
epochCache,
|
|
496
505
|
proofVerifier,
|
|
497
506
|
worldStateSynchronizer,
|
|
507
|
+
blockMinFeesProvider,
|
|
498
508
|
telemetry,
|
|
499
509
|
logger,
|
|
500
510
|
);
|
|
@@ -520,14 +530,12 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
520
530
|
// Create request response protocol handlers
|
|
521
531
|
const txHandler = reqRespTxHandler(this.mempools);
|
|
522
532
|
const goodbyeHandler = reqGoodbyeHandler(this.peerManager);
|
|
523
|
-
const blockHandler = reqRespBlockHandler(this.archiver);
|
|
524
533
|
const statusHandler = reqRespStatusHandler(this.protocolVersion, this.worldStateSynchronizer, this.logger);
|
|
525
534
|
|
|
526
535
|
const requestResponseHandlers: Partial<ReqRespSubProtocolHandlers> = {
|
|
527
536
|
[ReqRespSubProtocol.PING]: pingHandler,
|
|
528
537
|
[ReqRespSubProtocol.STATUS]: statusHandler.bind(this),
|
|
529
538
|
[ReqRespSubProtocol.GOODBYE]: goodbyeHandler.bind(this),
|
|
530
|
-
[ReqRespSubProtocol.BLOCK]: blockHandler.bind(this),
|
|
531
539
|
};
|
|
532
540
|
|
|
533
541
|
if (!this.config.disableTransactions) {
|
|
@@ -548,7 +556,6 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
548
556
|
...DEFAULT_SUB_PROTOCOL_VALIDATORS,
|
|
549
557
|
[ReqRespSubProtocol.TX]: this.validateRequestedTxs.bind(this),
|
|
550
558
|
[ReqRespSubProtocol.BLOCK_TXS]: this.validateRequestedBlockTxs.bind(this),
|
|
551
|
-
[ReqRespSubProtocol.BLOCK]: this.validateRequestedBlock.bind(this),
|
|
552
559
|
};
|
|
553
560
|
|
|
554
561
|
await this.peerManager.initializePeers();
|
|
@@ -912,6 +919,17 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
912
919
|
this.logger.error(`Error validating gossipsub message`, err, { msgId, source: source.toString(), topicType });
|
|
913
920
|
}
|
|
914
921
|
|
|
922
|
+
const validationTimeMs = timer.ms();
|
|
923
|
+
const mcacheWindowMs = this.config.gossipsubMcacheLength * this.config.gossipsubInterval;
|
|
924
|
+
if (validationTimeMs > mcacheWindowMs * 0.75) {
|
|
925
|
+
this.instrumentation.incSlowValidation(topicType);
|
|
926
|
+
this.logger.warn(
|
|
927
|
+
`Gossip validation for ${topicType} took ${validationTimeMs}ms, approaching mcache eviction window of ${mcacheWindowMs}ms. ` +
|
|
928
|
+
`Message forwarding may be skipped if validation exceeds the window.`,
|
|
929
|
+
{ msgId, source: source.toString(), topicType, validationTimeMs, mcacheWindowMs },
|
|
930
|
+
);
|
|
931
|
+
}
|
|
932
|
+
|
|
915
933
|
if (resultAndObj.result === TopicValidatorResult.Accept) {
|
|
916
934
|
this.logger.debug(`Message ${topicType} accepted by validator`, { msgId, source: source.toString(), topicType });
|
|
917
935
|
this.instrumentation.recordMessageValidation(topicType, timer);
|
|
@@ -1574,53 +1592,6 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1574
1592
|
}
|
|
1575
1593
|
}
|
|
1576
1594
|
|
|
1577
|
-
/**
|
|
1578
|
-
* Validates a BLOCK response.
|
|
1579
|
-
*
|
|
1580
|
-
* If a local copy exists, enforces hash equality. If missing, rejects (no penalty) since the hash cannot be verified.
|
|
1581
|
-
* Penalizes on block number mismatch or hash mismatch.
|
|
1582
|
-
*
|
|
1583
|
-
* @param requestedBlockNumber - The requested block number.
|
|
1584
|
-
* @param responseBlock - The block returned by the peer.
|
|
1585
|
-
* @param peerId - The peer that returned the block.
|
|
1586
|
-
* @returns True if the response is valid, false otherwise.
|
|
1587
|
-
*/
|
|
1588
|
-
@trackSpan('Libp2pService.validateRequestedBlock', (requestedBlockNumber, _responseBlock) => ({
|
|
1589
|
-
[Attributes.BLOCK_NUMBER]: requestedBlockNumber.toString(),
|
|
1590
|
-
}))
|
|
1591
|
-
protected async validateRequestedBlock(
|
|
1592
|
-
requestedBlockNumber: Fr,
|
|
1593
|
-
responseBlock: L2Block,
|
|
1594
|
-
peerId: PeerId,
|
|
1595
|
-
): Promise<boolean> {
|
|
1596
|
-
try {
|
|
1597
|
-
const reqNum = Number(requestedBlockNumber.toString());
|
|
1598
|
-
if (responseBlock.number !== reqNum) {
|
|
1599
|
-
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
|
|
1600
|
-
return false;
|
|
1601
|
-
}
|
|
1602
|
-
|
|
1603
|
-
const local = await this.archiver.getBlock(BlockNumber(reqNum));
|
|
1604
|
-
if (!local) {
|
|
1605
|
-
// We are missing the local block; we cannot verify the hash yet. Reject without penalizing.
|
|
1606
|
-
// TODO: Consider extending this validator to accept an expected hash or
|
|
1607
|
-
// performing quorum-based checks when using P2P syncing prior to L1 sync.
|
|
1608
|
-
this.logger.warn(`Local block ${reqNum} not found; rejecting BLOCK response without hash verification`);
|
|
1609
|
-
return false;
|
|
1610
|
-
}
|
|
1611
|
-
const [localHash, respHash] = await Promise.all([local.hash(), responseBlock.hash()]);
|
|
1612
|
-
if (!localHash.equals(respHash)) {
|
|
1613
|
-
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
1614
|
-
return false;
|
|
1615
|
-
}
|
|
1616
|
-
|
|
1617
|
-
return true;
|
|
1618
|
-
} catch (e) {
|
|
1619
|
-
this.logger.warn(`Error validating requested block`, e);
|
|
1620
|
-
return false;
|
|
1621
|
-
}
|
|
1622
|
-
}
|
|
1623
|
-
|
|
1624
1595
|
protected async validateRequestedTx(
|
|
1625
1596
|
tx: Tx,
|
|
1626
1597
|
peerId: PeerId,
|
|
@@ -1647,15 +1618,8 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1647
1618
|
});
|
|
1648
1619
|
}
|
|
1649
1620
|
|
|
1650
|
-
private
|
|
1651
|
-
|
|
1652
|
-
return this.feesCache.gasFees;
|
|
1653
|
-
}
|
|
1654
|
-
|
|
1655
|
-
const header = await this.archiver.getBlockHeader(blockNumber);
|
|
1656
|
-
const gasFees = header?.globalVariables.gasFees ?? GasFees.empty();
|
|
1657
|
-
this.feesCache = { blockNumber, gasFees };
|
|
1658
|
-
return gasFees;
|
|
1621
|
+
private getGasFees(): Promise<GasFees> {
|
|
1622
|
+
return this.blockMinFeesProvider.getCurrentMinFees();
|
|
1659
1623
|
}
|
|
1660
1624
|
|
|
1661
1625
|
/**
|
|
@@ -1697,7 +1661,7 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1697
1661
|
currentBlockNumber: BlockNumber,
|
|
1698
1662
|
nextSlotTimestamp: UInt64,
|
|
1699
1663
|
): Promise<Record<string, TransactionValidator>> {
|
|
1700
|
-
const gasFees = await this.getGasFees(
|
|
1664
|
+
const gasFees = await this.getGasFees();
|
|
1701
1665
|
const allowedInSetup = [
|
|
1702
1666
|
...(await getDefaultAllowedSetupFunctions()),
|
|
1703
1667
|
...(this.config.txPublicSetupAllowListExtend ?? []),
|
|
@@ -728,6 +728,12 @@ export class PeerManager implements PeerManagerInterface {
|
|
|
728
728
|
return;
|
|
729
729
|
}
|
|
730
730
|
|
|
731
|
+
// Don't dial peers that have exceeded the auth failure threshold
|
|
732
|
+
if (!this.isNodeAllowedToConnect(peerId)) {
|
|
733
|
+
this.logger.trace(`Skipping peer ${peerId} due to failed auth handshake attempts`);
|
|
734
|
+
return;
|
|
735
|
+
}
|
|
736
|
+
|
|
731
737
|
const [multiaddrTcp] = await Promise.all([enr.getFullMultiaddr('tcp')]);
|
|
732
738
|
|
|
733
739
|
this.logger.trace(`Handling discovered peer ${peerId} at ${multiaddrTcp?.toString() ?? 'undefined address'}`);
|
|
@@ -985,14 +991,14 @@ export class PeerManager implements PeerManagerInterface {
|
|
|
985
991
|
const peerIdStr = peerId.toString();
|
|
986
992
|
|
|
987
993
|
const existingEntry = this.failedAuthHandshakes.get(peerIdStr);
|
|
994
|
+
const failureCount = (existingEntry?.count || 0) + 1;
|
|
988
995
|
this.failedAuthHandshakes.set(peerIdStr, {
|
|
989
|
-
count:
|
|
996
|
+
count: failureCount,
|
|
990
997
|
lastFailureTimestamp: now,
|
|
991
998
|
});
|
|
992
999
|
|
|
993
1000
|
const connections = this.libP2PNode.getConnections(peerId);
|
|
994
1001
|
connections.forEach(conn => {
|
|
995
|
-
// We mark the IP address
|
|
996
1002
|
const address = conn.remoteAddr.nodeAddress().address;
|
|
997
1003
|
const existingAddressEntry = this.failedAuthHandshakes.get(address);
|
|
998
1004
|
this.failedAuthHandshakes.set(address, {
|
|
@@ -1000,6 +1006,15 @@ export class PeerManager implements PeerManagerInterface {
|
|
|
1000
1006
|
lastFailureTimestamp: now,
|
|
1001
1007
|
});
|
|
1002
1008
|
});
|
|
1009
|
+
|
|
1010
|
+
// Ban the peer from being re-dialed for a cooldown period (exponential backoff)
|
|
1011
|
+
const banTimeMs = this.config.peerFailedBanTimeMs ?? DEFAULT_FAILED_PEER_BAN_TIME_MS;
|
|
1012
|
+
const backoffMs = banTimeMs * Math.pow(2, Math.min(failureCount - 1, 5));
|
|
1013
|
+
this.timedOutPeers.set(peerIdStr, {
|
|
1014
|
+
peerId: peerIdStr,
|
|
1015
|
+
timeoutUntilMs: now + backoffMs,
|
|
1016
|
+
});
|
|
1017
|
+
this.cachedPeers.delete(peerIdStr);
|
|
1003
1018
|
}
|
|
1004
1019
|
|
|
1005
1020
|
/*
|
|
@@ -135,6 +135,12 @@ export class PeerScoring {
|
|
|
135
135
|
}
|
|
136
136
|
}
|
|
137
137
|
|
|
138
|
+
/** Resets all peer scores. Useful for benchmarks to prevent cross-case contamination. */
|
|
139
|
+
resetAllScores(): void {
|
|
140
|
+
this.scores.clear();
|
|
141
|
+
this.lastUpdateTime.clear();
|
|
142
|
+
}
|
|
143
|
+
|
|
138
144
|
removePeer(peerId: string): void {
|
|
139
145
|
this.scores.delete(peerId);
|
|
140
146
|
this.lastUpdateTime.delete(peerId);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type ConfigMappingsType, booleanConfigHelper, numberConfigHelper } from '@aztec/foundation/config';
|
|
2
2
|
|
|
3
3
|
export const DEFAULT_INDIVIDUAL_REQUEST_TIMEOUT_MS = 10_000;
|
|
4
4
|
export const DEFAULT_OVERALL_REQUEST_TIMEOUT_MS = 10_000; // Not currently used
|
|
@@ -27,7 +27,7 @@ export interface P2PReqRespConfig {
|
|
|
27
27
|
dialTimeoutMs: number;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
export const p2pReqRespConfigMappings:
|
|
30
|
+
export const p2pReqRespConfigMappings: ConfigMappingsType<P2PReqRespConfig> = {
|
|
31
31
|
overallRequestTimeoutMs: {
|
|
32
32
|
env: 'P2P_REQRESP_OVERALL_REQUEST_TIMEOUT_MS',
|
|
33
33
|
description: 'The overall timeout for a request response operation.',
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
2
|
-
import { L2Block } from '@aztec/stdlib/block';
|
|
3
|
-
import { MAX_L2_BLOCK_SIZE_KB } from '@aztec/stdlib/p2p';
|
|
4
1
|
import { TxArray, TxHashArray } from '@aztec/stdlib/tx';
|
|
5
2
|
|
|
6
3
|
import type { PeerId } from '@libp2p/interface';
|
|
@@ -24,7 +21,6 @@ export const PING_PROTOCOL = '/aztec/req/ping/1.0.0';
|
|
|
24
21
|
export const STATUS_PROTOCOL = '/aztec/req/status/1.0.0';
|
|
25
22
|
export const GOODBYE_PROTOCOL = '/aztec/req/goodbye/1.0.0';
|
|
26
23
|
export const TX_REQ_PROTOCOL = '/aztec/req/tx/1.0.0';
|
|
27
|
-
export const BLOCK_REQ_PROTOCOL = '/aztec/req/block/1.0.0';
|
|
28
24
|
export const AUTH_PROTOCOL = '/aztec/req/auth/1.0.0';
|
|
29
25
|
export const BLOCK_TXS_REQ_PROTOCOL = '/aztec/req/block_txs/1.0.0';
|
|
30
26
|
|
|
@@ -33,7 +29,6 @@ export enum ReqRespSubProtocol {
|
|
|
33
29
|
STATUS = STATUS_PROTOCOL,
|
|
34
30
|
GOODBYE = GOODBYE_PROTOCOL,
|
|
35
31
|
TX = TX_REQ_PROTOCOL,
|
|
36
|
-
BLOCK = BLOCK_REQ_PROTOCOL,
|
|
37
32
|
AUTH = AUTH_PROTOCOL,
|
|
38
33
|
BLOCK_TXS = BLOCK_TXS_REQ_PROTOCOL,
|
|
39
34
|
}
|
|
@@ -100,12 +95,29 @@ export type ReqRespSubProtocolValidators = {
|
|
|
100
95
|
[S in ReqRespSubProtocol]: ResponseValidator<any, any>;
|
|
101
96
|
};
|
|
102
97
|
|
|
98
|
+
/**
|
|
99
|
+
* Protocols that are always allowed without authentication, even when p2pAllowOnlyValidators is enabled.
|
|
100
|
+
* These are needed for the handshake and connection management flow.
|
|
101
|
+
* All other protocols require the remote peer to be authenticated.
|
|
102
|
+
*/
|
|
103
|
+
export const UNAUTHENTICATED_ALLOWED_PROTOCOLS: ReadonlySet<ReqRespSubProtocol> = new Set([
|
|
104
|
+
ReqRespSubProtocol.PING,
|
|
105
|
+
ReqRespSubProtocol.STATUS,
|
|
106
|
+
ReqRespSubProtocol.AUTH,
|
|
107
|
+
ReqRespSubProtocol.GOODBYE,
|
|
108
|
+
]);
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Callback that checks whether a peer should be rejected from req/resp data protocols.
|
|
112
|
+
* Returns true if the peer should be rejected (i.e. p2pAllowOnlyValidators is on and peer is unauthenticated).
|
|
113
|
+
*/
|
|
114
|
+
export type ShouldRejectPeer = (peerId: string) => boolean;
|
|
115
|
+
|
|
103
116
|
export const DEFAULT_SUB_PROTOCOL_VALIDATORS: ReqRespSubProtocolValidators = {
|
|
104
117
|
[ReqRespSubProtocol.PING]: noopValidator,
|
|
105
118
|
[ReqRespSubProtocol.STATUS]: noopValidator,
|
|
106
119
|
[ReqRespSubProtocol.TX]: noopValidator,
|
|
107
120
|
[ReqRespSubProtocol.GOODBYE]: noopValidator,
|
|
108
|
-
[ReqRespSubProtocol.BLOCK]: noopValidator,
|
|
109
121
|
[ReqRespSubProtocol.AUTH]: noopValidator,
|
|
110
122
|
[ReqRespSubProtocol.BLOCK_TXS]: noopValidator,
|
|
111
123
|
};
|
|
@@ -203,10 +215,6 @@ export const subProtocolMap = {
|
|
|
203
215
|
request: RequestableBuffer,
|
|
204
216
|
response: RequestableBuffer,
|
|
205
217
|
},
|
|
206
|
-
[ReqRespSubProtocol.BLOCK]: {
|
|
207
|
-
request: Fr, // block number
|
|
208
|
-
response: L2Block,
|
|
209
|
-
},
|
|
210
218
|
[ReqRespSubProtocol.AUTH]: {
|
|
211
219
|
request: AuthRequest,
|
|
212
220
|
response: AuthResponse,
|
|
@@ -229,7 +237,6 @@ export type ExpectedResponseSizeCalculator = (requestBuffer: Buffer) => number;
|
|
|
229
237
|
export const subProtocolSizeCalculators: Record<ReqRespSubProtocol, ExpectedResponseSizeCalculator> = {
|
|
230
238
|
[ReqRespSubProtocol.TX]: calculateTxResponseSize,
|
|
231
239
|
[ReqRespSubProtocol.BLOCK_TXS]: calculateBlockTxsResponseSize,
|
|
232
|
-
[ReqRespSubProtocol.BLOCK]: () => MAX_L2_BLOCK_SIZE_KB,
|
|
233
240
|
[ReqRespSubProtocol.STATUS]: () => 1,
|
|
234
241
|
[ReqRespSubProtocol.PING]: () => 1,
|
|
235
242
|
[ReqRespSubProtocol.AUTH]: () => 1,
|
|
@@ -264,5 +271,8 @@ export interface ReqRespInterface {
|
|
|
264
271
|
|
|
265
272
|
updateConfig(config: Partial<P2PReqRespConfig>): void;
|
|
266
273
|
|
|
274
|
+
/** Sets the callback used to reject unauthenticated peers on gated req/resp protocols. */
|
|
275
|
+
setShouldRejectPeer(checker: ShouldRejectPeer): void;
|
|
276
|
+
|
|
267
277
|
getConnectionSampler(): Pick<ConnectionSampler, 'getPeerListSortedByConnectionCountAsc'>;
|
|
268
278
|
}
|
|
@@ -51,9 +51,7 @@ export function reqRespTxHandler(mempools: MemPools): ReqRespSubProtocolHandler
|
|
|
51
51
|
* Per: https://github.com/AztecProtocol/aztec-packages/issues/15149#issuecomment-2999054485
|
|
52
52
|
* we define Q as max number of transactions per batch, the comment explains why we use 8.
|
|
53
53
|
*/
|
|
54
|
-
|
|
55
|
-
//more info: https://github.com/AztecProtocol/aztec-packages/pull/15516#pullrequestreview-2995474321
|
|
56
|
-
export function chunkTxHashesRequest(hashes: TxHash[], chunkSize = 1): Array<TxHashArray> {
|
|
54
|
+
export function chunkTxHashesRequest(hashes: TxHash[], chunkSize = 8): Array<TxHashArray> {
|
|
57
55
|
return chunk(hashes, chunkSize).map(chunk => new TxHashArray(...chunk));
|
|
58
56
|
}
|
|
59
57
|
|
|
@@ -42,16 +42,6 @@ export const DEFAULT_RATE_LIMITS: ReqRespSubProtocolRateLimits = {
|
|
|
42
42
|
quotaCount: 200,
|
|
43
43
|
},
|
|
44
44
|
},
|
|
45
|
-
[ReqRespSubProtocol.BLOCK]: {
|
|
46
|
-
peerLimit: {
|
|
47
|
-
quotaTimeMs: 1000,
|
|
48
|
-
quotaCount: 2,
|
|
49
|
-
},
|
|
50
|
-
globalLimit: {
|
|
51
|
-
quotaTimeMs: 1000,
|
|
52
|
-
quotaCount: 5,
|
|
53
|
-
},
|
|
54
|
-
},
|
|
55
45
|
[ReqRespSubProtocol.GOODBYE]: {
|
|
56
46
|
peerLimit: {
|
|
57
47
|
quotaTimeMs: 1000,
|
|
@@ -34,7 +34,9 @@ import {
|
|
|
34
34
|
type ReqRespSubProtocolHandlers,
|
|
35
35
|
type ReqRespSubProtocolRateLimits,
|
|
36
36
|
type ReqRespSubProtocolValidators,
|
|
37
|
+
type ShouldRejectPeer,
|
|
37
38
|
type SubProtocolMap,
|
|
39
|
+
UNAUTHENTICATED_ALLOWED_PROTOCOLS,
|
|
38
40
|
responseFromBuffer,
|
|
39
41
|
subProtocolSizeCalculators,
|
|
40
42
|
} from './interface.js';
|
|
@@ -72,6 +74,8 @@ export class ReqResp implements ReqRespInterface {
|
|
|
72
74
|
|
|
73
75
|
private snappyTransform: SnappyTransform;
|
|
74
76
|
|
|
77
|
+
private shouldRejectPeer: ShouldRejectPeer | undefined;
|
|
78
|
+
|
|
75
79
|
private metrics: ReqRespMetrics;
|
|
76
80
|
|
|
77
81
|
constructor(
|
|
@@ -108,6 +112,10 @@ export class ReqResp implements ReqRespInterface {
|
|
|
108
112
|
}
|
|
109
113
|
}
|
|
110
114
|
|
|
115
|
+
public setShouldRejectPeer(checker: ShouldRejectPeer): void {
|
|
116
|
+
this.shouldRejectPeer = checker;
|
|
117
|
+
}
|
|
118
|
+
|
|
111
119
|
get tracer() {
|
|
112
120
|
return this.metrics.tracer;
|
|
113
121
|
}
|
|
@@ -462,7 +470,7 @@ export class ReqResp implements ReqRespInterface {
|
|
|
462
470
|
);
|
|
463
471
|
return resp;
|
|
464
472
|
} catch (e: any) {
|
|
465
|
-
this.logger.
|
|
473
|
+
this.logger.debug(`SUBPROTOCOL: ${subProtocol}\n`, e);
|
|
466
474
|
// On error we immediately abort the stream, this is preferred way,
|
|
467
475
|
// because it signals to the sender that error happened, whereas
|
|
468
476
|
// closing the stream only closes our side and is much slower
|
|
@@ -596,6 +604,15 @@ export class ReqResp implements ReqRespInterface {
|
|
|
596
604
|
throw new ReqRespStatusError(ReqRespStatus.RATE_LIMIT_EXCEEDED);
|
|
597
605
|
}
|
|
598
606
|
|
|
607
|
+
// When p2pAllowOnlyValidators is enabled, reject unauthenticated peers on data protocols
|
|
608
|
+
if (
|
|
609
|
+
!UNAUTHENTICATED_ALLOWED_PROTOCOLS.has(protocol) &&
|
|
610
|
+
(this.shouldRejectPeer?.(connection.remotePeer.toString()) ?? false)
|
|
611
|
+
) {
|
|
612
|
+
this.logger.debug(`Rejecting unauthenticated peer ${connection.remotePeer} on gated protocol ${protocol}`);
|
|
613
|
+
throw new ReqRespStatusError(ReqRespStatus.FAILURE);
|
|
614
|
+
}
|
|
615
|
+
|
|
599
616
|
await this.processStream(protocol, incomingStream);
|
|
600
617
|
} catch (err: any) {
|
|
601
618
|
this.metrics.recordResponseError(protocol);
|
|
@@ -5,6 +5,7 @@ import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
|
5
5
|
import { retryUntil } from '@aztec/foundation/retry';
|
|
6
6
|
import { sleep } from '@aztec/foundation/sleep';
|
|
7
7
|
import { openTmpStore } from '@aztec/kv-store/lmdb-v2';
|
|
8
|
+
import { GasFees } from '@aztec/stdlib/gas';
|
|
8
9
|
import type { WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
|
|
9
10
|
import type { DataStoreConfig } from '@aztec/stdlib/kv-store';
|
|
10
11
|
|
|
@@ -102,6 +103,7 @@ export async function makeTestP2PClient(
|
|
|
102
103
|
proofVerifier,
|
|
103
104
|
mockWorldState,
|
|
104
105
|
mockEpochCache,
|
|
106
|
+
{ getCurrentMinFees: () => Promise.resolve(GasFees.empty()) },
|
|
105
107
|
'test-p2p-client',
|
|
106
108
|
undefined,
|
|
107
109
|
undefined,
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import type { EpochCacheInterface } from '@aztec/epoch-cache';
|
|
2
2
|
import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
3
|
+
import { sleep } from '@aztec/foundation/sleep';
|
|
3
4
|
import type { AztecAsyncKVStore } from '@aztec/kv-store';
|
|
4
5
|
import type { L2BlockSource } from '@aztec/stdlib/block';
|
|
5
6
|
import type { ContractDataSource } from '@aztec/stdlib/contract';
|
|
7
|
+
import type { BlockMinFeesProvider } from '@aztec/stdlib/gas';
|
|
6
8
|
import type { ClientProtocolCircuitVerifier, WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
|
|
7
9
|
import type { TelemetryClient } from '@aztec/telemetry-client';
|
|
8
10
|
|
|
@@ -55,6 +57,7 @@ export function getMockPubSubP2PServiceFactory(
|
|
|
55
57
|
proofVerifier: ClientProtocolCircuitVerifier;
|
|
56
58
|
worldStateSynchronizer: WorldStateSynchronizer;
|
|
57
59
|
peerStore: AztecAsyncKVStore;
|
|
60
|
+
blockMinFeesProvider: BlockMinFeesProvider;
|
|
58
61
|
telemetry: TelemetryClient;
|
|
59
62
|
logger: Logger;
|
|
60
63
|
},
|
|
@@ -75,6 +78,7 @@ export function getMockPubSubP2PServiceFactory(
|
|
|
75
78
|
deps.epochCache,
|
|
76
79
|
deps.proofVerifier,
|
|
77
80
|
deps.worldStateSynchronizer,
|
|
81
|
+
deps.blockMinFeesProvider,
|
|
78
82
|
deps.telemetry,
|
|
79
83
|
deps.logger,
|
|
80
84
|
);
|
|
@@ -100,6 +104,7 @@ class MockReqResp implements ReqRespInterface {
|
|
|
100
104
|
}
|
|
101
105
|
|
|
102
106
|
updateConfig(_config: Partial<P2PReqRespConfig>): void {}
|
|
107
|
+
setShouldRejectPeer(): void {}
|
|
103
108
|
|
|
104
109
|
start(
|
|
105
110
|
subProtocolHandlers: Partial<ReqRespSubProtocolHandlers>,
|
|
@@ -138,6 +143,11 @@ class MockReqResp implements ReqRespInterface {
|
|
|
138
143
|
const responses: InstanceType<SubProtocolMap[SubProtocol]['response']>[] = [];
|
|
139
144
|
const peers = this.network.getReqRespPeers().filter(p => !p.peerId.equals(this.peerId));
|
|
140
145
|
const targetPeers = pinnedPeer ? peers.filter(p => p.peerId.equals(pinnedPeer)) : peers;
|
|
146
|
+
const delayMs = this.network.getPropagationDelayMs();
|
|
147
|
+
|
|
148
|
+
if (delayMs > 0) {
|
|
149
|
+
await sleep(delayMs);
|
|
150
|
+
}
|
|
141
151
|
|
|
142
152
|
for (const request of requests) {
|
|
143
153
|
const requestBuffer = request.toBuffer();
|
|
@@ -174,7 +184,12 @@ class MockReqResp implements ReqRespInterface {
|
|
|
174
184
|
return { status: ReqRespStatus.SUCCESS, data: Buffer.from([]) };
|
|
175
185
|
}
|
|
176
186
|
try {
|
|
187
|
+
const delayMs = this.network.getPropagationDelayMs();
|
|
188
|
+
if (delayMs > 0) {
|
|
189
|
+
await sleep(delayMs);
|
|
190
|
+
}
|
|
177
191
|
const data = await handler(this.peerId, payload);
|
|
192
|
+
|
|
178
193
|
return { status: ReqRespStatus.SUCCESS, data };
|
|
179
194
|
} catch {
|
|
180
195
|
return { status: ReqRespStatus.FAILURE };
|
|
@@ -242,10 +257,10 @@ class MockGossipSubService extends TypedEventEmitter<GossipsubEvents> implements
|
|
|
242
257
|
score: (_peerId: PeerIdStr) => 0,
|
|
243
258
|
};
|
|
244
259
|
|
|
245
|
-
publish(topic: TopicStr, data: Uint8Array, _opts?: PublishOpts): Promise<PublishResult> {
|
|
260
|
+
async publish(topic: TopicStr, data: Uint8Array, _opts?: PublishOpts): Promise<PublishResult> {
|
|
246
261
|
this.logger.debug(`Publishing message on topic ${topic}`, { topic, sender: this.peerId.toString() });
|
|
247
|
-
this.network.publishToPeers(topic, data, this.peerId);
|
|
248
|
-
return
|
|
262
|
+
await this.network.publishToPeers(topic, data, this.peerId);
|
|
263
|
+
return { recipients: this.network.getPeers().filter(peer => !this.peerId.equals(peer)) };
|
|
249
264
|
}
|
|
250
265
|
|
|
251
266
|
receive(msg: GossipsubMessage) {
|
|
@@ -281,7 +296,8 @@ class MockGossipSubService extends TypedEventEmitter<GossipsubEvents> implements
|
|
|
281
296
|
|
|
282
297
|
/**
|
|
283
298
|
* Mock gossip sub network used for testing.
|
|
284
|
-
* All instances of MockGossipSubService connected to the same network
|
|
299
|
+
* All instances of MockGossipSubService connected to the same network receive the same messages,
|
|
300
|
+
* optionally delayed by a configurable propagation time.
|
|
285
301
|
*/
|
|
286
302
|
export class MockGossipSubNetwork {
|
|
287
303
|
private peers: MockGossipSubService[] = [];
|
|
@@ -290,6 +306,15 @@ export class MockGossipSubNetwork {
|
|
|
290
306
|
|
|
291
307
|
private logger = createLogger('p2p:test:mock-gossipsub-network');
|
|
292
308
|
|
|
309
|
+
constructor(
|
|
310
|
+
/** Artificial propagation delay in milliseconds applied to each message delivery. */
|
|
311
|
+
private propagationDelayMs: number = 0,
|
|
312
|
+
) {}
|
|
313
|
+
|
|
314
|
+
public getPropagationDelayMs(): number {
|
|
315
|
+
return this.propagationDelayMs;
|
|
316
|
+
}
|
|
317
|
+
|
|
293
318
|
public getPeers(): PeerId[] {
|
|
294
319
|
return this.peers.map(peer => peer.peerId);
|
|
295
320
|
}
|
|
@@ -306,7 +331,7 @@ export class MockGossipSubNetwork {
|
|
|
306
331
|
return this.reqRespPeers;
|
|
307
332
|
}
|
|
308
333
|
|
|
309
|
-
public publishToPeers(topic: TopicStr, data: Uint8Array, sender: PeerId): void {
|
|
334
|
+
public async publishToPeers(topic: TopicStr, data: Uint8Array, sender: PeerId): Promise<void> {
|
|
310
335
|
const msgId = (this.nextMsgId++).toString();
|
|
311
336
|
this.logger.debug(`Network is distributing message on topic ${topic}`, {
|
|
312
337
|
topic,
|
|
@@ -315,6 +340,10 @@ export class MockGossipSubNetwork {
|
|
|
315
340
|
msgId,
|
|
316
341
|
});
|
|
317
342
|
|
|
343
|
+
if (this.propagationDelayMs > 0) {
|
|
344
|
+
await sleep(this.propagationDelayMs);
|
|
345
|
+
}
|
|
346
|
+
|
|
318
347
|
const gossipSubMsg: GossipsubMessage = { msgId, msg: { type: 'unsigned', topic, data }, propagationSource: sender };
|
|
319
348
|
for (const peer of this.peers) {
|
|
320
349
|
if (peer.subscribedTopics.has(topic)) {
|
|
@@ -6,6 +6,7 @@ import { openTmpStore } from '@aztec/kv-store/lmdb-v2';
|
|
|
6
6
|
import type { L2BlockSource } from '@aztec/stdlib/block';
|
|
7
7
|
import { type ChainConfig, emptyChainConfig } from '@aztec/stdlib/config';
|
|
8
8
|
import type { ContractDataSource } from '@aztec/stdlib/contract';
|
|
9
|
+
import { GasFees } from '@aztec/stdlib/gas';
|
|
9
10
|
import type {
|
|
10
11
|
ClientProtocolCircuitVerifier,
|
|
11
12
|
IVCProofVerificationResult,
|
|
@@ -153,6 +154,8 @@ export async function createTestLibP2PService(
|
|
|
153
154
|
epochCache,
|
|
154
155
|
);
|
|
155
156
|
|
|
157
|
+
reqresp.setShouldRejectPeer(peerId => peerManager.shouldDisableP2PGossip(peerId));
|
|
158
|
+
|
|
156
159
|
p2pNode.services.pubsub.score.params.appSpecificWeight = APP_SPECIFIC_WEIGHT;
|
|
157
160
|
p2pNode.services.pubsub.score.params.appSpecificScore = (peerId: string) =>
|
|
158
161
|
peerManager.shouldDisableP2PGossip(peerId) ? -Infinity : peerManager.getPeerScore(peerId);
|
|
@@ -168,6 +171,7 @@ export async function createTestLibP2PService(
|
|
|
168
171
|
epochCache,
|
|
169
172
|
proofVerifier,
|
|
170
173
|
worldStateSynchronizer,
|
|
174
|
+
{ getCurrentMinFees: () => Promise.resolve(GasFees.empty()) },
|
|
171
175
|
telemetry,
|
|
172
176
|
);
|
|
173
177
|
}
|
|
@@ -187,7 +191,6 @@ export const MOCK_SUB_PROTOCOL_HANDLERS: ReqRespSubProtocolHandlers = {
|
|
|
187
191
|
[ReqRespSubProtocol.STATUS]: (_msg: any) => Promise.resolve(Buffer.from('status')),
|
|
188
192
|
[ReqRespSubProtocol.TX]: (_msg: any) => Promise.resolve(Buffer.from('tx')),
|
|
189
193
|
[ReqRespSubProtocol.GOODBYE]: (_msg: any) => Promise.resolve(Buffer.from('goodbye')),
|
|
190
|
-
[ReqRespSubProtocol.BLOCK]: (_msg: any) => Promise.resolve(Buffer.from('block')),
|
|
191
194
|
[ReqRespSubProtocol.AUTH]: (_msg: any) => Promise.resolve(Buffer.from('auth')),
|
|
192
195
|
[ReqRespSubProtocol.BLOCK_TXS]: (_msg: any) => Promise.resolve(Buffer.from('block_txs')),
|
|
193
196
|
};
|
|
@@ -199,7 +202,6 @@ export const MOCK_SUB_PROTOCOL_VALIDATORS: ReqRespSubProtocolValidators = {
|
|
|
199
202
|
[ReqRespSubProtocol.STATUS]: noopValidator,
|
|
200
203
|
[ReqRespSubProtocol.TX]: noopValidator,
|
|
201
204
|
[ReqRespSubProtocol.GOODBYE]: noopValidator,
|
|
202
|
-
[ReqRespSubProtocol.BLOCK]: noopValidator,
|
|
203
205
|
[ReqRespSubProtocol.AUTH]: noopValidator,
|
|
204
206
|
[ReqRespSubProtocol.BLOCK_TXS]: noopValidator,
|
|
205
207
|
};
|
|
@@ -287,6 +287,7 @@ export function createMockEpochCache(): EpochCacheInterface {
|
|
|
287
287
|
nowMs: 0n,
|
|
288
288
|
}),
|
|
289
289
|
isProposerPipeliningEnabled: () => false,
|
|
290
|
+
pipeliningOffset: () => 0,
|
|
290
291
|
computeProposerIndex: () => 0n,
|
|
291
292
|
getCurrentAndNextSlot: () => ({ currentSlot: SlotNumber.ZERO, nextSlot: SlotNumber.ZERO }),
|
|
292
293
|
getTargetAndNextSlot: () => ({ targetSlot: SlotNumber.ZERO, nextSlot: SlotNumber.ZERO }),
|