@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
|
@@ -372,12 +372,15 @@ function _apply_decs_2203_r(targetClass, memberDecs, classDecs, parentClass) {
|
|
|
372
372
|
}
|
|
373
373
|
var _dec, _dec1, _dec2, _dec3, _dec4, _dec5, _initProto;
|
|
374
374
|
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
375
|
-
import { maxBy, merge } from '@aztec/foundation/collection';
|
|
375
|
+
import { compactArray, maxBy, merge } from '@aztec/foundation/collection';
|
|
376
376
|
import { createLibp2pComponentLogger, createLogger } from '@aztec/foundation/log';
|
|
377
377
|
import { RunningPromise } from '@aztec/foundation/running-promise';
|
|
378
378
|
import { Timer } from '@aztec/foundation/timer';
|
|
379
379
|
import { protocolContractsHash } from '@aztec/protocol-contracts';
|
|
380
|
+
import { DEFAULT_MAX_BLOCKS_PER_CHECKPOINT } from '@aztec/stdlib/config';
|
|
381
|
+
import { getNetworkTxGasLimits } from '@aztec/stdlib/gas';
|
|
380
382
|
import { BlockProposal, CheckpointAttestation, CheckpointProposal, P2PMessage, PeerErrorSeverity, PeerErrorSeverityByHarshness, TopicType, createTopicString, getTopicsForConfig, metricsTopicStrToLabels } from '@aztec/stdlib/p2p';
|
|
383
|
+
import { ConsensusTimetable, getDefaultCheckpointProposalSyncGrace } from '@aztec/stdlib/timetable';
|
|
381
384
|
import { MerkleTreeId } from '@aztec/stdlib/trees';
|
|
382
385
|
import { Tx } from '@aztec/stdlib/tx';
|
|
383
386
|
import { compressComponentVersions } from '@aztec/stdlib/versioning';
|
|
@@ -404,14 +407,27 @@ import { convertToMultiaddr } from '../../util.js';
|
|
|
404
407
|
import { getVersions } from '../../versioning.js';
|
|
405
408
|
import { AztecDatastore } from '../data_store.js';
|
|
406
409
|
import { DiscV5Service } from '../discv5/discV5_service.js';
|
|
407
|
-
import { SnappyTransform,
|
|
410
|
+
import { SnappyTransform, getMsgIdFn, msgIdToStrFn } from '../encoding.js';
|
|
408
411
|
import { APP_SPECIFIC_WEIGHT, gossipScoreThresholds } from '../gossipsub/scoring.js';
|
|
409
412
|
import { createAllTopicScoreParams } from '../gossipsub/topic_score_params.js';
|
|
410
413
|
import { PeerManager } from '../peer-manager/peer_manager.js';
|
|
411
414
|
import { PeerScoring } from '../peer-manager/peer_scoring.js';
|
|
415
|
+
import { YAMUX_MAX_MESSAGE_SIZE_BYTES } from '../reqresp/config.js';
|
|
412
416
|
import { ReqRespSubProtocol, ValidationError, pingHandler, reqGoodbyeHandler, reqRespBlockTxsHandler, reqRespStatusHandler, reqRespTxHandler } from '../reqresp/index.js';
|
|
413
417
|
import { ReqResp } from '../reqresp/reqresp.js';
|
|
414
418
|
import { P2PInstrumentation } from './instrumentation.js';
|
|
419
|
+
/**
|
|
420
|
+
* Builds the {@link ConsensusTimetable} shared by the gossip validators for proposal/attestation receive-window
|
|
421
|
+
* bounds. Derived purely from protocol slot-timing constants plus the block sub-slot duration and the consensus
|
|
422
|
+
* materialization grace, so every node agrees on these bounds without depending on proposer operational budgets.
|
|
423
|
+
*/ function buildConsensusTimetable(config, l1Constants) {
|
|
424
|
+
const blockDuration = config.blockDurationMs / 1000;
|
|
425
|
+
return new ConsensusTimetable({
|
|
426
|
+
l1Constants,
|
|
427
|
+
blockDuration,
|
|
428
|
+
checkpointProposalSyncGrace: config.checkpointProposalSyncGraceSeconds ?? getDefaultCheckpointProposalSyncGrace(blockDuration)
|
|
429
|
+
});
|
|
430
|
+
}
|
|
415
431
|
_dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId, attestation)=>({
|
|
416
432
|
[Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber.toString()
|
|
417
433
|
})), _dec1 = trackSpan('Libp2pService.validateAndStoreBlockProposal', (_peerId, block)=>({
|
|
@@ -488,6 +504,7 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
488
504
|
protocolVersion;
|
|
489
505
|
topicStrings;
|
|
490
506
|
/** Callback invoked when a duplicate proposal is detected (triggers slashing). */ duplicateProposalCallback;
|
|
507
|
+
/** Callback invoked when an oversized block proposal is stored as slashing evidence (triggers slashing). */ oversizedProposalCallback;
|
|
491
508
|
/** Callback invoked when a duplicate attestation is detected (triggers slashing). */ duplicateAttestationCallback;
|
|
492
509
|
/** Callback invoked when a valid checkpoint attestation is accepted into the pool. */ checkpointAttestationCallback;
|
|
493
510
|
/**
|
|
@@ -528,26 +545,27 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
528
545
|
this.topicStrings[TopicType.block_proposal] = createTopicString(TopicType.block_proposal, this.protocolVersion);
|
|
529
546
|
this.topicStrings[TopicType.checkpoint_proposal] = createTopicString(TopicType.checkpoint_proposal, this.protocolVersion);
|
|
530
547
|
this.topicStrings[TopicType.checkpoint_attestation] = createTopicString(TopicType.checkpoint_attestation, this.protocolVersion);
|
|
531
|
-
|
|
548
|
+
// Build the consensus timetable once from protocol slot-timing constants and inject it into every
|
|
549
|
+
// validator so they share one set of receive-window bounds, independent of proposer operational budgets.
|
|
550
|
+
const consensusTimetable = buildConsensusTimetable(config, epochCache.getL1Constants());
|
|
532
551
|
const proposalValidatorOpts = {
|
|
533
552
|
txsPermitted: !config.disableTransactions,
|
|
534
553
|
maxTxsPerBlock: config.validateMaxTxsPerBlock ?? config.validateMaxTxsPerCheckpoint,
|
|
535
554
|
maxBlocksPerCheckpoint: config.maxBlocksPerCheckpoint,
|
|
536
|
-
p2pPropagationTime,
|
|
537
555
|
skipSlotValidation: config.skipProposalSlotValidation,
|
|
538
556
|
signatureContext: {
|
|
539
557
|
chainId: config.l1ChainId,
|
|
540
558
|
rollupAddress: config.rollupAddress
|
|
541
|
-
}
|
|
559
|
+
},
|
|
560
|
+
clockDisparityMs: config.maxGossipClockDisparityMs
|
|
542
561
|
};
|
|
543
|
-
this.blockProposalValidator = new BlockProposalValidator(epochCache, proposalValidatorOpts);
|
|
544
|
-
this.checkpointProposalValidator = new CheckpointProposalValidator(epochCache, proposalValidatorOpts);
|
|
562
|
+
this.blockProposalValidator = new BlockProposalValidator(epochCache, consensusTimetable, proposalValidatorOpts);
|
|
563
|
+
this.checkpointProposalValidator = new CheckpointProposalValidator(epochCache, consensusTimetable, proposalValidatorOpts);
|
|
545
564
|
const attestationValidatorOpts = {
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
signatureContext: proposalValidatorOpts.signatureContext
|
|
565
|
+
signatureContext: proposalValidatorOpts.signatureContext,
|
|
566
|
+
clockDisparityMs: config.maxGossipClockDisparityMs
|
|
549
567
|
};
|
|
550
|
-
this.checkpointAttestationValidator = config.fishermanMode ? new FishermanAttestationValidator(epochCache, mempools.attestationPool, telemetry, attestationValidatorOpts) : new CheckpointAttestationValidator(epochCache, attestationValidatorOpts);
|
|
568
|
+
this.checkpointAttestationValidator = config.fishermanMode ? new FishermanAttestationValidator(epochCache, consensusTimetable, mempools.attestationPool, telemetry, attestationValidatorOpts) : new CheckpointAttestationValidator(epochCache, consensusTimetable, attestationValidatorOpts);
|
|
551
569
|
this.gossipSubEventHandler = this.handleGossipSubEvent.bind(this);
|
|
552
570
|
this.blockReceivedCallback = async (block)=>{
|
|
553
571
|
this.logger.warn(`Handler for block received not yet registered on P2P service. Received block ${block.blockNumber} for slot ${block.slotNumber} from peer.`, {
|
|
@@ -577,7 +595,7 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
577
595
|
const bindAddrTcp = convertToMultiaddr(listenAddress, p2pPort, 'tcp');
|
|
578
596
|
const datastore = new AztecDatastore(peerStore);
|
|
579
597
|
const otelMetricsAdapter = new OtelMetricsAdapter(telemetry, logger.getBindings());
|
|
580
|
-
const peerDiscoveryService = new DiscV5Service(peerId, config, packageVersion, telemetry, createLogger(`${logger.module}:discv5_service`, logger.getBindings()));
|
|
598
|
+
const peerDiscoveryService = new DiscV5Service(peerId, config, packageVersion, telemetry, createLogger(`${logger.module}:discv5_service`, logger.getBindings()), peerStore);
|
|
581
599
|
// Seed libp2p's bootstrap discovery with private and trusted peers
|
|
582
600
|
const bootstrapNodes = [
|
|
583
601
|
...config.privatePeers,
|
|
@@ -592,34 +610,45 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
592
610
|
const versions = getVersions(config);
|
|
593
611
|
const protocolVersion = compressComponentVersions(versions);
|
|
594
612
|
const preferredPeersEnrs = config.preferredPeers.map((enr)=>ENR.decodeTxt(enr));
|
|
595
|
-
const directPeers = (await Promise.all(preferredPeersEnrs.map(async (enr)=>{
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
613
|
+
const directPeers = compactArray(await Promise.all(preferredPeersEnrs.map(async (enr)=>{
|
|
614
|
+
try {
|
|
615
|
+
const peerId = await enr.peerId();
|
|
616
|
+
const address = enr.getLocationMultiaddr('tcp');
|
|
617
|
+
if (address === undefined) {
|
|
618
|
+
throw new Error(`Direct peer ${peerId.toString()} has no TCP address, ENR: ${enr.encodeTxt()}`);
|
|
619
|
+
}
|
|
620
|
+
return {
|
|
621
|
+
id: peerId,
|
|
622
|
+
addrs: [
|
|
623
|
+
address
|
|
624
|
+
]
|
|
625
|
+
};
|
|
626
|
+
} catch (err) {
|
|
627
|
+
// A malformed configured ENR shouldn't abort node setup — skip it and log.
|
|
628
|
+
logger.warn(`Skipping preferred peer with invalid ENR`, {
|
|
629
|
+
err
|
|
630
|
+
});
|
|
631
|
+
return undefined;
|
|
600
632
|
}
|
|
601
|
-
|
|
602
|
-
id: peerId,
|
|
603
|
-
addrs: [
|
|
604
|
-
address
|
|
605
|
-
]
|
|
606
|
-
};
|
|
607
|
-
}))).filter((peer)=>peer !== undefined);
|
|
633
|
+
})));
|
|
608
634
|
const announceTcpMultiaddr = config.p2pIp ? [
|
|
609
635
|
convertToMultiaddr(config.p2pIp, p2pPort, 'tcp')
|
|
610
636
|
] : [];
|
|
611
|
-
// Create dynamic topic score params based on network configuration
|
|
637
|
+
// Create dynamic topic score params based on network configuration. Scoring uses the network-wide
|
|
638
|
+
// max-blocks-per-checkpoint config value directly to size expected per-slot message rates; these are
|
|
639
|
+
// peer-rate thresholds, not consensus deadlines, so they need no proposer operational budgets.
|
|
612
640
|
const l1Constants = epochCache.getL1Constants();
|
|
613
641
|
const topicScoreParams = createAllTopicScoreParams(protocolVersion, {
|
|
614
642
|
slotDurationMs: l1Constants.slotDuration * 1000,
|
|
615
|
-
ethereumSlotDuration: l1Constants.ethereumSlotDuration,
|
|
616
643
|
heartbeatIntervalMs: config.gossipsubInterval,
|
|
617
644
|
targetCommitteeSize: l1Constants.targetCommitteeSize,
|
|
618
|
-
|
|
619
|
-
l1PublishingTime: config.l1PublishingTime,
|
|
620
|
-
p2pPropagationTime: config.attestationPropagationTime,
|
|
645
|
+
maxBlocksPerCheckpoint: config.maxBlocksPerCheckpoint ?? DEFAULT_MAX_BLOCKS_PER_CHECKPOINT,
|
|
621
646
|
expectedBlockProposalsPerSlot: config.expectedBlockProposalsPerSlot
|
|
622
647
|
});
|
|
648
|
+
// Restrict gossipsub to exactly the topics we subscribe to. Without this, an arbitrary-topic
|
|
649
|
+
// message is transformed, msg-id'd and inserted into the seenCache before the subscription check,
|
|
650
|
+
// so a crafted topic colliding on msg id can suppress a real message as a duplicate.
|
|
651
|
+
const allowedTopics = getTopicsForConfig(config.disableTransactions).map((topic)=>createTopicString(topic, protocolVersion));
|
|
623
652
|
const node = await createLibp2p({
|
|
624
653
|
start: false,
|
|
625
654
|
peerId,
|
|
@@ -653,8 +682,11 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
653
682
|
],
|
|
654
683
|
datastore,
|
|
655
684
|
peerDiscovery,
|
|
685
|
+
// Pin the yamux frame size: MAX_REQRESP_REQUEST_SIZE_BYTES relies on a reqresp request fitting in one frame.
|
|
656
686
|
streamMuxers: [
|
|
657
|
-
yamux(
|
|
687
|
+
yamux({
|
|
688
|
+
maxMessageSize: YAMUX_MAX_MESSAGE_SIZE_BYTES
|
|
689
|
+
}),
|
|
658
690
|
mplex()
|
|
659
691
|
],
|
|
660
692
|
connectionEncryption: [
|
|
@@ -672,7 +704,7 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
672
704
|
},
|
|
673
705
|
connectionGater: {
|
|
674
706
|
denyInboundConnection: (maConn)=>{
|
|
675
|
-
const allowed = peerManager.
|
|
707
|
+
const allowed = peerManager.isAddressAllowedToConnect(maConn.remoteAddr.nodeAddress().address);
|
|
676
708
|
if (allowed) {
|
|
677
709
|
return false;
|
|
678
710
|
}
|
|
@@ -682,7 +714,7 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
682
714
|
denyInboundEncryptedConnection: (peerId, _maConn)=>{
|
|
683
715
|
//NOTE: it is not necessary to check address here because this was already done by
|
|
684
716
|
// denyInboundConnection
|
|
685
|
-
const allowed = peerManager.
|
|
717
|
+
const allowed = peerManager.isPeerAllowedToConnect(peerId);
|
|
686
718
|
if (allowed) {
|
|
687
719
|
return false;
|
|
688
720
|
}
|
|
@@ -709,9 +741,13 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
709
741
|
mcacheLength: config.gossipsubMcacheLength,
|
|
710
742
|
mcacheGossip: config.gossipsubMcacheGossip,
|
|
711
743
|
seenTTL: config.gossipsubSeenTTL,
|
|
744
|
+
allowedTopics,
|
|
745
|
+
// No fastMsgIdFn: the fast-path dedup cache keys on a non-cryptographic 64-bit hash of the
|
|
746
|
+
// raw data only (no topic), so a collision — accidental or engineered via a weak seed — drops
|
|
747
|
+
// a different message with no fallback to the full id. Dedup instead rests solely on the
|
|
748
|
+
// cryptographic, topic-framed msgIdFn below.
|
|
712
749
|
msgIdFn: getMsgIdFn,
|
|
713
750
|
msgIdToStrFn: msgIdToStrFn,
|
|
714
|
-
fastMsgIdFn: fastMsgIdFn,
|
|
715
751
|
dataTransform: new SnappyTransform(),
|
|
716
752
|
metricsRegister: otelMetricsAdapter,
|
|
717
753
|
metricsTopicStrToLabel: metricsTopicStrToLabels(protocolVersion),
|
|
@@ -896,6 +932,11 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
896
932
|
this.duplicateProposalCallback = callback;
|
|
897
933
|
}
|
|
898
934
|
/**
|
|
935
|
+
* Registers a callback to be invoked when an oversized block proposal is stored as slashing evidence.
|
|
936
|
+
*/ registerOversizedProposalCallback(callback) {
|
|
937
|
+
this.oversizedProposalCallback = callback;
|
|
938
|
+
}
|
|
939
|
+
/**
|
|
899
940
|
* Registers a callback to be invoked when a duplicate attestation is detected.
|
|
900
941
|
* A validator signing attestations for different proposals at the same slot.
|
|
901
942
|
* This callback is triggered on the first duplicate (when count goes from 1 to 2).
|
|
@@ -1342,9 +1383,10 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1342
1383
|
};
|
|
1343
1384
|
}
|
|
1344
1385
|
async processBlockFromPeer(payloadData, msgId, source) {
|
|
1345
|
-
const { result, obj: block, metadata: { isEquivocated } = {} } = await this.validateReceivedMessage(()=>this.validateAndStoreBlockProposal(source, BlockProposal.fromBuffer(payloadData)), msgId, source, TopicType.block_proposal);
|
|
1346
|
-
// If not accepted or
|
|
1347
|
-
|
|
1386
|
+
const { result, obj: block, metadata: { isEquivocated, isOversized } = {} } = await this.validateReceivedMessage(()=>this.validateAndStoreBlockProposal(source, BlockProposal.fromBuffer(payloadData)), msgId, source, TopicType.block_proposal);
|
|
1387
|
+
// If not accepted, equivocated, or oversized, return. Oversized proposals are re-broadcast as
|
|
1388
|
+
// slashing evidence but never attested or processed.
|
|
1389
|
+
if (result !== TopicValidatorResult.Accept || !block || isEquivocated || isOversized) {
|
|
1348
1390
|
return;
|
|
1349
1391
|
}
|
|
1350
1392
|
await this.processValidBlockProposal(block, source);
|
|
@@ -1367,6 +1409,10 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1367
1409
|
// Try to add the proposal: this handles existence check, cap check, and adding in one call
|
|
1368
1410
|
const { added, alreadyExists, count } = await this.mempools.attestationPool.tryAddBlockProposal(block);
|
|
1369
1411
|
const isEquivocated = count !== undefined && count > 1;
|
|
1412
|
+
// An oversized proposal (index at or beyond the consensus per-checkpoint limit) is structurally valid
|
|
1413
|
+
// proposer misbehavior: it is stored and re-broadcast as slashing evidence but never processed or
|
|
1414
|
+
// attested to. No-ops when maxBlocksPerCheckpoint is unset (local/test).
|
|
1415
|
+
const isOversized = this.config.maxBlocksPerCheckpoint !== undefined && block.indexWithinCheckpoint >= this.config.maxBlocksPerCheckpoint;
|
|
1370
1416
|
// Duplicate proposal received, no need to re-broadcast
|
|
1371
1417
|
if (alreadyExists) {
|
|
1372
1418
|
this.logger.debug(`Ignoring duplicate block proposal received`, {
|
|
@@ -1379,7 +1425,8 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1379
1425
|
result: TopicValidatorResult.Ignore,
|
|
1380
1426
|
obj: block,
|
|
1381
1427
|
metadata: {
|
|
1382
|
-
isEquivocated
|
|
1428
|
+
isEquivocated,
|
|
1429
|
+
isOversized
|
|
1383
1430
|
}
|
|
1384
1431
|
};
|
|
1385
1432
|
}
|
|
@@ -1395,11 +1442,30 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1395
1442
|
return {
|
|
1396
1443
|
result: TopicValidatorResult.Reject,
|
|
1397
1444
|
metadata: {
|
|
1398
|
-
isEquivocated
|
|
1445
|
+
isEquivocated,
|
|
1446
|
+
isOversized
|
|
1399
1447
|
},
|
|
1400
1448
|
severity: PeerErrorSeverity.HighToleranceError
|
|
1401
1449
|
};
|
|
1402
1450
|
}
|
|
1451
|
+
// The proposal was stored: if oversized, invoke the oversized callback so the proposer can be
|
|
1452
|
+
// slashed. Fired alongside (not instead of) equivocation detection below.
|
|
1453
|
+
if (isOversized) {
|
|
1454
|
+
const proposer = block.getSender();
|
|
1455
|
+
if (proposer) {
|
|
1456
|
+
this.logger.warn(`Detected oversized block proposal at slot ${block.slotNumber}`, {
|
|
1457
|
+
...block.toBlockInfo(),
|
|
1458
|
+
indexWithinCheckpoint: block.indexWithinCheckpoint,
|
|
1459
|
+
maxBlocksPerCheckpoint: this.config.maxBlocksPerCheckpoint,
|
|
1460
|
+
source: peerId.toString(),
|
|
1461
|
+
proposer: proposer.toString()
|
|
1462
|
+
});
|
|
1463
|
+
this.oversizedProposalCallback?.({
|
|
1464
|
+
slot: block.slotNumber,
|
|
1465
|
+
proposer
|
|
1466
|
+
});
|
|
1467
|
+
}
|
|
1468
|
+
}
|
|
1403
1469
|
// If this was a duplicate proposal, do not process it, but do invoke the duplicate callback,
|
|
1404
1470
|
// and do re-broadcast it so other nodes in the network know to slash the proposer
|
|
1405
1471
|
if (isEquivocated) {
|
|
@@ -1421,14 +1487,19 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1421
1487
|
result: TopicValidatorResult.Accept,
|
|
1422
1488
|
obj: block,
|
|
1423
1489
|
metadata: {
|
|
1424
|
-
isEquivocated
|
|
1490
|
+
isEquivocated,
|
|
1491
|
+
isOversized
|
|
1425
1492
|
}
|
|
1426
1493
|
};
|
|
1427
1494
|
}
|
|
1428
1495
|
// Otherwise, we're good to go!
|
|
1429
1496
|
return {
|
|
1430
1497
|
result: TopicValidatorResult.Accept,
|
|
1431
|
-
obj: block
|
|
1498
|
+
obj: block,
|
|
1499
|
+
metadata: {
|
|
1500
|
+
isEquivocated: false,
|
|
1501
|
+
isOversized
|
|
1502
|
+
}
|
|
1432
1503
|
};
|
|
1433
1504
|
}
|
|
1434
1505
|
// REFACTOR(palla): This method should be moved to the p2p_client or to a separate component,
|
|
@@ -1447,15 +1518,19 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1447
1518
|
const isValid = await this.blockReceivedCallback(block, sender);
|
|
1448
1519
|
if (!isValid) {
|
|
1449
1520
|
this.logger.info(`Block proposal validation failed for block ${block.blockNumber}`, block.toBlockInfo());
|
|
1521
|
+
// Release the protections this proposal created so its txs return to pending. Only entries still
|
|
1522
|
+
// keyed to this slot are cleared, so a tx referenced by a live proposal at another slot stays protected.
|
|
1523
|
+
await this.mempools.txPool.unprotectTxs(block.txHashes, slot);
|
|
1450
1524
|
}
|
|
1451
1525
|
}
|
|
1452
1526
|
/**
|
|
1453
1527
|
* Handle a gossiped checkpoint proposal.
|
|
1454
1528
|
* Validates and processes the checkpoint proposal, then triggers the callback for attestation.
|
|
1455
1529
|
*/ async handleGossipedCheckpointProposal(payloadData, msgId, source) {
|
|
1456
|
-
const { result, obj: checkpoint, metadata: { isEquivocated, processBlock } = {} } = await this.validateReceivedMessage(()=>this.validateAndStoreCheckpointProposal(source, CheckpointProposal.fromBuffer(payloadData)), msgId, source, TopicType.checkpoint_proposal);
|
|
1457
|
-
//
|
|
1458
|
-
|
|
1530
|
+
const { result, obj: checkpoint, metadata: { isEquivocated, processBlock, isOversized } = {} } = await this.validateReceivedMessage(()=>this.validateAndStoreCheckpointProposal(source, CheckpointProposal.fromBuffer(payloadData)), msgId, source, TopicType.checkpoint_proposal);
|
|
1531
|
+
// An oversized checkpoint is re-broadcast as slashing evidence but never attested or processed.
|
|
1532
|
+
// Process checkpoint proposal if valid and neither equivocated nor oversized.
|
|
1533
|
+
const processCheckpointFn = ()=>result === TopicValidatorResult.Accept && checkpoint && !isEquivocated && !isOversized ? this.processValidCheckpointProposal(checkpoint.toCore(), source) : Promise.resolve();
|
|
1459
1534
|
// If the checkpoint contained a valid last block, we process it even if the checkpoint itself is to be rejected
|
|
1460
1535
|
// TODO(palla/mbps): Is this ok? Should we be considering a block from a checkpoint that was equivocated?
|
|
1461
1536
|
const processBlockFn = ()=>processBlock && checkpoint && checkpoint.getBlockProposal() ? this.processValidBlockProposal(checkpoint.getBlockProposal(), source) : Promise.resolve();
|
|
@@ -1494,13 +1569,15 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1494
1569
|
// Extract and try to add the block proposal first if present
|
|
1495
1570
|
const blockProposal = checkpoint.getBlockProposal();
|
|
1496
1571
|
let processBlock = false;
|
|
1572
|
+
let isOversized = false;
|
|
1497
1573
|
if (blockProposal) {
|
|
1498
1574
|
this.logger.debug(`Validating block proposal from propagated checkpoint`, {
|
|
1499
1575
|
[Attributes.SLOT_NUMBER]: checkpoint.slotNumber.toString(),
|
|
1500
1576
|
[Attributes.P2P_ID]: peerId.toString()
|
|
1501
1577
|
});
|
|
1502
1578
|
const blockProposalResult = await this.validateAndStoreBlockProposal(peerId, blockProposal);
|
|
1503
|
-
const { obj, metadata: { isEquivocated } = {} } = blockProposalResult;
|
|
1579
|
+
const { obj, metadata: { isEquivocated, isOversized: blockIsOversized } = {} } = blockProposalResult;
|
|
1580
|
+
isOversized = blockIsOversized ?? false;
|
|
1504
1581
|
if (blockProposalResult.result === TopicValidatorResult.Reject || !obj || isEquivocated) {
|
|
1505
1582
|
this.logger.debug(`Rejecting checkpoint due to invalid last block proposal`, {
|
|
1506
1583
|
[Attributes.SLOT_NUMBER]: checkpoint.slotNumber.toString(),
|
|
@@ -1512,7 +1589,8 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1512
1589
|
result: TopicValidatorResult.Reject,
|
|
1513
1590
|
severity: 'severity' in blockProposalResult ? blockProposalResult.severity : PeerErrorSeverity.MidToleranceError
|
|
1514
1591
|
};
|
|
1515
|
-
} else if (blockProposalResult.result === TopicValidatorResult.Accept && obj && !isEquivocated) {
|
|
1592
|
+
} else if (blockProposalResult.result === TopicValidatorResult.Accept && obj && !isEquivocated && !isOversized) {
|
|
1593
|
+
// An oversized terminal block is re-broadcast as slashing evidence but never processed.
|
|
1516
1594
|
processBlock = true;
|
|
1517
1595
|
}
|
|
1518
1596
|
}
|
|
@@ -1532,11 +1610,12 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1532
1610
|
obj: checkpoint,
|
|
1533
1611
|
metadata: {
|
|
1534
1612
|
isEquivocated,
|
|
1535
|
-
processBlock
|
|
1613
|
+
processBlock,
|
|
1614
|
+
isOversized
|
|
1536
1615
|
}
|
|
1537
1616
|
};
|
|
1538
1617
|
}
|
|
1539
|
-
// Too many checkpoint proposals received for this slot, penalize peer and do not re-broadcast
|
|
1618
|
+
// Too many checkpoint proposals received for this slot, penalize peer and do not re-broadcast.
|
|
1540
1619
|
// Note: We still return the checkpoint obj so the lastBlock can be processed if valid
|
|
1541
1620
|
if (!added) {
|
|
1542
1621
|
this.logger.warn(`Penalizing peer for checkpoint proposal exceeding per-slot cap`, {
|
|
@@ -1549,7 +1628,8 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1549
1628
|
obj: checkpoint,
|
|
1550
1629
|
metadata: {
|
|
1551
1630
|
isEquivocated,
|
|
1552
|
-
processBlock
|
|
1631
|
+
processBlock,
|
|
1632
|
+
isOversized
|
|
1553
1633
|
},
|
|
1554
1634
|
severity: PeerErrorSeverity.HighToleranceError
|
|
1555
1635
|
};
|
|
@@ -1576,7 +1656,8 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1576
1656
|
obj: checkpoint,
|
|
1577
1657
|
metadata: {
|
|
1578
1658
|
isEquivocated,
|
|
1579
|
-
processBlock
|
|
1659
|
+
processBlock,
|
|
1660
|
+
isOversized
|
|
1580
1661
|
}
|
|
1581
1662
|
};
|
|
1582
1663
|
}
|
|
@@ -1586,7 +1667,8 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1586
1667
|
obj: checkpoint,
|
|
1587
1668
|
metadata: {
|
|
1588
1669
|
processBlock,
|
|
1589
|
-
isEquivocated
|
|
1670
|
+
isEquivocated,
|
|
1671
|
+
isOversized
|
|
1590
1672
|
}
|
|
1591
1673
|
};
|
|
1592
1674
|
}
|
|
@@ -1738,10 +1820,10 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1738
1820
|
];
|
|
1739
1821
|
const blockNumber = BlockNumber(currentBlockNumber + 1);
|
|
1740
1822
|
const l1Constants = await this.archiver.getL1Constants();
|
|
1823
|
+
const networkTxGasLimits = getNetworkTxGasLimits(this.config, l1Constants);
|
|
1741
1824
|
return createFirstStageTxValidationsForGossipedTransactions(nextSlotTimestamp, blockNumber, this.worldStateSynchronizer, gasFees, this.config.l1ChainId, this.config.rollupVersion, protocolContractsHash, this.archiver, !this.config.disableTransactions, allowedInSetup, this.logger.getBindings(), {
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
maxBlockDAGas: this.config.validateMaxDABlockGas
|
|
1825
|
+
maxTxL2Gas: networkTxGasLimits.l2Gas,
|
|
1826
|
+
maxTxDAGas: networkTxGasLimits.daGas
|
|
1745
1827
|
});
|
|
1746
1828
|
}
|
|
1747
1829
|
/** Creates the second stage (expensive proof verification) validators for gossiped transactions. */ createSecondStageMessageValidators() {
|
|
@@ -129,7 +129,20 @@ export declare class PeerManager implements PeerManagerInterface {
|
|
|
129
129
|
shouldDisableP2PGossip(peerId: string): boolean;
|
|
130
130
|
getPeers(includePending?: boolean): PeerInfo[];
|
|
131
131
|
isAuthenticatedPeer(peerId: PeerId): boolean;
|
|
132
|
-
|
|
132
|
+
/**
|
|
133
|
+
* Whether a peer is allowed to connect, given its peer id. Rejects peers serving an active ban and
|
|
134
|
+
* peers that have exceeded the failed auth-handshake limit. Use this once the peer id is known —
|
|
135
|
+
* i.e. for the encrypted-inbound gater and when dialing.
|
|
136
|
+
*/
|
|
137
|
+
isPeerAllowedToConnect(peerId: string | PeerId): boolean;
|
|
138
|
+
/**
|
|
139
|
+
* Whether a connection from an address is allowed. Bans are keyed by peer id, which isn't known at
|
|
140
|
+
* the raw-inbound layer, so only the failed auth-handshake limit (also tracked per address) is
|
|
141
|
+
* enforced here; the ban is applied once the peer id is known via {@link isPeerAllowedToConnect}.
|
|
142
|
+
*/
|
|
143
|
+
isAddressAllowedToConnect(address: string): boolean;
|
|
144
|
+
/** Whether the failed auth-handshake count for a peer id or address is below the configured limit. */
|
|
145
|
+
private isWithinFailedAuthLimit;
|
|
133
146
|
/**
|
|
134
147
|
* Discovers peers.
|
|
135
148
|
*/
|
|
@@ -175,4 +188,4 @@ export declare class PeerManager implements PeerManagerInterface {
|
|
|
175
188
|
handleAuthRequestFromPeer(_authRequest: AuthRequest, peerId: PeerId): Promise<StatusMessage>;
|
|
176
189
|
private updateAuthenticatedPeers;
|
|
177
190
|
}
|
|
178
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
191
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGVlcl9tYW5hZ2VyLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvc2VydmljZXMvcGVlci1tYW5hZ2VyL3BlZXJfbWFuYWdlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssRUFBRSxtQkFBbUIsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBSTlELE9BQU8sS0FBSyxFQUFFLFVBQVUsRUFBRSxNQUFNLCtCQUErQixDQUFDO0FBR2hFLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUN2RCxPQUFPLEtBQUssRUFBRSxRQUFRLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUN4RixPQUFPLEtBQUssRUFBRSxpQkFBaUIsRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBQzNELE9BQU8sS0FBSyxFQUFFLGVBQWUsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBRS9ELE9BQU8sS0FBSyxFQUFjLE1BQU0sRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBTTVELE9BQU8sS0FBSyxFQUFFLFNBQVMsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBRWpELE9BQU8sS0FBSyxFQUFFLFVBQVUsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUVoRCxPQUFPLEVBQUUsV0FBVyxFQUFnQixNQUFNLDhCQUE4QixDQUFDO0FBQ3pFLE9BQU8sRUFBRSxhQUFhLEVBQXVCLE1BQU0saUNBQWlDLENBQUM7QUFDckYsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBQy9ELE9BQU8sS0FBSyxFQUFFLE9BQU8sRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBRXJELE9BQU8sS0FBSyxFQUFFLG9CQUFvQixFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQzFELE9BQU8sS0FBSyxFQUFFLG9CQUFvQixFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFFM0QsT0FBTyxFQUFrQixLQUFLLFdBQVcsRUFBRSxNQUFNLG1C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
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"peer_manager.d.ts","sourceRoot":"","sources":["../../../src/services/peer-manager/peer_manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"peer_manager.d.ts","sourceRoot":"","sources":["../../../src/services/peer-manager/peer_manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { compactArray } from '@aztec/foundation/collection';
|
|
1
2
|
import { makeEthSignDigest, tryRecoverAddress } from '@aztec/foundation/crypto/secp256k1-signer';
|
|
2
3
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
3
4
|
import { createLogger } from '@aztec/foundation/log';
|
|
@@ -127,6 +128,7 @@ export class PeerManager {
|
|
|
127
128
|
async heartbeat() {
|
|
128
129
|
this.heartbeatCounter++;
|
|
129
130
|
this.peerScoring.decayAllScores();
|
|
131
|
+
this.peerScoring.pruneExpiredBans();
|
|
130
132
|
this.cleanupExpiredTimeouts();
|
|
131
133
|
await this.setupDirectPeersIfValidator();
|
|
132
134
|
await this.updateAuthenticatedPeers();
|
|
@@ -150,19 +152,27 @@ export class PeerManager {
|
|
|
150
152
|
}
|
|
151
153
|
const preferredPeersEnrs = this.config.preferredPeers.map((enr)=>ENR.decodeTxt(enr));
|
|
152
154
|
await Promise.all(preferredPeersEnrs.map((enr)=>enr.peerId())).then((peerIds)=>peerIds.forEach((peerId)=>this.preferredPeers.add(peerId.toString()))).catch((e)=>this.logger.error('Error initializing preferred peers', e));
|
|
153
|
-
const directPeers = (await Promise.all(preferredPeersEnrs.map(async (enr)=>{
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
155
|
+
const directPeers = compactArray(await Promise.all(preferredPeersEnrs.map(async (enr)=>{
|
|
156
|
+
try {
|
|
157
|
+
const peerId = await enr.peerId();
|
|
158
|
+
const address = enr.getLocationMultiaddr('tcp');
|
|
159
|
+
if (address === undefined) {
|
|
160
|
+
throw new Error(`Direct peer ${peerId.toString()} has no TCP address, ENR: ${enr.encodeTxt()}`);
|
|
161
|
+
}
|
|
162
|
+
return {
|
|
163
|
+
id: peerId,
|
|
164
|
+
addrs: [
|
|
165
|
+
address
|
|
166
|
+
]
|
|
167
|
+
};
|
|
168
|
+
} catch (err) {
|
|
169
|
+
// A malformed configured ENR shouldn't abort preferred-peer setup — skip it and log.
|
|
170
|
+
this.logger.warn(`Skipping preferred peer with invalid ENR`, {
|
|
171
|
+
err
|
|
172
|
+
});
|
|
173
|
+
return undefined;
|
|
158
174
|
}
|
|
159
|
-
|
|
160
|
-
id: peerId,
|
|
161
|
-
addrs: [
|
|
162
|
-
address
|
|
163
|
-
]
|
|
164
|
-
};
|
|
165
|
-
}))).filter((peer)=>peer !== undefined);
|
|
175
|
+
})));
|
|
166
176
|
await Promise.all(directPeers.map((peer)=>{
|
|
167
177
|
this.libP2PNode.services.pubsub.direct.add(peer.id.toString());
|
|
168
178
|
return this.libP2PNode.peerStore.merge(peer.id, {
|
|
@@ -390,14 +400,32 @@ export class PeerManager {
|
|
|
390
400
|
* @param id: Address of the node or it's peerId
|
|
391
401
|
*
|
|
392
402
|
* @returns: True if node is allowed to connect, otherwise false
|
|
393
|
-
* */
|
|
394
|
-
|
|
403
|
+
* */ /**
|
|
404
|
+
* Whether a peer is allowed to connect, given its peer id. Rejects peers serving an active ban and
|
|
405
|
+
* peers that have exceeded the failed auth-handshake limit. Use this once the peer id is known —
|
|
406
|
+
* i.e. for the encrypted-inbound gater and when dialing.
|
|
407
|
+
*/ isPeerAllowedToConnect(peerId) {
|
|
408
|
+
const id = peerId.toString();
|
|
409
|
+
if (this.peerScoring.getScoreState(id) === PeerScoreState.Banned) {
|
|
410
|
+
return false;
|
|
411
|
+
}
|
|
412
|
+
return this.isWithinFailedAuthLimit(id);
|
|
413
|
+
}
|
|
414
|
+
/**
|
|
415
|
+
* Whether a connection from an address is allowed. Bans are keyed by peer id, which isn't known at
|
|
416
|
+
* the raw-inbound layer, so only the failed auth-handshake limit (also tracked per address) is
|
|
417
|
+
* enforced here; the ban is applied once the peer id is known via {@link isPeerAllowedToConnect}.
|
|
418
|
+
*/ isAddressAllowedToConnect(address) {
|
|
419
|
+
return this.isWithinFailedAuthLimit(address);
|
|
420
|
+
}
|
|
421
|
+
/** Whether the failed auth-handshake count for a peer id or address is below the configured limit. */ isWithinFailedAuthLimit(key) {
|
|
422
|
+
const entry = this.failedAuthHandshakes.get(key);
|
|
395
423
|
if (!entry) {
|
|
396
424
|
return true;
|
|
397
425
|
}
|
|
398
426
|
// In case entry is too old, remove it and allow connection
|
|
399
427
|
if (this.dateProvider.now() - entry.lastFailureTimestamp > FAILED_AUTH_HANDSHAKE_EXPIRY_MS) {
|
|
400
|
-
this.failedAuthHandshakes.delete(
|
|
428
|
+
this.failedAuthHandshakes.delete(key);
|
|
401
429
|
return true;
|
|
402
430
|
}
|
|
403
431
|
return entry.count <= this.config.p2pMaxFailedAuthAttemptsAllowed;
|
|
@@ -572,9 +600,9 @@ export class PeerManager {
|
|
|
572
600
|
if (this.peerScoring.getScoreState(peerIdString) != PeerScoreState.Healthy) {
|
|
573
601
|
return;
|
|
574
602
|
}
|
|
575
|
-
// Don't dial peers that have exceeded the auth failure threshold
|
|
576
|
-
if (!this.
|
|
577
|
-
this.logger.trace(`Skipping peer ${peerId} due to failed auth handshake attempts`);
|
|
603
|
+
// Don't dial banned peers or those that have exceeded the auth failure threshold
|
|
604
|
+
if (!this.isPeerAllowedToConnect(peerId)) {
|
|
605
|
+
this.logger.trace(`Skipping peer ${peerId} due to ban or failed auth handshake attempts`);
|
|
578
606
|
return;
|
|
579
607
|
}
|
|
580
608
|
const [multiaddrTcp] = await Promise.all([
|
|
@@ -19,13 +19,40 @@ export declare class PeerScoring {
|
|
|
19
19
|
[key in PeerErrorSeverity]: number;
|
|
20
20
|
};
|
|
21
21
|
private peerStateCounter;
|
|
22
|
+
/** Active bans, keyed by peer id. Held in memory only, so they are cleared on restart. */
|
|
23
|
+
private bannedPeers;
|
|
24
|
+
/**
|
|
25
|
+
* How long a peer remains banned once its score crosses MIN_SCORE_BEFORE_BAN. While banned, the
|
|
26
|
+
* peer's ban score is returned by getScore regardless of decay, so it cannot recover its way out
|
|
27
|
+
* of the ban early. After the ban expires the live (decayed) score takes over again.
|
|
28
|
+
*/
|
|
29
|
+
private readonly banDurationMs;
|
|
22
30
|
constructor(config: P2PConfig, telemetry?: TelemetryClient, dateProvider?: DateProvider);
|
|
23
31
|
penalizePeer(peerId: PeerId, penalty: PeerErrorSeverity): number;
|
|
24
32
|
updateScore(peerId: string, scoreDelta: number): number;
|
|
33
|
+
/**
|
|
34
|
+
* Records a ban for a peer whose score has crossed the ban threshold, with an expiry banDurationMs
|
|
35
|
+
* in the future. No-op if the score is above the threshold or the peer is already serving an active
|
|
36
|
+
* ban (an existing ban is not extended; the original window stands). A previously expired ban does
|
|
37
|
+
* not block a fresh one — getActiveBanScore prunes it first.
|
|
38
|
+
*/
|
|
39
|
+
private maybeBanPeer;
|
|
25
40
|
decayAllScores(): void;
|
|
41
|
+
/**
|
|
42
|
+
* Removes bans whose window has elapsed. Expired bans are otherwise only pruned lazily when their
|
|
43
|
+
* peer's score is next queried, so a banned peer that disconnects and is never queried again would
|
|
44
|
+
* linger in the map. Called periodically (per heartbeat) to bound the ban map's size.
|
|
45
|
+
*/
|
|
46
|
+
pruneExpiredBans(): void;
|
|
26
47
|
/** Resets all peer scores. Useful for benchmarks to prevent cross-case contamination. */
|
|
27
48
|
resetAllScores(): void;
|
|
28
49
|
removePeer(peerId: string): void;
|
|
50
|
+
/**
|
|
51
|
+
* The single source of truth for whether a peer is banned. Returns the ban score while the ban is
|
|
52
|
+
* active, or undefined if the peer is not banned. A ban that has expired is lazily lifted before
|
|
53
|
+
* returning undefined, so callers never see a stale ban.
|
|
54
|
+
*/
|
|
55
|
+
private getActiveBanScore;
|
|
29
56
|
getScore(peerId: string): number;
|
|
30
57
|
getScoreState(peerId: string): PeerScoreState;
|
|
31
58
|
getStats(): {
|
|
@@ -35,4 +62,4 @@ export declare class PeerScoring {
|
|
|
35
62
|
bannedCount: number;
|
|
36
63
|
};
|
|
37
64
|
}
|
|
38
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
65
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGVlcl9zY29yaW5nLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvc2VydmljZXMvcGVlci1tYW5hZ2VyL3BlZXJfc2NvcmluZy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFFQSxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDdkQsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFDdEQsT0FBTyxFQUdMLEtBQUssZUFBZSxFQUlyQixNQUFNLHlCQUF5QixDQUFDO0FBRWpDLE9BQU8sS0FBSyxFQUFFLE1BQU0sRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBRWhELE9BQU8sS0FBSyxFQUFFLFNBQVMsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBdUJqRCxvQkFBWSxjQUFjO0lBQ3hCLE1BQU0sSUFBQTtJQUNOLFVBQVUsSUFBQTtJQUNWLE9BQU8sSUFBQTtDQUNSO0FBb0JELHFCQUFhLFdBQVc7SUFzQnBCLE9BQU8sQ0FBQyxRQUFRLENBQUMsWUFBWTtJQXJCL0IsT0FBTyxDQUFDLE1BQU0sQ0FBb0M7SUFDbEQsT0FBTyxDQUFDLE1BQU0sQ0FBa0M7SUFDaEQsT0FBTyxDQUFDLGNBQWMsQ0FBa0M7SUFDeEQsT0FBTyxDQUFDLGFBQWEsQ0FBYTtJQUNsQyxPQUFPLENBQUMsV0FBVyxDQUFPO0lBQzFCLGFBQWEsRUFBRTtTQUFHLEdBQUcsSUFBSSxpQkFBaUIsR0FBRyxNQUFNO0tBQUUsQ0FBQztJQUV0RCxPQUFPLENBQUMsZ0JBQWdCLENBQWdCO0lBRXhDLDBGQUEwRjtJQUMxRixPQUFPLENBQUMsV0FBVyxDQUFxQztJQUN4RDs7OztPQUlHO0lBQ0gsT0FBTyxDQUFDLFFBQVEsQ0FBQyxhQUFhLENBQVM7SUFFdkMsWUFDRSxNQUFNLEVBQUUsU0FBUyxFQUNqQixTQUFTLEdBQUUsZUFBc0MsRUFDaEMsWUFBWSxHQUFFLFlBQWlDLEVBa0JqRTtJQUVNLFlBQVksQ0FBQyxNQUFNLEVBQUUsTUFBTSxFQUFFLE9BQU8sRUFBRSxpQkFBaUIsVUFNN0Q7SUFFRCxXQUFXLENBQUMsTUFBTSxFQUFFLE1BQU0sRUFBRSxVQUFVLEVBQUUsTUFBTSxHQUFHLE1BQU0sQ0FvQnREO0lBRUQ7Ozs7O09BS0c7SUFDSCxPQUFPLENBQUMsWUFBWTtJQWFwQixjQUFjLElBQUksSUFBSSxDQWlCckI7SUFFRDs7OztPQUlHO0lBQ0gsZ0JBQWdCLElBQUksSUFBSSxDQU12QjtJQUVELHlGQUF5RjtJQUN6RixjQUFjLElBQUksSUFBSSxDQUlyQjtJQUVELFVBQVUsQ0FBQyxNQUFNLEVBQUUsTUFBTSxHQUFHLElBQUksQ0FHL0I7SUFFRDs7OztPQUlHO0lBQ0gsT0FBTyxDQUFDLGlCQUFpQjtJQWF6QixRQUFRLENBQUMsTUFBTSxFQUFFLE1BQU0sR0FBRyxNQUFNLENBSS9CO0lBRU0sYUFBYSxDQUFDLE1BQU0sRUFBRSxNQUFNLEdBQUcsY0FBYyxDQVduRDtJQUVELFFBQVEsSUFBSTtRQUFFLFdBQVcsRUFBRSxNQUFNLENBQUM7UUFBQyxZQUFZLEVBQUUsTUFBTSxDQUFDO1FBQUMsZUFBZSxFQUFFLE1BQU0sQ0FBQztRQUFDLFdBQVcsRUFBRSxNQUFNLENBQUE7S0FBRSxDQThCdEc7Q0FDRiJ9
|