@aztec/p2p 0.0.1-commit.8c0b8ff → 0.0.1-commit.8cb2d04d8
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 +2 -2
- package/dest/client/factory.d.ts.map +1 -1
- package/dest/client/factory.js +1 -0
- package/dest/client/interface.d.ts +9 -2
- package/dest/client/interface.d.ts.map +1 -1
- package/dest/client/p2p_client.d.ts +3 -2
- package/dest/client/p2p_client.d.ts.map +1 -1
- package/dest/client/p2p_client.js +30 -8
- package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.js +17 -6
- package/dest/config.d.ts +107 -103
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +17 -12
- package/dest/errors/p2p-service.error.d.ts +9 -0
- package/dest/errors/p2p-service.error.d.ts.map +1 -0
- package/dest/errors/p2p-service.error.js +10 -0
- package/dest/index.d.ts +1 -2
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +0 -1
- package/dest/mem_pools/attestation_pool/attestation_pool.d.ts +7 -5
- package/dest/mem_pools/attestation_pool/attestation_pool.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/attestation_pool.js +16 -9
- package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.js +6 -6
- package/dest/mem_pools/index.d.ts +1 -2
- package/dest/mem_pools/index.d.ts.map +1 -1
- package/dest/mem_pools/instrumentation.d.ts +4 -2
- package/dest/mem_pools/instrumentation.d.ts.map +1 -1
- package/dest/mem_pools/instrumentation.js +16 -14
- 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 +7 -5
- package/dest/mem_pools/tx_pool_v2/interfaces.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/interfaces.js +1 -0
- package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts +5 -6
- package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/tx_metadata.js +6 -2
- package/dest/mem_pools/tx_pool_v2/tx_pool_indices.d.ts +1 -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 +26 -43
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts +1 -1
- 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 +3 -0
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts +2 -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 +18 -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 +20 -11
- 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 +54 -3
- 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 +19 -11
- package/dest/msg_validators/tx_validator/archive_cache.js +1 -1
- package/dest/msg_validators/tx_validator/gas_validator.d.ts +1 -1
- package/dest/msg_validators/tx_validator/gas_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/gas_validator.js +11 -9
- package/dest/msg_validators/tx_validator/metadata_validator.d.ts +1 -1
- package/dest/msg_validators/tx_validator/metadata_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/metadata_validator.js +4 -4
- 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 +6 -3
- package/dest/services/dummy_service.d.ts.map +1 -1
- package/dest/services/dummy_service.js +6 -1
- 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 +15 -25
- package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
- package/dest/services/libp2p/libp2p_service.js +150 -115
- package/dest/services/peer-manager/metrics.d.ts +3 -1
- package/dest/services/peer-manager/metrics.d.ts.map +1 -1
- package/dest/services/peer-manager/metrics.js +6 -0
- package/dest/services/peer-manager/peer_manager.d.ts +6 -2
- package/dest/services/peer-manager/peer_manager.d.ts.map +1 -1
- package/dest/services/peer-manager/peer_manager.js +39 -11
- package/dest/services/peer-manager/peer_scoring.d.ts +7 -2
- package/dest/services/peer-manager/peer_scoring.d.ts.map +1 -1
- package/dest/services/peer-manager/peer_scoring.js +32 -10
- package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts +11 -8
- package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts.map +1 -1
- package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.js +82 -101
- package/dest/services/reqresp/batch-tx-requester/interface.d.ts +3 -2
- package/dest/services/reqresp/batch-tx-requester/interface.d.ts.map +1 -1
- package/dest/services/reqresp/batch-tx-requester/missing_txs.d.ts +5 -4
- package/dest/services/reqresp/batch-tx-requester/missing_txs.d.ts.map +1 -1
- package/dest/services/reqresp/batch-tx-requester/missing_txs.js +13 -7
- package/dest/services/reqresp/batch-tx-requester/peer_collection.d.ts +19 -11
- package/dest/services/reqresp/batch-tx-requester/peer_collection.d.ts.map +1 -1
- package/dest/services/reqresp/batch-tx-requester/peer_collection.js +52 -15
- 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 +13 -3
- package/dest/services/service.d.ts +5 -2
- package/dest/services/service.d.ts.map +1 -1
- package/dest/services/tx_collection/fast_tx_collection.d.ts +1 -4
- package/dest/services/tx_collection/fast_tx_collection.d.ts.map +1 -1
- package/dest/services/tx_collection/fast_tx_collection.js +57 -73
- package/dest/services/tx_collection/proposal_tx_collector.d.ts +6 -7
- package/dest/services/tx_collection/proposal_tx_collector.d.ts.map +1 -1
- package/dest/services/tx_collection/proposal_tx_collector.js +4 -4
- package/dest/services/tx_collection/request_tracker.d.ts +53 -0
- package/dest/services/tx_collection/request_tracker.d.ts.map +1 -0
- package/dest/services/tx_collection/request_tracker.js +84 -0
- package/dest/services/tx_collection/slow_tx_collection.js +1 -1
- package/dest/services/tx_collection/tx_collection.d.ts +3 -6
- package/dest/services/tx_collection/tx_collection.d.ts.map +1 -1
- 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/mock-pubsub.d.ts +11 -3
- package/dest/test-helpers/mock-pubsub.d.ts.map +1 -1
- package/dest/test-helpers/mock-pubsub.js +35 -10
- 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 +1 -2
- 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 +21 -2
- package/dest/testbench/p2p_client_testbench_worker.js +66 -15
- 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 +51 -2
- package/dest/util.d.ts +1 -1
- package/package.json +14 -14
- package/src/client/factory.ts +2 -1
- package/src/client/interface.ts +9 -1
- package/src/client/p2p_client.ts +34 -9
- package/src/client/test/tx_proposal_collector/proposal_tx_collector_worker.ts +19 -9
- package/src/config.ts +29 -17
- package/src/errors/p2p-service.error.ts +11 -0
- package/src/index.ts +0 -1
- package/src/mem_pools/attestation_pool/attestation_pool.ts +17 -12
- package/src/mem_pools/attestation_pool/attestation_pool_test_suite.ts +6 -6
- package/src/mem_pools/index.ts +0 -3
- package/src/mem_pools/instrumentation.ts +17 -13
- 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 +7 -4
- package/src/mem_pools/tx_pool_v2/tx_metadata.ts +12 -6
- package/src/mem_pools/tx_pool_v2/tx_pool_indices.ts +29 -43
- package/src/mem_pools/tx_pool_v2/tx_pool_v2.ts +3 -0
- package/src/mem_pools/tx_pool_v2/tx_pool_v2_impl.ts +19 -1
- package/src/msg_validators/attestation_validator/README.md +1 -1
- package/src/msg_validators/attestation_validator/attestation_validator.ts +21 -9
- package/src/msg_validators/attestation_validator/fisherman_attestation_validator.ts +4 -1
- package/src/msg_validators/clock_tolerance.ts +72 -3
- package/src/msg_validators/proposal_validator/README.md +4 -4
- 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 +17 -10
- package/src/msg_validators/tx_validator/archive_cache.ts +1 -1
- package/src/msg_validators/tx_validator/gas_validator.ts +25 -9
- package/src/msg_validators/tx_validator/metadata_validator.ts +12 -4
- package/src/services/data_store.ts +5 -13
- package/src/services/dummy_service.ts +8 -2
- 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 +146 -130
- package/src/services/peer-manager/metrics.ts +7 -0
- package/src/services/peer-manager/peer_manager.ts +45 -11
- package/src/services/peer-manager/peer_scoring.ts +27 -5
- package/src/services/reqresp/batch-tx-requester/README.md +46 -7
- package/src/services/reqresp/batch-tx-requester/batch_tx_requester.ts +78 -111
- package/src/services/reqresp/batch-tx-requester/interface.ts +2 -1
- package/src/services/reqresp/batch-tx-requester/missing_txs.ts +13 -6
- package/src/services/reqresp/batch-tx-requester/peer_collection.ts +68 -24
- 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 +21 -2
- package/src/services/service.ts +6 -1
- package/src/services/tx_collection/fast_tx_collection.ts +57 -83
- package/src/services/tx_collection/proposal_tx_collector.ts +8 -13
- package/src/services/tx_collection/request_tracker.ts +127 -0
- package/src/services/tx_collection/slow_tx_collection.ts +1 -1
- package/src/services/tx_collection/tx_collection.ts +3 -5
- package/src/test-helpers/make-test-p2p-clients.ts +1 -1
- package/src/test-helpers/mock-pubsub.ts +31 -5
- package/src/test-helpers/reqresp-nodes.ts +3 -3
- package/src/test-helpers/testbench-utils.ts +29 -3
- package/src/testbench/p2p_client_testbench_worker.ts +71 -15
- package/src/testbench/worker_client_manager.ts +57 -2
- package/src/util.ts +1 -1
- package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts +0 -125
- package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.js +0 -596
- package/dest/mem_pools/tx_pool/eviction/eviction_manager.d.ts +0 -32
- package/dest/mem_pools/tx_pool/eviction/eviction_manager.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/eviction/eviction_manager.js +0 -112
- package/dest/mem_pools/tx_pool/eviction/eviction_strategy.d.ts +0 -157
- package/dest/mem_pools/tx_pool/eviction/eviction_strategy.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/eviction/eviction_strategy.js +0 -52
- package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.d.ts +0 -16
- package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.js +0 -123
- package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.d.ts +0 -17
- package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.js +0 -84
- package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.d.ts +0 -19
- package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.js +0 -78
- package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.d.ts +0 -26
- package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.js +0 -84
- package/dest/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.d.ts +0 -25
- package/dest/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.js +0 -57
- package/dest/mem_pools/tx_pool/index.d.ts +0 -3
- package/dest/mem_pools/tx_pool/index.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/index.js +0 -2
- package/dest/mem_pools/tx_pool/priority.d.ts +0 -12
- package/dest/mem_pools/tx_pool/priority.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/priority.js +0 -15
- package/dest/mem_pools/tx_pool/tx_pool.d.ts +0 -127
- package/dest/mem_pools/tx_pool/tx_pool.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/tx_pool.js +0 -3
- package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts +0 -7
- package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/tx_pool_test_suite.js +0 -402
- 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/dest/services/tx_collection/missing_txs_tracker.d.ts +0 -32
- package/dest/services/tx_collection/missing_txs_tracker.d.ts.map +0 -1
- package/dest/services/tx_collection/missing_txs_tracker.js +0 -27
- package/src/mem_pools/tx_pool/README.md +0 -270
- package/src/mem_pools/tx_pool/aztec_kv_tx_pool.ts +0 -746
- package/src/mem_pools/tx_pool/eviction/eviction_manager.ts +0 -132
- package/src/mem_pools/tx_pool/eviction/eviction_strategy.ts +0 -208
- package/src/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.ts +0 -163
- package/src/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.ts +0 -104
- package/src/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.ts +0 -93
- package/src/mem_pools/tx_pool/eviction/low_priority_eviction_rule.ts +0 -106
- package/src/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.ts +0 -75
- package/src/mem_pools/tx_pool/index.ts +0 -2
- package/src/mem_pools/tx_pool/priority.ts +0 -20
- package/src/mem_pools/tx_pool/tx_pool.ts +0 -141
- package/src/mem_pools/tx_pool/tx_pool_test_suite.ts +0 -321
- package/src/services/reqresp/protocols/block.ts +0 -37
- package/src/services/tx_collection/missing_txs_tracker.ts +0 -52
|
@@ -370,7 +370,7 @@ function applyDecs2203RFactory() {
|
|
|
370
370
|
function _apply_decs_2203_r(targetClass, memberDecs, classDecs, parentClass) {
|
|
371
371
|
return (_apply_decs_2203_r = applyDecs2203RFactory())(targetClass, memberDecs, classDecs, parentClass);
|
|
372
372
|
}
|
|
373
|
-
var _dec, _dec1, _dec2, _dec3, _dec4, _dec5, _dec6,
|
|
373
|
+
var _dec, _dec1, _dec2, _dec3, _dec4, _dec5, _dec6, _initProto;
|
|
374
374
|
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
375
375
|
import { maxBy } from '@aztec/foundation/collection';
|
|
376
376
|
import { createLibp2pComponentLogger, createLogger } from '@aztec/foundation/log';
|
|
@@ -395,6 +395,7 @@ import { mplex } from '@libp2p/mplex';
|
|
|
395
395
|
import { tcp } from '@libp2p/tcp';
|
|
396
396
|
import { ENR } from '@nethermindeth/enr';
|
|
397
397
|
import { createLibp2p } from 'libp2p';
|
|
398
|
+
import { CheckpointProposalReceivedCallbackNotRegisteredError } from '../../errors/p2p-service.error.js';
|
|
398
399
|
import { BlockProposalValidator, CheckpointAttestationValidator, CheckpointProposalValidator, DoubleSpendTxValidator, FishermanAttestationValidator, getDefaultAllowedSetupFunctions } from '../../msg_validators/index.js';
|
|
399
400
|
import { MessageSeenValidator } from '../../msg_validators/msg_seen_validator/msg_seen_validator.js';
|
|
400
401
|
import { createFirstStageTxValidationsForGossipedTransactions, createSecondStageTxValidationsForGossipedTransactions, createTxValidatorForBlockProposalReceivedTxs, createTxValidatorForReqResponseReceivedTxs } from '../../msg_validators/tx_validator/factory.js';
|
|
@@ -408,7 +409,7 @@ import { APP_SPECIFIC_WEIGHT, gossipScoreThresholds } from '../gossipsub/scoring
|
|
|
408
409
|
import { createAllTopicScoreParams } from '../gossipsub/topic_score_params.js';
|
|
409
410
|
import { PeerManager } from '../peer-manager/peer_manager.js';
|
|
410
411
|
import { PeerScoring } from '../peer-manager/peer_scoring.js';
|
|
411
|
-
import { DEFAULT_SUB_PROTOCOL_VALIDATORS, ReqRespSubProtocol, ValidationError, pingHandler, reqGoodbyeHandler,
|
|
412
|
+
import { DEFAULT_SUB_PROTOCOL_VALIDATORS, ReqRespSubProtocol, ValidationError, pingHandler, reqGoodbyeHandler, reqRespBlockTxsHandler, reqRespStatusHandler, reqRespTxHandler } from '../reqresp/index.js';
|
|
412
413
|
import { ReqResp } from '../reqresp/reqresp.js';
|
|
413
414
|
import { P2PInstrumentation } from './instrumentation.js';
|
|
414
415
|
_dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId, attestation)=>({
|
|
@@ -430,12 +431,6 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
430
431
|
[Attributes.BLOCK_ARCHIVE]: request.archiveRoot.toString()
|
|
431
432
|
})), _dec6 = trackSpan('Libp2pService.validateRequestedTx', (requestedTxHash, _responseTx)=>({
|
|
432
433
|
[Attributes.TX_HASH]: requestedTxHash.toString()
|
|
433
|
-
})), _dec7 = trackSpan('Libp2pService.validateRequestedBlock', (requestedBlockNumber, _responseBlock)=>({
|
|
434
|
-
[Attributes.BLOCK_NUMBER]: requestedBlockNumber.toString()
|
|
435
|
-
})), _dec8 = trackSpan('Libp2pService.validateCheckpointAttestation', async (_, attestation)=>({
|
|
436
|
-
[Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber,
|
|
437
|
-
[Attributes.BLOCK_ARCHIVE]: attestation.archive.toString(),
|
|
438
|
-
[Attributes.P2P_ID]: await attestation.p2pMessageLoggingIdentifier().then((i)=>i.toString())
|
|
439
434
|
}));
|
|
440
435
|
/**
|
|
441
436
|
* Lib P2P implementation of the P2PService interface.
|
|
@@ -486,16 +481,6 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
486
481
|
_dec6,
|
|
487
482
|
2,
|
|
488
483
|
"validateRequestedTxs"
|
|
489
|
-
],
|
|
490
|
-
[
|
|
491
|
-
_dec7,
|
|
492
|
-
2,
|
|
493
|
-
"validateRequestedBlock"
|
|
494
|
-
],
|
|
495
|
-
[
|
|
496
|
-
_dec8,
|
|
497
|
-
2,
|
|
498
|
-
"validateCheckpointAttestation"
|
|
499
484
|
]
|
|
500
485
|
], []));
|
|
501
486
|
}
|
|
@@ -519,7 +504,12 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
519
504
|
* Callback for when a checkpoint proposal is received from a peer.
|
|
520
505
|
* @param checkpoint - The checkpoint proposal received from the peer.
|
|
521
506
|
* @returns The attestations for the checkpoint, if any.
|
|
522
|
-
*/
|
|
507
|
+
*/ allNodesCheckpointReceivedCallback;
|
|
508
|
+
/**
|
|
509
|
+
* Callback for when a checkpoint proposal is received - specifically for validators - from a peer.
|
|
510
|
+
* @param checkpoint - The checkpoint proposal received from the peer.
|
|
511
|
+
* @returns The attestations for the checkpoint, if any.
|
|
512
|
+
*/ validatorCheckpointReceivedCallback;
|
|
523
513
|
gossipSubEventHandler;
|
|
524
514
|
instrumentation;
|
|
525
515
|
telemetry;
|
|
@@ -541,13 +531,19 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
541
531
|
this.topicStrings[TopicType.block_proposal] = createTopicString(TopicType.block_proposal, this.protocolVersion);
|
|
542
532
|
this.topicStrings[TopicType.checkpoint_proposal] = createTopicString(TopicType.checkpoint_proposal, this.protocolVersion);
|
|
543
533
|
this.topicStrings[TopicType.checkpoint_attestation] = createTopicString(TopicType.checkpoint_attestation, this.protocolVersion);
|
|
534
|
+
const p2pPropagationTime = config.attestationPropagationTime;
|
|
544
535
|
const proposalValidatorOpts = {
|
|
545
536
|
txsPermitted: !config.disableTransactions,
|
|
546
|
-
maxTxsPerBlock: config.validateMaxTxsPerBlock ?? config.validateMaxTxsPerCheckpoint
|
|
537
|
+
maxTxsPerBlock: config.validateMaxTxsPerBlock ?? config.validateMaxTxsPerCheckpoint,
|
|
538
|
+
p2pPropagationTime
|
|
547
539
|
};
|
|
548
540
|
this.blockProposalValidator = new BlockProposalValidator(epochCache, proposalValidatorOpts);
|
|
549
541
|
this.checkpointProposalValidator = new CheckpointProposalValidator(epochCache, proposalValidatorOpts);
|
|
550
|
-
this.checkpointAttestationValidator = config.fishermanMode ? new FishermanAttestationValidator(epochCache, mempools.attestationPool, telemetry
|
|
542
|
+
this.checkpointAttestationValidator = config.fishermanMode ? new FishermanAttestationValidator(epochCache, mempools.attestationPool, telemetry, {
|
|
543
|
+
l1PublishingTime: config.l1PublishingTime
|
|
544
|
+
}) : new CheckpointAttestationValidator(epochCache, {
|
|
545
|
+
l1PublishingTime: config.l1PublishingTime
|
|
546
|
+
});
|
|
551
547
|
this.gossipSubEventHandler = this.handleGossipSubEvent.bind(this);
|
|
552
548
|
this.blockReceivedCallback = async (block)=>{
|
|
553
549
|
this.logger.warn(`Handler for block received not yet registered on P2P service. Received block ${block.blockNumber} for slot ${block.slotNumber} from peer.`, {
|
|
@@ -555,8 +551,10 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
555
551
|
});
|
|
556
552
|
return true;
|
|
557
553
|
};
|
|
558
|
-
this.
|
|
559
|
-
|
|
554
|
+
this.allNodesCheckpointReceivedCallback = (_checkpoint)=>{
|
|
555
|
+
throw new CheckpointProposalReceivedCallbackNotRegisteredError();
|
|
556
|
+
};
|
|
557
|
+
this.validatorCheckpointReceivedCallback = (_checkpoint)=>{
|
|
560
558
|
return Promise.resolve(undefined);
|
|
561
559
|
};
|
|
562
560
|
}
|
|
@@ -609,9 +607,12 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
609
607
|
const l1Constants = epochCache.getL1Constants();
|
|
610
608
|
const topicScoreParams = createAllTopicScoreParams(protocolVersion, {
|
|
611
609
|
slotDurationMs: l1Constants.slotDuration * 1000,
|
|
610
|
+
ethereumSlotDuration: l1Constants.ethereumSlotDuration,
|
|
612
611
|
heartbeatIntervalMs: config.gossipsubInterval,
|
|
613
612
|
targetCommitteeSize: l1Constants.targetCommitteeSize,
|
|
614
613
|
blockDurationMs: config.blockDurationMs,
|
|
614
|
+
l1PublishingTime: config.l1PublishingTime,
|
|
615
|
+
p2pPropagationTime: config.attestationPropagationTime,
|
|
615
616
|
expectedBlockProposalsPerSlot: config.expectedBlockProposalsPerSlot
|
|
616
617
|
});
|
|
617
618
|
const node = await createLibp2p({
|
|
@@ -726,6 +727,8 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
726
727
|
const peerScoring = new PeerScoring(config, telemetry);
|
|
727
728
|
const reqresp = new ReqResp(config, node, peerScoring, createLogger(`${logger.module}:reqresp`));
|
|
728
729
|
const peerManager = new PeerManager(node, peerDiscoveryService, config, telemetry, createLogger(`${logger.module}:peer_manager`), peerScoring, reqresp, worldStateSynchronizer, protocolVersion, epochCache);
|
|
730
|
+
// Gate req/resp data protocols for unauthenticated peers when p2pAllowOnlyValidators is enabled
|
|
731
|
+
reqresp.setShouldRejectPeer((peerId)=>peerManager.shouldDisableP2PGossip(peerId));
|
|
729
732
|
// Configure application-specific scoring for gossipsub.
|
|
730
733
|
// The weight scales app score to align with gossipsub thresholds:
|
|
731
734
|
// - Disconnect (-50) × 10 = -500 = gossipThreshold (stops receiving gossip)
|
|
@@ -752,13 +755,11 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
752
755
|
// Create request response protocol handlers
|
|
753
756
|
const txHandler = reqRespTxHandler(this.mempools);
|
|
754
757
|
const goodbyeHandler = reqGoodbyeHandler(this.peerManager);
|
|
755
|
-
const blockHandler = reqRespBlockHandler(this.archiver);
|
|
756
758
|
const statusHandler = reqRespStatusHandler(this.protocolVersion, this.worldStateSynchronizer, this.logger);
|
|
757
759
|
const requestResponseHandlers = {
|
|
758
760
|
[ReqRespSubProtocol.PING]: pingHandler,
|
|
759
761
|
[ReqRespSubProtocol.STATUS]: statusHandler.bind(this),
|
|
760
|
-
[ReqRespSubProtocol.GOODBYE]: goodbyeHandler.bind(this)
|
|
761
|
-
[ReqRespSubProtocol.BLOCK]: blockHandler.bind(this)
|
|
762
|
+
[ReqRespSubProtocol.GOODBYE]: goodbyeHandler.bind(this)
|
|
762
763
|
};
|
|
763
764
|
if (!this.config.disableTransactions) {
|
|
764
765
|
const blockTxsHandler = reqRespBlockTxsHandler(this.mempools.attestationPool, this.archiver, this.mempools.txPool);
|
|
@@ -771,8 +772,7 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
771
772
|
const reqrespSubProtocolValidators = {
|
|
772
773
|
...DEFAULT_SUB_PROTOCOL_VALIDATORS,
|
|
773
774
|
[ReqRespSubProtocol.TX]: this.validateRequestedTxs.bind(this),
|
|
774
|
-
[ReqRespSubProtocol.BLOCK_TXS]: this.validateRequestedBlockTxs.bind(this)
|
|
775
|
-
[ReqRespSubProtocol.BLOCK]: this.validateRequestedBlock.bind(this)
|
|
775
|
+
[ReqRespSubProtocol.BLOCK_TXS]: this.validateRequestedBlockTxs.bind(this)
|
|
776
776
|
};
|
|
777
777
|
await this.peerManager.initializePeers();
|
|
778
778
|
await this.reqresp.start(requestResponseHandlers, reqrespSubProtocolValidators);
|
|
@@ -860,8 +860,14 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
860
860
|
registerBlockReceivedCallback(callback) {
|
|
861
861
|
this.blockReceivedCallback = callback;
|
|
862
862
|
}
|
|
863
|
-
|
|
864
|
-
this.
|
|
863
|
+
registerValidatorCheckpointReceivedCallback(callback) {
|
|
864
|
+
this.validatorCheckpointReceivedCallback = callback;
|
|
865
|
+
}
|
|
866
|
+
registerAllNodesCheckpointReceivedCallback(callback) {
|
|
867
|
+
this.allNodesCheckpointReceivedCallback = callback;
|
|
868
|
+
}
|
|
869
|
+
async notifyOwnCheckpointProposal(checkpoint) {
|
|
870
|
+
await this.allNodesCheckpointReceivedCallback(checkpoint, this.node.peerId);
|
|
865
871
|
}
|
|
866
872
|
/**
|
|
867
873
|
* Registers a callback to be invoked when a duplicate proposal is detected.
|
|
@@ -927,6 +933,12 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
927
933
|
if (!validator || !validator.addMessage(msgId)) {
|
|
928
934
|
this.instrumentation.incMessagePrevalidationStatus(false, topicType);
|
|
929
935
|
this.node.services.pubsub.reportMessageValidationResult(msgId, source.toString(), TopicValidatorResult.Ignore);
|
|
936
|
+
if (topicType === TopicType.tx) {
|
|
937
|
+
this.logger.verbose(`Ignoring already-seen tx gossip message`, {
|
|
938
|
+
msgId,
|
|
939
|
+
source: source.toString()
|
|
940
|
+
});
|
|
941
|
+
}
|
|
930
942
|
return {
|
|
931
943
|
result: false,
|
|
932
944
|
topicType
|
|
@@ -1032,29 +1044,79 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1032
1044
|
return;
|
|
1033
1045
|
}
|
|
1034
1046
|
async validateReceivedMessage(validationFunc, msgId, source, topicType) {
|
|
1047
|
+
// Default to reject result with a penalty if validation function throws an error
|
|
1035
1048
|
let resultAndObj = {
|
|
1036
|
-
result: TopicValidatorResult.Reject
|
|
1049
|
+
result: TopicValidatorResult.Reject,
|
|
1050
|
+
severity: PeerErrorSeverity.MidToleranceError
|
|
1037
1051
|
};
|
|
1038
1052
|
const timer = new Timer();
|
|
1039
1053
|
try {
|
|
1040
1054
|
resultAndObj = await validationFunc();
|
|
1041
1055
|
} catch (err) {
|
|
1042
|
-
this.
|
|
1043
|
-
this.logger.error(`Error deserializing and validating gossipsub message`, err, {
|
|
1056
|
+
this.logger.error(`Error validating gossipsub message`, err, {
|
|
1044
1057
|
msgId,
|
|
1045
1058
|
source: source.toString(),
|
|
1046
1059
|
topicType
|
|
1047
1060
|
});
|
|
1048
1061
|
}
|
|
1062
|
+
const validationTimeMs = timer.ms();
|
|
1063
|
+
const mcacheWindowMs = this.config.gossipsubMcacheLength * this.config.gossipsubInterval;
|
|
1064
|
+
if (validationTimeMs > mcacheWindowMs * 0.75) {
|
|
1065
|
+
this.instrumentation.incSlowValidation(topicType);
|
|
1066
|
+
this.logger.warn(`Gossip validation for ${topicType} took ${validationTimeMs}ms, approaching mcache eviction window of ${mcacheWindowMs}ms. ` + `Message forwarding may be skipped if validation exceeds the window.`, {
|
|
1067
|
+
msgId,
|
|
1068
|
+
source: source.toString(),
|
|
1069
|
+
topicType,
|
|
1070
|
+
validationTimeMs,
|
|
1071
|
+
mcacheWindowMs
|
|
1072
|
+
});
|
|
1073
|
+
}
|
|
1049
1074
|
if (resultAndObj.result === TopicValidatorResult.Accept) {
|
|
1075
|
+
this.logger.debug(`Message ${topicType} accepted by validator`, {
|
|
1076
|
+
msgId,
|
|
1077
|
+
source: source.toString(),
|
|
1078
|
+
topicType
|
|
1079
|
+
});
|
|
1050
1080
|
this.instrumentation.recordMessageValidation(topicType, timer);
|
|
1081
|
+
} else if (resultAndObj.result === TopicValidatorResult.Reject) {
|
|
1082
|
+
this.logger.warn(`Message ${topicType} rejected by validator with severity ${resultAndObj.severity}`, {
|
|
1083
|
+
msgId,
|
|
1084
|
+
source: source.toString(),
|
|
1085
|
+
topicType,
|
|
1086
|
+
severity: resultAndObj.severity
|
|
1087
|
+
});
|
|
1088
|
+
this.peerManager.penalizePeer(source, resultAndObj.severity);
|
|
1089
|
+
} else {
|
|
1090
|
+
this.logger.trace(`Message ${topicType} ignored by validator`, {
|
|
1091
|
+
msgId,
|
|
1092
|
+
source: source.toString(),
|
|
1093
|
+
topicType
|
|
1094
|
+
});
|
|
1051
1095
|
}
|
|
1052
1096
|
this.node.services.pubsub.reportMessageValidationResult(msgId, source.toString(), resultAndObj.result);
|
|
1053
1097
|
return resultAndObj;
|
|
1054
1098
|
}
|
|
1099
|
+
tryDeserialize(deserializeFunc, msgId, source) {
|
|
1100
|
+
try {
|
|
1101
|
+
return deserializeFunc();
|
|
1102
|
+
} catch (err) {
|
|
1103
|
+
this.logger.warn(`Failed to deserialize gossipsub message from buffer`, {
|
|
1104
|
+
err,
|
|
1105
|
+
msgId,
|
|
1106
|
+
source: source.toString()
|
|
1107
|
+
});
|
|
1108
|
+
return undefined;
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1055
1111
|
async handleGossipedTx(payloadData, msgId, source) {
|
|
1056
1112
|
const validationFunc = async ()=>{
|
|
1057
|
-
const tx = Tx.fromBuffer(payloadData);
|
|
1113
|
+
const tx = this.tryDeserialize(()=>Tx.fromBuffer(payloadData), msgId, source);
|
|
1114
|
+
if (!tx) {
|
|
1115
|
+
return {
|
|
1116
|
+
result: TopicValidatorResult.Reject,
|
|
1117
|
+
severity: PeerErrorSeverity.LowToleranceError
|
|
1118
|
+
};
|
|
1119
|
+
}
|
|
1058
1120
|
const currentBlockNumber = await this.archiver.getBlockNumber();
|
|
1059
1121
|
const { ts: nextSlotTimestamp } = this.epochCache.getEpochAndSlotInNextL1Slot();
|
|
1060
1122
|
// Stage 1: fast validators (metadata, data, timestamps, double-spend, gas, phases, block header)
|
|
@@ -1070,14 +1132,22 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1070
1132
|
const txBlockNumber = BlockNumber(currentBlockNumber + 1);
|
|
1071
1133
|
severity = await this.handleDoubleSpendFailure(tx, txBlockNumber);
|
|
1072
1134
|
}
|
|
1073
|
-
this.
|
|
1135
|
+
this.logger.verbose(`Rejecting gossiped tx ${tx.getTxHash().toString()}: stage 1 validation failed`, {
|
|
1136
|
+
validator: name,
|
|
1137
|
+
severity,
|
|
1138
|
+
source: source.toString()
|
|
1139
|
+
});
|
|
1074
1140
|
return {
|
|
1075
|
-
result: TopicValidatorResult.Reject
|
|
1141
|
+
result: TopicValidatorResult.Reject,
|
|
1142
|
+
severity
|
|
1076
1143
|
};
|
|
1077
1144
|
}
|
|
1078
1145
|
// Pool pre-check: see if the pool would accept this tx before doing expensive proof verification
|
|
1079
1146
|
const canAdd = await this.mempools.txPool.canAddPendingTx(tx);
|
|
1080
1147
|
if (canAdd === 'ignored') {
|
|
1148
|
+
this.logger.verbose(`Ignoring gossiped tx ${tx.getTxHash().toString()}: pool pre-check returned ignored`, {
|
|
1149
|
+
source: source.toString()
|
|
1150
|
+
});
|
|
1081
1151
|
return {
|
|
1082
1152
|
result: TopicValidatorResult.Ignore,
|
|
1083
1153
|
obj: tx
|
|
@@ -1087,10 +1157,15 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1087
1157
|
const secondStageValidators = this.createSecondStageMessageValidators();
|
|
1088
1158
|
const secondStageOutcome = await this.runValidations(tx, secondStageValidators);
|
|
1089
1159
|
if (!secondStageOutcome.allPassed) {
|
|
1090
|
-
const { severity } = secondStageOutcome.failure;
|
|
1091
|
-
this.
|
|
1160
|
+
const { severity, name } = secondStageOutcome.failure;
|
|
1161
|
+
this.logger.verbose(`Rejecting gossiped tx ${tx.getTxHash().toString()}: stage 2 validation failed`, {
|
|
1162
|
+
validator: name,
|
|
1163
|
+
severity,
|
|
1164
|
+
source: source.toString()
|
|
1165
|
+
});
|
|
1092
1166
|
return {
|
|
1093
|
-
result: TopicValidatorResult.Reject
|
|
1167
|
+
result: TopicValidatorResult.Reject,
|
|
1168
|
+
severity
|
|
1094
1169
|
};
|
|
1095
1170
|
}
|
|
1096
1171
|
// Pool add: persist the tx
|
|
@@ -1102,7 +1177,7 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1102
1177
|
});
|
|
1103
1178
|
const wasAccepted = addResult.accepted.some((h)=>h.equals(txHash));
|
|
1104
1179
|
const wasIgnored = addResult.ignored.some((h)=>h.equals(txHash));
|
|
1105
|
-
this.logger.
|
|
1180
|
+
this.logger.verbose(`Validate propagated tx ${txHash.toString()}`, {
|
|
1106
1181
|
wasAccepted,
|
|
1107
1182
|
wasIgnored,
|
|
1108
1183
|
[Attributes.P2P_ID]: source.toString()
|
|
@@ -1122,9 +1197,9 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1122
1197
|
source: source.toString(),
|
|
1123
1198
|
txHash: txHash.toString()
|
|
1124
1199
|
});
|
|
1125
|
-
this.peerManager.penalizePeer(source, PeerErrorSeverity.HighToleranceError);
|
|
1126
1200
|
return {
|
|
1127
|
-
result: TopicValidatorResult.Reject
|
|
1201
|
+
result: TopicValidatorResult.Reject,
|
|
1202
|
+
severity: PeerErrorSeverity.HighToleranceError
|
|
1128
1203
|
};
|
|
1129
1204
|
}
|
|
1130
1205
|
};
|
|
@@ -1145,7 +1220,16 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1145
1220
|
* Process a checkpoint attestation from a peer.
|
|
1146
1221
|
* Validates the attestation and adds it to the pool.
|
|
1147
1222
|
*/ async processCheckpointAttestationFromPeer(payloadData, msgId, source) {
|
|
1148
|
-
const { result, obj: attestation } = await this.validateReceivedMessage(()=>
|
|
1223
|
+
const { result, obj: attestation } = await this.validateReceivedMessage(()=>{
|
|
1224
|
+
const attestation = this.tryDeserialize(()=>CheckpointAttestation.fromBuffer(payloadData), msgId, source);
|
|
1225
|
+
if (!attestation) {
|
|
1226
|
+
return Promise.resolve({
|
|
1227
|
+
result: TopicValidatorResult.Reject,
|
|
1228
|
+
severity: PeerErrorSeverity.LowToleranceError
|
|
1229
|
+
});
|
|
1230
|
+
}
|
|
1231
|
+
return this.validateAndStoreCheckpointAttestation(source, attestation);
|
|
1232
|
+
}, msgId, source, TopicType.checkpoint_attestation);
|
|
1149
1233
|
if (result !== TopicValidatorResult.Accept || !attestation) {
|
|
1150
1234
|
return;
|
|
1151
1235
|
}
|
|
@@ -1160,9 +1244,9 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1160
1244
|
const validationResult = await this.checkpointAttestationValidator.validate(attestation);
|
|
1161
1245
|
if (validationResult.result === 'reject') {
|
|
1162
1246
|
this.logger.warn(`Penalizing peer ${peerId} for checkpoint attestation validation failure`);
|
|
1163
|
-
this.peerManager.penalizePeer(peerId, validationResult.severity);
|
|
1164
1247
|
return {
|
|
1165
|
-
result: TopicValidatorResult.Reject
|
|
1248
|
+
result: TopicValidatorResult.Reject,
|
|
1249
|
+
severity: validationResult.severity
|
|
1166
1250
|
};
|
|
1167
1251
|
}
|
|
1168
1252
|
if (validationResult.result === 'ignore') {
|
|
@@ -1189,9 +1273,9 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1189
1273
|
obj: attestation
|
|
1190
1274
|
};
|
|
1191
1275
|
}
|
|
1192
|
-
// Could not add (cap reached for signer),
|
|
1276
|
+
// Could not add (cap reached for signer), penalize and do not re-broadcast
|
|
1193
1277
|
if (!added) {
|
|
1194
|
-
this.logger.warn(`
|
|
1278
|
+
this.logger.warn(`Rejecting checkpoint attestation due to cap`, {
|
|
1195
1279
|
slot: slot.toString(),
|
|
1196
1280
|
archive: attestation.archive.toString(),
|
|
1197
1281
|
source: peerId.toString(),
|
|
@@ -1199,8 +1283,8 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1199
1283
|
count
|
|
1200
1284
|
});
|
|
1201
1285
|
return {
|
|
1202
|
-
result: TopicValidatorResult.
|
|
1203
|
-
|
|
1286
|
+
result: TopicValidatorResult.Reject,
|
|
1287
|
+
severity: PeerErrorSeverity.HighToleranceError
|
|
1204
1288
|
};
|
|
1205
1289
|
}
|
|
1206
1290
|
// Check if this is a duplicate attestation (signer attested to a different proposal at the same slot)
|
|
@@ -1238,9 +1322,9 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1238
1322
|
const validationResult = await this.blockProposalValidator.validate(block);
|
|
1239
1323
|
if (validationResult.result === 'reject') {
|
|
1240
1324
|
this.logger.warn(`Penalizing peer ${peerId} for block proposal validation failure`);
|
|
1241
|
-
this.peerManager.penalizePeer(peerId, validationResult.severity);
|
|
1242
1325
|
return {
|
|
1243
|
-
result: TopicValidatorResult.Reject
|
|
1326
|
+
result: TopicValidatorResult.Reject,
|
|
1327
|
+
severity: validationResult.severity
|
|
1244
1328
|
};
|
|
1245
1329
|
}
|
|
1246
1330
|
if (validationResult.result === 'ignore') {
|
|
@@ -1270,7 +1354,6 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1270
1354
|
}
|
|
1271
1355
|
// Too many blocks received for this slot and index, penalize peer and do not re-broadcast
|
|
1272
1356
|
if (!added) {
|
|
1273
|
-
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.HighToleranceError);
|
|
1274
1357
|
this.logger.warn(`Penalizing peer for block proposal exceeding per-position cap`, {
|
|
1275
1358
|
...block.toBlockInfo(),
|
|
1276
1359
|
indexWithinCheckpoint: block.indexWithinCheckpoint,
|
|
@@ -1282,7 +1365,8 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1282
1365
|
result: TopicValidatorResult.Reject,
|
|
1283
1366
|
metadata: {
|
|
1284
1367
|
isEquivocated
|
|
1285
|
-
}
|
|
1368
|
+
},
|
|
1369
|
+
severity: PeerErrorSeverity.HighToleranceError
|
|
1286
1370
|
};
|
|
1287
1371
|
}
|
|
1288
1372
|
// If this was a duplicate proposal, do not process it, but do invoke the duplicate callback,
|
|
@@ -1356,9 +1440,9 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1356
1440
|
const validationResult = await this.checkpointProposalValidator.validate(checkpoint);
|
|
1357
1441
|
if (validationResult.result === 'reject') {
|
|
1358
1442
|
this.logger.warn(`Penalizing peer ${peerId} for checkpoint proposal validation failure`);
|
|
1359
|
-
this.peerManager.penalizePeer(peerId, validationResult.severity);
|
|
1360
1443
|
return {
|
|
1361
|
-
result: TopicValidatorResult.Reject
|
|
1444
|
+
result: TopicValidatorResult.Reject,
|
|
1445
|
+
severity: validationResult.severity
|
|
1362
1446
|
};
|
|
1363
1447
|
}
|
|
1364
1448
|
if (validationResult.result === 'ignore') {
|
|
@@ -1375,18 +1459,20 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1375
1459
|
[Attributes.SLOT_NUMBER]: checkpoint.slotNumber.toString(),
|
|
1376
1460
|
[Attributes.P2P_ID]: peerId.toString()
|
|
1377
1461
|
});
|
|
1378
|
-
const
|
|
1379
|
-
|
|
1462
|
+
const blockProposalResult = await this.validateAndStoreBlockProposal(peerId, blockProposal);
|
|
1463
|
+
const { obj, metadata: { isEquivocated } = {} } = blockProposalResult;
|
|
1464
|
+
if (blockProposalResult.result === TopicValidatorResult.Reject || !obj || isEquivocated) {
|
|
1380
1465
|
this.logger.debug(`Rejecting checkpoint due to invalid last block proposal`, {
|
|
1381
1466
|
[Attributes.SLOT_NUMBER]: checkpoint.slotNumber.toString(),
|
|
1382
1467
|
[Attributes.P2P_ID]: peerId.toString(),
|
|
1383
1468
|
isEquivocated,
|
|
1384
|
-
result
|
|
1469
|
+
result: blockProposalResult.result
|
|
1385
1470
|
});
|
|
1386
1471
|
return {
|
|
1387
|
-
result: TopicValidatorResult.Reject
|
|
1472
|
+
result: TopicValidatorResult.Reject,
|
|
1473
|
+
severity: 'severity' in blockProposalResult ? blockProposalResult.severity : PeerErrorSeverity.MidToleranceError
|
|
1388
1474
|
};
|
|
1389
|
-
} else if (result === TopicValidatorResult.Accept && obj && !isEquivocated) {
|
|
1475
|
+
} else if (blockProposalResult.result === TopicValidatorResult.Accept && obj && !isEquivocated) {
|
|
1390
1476
|
processBlock = true;
|
|
1391
1477
|
}
|
|
1392
1478
|
}
|
|
@@ -1413,7 +1499,6 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1413
1499
|
// Too many checkpoint proposals received for this slot, penalize peer and do not re-broadcast
|
|
1414
1500
|
// Note: We still return the checkpoint obj so the lastBlock can be processed if valid
|
|
1415
1501
|
if (!added) {
|
|
1416
|
-
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.HighToleranceError);
|
|
1417
1502
|
this.logger.warn(`Penalizing peer for checkpoint proposal exceeding per-slot cap`, {
|
|
1418
1503
|
...checkpoint.toCheckpointInfo(),
|
|
1419
1504
|
count,
|
|
@@ -1425,7 +1510,8 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1425
1510
|
metadata: {
|
|
1426
1511
|
isEquivocated,
|
|
1427
1512
|
processBlock
|
|
1428
|
-
}
|
|
1513
|
+
},
|
|
1514
|
+
severity: PeerErrorSeverity.HighToleranceError
|
|
1429
1515
|
};
|
|
1430
1516
|
}
|
|
1431
1517
|
// If this was a duplicate proposal, do not process it, but do invoke the duplicate callback,
|
|
@@ -1475,9 +1561,10 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1475
1561
|
archive: checkpoint.archive.toString(),
|
|
1476
1562
|
source: sender.toString()
|
|
1477
1563
|
});
|
|
1564
|
+
await this.allNodesCheckpointReceivedCallback(checkpoint, sender);
|
|
1478
1565
|
// Call the checkpoint received callback with the core version (without lastBlock)
|
|
1479
1566
|
// to validate and potentially generate attestations
|
|
1480
|
-
const attestations = await this.
|
|
1567
|
+
const attestations = await this.validatorCheckpointReceivedCallback(checkpoint, sender);
|
|
1481
1568
|
if (attestations && attestations.length > 0) {
|
|
1482
1569
|
// If the callback returned attestations, add them to the pool and propagate them
|
|
1483
1570
|
await this.mempools.attestationPool.addOwnCheckpointAttestations(attestations);
|
|
@@ -1597,45 +1684,6 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1597
1684
|
return false;
|
|
1598
1685
|
}
|
|
1599
1686
|
}
|
|
1600
|
-
/**
|
|
1601
|
-
* Validates a BLOCK response.
|
|
1602
|
-
*
|
|
1603
|
-
* If a local copy exists, enforces hash equality. If missing, rejects (no penalty) since the hash cannot be verified.
|
|
1604
|
-
* Penalizes on block number mismatch or hash mismatch.
|
|
1605
|
-
*
|
|
1606
|
-
* @param requestedBlockNumber - The requested block number.
|
|
1607
|
-
* @param responseBlock - The block returned by the peer.
|
|
1608
|
-
* @param peerId - The peer that returned the block.
|
|
1609
|
-
* @returns True if the response is valid, false otherwise.
|
|
1610
|
-
*/ async validateRequestedBlock(requestedBlockNumber, responseBlock, peerId) {
|
|
1611
|
-
try {
|
|
1612
|
-
const reqNum = Number(requestedBlockNumber.toString());
|
|
1613
|
-
if (responseBlock.number !== reqNum) {
|
|
1614
|
-
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
|
|
1615
|
-
return false;
|
|
1616
|
-
}
|
|
1617
|
-
const local = await this.archiver.getBlock(BlockNumber(reqNum));
|
|
1618
|
-
if (!local) {
|
|
1619
|
-
// We are missing the local block; we cannot verify the hash yet. Reject without penalizing.
|
|
1620
|
-
// TODO: Consider extending this validator to accept an expected hash or
|
|
1621
|
-
// performing quorum-based checks when using P2P syncing prior to L1 sync.
|
|
1622
|
-
this.logger.warn(`Local block ${reqNum} not found; rejecting BLOCK response without hash verification`);
|
|
1623
|
-
return false;
|
|
1624
|
-
}
|
|
1625
|
-
const [localHash, respHash] = await Promise.all([
|
|
1626
|
-
local.hash(),
|
|
1627
|
-
responseBlock.hash()
|
|
1628
|
-
]);
|
|
1629
|
-
if (!localHash.equals(respHash)) {
|
|
1630
|
-
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
1631
|
-
return false;
|
|
1632
|
-
}
|
|
1633
|
-
return true;
|
|
1634
|
-
} catch (e) {
|
|
1635
|
-
this.logger.warn(`Error validating requested block`, e);
|
|
1636
|
-
return false;
|
|
1637
|
-
}
|
|
1638
|
-
}
|
|
1639
1687
|
async validateRequestedTx(tx, peerId, txValidator, requested) {
|
|
1640
1688
|
const penalize = (severity)=>this.peerManager.penalizePeer(peerId, severity);
|
|
1641
1689
|
if (requested && !requested.has(tx.getTxHash().toString())) {
|
|
@@ -1776,19 +1824,6 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1776
1824
|
}
|
|
1777
1825
|
return PeerErrorSeverity.HighToleranceError;
|
|
1778
1826
|
}
|
|
1779
|
-
/**
|
|
1780
|
-
* Validate a checkpoint attestation.
|
|
1781
|
-
*
|
|
1782
|
-
* @param attestation - The checkpoint attestation to validate.
|
|
1783
|
-
* @returns True if the checkpoint attestation is valid, false otherwise.
|
|
1784
|
-
*/ async validateCheckpointAttestation(peerId, attestation) {
|
|
1785
|
-
const result = await this.checkpointAttestationValidator.validate(attestation);
|
|
1786
|
-
if (result.result === 'reject') {
|
|
1787
|
-
this.logger.warn(`Penalizing peer ${peerId} for checkpoint attestation validation failure`);
|
|
1788
|
-
this.peerManager.penalizePeer(peerId, result.severity);
|
|
1789
|
-
}
|
|
1790
|
-
return result;
|
|
1791
|
-
}
|
|
1792
1827
|
getPeerScore(peerId) {
|
|
1793
1828
|
return this.node.services.pubsub.score.score(peerId.toString());
|
|
1794
1829
|
}
|
|
@@ -6,6 +6,7 @@ export declare class PeerManagerMetrics {
|
|
|
6
6
|
private sentGoodbyes;
|
|
7
7
|
private receivedGoodbyes;
|
|
8
8
|
private peerCount;
|
|
9
|
+
private healthyPeerCount;
|
|
9
10
|
private lowScoreDisconnects;
|
|
10
11
|
private peerConnectionDuration;
|
|
11
12
|
private peerConnectedAt;
|
|
@@ -14,8 +15,9 @@ export declare class PeerManagerMetrics {
|
|
|
14
15
|
recordGoodbyeSent(reason: GoodByeReason): void;
|
|
15
16
|
recordGoodbyeReceived(reason: GoodByeReason): void;
|
|
16
17
|
recordPeerCount(count: number): void;
|
|
18
|
+
recordHealthyPeerCount(count: number): void;
|
|
17
19
|
recordLowScoreDisconnect(scoreState: 'Banned' | 'Disconnect'): void;
|
|
18
20
|
peerConnected(id: PeerId): void;
|
|
19
21
|
peerDisconnected(id: PeerId): void;
|
|
20
22
|
}
|
|
21
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
23
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWV0cmljcy5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3NlcnZpY2VzL3BlZXItbWFuYWdlci9tZXRyaWNzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFLTCxLQUFLLGVBQWUsRUFDcEIsS0FBSyxNQUFNLEVBSVosTUFBTSx5QkFBeUIsQ0FBQztBQUVqQyxPQUFPLEtBQUssRUFBRSxNQUFNLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQztBQUVoRCxPQUFPLEVBQUUsYUFBYSxFQUF1QixNQUFNLCtCQUErQixDQUFDO0FBRW5GLHFCQUFhLGtCQUFrQjthQWFYLGVBQWUsRUFBRSxlQUFlO0lBWmxELE9BQU8sQ0FBQyxZQUFZLENBQWdCO0lBQ3BDLE9BQU8sQ0FBQyxnQkFBZ0IsQ0FBZ0I7SUFDeEMsT0FBTyxDQUFDLFNBQVMsQ0FBUTtJQUN6QixPQUFPLENBQUMsZ0JBQWdCLENBQVE7SUFDaEMsT0FBTyxDQUFDLG1CQUFtQixDQUFnQjtJQUMzQyxPQUFPLENBQUMsc0JBQXNCLENBQVk7SUFFMUMsT0FBTyxDQUFDLGVBQWUsQ0FBa0Q7SUFFekUsU0FBZ0IsTUFBTSxFQUFFLE1BQU0sQ0FBQztJQUUvQixZQUNrQixlQUFlLEdBQUUsZUFBc0MsRUFDdkUsSUFBSSxTQUFnQixFQTJCckI7SUFFTSxpQkFBaUIsQ0FBQyxNQUFNLEVBQUUsYUFBYSxRQUU3QztJQUVNLHFCQUFxQixDQUFDLE1BQU0sRUFBRSxhQUFhLFFBRWpEO0lBRU0sZUFBZSxDQUFDLEtBQUssRUFBRSxNQUFNLFFBRW5DO0lBRU0sc0JBQXNCLENBQUMsS0FBSyxFQUFFLE1BQU0sUUFFMUM7SUFFTSx3QkFBd0IsQ0FBQyxVQUFVLEVBQUUsUUFBUSxHQUFHLFlBQVksUUFFbEU7SUFFTSxhQUFhLENBQUMsRUFBRSxFQUFFLE1BQU0sUUFFOUI7SUFFTSxnQkFBZ0IsQ0FBQyxFQUFFLEVBQUUsTUFBTSxRQU1qQztDQUNGIn0=
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metrics.d.ts","sourceRoot":"","sources":["../../../src/services/peer-manager/metrics.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,eAAe,EACpB,KAAK,MAAM,EAIZ,MAAM,yBAAyB,CAAC;AAEjC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAEhD,OAAO,EAAE,aAAa,EAAuB,MAAM,+BAA+B,CAAC;AAEnF,qBAAa,kBAAkB;
|
|
1
|
+
{"version":3,"file":"metrics.d.ts","sourceRoot":"","sources":["../../../src/services/peer-manager/metrics.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,eAAe,EACpB,KAAK,MAAM,EAIZ,MAAM,yBAAyB,CAAC;AAEjC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAEhD,OAAO,EAAE,aAAa,EAAuB,MAAM,+BAA+B,CAAC;AAEnF,qBAAa,kBAAkB;aAaX,eAAe,EAAE,eAAe;IAZlD,OAAO,CAAC,YAAY,CAAgB;IACpC,OAAO,CAAC,gBAAgB,CAAgB;IACxC,OAAO,CAAC,SAAS,CAAQ;IACzB,OAAO,CAAC,gBAAgB,CAAQ;IAChC,OAAO,CAAC,mBAAmB,CAAgB;IAC3C,OAAO,CAAC,sBAAsB,CAAY;IAE1C,OAAO,CAAC,eAAe,CAAkD;IAEzE,SAAgB,MAAM,EAAE,MAAM,CAAC;IAE/B,YACkB,eAAe,GAAE,eAAsC,EACvE,IAAI,SAAgB,EA2BrB;IAEM,iBAAiB,CAAC,MAAM,EAAE,aAAa,QAE7C;IAEM,qBAAqB,CAAC,MAAM,EAAE,aAAa,QAEjD;IAEM,eAAe,CAAC,KAAK,EAAE,MAAM,QAEnC;IAEM,sBAAsB,CAAC,KAAK,EAAE,MAAM,QAE1C;IAEM,wBAAwB,CAAC,UAAU,EAAE,QAAQ,GAAG,YAAY,QAElE;IAEM,aAAa,CAAC,EAAE,EAAE,MAAM,QAE9B;IAEM,gBAAgB,CAAC,EAAE,EAAE,MAAM,QAMjC;CACF"}
|
|
@@ -5,6 +5,7 @@ export class PeerManagerMetrics {
|
|
|
5
5
|
sentGoodbyes;
|
|
6
6
|
receivedGoodbyes;
|
|
7
7
|
peerCount;
|
|
8
|
+
healthyPeerCount;
|
|
8
9
|
lowScoreDisconnects;
|
|
9
10
|
peerConnectionDuration;
|
|
10
11
|
peerConnectedAt;
|
|
@@ -27,6 +28,7 @@ export class PeerManagerMetrics {
|
|
|
27
28
|
this.sentGoodbyes = createUpDownCounterWithDefault(meter, Metrics.PEER_MANAGER_GOODBYES_SENT, goodbyeReasonAttrs);
|
|
28
29
|
this.receivedGoodbyes = createUpDownCounterWithDefault(meter, Metrics.PEER_MANAGER_GOODBYES_RECEIVED, goodbyeReasonAttrs);
|
|
29
30
|
this.peerCount = meter.createGauge(Metrics.PEER_MANAGER_PEER_COUNT);
|
|
31
|
+
this.healthyPeerCount = meter.createGauge(Metrics.PEER_MANAGER_HEALTHY_PEER_COUNT);
|
|
30
32
|
this.lowScoreDisconnects = createUpDownCounterWithDefault(meter, Metrics.PEER_MANAGER_LOW_SCORE_DISCONNECTS, {
|
|
31
33
|
[Attributes.P2P_PEER_SCORE_STATE]: [
|
|
32
34
|
'Banned',
|
|
@@ -48,6 +50,9 @@ export class PeerManagerMetrics {
|
|
|
48
50
|
recordPeerCount(count) {
|
|
49
51
|
this.peerCount.record(count);
|
|
50
52
|
}
|
|
53
|
+
recordHealthyPeerCount(count) {
|
|
54
|
+
this.healthyPeerCount.record(count);
|
|
55
|
+
}
|
|
51
56
|
recordLowScoreDisconnect(scoreState) {
|
|
52
57
|
this.lowScoreDisconnects.add(1, {
|
|
53
58
|
[Attributes.P2P_PEER_SCORE_STATE]: scoreState
|
|
@@ -60,6 +65,7 @@ export class PeerManagerMetrics {
|
|
|
60
65
|
const connectedAt = this.peerConnectedAt.get(id.toString());
|
|
61
66
|
if (connectedAt) {
|
|
62
67
|
this.peerConnectionDuration.record(Date.now() - connectedAt);
|
|
68
|
+
this.peerConnectedAt.delete(id.toString());
|
|
63
69
|
}
|
|
64
70
|
}
|
|
65
71
|
}
|
|
@@ -53,11 +53,15 @@ export declare class PeerManager implements PeerManagerInterface {
|
|
|
53
53
|
heartbeat(): Promise<void>;
|
|
54
54
|
setupDirectPeersIfValidator(): Promise<void>;
|
|
55
55
|
/**
|
|
56
|
-
* Cleans up expired timeouts.
|
|
56
|
+
* Cleans up expired timeouts and stale failed-auth-handshake entries.
|
|
57
57
|
*
|
|
58
58
|
* When peers fail to dial after a number of retries, they are temporarily timed out.
|
|
59
59
|
* This function removes any peers that have been in the timed out state for too long.
|
|
60
60
|
* To give them a chance to reconnect.
|
|
61
|
+
*
|
|
62
|
+
* Also evicts entries from the failed-auth-handshake map whose expiry window has passed.
|
|
63
|
+
* Without this, peers that probe once and never reconnect would leave their entries in the
|
|
64
|
+
* map forever, causing an unbounded memory leak.
|
|
61
65
|
*/
|
|
62
66
|
private cleanupExpiredTimeouts;
|
|
63
67
|
private processScheduledDisconnects;
|
|
@@ -171,4 +175,4 @@ export declare class PeerManager implements PeerManagerInterface {
|
|
|
171
175
|
handleAuthRequestFromPeer(_authRequest: AuthRequest, peerId: PeerId): Promise<StatusMessage>;
|
|
172
176
|
private updateAuthenticatedPeers;
|
|
173
177
|
}
|
|
174
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
178
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGVlcl9tYW5hZ2VyLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvc2VydmljZXMvcGVlci1tYW5hZ2VyL3BlZXJfbWFuYWdlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssRUFBRSxtQkFBbUIsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBRzlELE9BQU8sS0FBSyxFQUFFLFVBQVUsRUFBRSxNQUFNLCtCQUErQixDQUFDO0FBR2hFLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUN2RCxPQUFPLEtBQUssRUFBRSxRQUFRLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUN4RixPQUFPLEtBQUssRUFBRSxpQkFBaUIsRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBQzNELE9BQU8sS0FBSyxFQUFFLGVBQWUsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBRS9ELE9BQU8sS0FBSyxFQUFjLE1BQU0sRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBTTVELE9BQU8sS0FBSyxFQUFFLFNBQVMsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBRWpELE9BQU8sS0FBSyxFQUFFLFVBQVUsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUVoRCxPQUFPLEVBQUUsV0FBVyxFQUFnQixNQUFNLDhCQUE4QixDQUFDO0FBQ3pFLE9BQU8sRUFBRSxhQUFhLEVBQXVCLE1BQU0saUNBQWlDLENBQUM7QUFDckYsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBQy9ELE9BQU8sS0FBSyxFQUFFLE9BQU8sRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBRXJELE9BQU8sS0FBSyxFQUFFLG9CQUFvQixFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQzFELE9BQU8sS0FBSyxFQUFFLG9CQUFvQixFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFFM0QsT0FBTyxFQUFrQixLQUFLLFdBQVcsRUFBRSxNQUFNLG1C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
|