@aztec/p2p 0.0.0-test.0 → 0.0.1-commit.023c3e5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dest/bootstrap/bootstrap.d.ts +4 -3
- package/dest/bootstrap/bootstrap.d.ts.map +1 -1
- package/dest/bootstrap/bootstrap.js +26 -13
- package/dest/client/factory.d.ts +15 -5
- package/dest/client/factory.d.ts.map +1 -1
- package/dest/client/factory.js +61 -25
- package/dest/client/index.d.ts +2 -1
- package/dest/client/index.d.ts.map +1 -1
- package/dest/client/index.js +1 -0
- package/dest/client/interface.d.ts +170 -0
- package/dest/client/interface.d.ts.map +1 -0
- package/dest/client/interface.js +9 -0
- package/dest/client/p2p_client.d.ts +75 -193
- package/dest/client/p2p_client.d.ts.map +1 -1
- package/dest/client/p2p_client.js +765 -229
- package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.d.ts +2 -0
- package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.d.ts.map +1 -0
- package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.js +305 -0
- package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker_protocol.d.ts +73 -0
- package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker_protocol.d.ts.map +1 -0
- package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker_protocol.js +8 -0
- package/dest/config.d.ts +154 -125
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +182 -34
- package/dest/enr/generate-enr.d.ts +11 -3
- package/dest/enr/generate-enr.d.ts.map +1 -1
- package/dest/enr/generate-enr.js +27 -5
- package/dest/enr/index.d.ts +1 -1
- package/dest/errors/attestation-pool.error.d.ts +7 -0
- package/dest/errors/attestation-pool.error.d.ts.map +1 -0
- package/dest/errors/attestation-pool.error.js +12 -0
- package/dest/errors/reqresp.error.d.ts +1 -1
- package/dest/errors/reqresp.error.d.ts.map +1 -1
- package/dest/index.d.ts +4 -1
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +2 -0
- package/dest/mem_pools/attestation_pool/attestation_pool.d.ts +104 -25
- package/dest/mem_pools/attestation_pool/attestation_pool.d.ts.map +1 -1
- 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 +299 -174
- package/dest/mem_pools/attestation_pool/index.d.ts +1 -1
- package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts +29 -11
- package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/kv_attestation_pool.js +168 -62
- package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts +24 -10
- package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/memory_attestation_pool.js +133 -82
- package/dest/mem_pools/attestation_pool/mocks.d.ts +234 -11
- package/dest/mem_pools/attestation_pool/mocks.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/mocks.js +19 -21
- package/dest/mem_pools/index.d.ts +1 -1
- package/dest/mem_pools/instrumentation.d.ts +16 -12
- package/dest/mem_pools/instrumentation.d.ts.map +1 -1
- package/dest/mem_pools/instrumentation.js +56 -41
- package/dest/mem_pools/interface.d.ts +3 -4
- package/dest/mem_pools/interface.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts +75 -16
- package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.js +493 -142
- package/dest/mem_pools/tx_pool/eviction/eviction_manager.d.ts +32 -0
- package/dest/mem_pools/tx_pool/eviction/eviction_manager.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool/eviction/eviction_manager.js +112 -0
- package/dest/mem_pools/tx_pool/eviction/eviction_strategy.d.ts +157 -0
- package/dest/mem_pools/tx_pool/eviction/eviction_strategy.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool/eviction/eviction_strategy.js +52 -0
- package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.d.ts +16 -0
- package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.js +122 -0
- package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.d.ts +17 -0
- package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.js +84 -0
- package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.d.ts +19 -0
- package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.js +78 -0
- package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.d.ts +26 -0
- package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.js +84 -0
- package/dest/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.d.ts +25 -0
- package/dest/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.js +57 -0
- package/dest/mem_pools/tx_pool/index.d.ts +1 -2
- package/dest/mem_pools/tx_pool/index.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/index.js +0 -1
- package/dest/mem_pools/tx_pool/priority.d.ts +5 -1
- package/dest/mem_pools/tx_pool/priority.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/priority.js +7 -2
- package/dest/mem_pools/tx_pool/tx_pool.d.ts +72 -11
- package/dest/mem_pools/tx_pool/tx_pool.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts +1 -1
- package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/tx_pool_test_suite.js +276 -45
- package/dest/msg_validators/attestation_validator/attestation_validator.d.ts +7 -5
- package/dest/msg_validators/attestation_validator/attestation_validator.d.ts.map +1 -1
- package/dest/msg_validators/attestation_validator/attestation_validator.js +79 -10
- package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts +20 -0
- package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts.map +1 -0
- package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.js +76 -0
- package/dest/msg_validators/attestation_validator/index.d.ts +2 -1
- package/dest/msg_validators/attestation_validator/index.d.ts.map +1 -1
- package/dest/msg_validators/attestation_validator/index.js +1 -0
- package/dest/msg_validators/clock_tolerance.d.ts +21 -0
- package/dest/msg_validators/clock_tolerance.d.ts.map +1 -0
- package/dest/msg_validators/clock_tolerance.js +37 -0
- package/dest/msg_validators/index.d.ts +2 -2
- package/dest/msg_validators/index.d.ts.map +1 -1
- package/dest/msg_validators/index.js +1 -1
- package/dest/msg_validators/msg_seen_validator/msg_seen_validator.d.ts +10 -0
- package/dest/msg_validators/msg_seen_validator/msg_seen_validator.d.ts.map +1 -0
- package/dest/msg_validators/msg_seen_validator/msg_seen_validator.js +36 -0
- package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts +9 -0
- package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts.map +1 -0
- package/dest/msg_validators/proposal_validator/block_proposal_validator.js +6 -0
- package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts +9 -0
- package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts.map +1 -0
- package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.js +6 -0
- package/dest/msg_validators/proposal_validator/index.d.ts +4 -0
- package/dest/msg_validators/proposal_validator/index.d.ts.map +1 -0
- package/dest/msg_validators/proposal_validator/index.js +3 -0
- package/dest/msg_validators/proposal_validator/proposal_validator.d.ts +13 -0
- package/dest/msg_validators/proposal_validator/proposal_validator.d.ts.map +1 -0
- package/dest/msg_validators/proposal_validator/proposal_validator.js +104 -0
- package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.d.ts +23 -0
- package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.d.ts.map +1 -0
- package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.js +212 -0
- package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts +1 -1
- package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/allowed_public_setup.d.ts +3 -0
- package/dest/msg_validators/tx_validator/allowed_public_setup.d.ts.map +1 -0
- package/dest/msg_validators/tx_validator/allowed_public_setup.js +27 -0
- package/dest/msg_validators/tx_validator/archive_cache.d.ts +14 -0
- package/dest/msg_validators/tx_validator/archive_cache.d.ts.map +1 -0
- package/dest/msg_validators/tx_validator/archive_cache.js +22 -0
- package/dest/msg_validators/tx_validator/block_header_validator.d.ts +5 -4
- package/dest/msg_validators/tx_validator/block_header_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/block_header_validator.js +7 -6
- package/dest/msg_validators/tx_validator/data_validator.d.ts +3 -1
- package/dest/msg_validators/tx_validator/data_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/data_validator.js +60 -87
- package/dest/msg_validators/tx_validator/double_spend_validator.d.ts +3 -4
- package/dest/msg_validators/tx_validator/double_spend_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/double_spend_validator.js +24 -29
- package/dest/msg_validators/tx_validator/factory.d.ts +21 -0
- package/dest/msg_validators/tx_validator/factory.d.ts.map +1 -0
- package/dest/msg_validators/tx_validator/factory.js +84 -0
- package/dest/msg_validators/tx_validator/fee_payer_balance.d.ts +10 -0
- package/dest/msg_validators/tx_validator/fee_payer_balance.d.ts.map +1 -0
- package/dest/msg_validators/tx_validator/fee_payer_balance.js +20 -0
- package/dest/msg_validators/tx_validator/gas_validator.d.ts +12 -0
- package/dest/msg_validators/tx_validator/gas_validator.d.ts.map +1 -0
- package/dest/msg_validators/tx_validator/gas_validator.js +110 -0
- package/dest/msg_validators/tx_validator/index.d.ts +9 -1
- package/dest/msg_validators/tx_validator/index.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/index.js +8 -0
- package/dest/msg_validators/tx_validator/metadata_validator.d.ts +10 -5
- package/dest/msg_validators/tx_validator/metadata_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/metadata_validator.js +40 -21
- package/dest/msg_validators/tx_validator/phases_validator.d.ts +15 -0
- package/dest/msg_validators/tx_validator/phases_validator.d.ts.map +1 -0
- package/dest/msg_validators/tx_validator/phases_validator.js +93 -0
- package/dest/msg_validators/tx_validator/size_validator.d.ts +8 -0
- package/dest/msg_validators/tx_validator/size_validator.d.ts.map +1 -0
- package/dest/msg_validators/tx_validator/size_validator.js +23 -0
- package/dest/msg_validators/tx_validator/test_utils.d.ts +17 -0
- package/dest/msg_validators/tx_validator/test_utils.d.ts.map +1 -0
- package/dest/msg_validators/tx_validator/test_utils.js +22 -0
- package/dest/msg_validators/tx_validator/timestamp_validator.d.ts +14 -0
- package/dest/msg_validators/tx_validator/timestamp_validator.d.ts.map +1 -0
- package/dest/msg_validators/tx_validator/timestamp_validator.js +32 -0
- package/dest/msg_validators/tx_validator/tx_permitted_validator.d.ts +9 -0
- package/dest/msg_validators/tx_validator/tx_permitted_validator.d.ts.map +1 -0
- package/dest/msg_validators/tx_validator/tx_permitted_validator.js +24 -0
- package/dest/msg_validators/tx_validator/tx_proof_validator.d.ts +3 -2
- package/dest/msg_validators/tx_validator/tx_proof_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/tx_proof_validator.js +8 -7
- 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 +10 -6
- package/dest/services/discv5/discV5_service.d.ts +10 -9
- package/dest/services/discv5/discV5_service.d.ts.map +1 -1
- package/dest/services/discv5/discV5_service.js +64 -37
- package/dest/services/dummy_service.d.ts +66 -11
- package/dest/services/dummy_service.d.ts.map +1 -1
- package/dest/services/dummy_service.js +130 -5
- package/dest/services/encoding.d.ts +26 -7
- package/dest/services/encoding.d.ts.map +1 -1
- package/dest/services/encoding.js +75 -6
- package/dest/services/gossipsub/scoring.d.ts +1 -1
- package/dest/services/index.d.ts +5 -1
- package/dest/services/index.d.ts.map +1 -1
- package/dest/services/index.js +4 -0
- package/dest/services/libp2p/instrumentation.d.ts +20 -0
- package/dest/services/libp2p/instrumentation.d.ts.map +1 -0
- package/dest/services/libp2p/instrumentation.js +122 -0
- package/dest/services/libp2p/libp2p_service.d.ts +107 -95
- package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
- package/dest/services/libp2p/libp2p_service.js +1328 -313
- package/dest/services/peer-manager/interface.d.ts +23 -0
- package/dest/services/peer-manager/interface.d.ts.map +1 -0
- package/dest/services/peer-manager/interface.js +1 -0
- package/dest/services/peer-manager/metrics.d.ts +12 -3
- package/dest/services/peer-manager/metrics.d.ts.map +1 -1
- package/dest/services/peer-manager/metrics.js +44 -12
- package/dest/services/peer-manager/peer_manager.d.ts +103 -23
- package/dest/services/peer-manager/peer_manager.d.ts.map +1 -1
- package/dest/services/peer-manager/peer_manager.js +551 -82
- 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 +43 -2
- package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts +47 -0
- package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts.map +1 -0
- package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.js +566 -0
- package/dest/services/reqresp/batch-tx-requester/config.d.ts +17 -0
- package/dest/services/reqresp/batch-tx-requester/config.d.ts.map +1 -0
- package/dest/services/reqresp/batch-tx-requester/config.js +27 -0
- package/dest/services/reqresp/batch-tx-requester/interface.d.ts +50 -0
- package/dest/services/reqresp/batch-tx-requester/interface.d.ts.map +1 -0
- package/dest/services/reqresp/batch-tx-requester/interface.js +1 -0
- package/dest/services/reqresp/batch-tx-requester/missing_txs.d.ts +37 -0
- package/dest/services/reqresp/batch-tx-requester/missing_txs.d.ts.map +1 -0
- package/dest/services/reqresp/batch-tx-requester/missing_txs.js +151 -0
- package/dest/services/reqresp/batch-tx-requester/peer_collection.d.ts +54 -0
- package/dest/services/reqresp/batch-tx-requester/peer_collection.d.ts.map +1 -0
- package/dest/services/reqresp/batch-tx-requester/peer_collection.js +139 -0
- package/dest/services/reqresp/batch-tx-requester/tx_validator.d.ts +20 -0
- package/dest/services/reqresp/batch-tx-requester/tx_validator.d.ts.map +1 -0
- package/dest/services/reqresp/batch-tx-requester/tx_validator.js +21 -0
- package/dest/services/reqresp/config.d.ts +11 -9
- package/dest/services/reqresp/config.d.ts.map +1 -1
- package/dest/services/reqresp/config.js +18 -4
- package/dest/services/reqresp/connection-sampler/batch_connection_sampler.d.ts +23 -4
- package/dest/services/reqresp/connection-sampler/batch_connection_sampler.d.ts.map +1 -1
- package/dest/services/reqresp/connection-sampler/batch_connection_sampler.js +73 -10
- package/dest/services/reqresp/connection-sampler/connection_sampler.d.ts +32 -17
- package/dest/services/reqresp/connection-sampler/connection_sampler.d.ts.map +1 -1
- package/dest/services/reqresp/connection-sampler/connection_sampler.js +154 -84
- package/dest/services/reqresp/constants.d.ts +12 -0
- package/dest/services/reqresp/constants.d.ts.map +1 -0
- package/dest/services/reqresp/constants.js +7 -0
- package/dest/services/reqresp/index.d.ts +3 -2
- package/dest/services/reqresp/index.d.ts.map +1 -1
- package/dest/services/reqresp/index.js +2 -1
- package/dest/services/reqresp/interface.d.ts +75 -24
- package/dest/services/reqresp/interface.d.ts.map +1 -1
- package/dest/services/reqresp/interface.js +46 -27
- package/dest/services/reqresp/metrics.d.ts +6 -5
- package/dest/services/reqresp/metrics.d.ts.map +1 -1
- package/dest/services/reqresp/metrics.js +17 -21
- package/dest/services/reqresp/protocols/auth.d.ts +43 -0
- package/dest/services/reqresp/protocols/auth.d.ts.map +1 -0
- package/dest/services/reqresp/protocols/auth.js +71 -0
- package/dest/services/reqresp/protocols/block.d.ts +6 -1
- package/dest/services/reqresp/protocols/block.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/block.js +30 -6
- package/dest/services/reqresp/protocols/block_txs/bitvector.d.ts +34 -0
- package/dest/services/reqresp/protocols/block_txs/bitvector.d.ts.map +1 -0
- package/dest/services/reqresp/protocols/block_txs/bitvector.js +87 -0
- package/dest/services/reqresp/protocols/block_txs/block_txs_handler.d.ts +11 -0
- package/dest/services/reqresp/protocols/block_txs/block_txs_handler.d.ts.map +1 -0
- package/dest/services/reqresp/protocols/block_txs/block_txs_handler.js +52 -0
- package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.d.ts +59 -0
- package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.d.ts.map +1 -0
- package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.js +105 -0
- package/dest/services/reqresp/protocols/block_txs/index.d.ts +4 -0
- package/dest/services/reqresp/protocols/block_txs/index.d.ts.map +1 -0
- package/dest/services/reqresp/protocols/block_txs/index.js +3 -0
- package/dest/services/reqresp/protocols/goodbye.d.ts +3 -5
- package/dest/services/reqresp/protocols/goodbye.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/goodbye.js +7 -7
- package/dest/services/reqresp/protocols/index.d.ts +3 -1
- package/dest/services/reqresp/protocols/index.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/index.js +2 -0
- package/dest/services/reqresp/protocols/ping.d.ts +1 -3
- package/dest/services/reqresp/protocols/ping.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/status.d.ts +40 -7
- package/dest/services/reqresp/protocols/status.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/status.js +76 -5
- package/dest/services/reqresp/protocols/tx.d.ts +14 -4
- package/dest/services/reqresp/protocols/tx.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/tx.js +34 -6
- package/dest/services/reqresp/rate-limiter/index.d.ts +1 -1
- package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts +6 -4
- package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts.map +1 -1
- package/dest/services/reqresp/rate-limiter/rate_limiter.js +10 -2
- 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 +21 -1
- package/dest/services/reqresp/reqresp.d.ts +29 -66
- package/dest/services/reqresp/reqresp.d.ts.map +1 -1
- package/dest/services/reqresp/reqresp.js +753 -248
- package/dest/services/reqresp/status.d.ts +10 -4
- package/dest/services/reqresp/status.d.ts.map +1 -1
- package/dest/services/reqresp/status.js +9 -2
- package/dest/services/service.d.ts +40 -20
- package/dest/services/service.d.ts.map +1 -1
- package/dest/services/tx_collection/config.d.ts +28 -0
- package/dest/services/tx_collection/config.d.ts.map +1 -0
- package/dest/services/tx_collection/config.js +66 -0
- package/dest/services/tx_collection/fast_tx_collection.d.ts +53 -0
- package/dest/services/tx_collection/fast_tx_collection.d.ts.map +1 -0
- package/dest/services/tx_collection/fast_tx_collection.js +311 -0
- package/dest/services/tx_collection/index.d.ts +4 -0
- package/dest/services/tx_collection/index.d.ts.map +1 -0
- package/dest/services/tx_collection/index.js +3 -0
- package/dest/services/tx_collection/instrumentation.d.ts +10 -0
- package/dest/services/tx_collection/instrumentation.d.ts.map +1 -0
- package/dest/services/tx_collection/instrumentation.js +31 -0
- package/dest/services/tx_collection/proposal_tx_collector.d.ts +48 -0
- package/dest/services/tx_collection/proposal_tx_collector.d.ts.map +1 -0
- package/dest/services/tx_collection/proposal_tx_collector.js +50 -0
- package/dest/services/tx_collection/slow_tx_collection.d.ts +53 -0
- package/dest/services/tx_collection/slow_tx_collection.d.ts.map +1 -0
- package/dest/services/tx_collection/slow_tx_collection.js +177 -0
- package/dest/services/tx_collection/tx_collection.d.ts +110 -0
- package/dest/services/tx_collection/tx_collection.d.ts.map +1 -0
- package/dest/services/tx_collection/tx_collection.js +128 -0
- package/dest/services/tx_collection/tx_collection_sink.d.ts +30 -0
- package/dest/services/tx_collection/tx_collection_sink.d.ts.map +1 -0
- package/dest/services/tx_collection/tx_collection_sink.js +111 -0
- package/dest/services/tx_collection/tx_source.d.ts +18 -0
- package/dest/services/tx_collection/tx_source.d.ts.map +1 -0
- package/dest/services/tx_collection/tx_source.js +31 -0
- package/dest/services/tx_provider.d.ts +51 -0
- package/dest/services/tx_provider.d.ts.map +1 -0
- package/dest/services/tx_provider.js +219 -0
- package/dest/services/tx_provider_instrumentation.d.ts +16 -0
- package/dest/services/tx_provider_instrumentation.d.ts.map +1 -0
- package/dest/services/tx_provider_instrumentation.js +34 -0
- package/dest/test-helpers/generate-peer-id-private-keys.d.ts +1 -1
- package/dest/test-helpers/get-ports.d.ts +1 -1
- package/dest/test-helpers/get-ports.d.ts.map +1 -1
- package/dest/test-helpers/index.d.ts +4 -1
- package/dest/test-helpers/index.d.ts.map +1 -1
- package/dest/test-helpers/index.js +3 -0
- package/dest/test-helpers/make-enrs.d.ts +1 -1
- package/dest/test-helpers/make-enrs.d.ts.map +1 -1
- package/dest/test-helpers/make-enrs.js +4 -5
- package/dest/test-helpers/make-test-p2p-clients.d.ts +33 -5
- package/dest/test-helpers/make-test-p2p-clients.d.ts.map +1 -1
- package/dest/test-helpers/make-test-p2p-clients.js +86 -16
- package/dest/test-helpers/mock-pubsub.d.ts +59 -0
- package/dest/test-helpers/mock-pubsub.d.ts.map +1 -0
- package/dest/test-helpers/mock-pubsub.js +130 -0
- package/dest/test-helpers/mock-tx-helpers.d.ts +12 -0
- package/dest/test-helpers/mock-tx-helpers.d.ts.map +1 -0
- package/dest/test-helpers/mock-tx-helpers.js +19 -0
- package/dest/test-helpers/reqresp-nodes.d.ts +15 -11
- package/dest/test-helpers/reqresp-nodes.d.ts.map +1 -1
- package/dest/test-helpers/reqresp-nodes.js +62 -28
- package/dest/test-helpers/test_tx_provider.d.ts +40 -0
- package/dest/test-helpers/test_tx_provider.d.ts.map +1 -0
- package/dest/test-helpers/test_tx_provider.js +41 -0
- package/dest/test-helpers/testbench-utils.d.ts +158 -0
- package/dest/test-helpers/testbench-utils.d.ts.map +1 -0
- package/dest/test-helpers/testbench-utils.js +297 -0
- package/dest/testbench/p2p_client_testbench_worker.d.ts +28 -2
- package/dest/testbench/p2p_client_testbench_worker.d.ts.map +1 -1
- package/dest/testbench/p2p_client_testbench_worker.js +259 -90
- package/dest/testbench/parse_log_file.d.ts +1 -1
- package/dest/testbench/parse_log_file.js +4 -4
- package/dest/testbench/testbench.d.ts +1 -1
- package/dest/testbench/testbench.js +4 -4
- package/dest/testbench/worker_client_manager.d.ts +51 -11
- package/dest/testbench/worker_client_manager.d.ts.map +1 -1
- package/dest/testbench/worker_client_manager.js +232 -53
- package/dest/types/index.d.ts +4 -2
- package/dest/types/index.d.ts.map +1 -1
- package/dest/types/index.js +2 -0
- package/dest/util.d.ts +24 -16
- package/dest/util.d.ts.map +1 -1
- package/dest/util.js +75 -69
- package/dest/versioning.d.ts +4 -4
- package/dest/versioning.d.ts.map +1 -1
- package/dest/versioning.js +8 -3
- package/package.json +32 -27
- package/src/bootstrap/bootstrap.ts +34 -15
- package/src/client/factory.ts +135 -53
- package/src/client/index.ts +1 -0
- package/src/client/interface.ts +213 -0
- package/src/client/p2p_client.ts +476 -383
- package/src/client/test/tx_proposal_collector/README.md +227 -0
- package/src/client/test/tx_proposal_collector/proposal_tx_collector_worker.ts +336 -0
- package/src/client/test/tx_proposal_collector/proposal_tx_collector_worker_protocol.ts +43 -0
- package/src/config.ts +304 -134
- package/src/enr/generate-enr.ts +39 -6
- package/src/errors/attestation-pool.error.ts +13 -0
- package/src/index.ts +4 -0
- package/src/mem_pools/attestation_pool/attestation_pool.ts +119 -24
- package/src/mem_pools/attestation_pool/attestation_pool_test_suite.ts +352 -201
- package/src/mem_pools/attestation_pool/kv_attestation_pool.ts +233 -72
- package/src/mem_pools/attestation_pool/memory_attestation_pool.ts +199 -96
- package/src/mem_pools/attestation_pool/mocks.ts +24 -17
- package/src/mem_pools/instrumentation.ts +72 -48
- package/src/mem_pools/interface.ts +2 -4
- package/src/mem_pools/tx_pool/README.md +270 -0
- package/src/mem_pools/tx_pool/aztec_kv_tx_pool.ts +580 -143
- package/src/mem_pools/tx_pool/eviction/eviction_manager.ts +132 -0
- package/src/mem_pools/tx_pool/eviction/eviction_strategy.ts +208 -0
- package/src/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.ts +162 -0
- package/src/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.ts +104 -0
- package/src/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.ts +93 -0
- package/src/mem_pools/tx_pool/eviction/low_priority_eviction_rule.ts +106 -0
- package/src/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.ts +75 -0
- package/src/mem_pools/tx_pool/index.ts +0 -1
- package/src/mem_pools/tx_pool/priority.ts +9 -2
- package/src/mem_pools/tx_pool/tx_pool.ts +75 -10
- package/src/mem_pools/tx_pool/tx_pool_test_suite.ts +225 -36
- package/src/msg_validators/attestation_validator/attestation_validator.ts +72 -14
- package/src/msg_validators/attestation_validator/fisherman_attestation_validator.ts +94 -0
- package/src/msg_validators/attestation_validator/index.ts +1 -0
- package/src/msg_validators/clock_tolerance.ts +51 -0
- package/src/msg_validators/index.ts +1 -1
- package/src/msg_validators/msg_seen_validator/msg_seen_validator.ts +36 -0
- package/src/msg_validators/proposal_validator/block_proposal_validator.ts +10 -0
- package/src/msg_validators/proposal_validator/checkpoint_proposal_validator.ts +13 -0
- package/src/msg_validators/proposal_validator/index.ts +3 -0
- package/src/msg_validators/proposal_validator/proposal_validator.ts +92 -0
- package/src/msg_validators/proposal_validator/proposal_validator_test_suite.ts +230 -0
- package/src/msg_validators/tx_validator/allowed_public_setup.ts +35 -0
- package/src/msg_validators/tx_validator/archive_cache.ts +28 -0
- package/src/msg_validators/tx_validator/block_header_validator.ts +10 -9
- package/src/msg_validators/tx_validator/data_validator.ts +95 -71
- package/src/msg_validators/tx_validator/double_spend_validator.ts +23 -20
- package/src/msg_validators/tx_validator/factory.ts +151 -0
- package/src/msg_validators/tx_validator/fee_payer_balance.ts +40 -0
- package/src/msg_validators/tx_validator/gas_validator.ts +123 -0
- package/src/msg_validators/tx_validator/index.ts +8 -0
- package/src/msg_validators/tx_validator/metadata_validator.ts +72 -24
- package/src/msg_validators/tx_validator/phases_validator.ts +118 -0
- package/src/msg_validators/tx_validator/size_validator.ts +22 -0
- package/src/msg_validators/tx_validator/test_utils.ts +43 -0
- package/src/msg_validators/tx_validator/timestamp_validator.ts +52 -0
- package/src/msg_validators/tx_validator/tx_permitted_validator.ts +22 -0
- package/src/msg_validators/tx_validator/tx_proof_validator.ts +14 -8
- package/src/services/data_store.ts +10 -7
- package/src/services/discv5/discV5_service.ts +85 -39
- package/src/services/dummy_service.ts +198 -9
- package/src/services/encoding.ts +82 -6
- package/src/services/index.ts +4 -0
- package/src/services/libp2p/instrumentation.ts +126 -0
- package/src/services/libp2p/libp2p_service.ts +1170 -353
- package/src/services/peer-manager/interface.ts +29 -0
- package/src/services/peer-manager/metrics.ts +55 -12
- package/src/services/peer-manager/peer_manager.ts +657 -80
- package/src/services/peer-manager/peer_scoring.ts +45 -3
- package/src/services/reqresp/batch-tx-requester/README.md +305 -0
- package/src/services/reqresp/batch-tx-requester/batch_tx_requester.ts +706 -0
- package/src/services/reqresp/batch-tx-requester/config.ts +40 -0
- package/src/services/reqresp/batch-tx-requester/interface.ts +57 -0
- package/src/services/reqresp/batch-tx-requester/missing_txs.ts +209 -0
- package/src/services/reqresp/batch-tx-requester/peer_collection.ts +205 -0
- package/src/services/reqresp/batch-tx-requester/tx_validator.ts +37 -0
- package/src/services/reqresp/config.ts +26 -9
- package/src/services/reqresp/connection-sampler/batch_connection_sampler.ts +77 -10
- package/src/services/reqresp/connection-sampler/connection_sampler.ts +166 -95
- package/src/services/reqresp/constants.ts +14 -0
- package/src/services/reqresp/index.ts +2 -0
- package/src/services/reqresp/interface.ts +95 -37
- package/src/services/reqresp/metrics.ts +40 -28
- package/src/services/reqresp/protocols/auth.ts +83 -0
- package/src/services/reqresp/protocols/block.ts +26 -4
- package/src/services/reqresp/protocols/block_txs/bitvector.ts +106 -0
- package/src/services/reqresp/protocols/block_txs/block_txs_handler.ts +67 -0
- package/src/services/reqresp/protocols/block_txs/block_txs_reqresp.ts +121 -0
- package/src/services/reqresp/protocols/block_txs/index.ts +3 -0
- package/src/services/reqresp/protocols/goodbye.ts +9 -7
- package/src/services/reqresp/protocols/index.ts +2 -0
- package/src/services/reqresp/protocols/status.ts +121 -5
- package/src/services/reqresp/protocols/tx.ts +36 -8
- package/src/services/reqresp/rate-limiter/rate_limiter.ts +12 -3
- package/src/services/reqresp/rate-limiter/rate_limits.ts +21 -1
- package/src/services/reqresp/reqresp.ts +449 -271
- package/src/services/reqresp/status.ts +12 -3
- package/src/services/service.ts +65 -22
- package/src/services/tx_collection/config.ts +98 -0
- package/src/services/tx_collection/fast_tx_collection.ts +364 -0
- package/src/services/tx_collection/index.ts +7 -0
- package/src/services/tx_collection/instrumentation.ts +35 -0
- package/src/services/tx_collection/proposal_tx_collector.ts +114 -0
- package/src/services/tx_collection/slow_tx_collection.ts +233 -0
- package/src/services/tx_collection/tx_collection.ts +216 -0
- package/src/services/tx_collection/tx_collection_sink.ts +129 -0
- package/src/services/tx_collection/tx_source.ts +37 -0
- package/src/services/tx_provider.ts +232 -0
- package/src/services/tx_provider_instrumentation.ts +54 -0
- package/src/test-helpers/index.ts +3 -0
- package/src/test-helpers/make-enrs.ts +4 -5
- package/src/test-helpers/make-test-p2p-clients.ts +111 -21
- package/src/test-helpers/mock-pubsub.ts +188 -0
- package/src/test-helpers/mock-tx-helpers.ts +24 -0
- package/src/test-helpers/reqresp-nodes.ts +87 -36
- package/src/test-helpers/test_tx_provider.ts +64 -0
- package/src/test-helpers/testbench-utils.ts +374 -0
- package/src/testbench/p2p_client_testbench_worker.ts +434 -89
- package/src/testbench/parse_log_file.ts +4 -4
- package/src/testbench/testbench.ts +4 -4
- package/src/testbench/worker_client_manager.ts +315 -59
- package/src/types/index.ts +2 -0
- package/src/util.ts +105 -91
- package/src/versioning.ts +11 -4
- package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts +0 -56
- package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/memory_tx_pool.js +0 -141
- package/dest/msg_validators/block_proposal_validator/block_proposal_validator.d.ts +0 -8
- package/dest/msg_validators/block_proposal_validator/block_proposal_validator.d.ts.map +0 -1
- package/dest/msg_validators/block_proposal_validator/block_proposal_validator.js +0 -21
- package/dest/msg_validators/block_proposal_validator/index.d.ts +0 -2
- package/dest/msg_validators/block_proposal_validator/index.d.ts.map +0 -1
- package/dest/msg_validators/block_proposal_validator/index.js +0 -1
- package/src/mem_pools/tx_pool/memory_tx_pool.ts +0 -174
- package/src/msg_validators/block_proposal_validator/block_proposal_validator.ts +0 -29
- package/src/msg_validators/block_proposal_validator/index.ts +0 -1
|
@@ -1,26 +1,44 @@
|
|
|
1
1
|
import type { EpochCacheInterface } from '@aztec/epoch-cache';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
2
|
+
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
3
|
+
import { randomInt } from '@aztec/foundation/crypto/random';
|
|
4
|
+
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
5
|
+
import { type Logger, createLibp2pComponentLogger, createLogger } from '@aztec/foundation/log';
|
|
5
6
|
import { RunningPromise } from '@aztec/foundation/running-promise';
|
|
7
|
+
import { Timer } from '@aztec/foundation/timer';
|
|
6
8
|
import type { AztecAsyncKVStore } from '@aztec/kv-store';
|
|
7
|
-
import
|
|
9
|
+
import { protocolContractsHash } from '@aztec/protocol-contracts';
|
|
10
|
+
import type { EthAddress, L2Block, L2BlockSource } from '@aztec/stdlib/block';
|
|
11
|
+
import type { ContractDataSource } from '@aztec/stdlib/contract';
|
|
12
|
+
import { GasFees } from '@aztec/stdlib/gas';
|
|
8
13
|
import type { ClientProtocolCircuitVerifier, PeerInfo, WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
|
|
9
14
|
import {
|
|
10
|
-
BlockAttestation,
|
|
11
15
|
BlockProposal,
|
|
16
|
+
CheckpointAttestation,
|
|
17
|
+
CheckpointProposal,
|
|
18
|
+
type CheckpointProposalCore,
|
|
12
19
|
type Gossipable,
|
|
13
20
|
P2PClientType,
|
|
21
|
+
P2PMessage,
|
|
22
|
+
type ValidationResult as P2PValidationResult,
|
|
14
23
|
PeerErrorSeverity,
|
|
15
|
-
|
|
16
|
-
|
|
24
|
+
TopicType,
|
|
25
|
+
createTopicString,
|
|
26
|
+
getTopicsForClientAndConfig,
|
|
17
27
|
metricsTopicStrToLabels,
|
|
18
28
|
} from '@aztec/stdlib/p2p';
|
|
19
29
|
import { MerkleTreeId } from '@aztec/stdlib/trees';
|
|
20
|
-
import { Tx, type TxHash, type TxValidationResult } from '@aztec/stdlib/tx';
|
|
21
|
-
import
|
|
30
|
+
import { Tx, type TxHash, type TxValidationResult, type TxValidator } from '@aztec/stdlib/tx';
|
|
31
|
+
import type { UInt64 } from '@aztec/stdlib/types';
|
|
32
|
+
import { compressComponentVersions } from '@aztec/stdlib/versioning';
|
|
33
|
+
import {
|
|
34
|
+
Attributes,
|
|
35
|
+
OtelMetricsAdapter,
|
|
36
|
+
SpanStatusCode,
|
|
37
|
+
type TelemetryClient,
|
|
38
|
+
WithTracer,
|
|
39
|
+
trackSpan,
|
|
40
|
+
} from '@aztec/telemetry-client';
|
|
22
41
|
|
|
23
|
-
import type { ENR } from '@chainsafe/enr';
|
|
24
42
|
import {
|
|
25
43
|
type GossipSub,
|
|
26
44
|
type GossipSubComponents,
|
|
@@ -33,41 +51,73 @@ import { noise } from '@chainsafe/libp2p-noise';
|
|
|
33
51
|
import { yamux } from '@chainsafe/libp2p-yamux';
|
|
34
52
|
import { bootstrap } from '@libp2p/bootstrap';
|
|
35
53
|
import { identify } from '@libp2p/identify';
|
|
36
|
-
import { type Message, type PeerId, TopicValidatorResult } from '@libp2p/interface';
|
|
54
|
+
import { type Message, type MultiaddrConnection, type PeerId, TopicValidatorResult } from '@libp2p/interface';
|
|
37
55
|
import type { ConnectionManager } from '@libp2p/interface-internal';
|
|
38
|
-
import '@libp2p/kad-dht';
|
|
39
56
|
import { mplex } from '@libp2p/mplex';
|
|
40
57
|
import { tcp } from '@libp2p/tcp';
|
|
58
|
+
import { ENR } from '@nethermindeth/enr';
|
|
41
59
|
import { createLibp2p } from 'libp2p';
|
|
42
60
|
|
|
43
61
|
import type { P2PConfig } from '../../config.js';
|
|
62
|
+
import { ProposalSlotCapExceededError } from '../../errors/attestation-pool.error.js';
|
|
44
63
|
import type { MemPools } from '../../mem_pools/interface.js';
|
|
45
|
-
import { AttestationValidator, BlockProposalValidator } from '../../msg_validators/index.js';
|
|
46
64
|
import {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
} from '../../msg_validators/
|
|
65
|
+
BlockProposalValidator,
|
|
66
|
+
CheckpointAttestationValidator,
|
|
67
|
+
CheckpointProposalValidator,
|
|
68
|
+
FishermanAttestationValidator,
|
|
69
|
+
} from '../../msg_validators/index.js';
|
|
70
|
+
import { MessageSeenValidator } from '../../msg_validators/msg_seen_validator/msg_seen_validator.js';
|
|
71
|
+
import { getDefaultAllowedSetupFunctions } from '../../msg_validators/tx_validator/allowed_public_setup.js';
|
|
72
|
+
import {
|
|
73
|
+
type MessageValidator,
|
|
74
|
+
createTxMessageValidators,
|
|
75
|
+
createTxReqRespValidator,
|
|
76
|
+
} from '../../msg_validators/tx_validator/factory.js';
|
|
77
|
+
import { DoubleSpendTxValidator } from '../../msg_validators/tx_validator/index.js';
|
|
52
78
|
import { GossipSubEvent } from '../../types/index.js';
|
|
53
79
|
import { type PubSubLibp2p, convertToMultiaddr } from '../../util.js';
|
|
80
|
+
import { getVersions } from '../../versioning.js';
|
|
54
81
|
import { AztecDatastore } from '../data_store.js';
|
|
82
|
+
import { DiscV5Service } from '../discv5/discV5_service.js';
|
|
55
83
|
import { SnappyTransform, fastMsgIdFn, getMsgIdFn, msgIdToStrFn } from '../encoding.js';
|
|
56
84
|
import { gossipScoreThresholds } from '../gossipsub/scoring.js';
|
|
85
|
+
import type { PeerManagerInterface } from '../peer-manager/interface.js';
|
|
57
86
|
import { PeerManager } from '../peer-manager/peer_manager.js';
|
|
58
87
|
import { PeerScoring } from '../peer-manager/peer_scoring.js';
|
|
59
|
-
import {
|
|
88
|
+
import type { BatchTxRequesterLibP2PService } from '../reqresp/batch-tx-requester/interface.js';
|
|
89
|
+
import type { P2PReqRespConfig } from '../reqresp/config.js';
|
|
90
|
+
import {
|
|
91
|
+
DEFAULT_SUB_PROTOCOL_VALIDATORS,
|
|
92
|
+
type ReqRespInterface,
|
|
93
|
+
type ReqRespResponse,
|
|
94
|
+
ReqRespSubProtocol,
|
|
95
|
+
type ReqRespSubProtocolHandler,
|
|
96
|
+
type ReqRespSubProtocolHandlers,
|
|
97
|
+
type ReqRespSubProtocolValidators,
|
|
98
|
+
type SubProtocolMap,
|
|
99
|
+
ValidationError,
|
|
100
|
+
} from '../reqresp/interface.js';
|
|
101
|
+
import { reqRespBlockTxsHandler } from '../reqresp/protocols/block_txs/block_txs_handler.js';
|
|
60
102
|
import { reqGoodbyeHandler } from '../reqresp/protocols/goodbye.js';
|
|
61
|
-
import {
|
|
103
|
+
import {
|
|
104
|
+
AuthRequest,
|
|
105
|
+
BlockTxsRequest,
|
|
106
|
+
BlockTxsResponse,
|
|
107
|
+
StatusMessage,
|
|
108
|
+
pingHandler,
|
|
109
|
+
reqRespBlockHandler,
|
|
110
|
+
reqRespStatusHandler,
|
|
111
|
+
reqRespTxHandler,
|
|
112
|
+
} from '../reqresp/protocols/index.js';
|
|
62
113
|
import { ReqResp } from '../reqresp/reqresp.js';
|
|
63
|
-
import type {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
}
|
|
114
|
+
import type {
|
|
115
|
+
P2PBlockReceivedCallback,
|
|
116
|
+
P2PCheckpointReceivedCallback,
|
|
117
|
+
P2PService,
|
|
118
|
+
PeerDiscoveryService,
|
|
119
|
+
} from '../service.js';
|
|
120
|
+
import { P2PInstrumentation } from './instrumentation.js';
|
|
71
121
|
|
|
72
122
|
interface ValidationResult {
|
|
73
123
|
name: string;
|
|
@@ -77,74 +127,125 @@ interface ValidationResult {
|
|
|
77
127
|
|
|
78
128
|
type ValidationOutcome = { allPassed: true } | { allPassed: false; failure: ValidationResult };
|
|
79
129
|
|
|
130
|
+
// REFACTOR: Unify with the type above
|
|
131
|
+
type ReceivedMessageValidationResult<T> =
|
|
132
|
+
| { obj: T; result: Exclude<TopicValidatorResult, TopicValidatorResult.Reject> }
|
|
133
|
+
| { obj?: undefined; result: TopicValidatorResult.Reject };
|
|
134
|
+
|
|
80
135
|
/**
|
|
81
136
|
* Lib P2P implementation of the P2PService interface.
|
|
82
137
|
*/
|
|
83
|
-
export class LibP2PService<T extends P2PClientType> extends WithTracer implements P2PService {
|
|
84
|
-
private jobQueue: SerialQueue = new SerialQueue();
|
|
85
|
-
private peerManager: PeerManager;
|
|
138
|
+
export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends WithTracer implements P2PService {
|
|
86
139
|
private discoveryRunningPromise?: RunningPromise;
|
|
140
|
+
private msgIdSeenValidators: Record<TopicType, MessageSeenValidator> = {} as Record<TopicType, MessageSeenValidator>;
|
|
87
141
|
|
|
88
142
|
// Message validators
|
|
89
|
-
private attestationValidator: AttestationValidator;
|
|
90
143
|
private blockProposalValidator: BlockProposalValidator;
|
|
144
|
+
private checkpointProposalValidator: CheckpointProposalValidator;
|
|
145
|
+
private checkpointAttestationValidator: CheckpointAttestationValidator;
|
|
146
|
+
|
|
147
|
+
private protocolVersion = '';
|
|
148
|
+
private topicStrings: Record<TopicType, string> = {} as Record<TopicType, string>;
|
|
91
149
|
|
|
92
|
-
|
|
93
|
-
public reqresp: ReqResp;
|
|
150
|
+
private feesCache: { blockNumber: BlockNumber; gasFees: GasFees } | undefined;
|
|
94
151
|
|
|
95
152
|
/**
|
|
96
153
|
* Callback for when a block is received from a peer.
|
|
97
154
|
* @param block - The block received from the peer.
|
|
98
155
|
* @returns The attestation for the block, if any.
|
|
99
156
|
*/
|
|
100
|
-
private blockReceivedCallback:
|
|
157
|
+
private blockReceivedCallback: P2PBlockReceivedCallback;
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Callback for when a checkpoint proposal is received from a peer.
|
|
161
|
+
* @param checkpoint - The checkpoint proposal received from the peer.
|
|
162
|
+
* @returns The attestations for the checkpoint, if any.
|
|
163
|
+
*/
|
|
164
|
+
private checkpointReceivedCallback: P2PCheckpointReceivedCallback;
|
|
165
|
+
|
|
166
|
+
private gossipSubEventHandler: (e: CustomEvent<GossipsubMessage>) => void;
|
|
167
|
+
|
|
168
|
+
private instrumentation: P2PInstrumentation;
|
|
169
|
+
|
|
170
|
+
private telemetry: TelemetryClient;
|
|
171
|
+
|
|
172
|
+
protected logger: Logger;
|
|
101
173
|
|
|
102
174
|
constructor(
|
|
103
175
|
private clientType: T,
|
|
104
176
|
private config: P2PConfig,
|
|
105
|
-
|
|
177
|
+
protected node: PubSubLibp2p,
|
|
106
178
|
private peerDiscoveryService: PeerDiscoveryService,
|
|
107
|
-
private
|
|
108
|
-
private
|
|
109
|
-
|
|
179
|
+
private reqresp: ReqRespInterface,
|
|
180
|
+
private peerManager: PeerManagerInterface,
|
|
181
|
+
protected mempools: MemPools,
|
|
182
|
+
private archiver: L2BlockSource & ContractDataSource,
|
|
183
|
+
private epochCache: EpochCacheInterface,
|
|
110
184
|
private proofVerifier: ClientProtocolCircuitVerifier,
|
|
111
185
|
private worldStateSynchronizer: WorldStateSynchronizer,
|
|
112
186
|
telemetry: TelemetryClient,
|
|
113
|
-
|
|
187
|
+
logger: Logger = createLogger('p2p:libp2p_service'),
|
|
114
188
|
) {
|
|
115
189
|
super(telemetry, 'LibP2PService');
|
|
190
|
+
this.telemetry = telemetry;
|
|
116
191
|
|
|
117
|
-
|
|
118
|
-
this.
|
|
192
|
+
// Create child logger with fisherman prefix if in fisherman mode
|
|
193
|
+
this.logger = config.fishermanMode ? logger.createChild('[FISHERMAN]') : logger;
|
|
119
194
|
|
|
120
|
-
this.
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
195
|
+
this.instrumentation = new P2PInstrumentation(telemetry, 'LibP2PService');
|
|
196
|
+
|
|
197
|
+
this.msgIdSeenValidators[TopicType.tx] = new MessageSeenValidator(config.seenMessageCacheSize);
|
|
198
|
+
this.msgIdSeenValidators[TopicType.block_proposal] = new MessageSeenValidator(config.seenMessageCacheSize);
|
|
199
|
+
this.msgIdSeenValidators[TopicType.checkpoint_proposal] = new MessageSeenValidator(config.seenMessageCacheSize);
|
|
200
|
+
this.msgIdSeenValidators[TopicType.checkpoint_attestation] = new MessageSeenValidator(config.seenMessageCacheSize);
|
|
201
|
+
|
|
202
|
+
const versions = getVersions(config);
|
|
203
|
+
this.protocolVersion = compressComponentVersions(versions);
|
|
204
|
+
logger.info(`Started libp2p service with protocol version ${this.protocolVersion}`);
|
|
205
|
+
|
|
206
|
+
this.topicStrings[TopicType.tx] = createTopicString(TopicType.tx, this.protocolVersion);
|
|
207
|
+
this.topicStrings[TopicType.block_proposal] = createTopicString(TopicType.block_proposal, this.protocolVersion);
|
|
208
|
+
this.topicStrings[TopicType.checkpoint_proposal] = createTopicString(
|
|
209
|
+
TopicType.checkpoint_proposal,
|
|
210
|
+
this.protocolVersion,
|
|
211
|
+
);
|
|
212
|
+
this.topicStrings[TopicType.checkpoint_attestation] = createTopicString(
|
|
213
|
+
TopicType.checkpoint_attestation,
|
|
214
|
+
this.protocolVersion,
|
|
128
215
|
);
|
|
129
216
|
|
|
130
|
-
|
|
131
|
-
this.
|
|
132
|
-
|
|
133
|
-
};
|
|
134
|
-
this.
|
|
217
|
+
this.blockProposalValidator = new BlockProposalValidator(epochCache, { txsPermitted: !config.disableTransactions });
|
|
218
|
+
this.checkpointProposalValidator = new CheckpointProposalValidator(epochCache, {
|
|
219
|
+
txsPermitted: !config.disableTransactions,
|
|
220
|
+
});
|
|
221
|
+
this.checkpointAttestationValidator = config.fishermanMode
|
|
222
|
+
? new FishermanAttestationValidator(epochCache, mempools.attestationPool, telemetry)
|
|
223
|
+
: new CheckpointAttestationValidator(epochCache);
|
|
135
224
|
|
|
136
|
-
this.
|
|
137
|
-
this.blockProposalValidator = new BlockProposalValidator(epochCache);
|
|
225
|
+
this.gossipSubEventHandler = this.handleGossipSubEvent.bind(this);
|
|
138
226
|
|
|
139
|
-
this.blockReceivedCallback = async (block: BlockProposal): Promise<
|
|
227
|
+
this.blockReceivedCallback = async (block: BlockProposal): Promise<boolean> => {
|
|
140
228
|
this.logger.debug(
|
|
141
|
-
`Handler not yet registered: Block received callback not set. Received block for slot ${block.slotNumber
|
|
142
|
-
{ p2pMessageIdentifier: await block.
|
|
229
|
+
`Handler not yet registered: Block received callback not set. Received block for slot ${block.slotNumber} from peer.`,
|
|
230
|
+
{ p2pMessageIdentifier: await block.p2pMessageLoggingIdentifier() },
|
|
143
231
|
);
|
|
144
|
-
return
|
|
232
|
+
return false;
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
this.checkpointReceivedCallback = (
|
|
236
|
+
checkpoint: CheckpointProposalCore,
|
|
237
|
+
): Promise<CheckpointAttestation[] | undefined> => {
|
|
238
|
+
this.logger.debug(
|
|
239
|
+
`Handler not yet registered: Checkpoint received callback not set. Received checkpoint for slot ${checkpoint.slotNumber} from peer.`,
|
|
240
|
+
);
|
|
241
|
+
return Promise.resolve(undefined);
|
|
145
242
|
};
|
|
146
243
|
}
|
|
147
244
|
|
|
245
|
+
public updateConfig(config: Partial<P2PReqRespConfig>) {
|
|
246
|
+
this.reqresp.updateConfig(config);
|
|
247
|
+
}
|
|
248
|
+
|
|
148
249
|
/**
|
|
149
250
|
* Creates an instance of the LibP2P service.
|
|
150
251
|
* @param config - The configuration to use when creating the service.
|
|
@@ -154,69 +255,152 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
|
|
|
154
255
|
public static async new<T extends P2PClientType>(
|
|
155
256
|
clientType: T,
|
|
156
257
|
config: P2PConfig,
|
|
157
|
-
peerDiscoveryService: PeerDiscoveryService,
|
|
158
258
|
peerId: PeerId,
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
259
|
+
deps: {
|
|
260
|
+
mempools: MemPools;
|
|
261
|
+
l2BlockSource: L2BlockSource & ContractDataSource;
|
|
262
|
+
epochCache: EpochCacheInterface;
|
|
263
|
+
proofVerifier: ClientProtocolCircuitVerifier;
|
|
264
|
+
worldStateSynchronizer: WorldStateSynchronizer;
|
|
265
|
+
peerStore: AztecAsyncKVStore;
|
|
266
|
+
telemetry: TelemetryClient;
|
|
267
|
+
logger: Logger;
|
|
268
|
+
packageVersion: string;
|
|
269
|
+
},
|
|
167
270
|
) {
|
|
168
|
-
const {
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
271
|
+
const {
|
|
272
|
+
worldStateSynchronizer,
|
|
273
|
+
epochCache,
|
|
274
|
+
l2BlockSource,
|
|
275
|
+
mempools,
|
|
276
|
+
proofVerifier,
|
|
277
|
+
peerStore,
|
|
278
|
+
telemetry,
|
|
279
|
+
logger,
|
|
280
|
+
packageVersion,
|
|
281
|
+
} = deps;
|
|
282
|
+
const { p2pPort, maxPeerCount, listenAddress } = config;
|
|
283
|
+
const bindAddrTcp = convertToMultiaddr(listenAddress, p2pPort, 'tcp');
|
|
172
284
|
|
|
173
|
-
const datastore = new AztecDatastore(
|
|
285
|
+
const datastore = new AztecDatastore(peerStore);
|
|
174
286
|
|
|
175
|
-
const otelMetricsAdapter = new OtelMetricsAdapter(telemetry);
|
|
287
|
+
const otelMetricsAdapter = new OtelMetricsAdapter(telemetry, logger.getBindings());
|
|
288
|
+
|
|
289
|
+
const peerDiscoveryService = new DiscV5Service(
|
|
290
|
+
peerId,
|
|
291
|
+
config,
|
|
292
|
+
packageVersion,
|
|
293
|
+
telemetry,
|
|
294
|
+
createLogger(`${logger.module}:discv5_service`, logger.getBindings()),
|
|
295
|
+
);
|
|
296
|
+
|
|
297
|
+
// Seed libp2p's bootstrap discovery with private and trusted peers
|
|
298
|
+
const bootstrapNodes = [...config.privatePeers, ...config.trustedPeers];
|
|
176
299
|
|
|
177
|
-
// If bootstrap nodes are provided, also provide them to the p2p service
|
|
178
300
|
const peerDiscovery = [];
|
|
179
|
-
if (
|
|
180
|
-
peerDiscovery.push(bootstrap({ list:
|
|
301
|
+
if (bootstrapNodes.length > 0) {
|
|
302
|
+
peerDiscovery.push(bootstrap({ list: bootstrapNodes }));
|
|
181
303
|
}
|
|
182
304
|
|
|
305
|
+
const versions = getVersions(config);
|
|
306
|
+
const protocolVersion = compressComponentVersions(versions);
|
|
307
|
+
|
|
308
|
+
const txTopic = createTopicString(TopicType.tx, protocolVersion);
|
|
309
|
+
const blockProposalTopic = createTopicString(TopicType.block_proposal, protocolVersion);
|
|
310
|
+
const checkpointProposalTopic = createTopicString(TopicType.checkpoint_proposal, protocolVersion);
|
|
311
|
+
const checkpointAttestationTopic = createTopicString(TopicType.checkpoint_attestation, protocolVersion);
|
|
312
|
+
|
|
313
|
+
const preferredPeersEnrs: ENR[] = config.preferredPeers.map(enr => ENR.decodeTxt(enr));
|
|
314
|
+
const directPeers = (
|
|
315
|
+
await Promise.all(
|
|
316
|
+
preferredPeersEnrs.map(async enr => {
|
|
317
|
+
const peerId = await enr.peerId();
|
|
318
|
+
const address = enr.getLocationMultiaddr('tcp');
|
|
319
|
+
if (address === undefined) {
|
|
320
|
+
throw new Error(`Direct peer ${peerId.toString()} has no TCP address, ENR: ${enr.encodeTxt()}`);
|
|
321
|
+
}
|
|
322
|
+
return {
|
|
323
|
+
id: peerId,
|
|
324
|
+
addrs: [address],
|
|
325
|
+
};
|
|
326
|
+
}),
|
|
327
|
+
)
|
|
328
|
+
).filter(peer => peer !== undefined);
|
|
329
|
+
|
|
330
|
+
const announceTcpMultiaddr = config.p2pIp ? [convertToMultiaddr(config.p2pIp, p2pPort, 'tcp')] : [];
|
|
331
|
+
|
|
183
332
|
const node = await createLibp2p({
|
|
184
333
|
start: false,
|
|
185
334
|
peerId,
|
|
186
335
|
addresses: {
|
|
187
336
|
listen: [bindAddrTcp],
|
|
188
|
-
announce:
|
|
337
|
+
announce: announceTcpMultiaddr,
|
|
189
338
|
},
|
|
190
339
|
transports: [
|
|
191
340
|
tcp({
|
|
192
|
-
|
|
341
|
+
// It's better to have this number a bit higher than our maxPeerCount because it's sets the limit on transport (TCP) layer
|
|
342
|
+
// The connection attempts to the node on TCP layer are not necessarily valid Aztec peers so we want to have a bit of leeway here
|
|
343
|
+
// If we hit the limit, the connection will be temporarily accepted and immediately dropped.
|
|
344
|
+
// Docs: https://nodejs.org/api/net.html#servermaxconnections
|
|
345
|
+
maxConnections: maxPeerCount * 2,
|
|
193
346
|
// socket option: the maximum length of the queue of pending connections
|
|
194
|
-
// https://nodejs.org/dist/latest-
|
|
347
|
+
// https://nodejs.org/dist/latest-v22.x/docs/api/net.html#serverlisten
|
|
195
348
|
// it's not safe if we increase this number
|
|
196
349
|
backlog: 5,
|
|
197
350
|
closeServerOnMaxConnections: {
|
|
198
|
-
|
|
199
|
-
|
|
351
|
+
// The property `maxConnections` will protect us against the most DDOS attack
|
|
352
|
+
// This property protects us in case of burst of new connections where server is not able to close them quickly enough
|
|
353
|
+
// In case closeAbove is reached, the server stops listening altogether
|
|
354
|
+
// It's important that there is enough difference between closeAbove and listenAbove,
|
|
355
|
+
// otherwise the server.listener will flap between being closed and open potentially degrading perf even more
|
|
356
|
+
closeAbove: maxPeerCount * 3,
|
|
357
|
+
listenBelow: Math.floor(maxPeerCount * 0.9),
|
|
200
358
|
},
|
|
201
359
|
}),
|
|
202
360
|
],
|
|
203
361
|
datastore,
|
|
204
362
|
peerDiscovery,
|
|
205
|
-
streamMuxers: [
|
|
363
|
+
streamMuxers: [yamux(), mplex()],
|
|
206
364
|
connectionEncryption: [noise()],
|
|
207
365
|
connectionManager: {
|
|
208
|
-
minConnections: 0,
|
|
209
|
-
|
|
366
|
+
minConnections: 0, // Disable libp2p peer dialing, we do it manually
|
|
367
|
+
// We set maxConnections above maxPeerCount because if we hit limit of maxPeerCount
|
|
368
|
+
// libp2p will start aggressively rejecting all new connections, preventing network discovery and crawling.
|
|
369
|
+
maxConnections: maxPeerCount * 2,
|
|
210
370
|
maxParallelDials: 100,
|
|
211
371
|
dialTimeout: 30_000,
|
|
212
372
|
maxPeerAddrsToDial: 5,
|
|
213
373
|
maxIncomingPendingConnections: 5,
|
|
214
374
|
},
|
|
375
|
+
connectionGater: {
|
|
376
|
+
denyInboundConnection: (maConn: MultiaddrConnection) => {
|
|
377
|
+
const allowed = peerManager.isNodeAllowedToConnect(maConn.remoteAddr.nodeAddress().address);
|
|
378
|
+
if (allowed) {
|
|
379
|
+
return false;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
logger.debug(`Connection gater: Denying inbound connection from ${maConn.remoteAddr.toString()}`);
|
|
383
|
+
return true;
|
|
384
|
+
},
|
|
385
|
+
denyInboundEncryptedConnection: (peerId: PeerId, _maConn: MultiaddrConnection) => {
|
|
386
|
+
//NOTE: it is not necessary to check address here because this was already done by
|
|
387
|
+
// denyInboundConnection
|
|
388
|
+
const allowed = peerManager.isNodeAllowedToConnect(peerId);
|
|
389
|
+
if (allowed) {
|
|
390
|
+
return false;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
logger.debug(`Connection gater: Denying inbound encrypted connection from ${peerId.toString()}`);
|
|
394
|
+
return true;
|
|
395
|
+
},
|
|
396
|
+
},
|
|
215
397
|
services: {
|
|
216
398
|
identify: identify({
|
|
217
399
|
protocolPrefix: 'aztec',
|
|
400
|
+
runOnConnectionOpen: true,
|
|
218
401
|
}),
|
|
219
402
|
pubsub: gossipsub({
|
|
403
|
+
directPeers,
|
|
220
404
|
debugName: 'gossipsub',
|
|
221
405
|
globalSignaturePolicy: SignaturePolicy.StrictNoSign,
|
|
222
406
|
allowPublishToZeroTopicPeers: true,
|
|
@@ -228,29 +412,35 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
|
|
|
228
412
|
heartbeatInterval: config.gossipsubInterval,
|
|
229
413
|
mcacheLength: config.gossipsubMcacheLength,
|
|
230
414
|
mcacheGossip: config.gossipsubMcacheGossip,
|
|
415
|
+
seenTTL: config.gossipsubSeenTTL,
|
|
231
416
|
msgIdFn: getMsgIdFn,
|
|
232
417
|
msgIdToStrFn: msgIdToStrFn,
|
|
233
418
|
fastMsgIdFn: fastMsgIdFn,
|
|
234
419
|
dataTransform: new SnappyTransform(),
|
|
235
420
|
metricsRegister: otelMetricsAdapter,
|
|
236
|
-
metricsTopicStrToLabel: metricsTopicStrToLabels(),
|
|
421
|
+
metricsTopicStrToLabel: metricsTopicStrToLabels(protocolVersion),
|
|
237
422
|
asyncValidation: true,
|
|
238
423
|
scoreThresholds: gossipScoreThresholds,
|
|
239
424
|
scoreParams: createPeerScoreParams({
|
|
240
425
|
// IPColocation factor can be disabled for local testing - default to -5
|
|
241
426
|
IPColocationFactorWeight: config.debugDisableColocationPenalty ? 0 : -5.0,
|
|
242
427
|
topics: {
|
|
243
|
-
[
|
|
428
|
+
[txTopic]: createTopicScoreParams({
|
|
244
429
|
topicWeight: 1,
|
|
245
430
|
invalidMessageDeliveriesWeight: -20,
|
|
246
431
|
invalidMessageDeliveriesDecay: 0.5,
|
|
247
432
|
}),
|
|
248
|
-
[
|
|
433
|
+
[blockProposalTopic]: createTopicScoreParams({
|
|
249
434
|
topicWeight: 1,
|
|
250
435
|
invalidMessageDeliveriesWeight: -20,
|
|
251
436
|
invalidMessageDeliveriesDecay: 0.5,
|
|
252
437
|
}),
|
|
253
|
-
[
|
|
438
|
+
[checkpointProposalTopic]: createTopicScoreParams({
|
|
439
|
+
topicWeight: 1,
|
|
440
|
+
invalidMessageDeliveriesWeight: -20,
|
|
441
|
+
invalidMessageDeliveriesDecay: 0.5,
|
|
442
|
+
}),
|
|
443
|
+
[checkpointAttestationTopic]: createTopicScoreParams({
|
|
254
444
|
topicWeight: 1,
|
|
255
445
|
invalidMessageDeliveriesWeight: -20,
|
|
256
446
|
invalidMessageDeliveriesDecay: 0.5,
|
|
@@ -262,14 +452,37 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
|
|
|
262
452
|
connectionManager: components.connectionManager,
|
|
263
453
|
}),
|
|
264
454
|
},
|
|
265
|
-
logger: createLibp2pComponentLogger(logger.module),
|
|
455
|
+
logger: createLibp2pComponentLogger(logger.module, logger.getBindings()),
|
|
266
456
|
});
|
|
267
457
|
|
|
458
|
+
const peerScoring = new PeerScoring(config, telemetry);
|
|
459
|
+
const reqresp = new ReqResp(config, node, peerScoring, createLogger(`${logger.module}:reqresp`));
|
|
460
|
+
|
|
461
|
+
const peerManager = new PeerManager(
|
|
462
|
+
node,
|
|
463
|
+
peerDiscoveryService,
|
|
464
|
+
config,
|
|
465
|
+
telemetry,
|
|
466
|
+
createLogger(`${logger.module}:peer_manager`),
|
|
467
|
+
peerScoring,
|
|
468
|
+
reqresp,
|
|
469
|
+
worldStateSynchronizer,
|
|
470
|
+
protocolVersion,
|
|
471
|
+
epochCache,
|
|
472
|
+
);
|
|
473
|
+
|
|
474
|
+
// Update gossipsub score params
|
|
475
|
+
node.services.pubsub.score.params.appSpecificWeight = 10;
|
|
476
|
+
node.services.pubsub.score.params.appSpecificScore = (peerId: string) =>
|
|
477
|
+
peerManager.shouldDisableP2PGossip(peerId) ? -Infinity : peerManager.getPeerScore(peerId);
|
|
478
|
+
|
|
268
479
|
return new LibP2PService(
|
|
269
480
|
clientType,
|
|
270
481
|
config,
|
|
271
482
|
node,
|
|
272
483
|
peerDiscoveryService,
|
|
484
|
+
reqresp,
|
|
485
|
+
peerManager,
|
|
273
486
|
mempools,
|
|
274
487
|
l2BlockSource,
|
|
275
488
|
epochCache,
|
|
@@ -291,55 +504,72 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
|
|
|
291
504
|
}
|
|
292
505
|
|
|
293
506
|
// Get listen & announce addresses for logging
|
|
294
|
-
const {
|
|
295
|
-
if (!
|
|
507
|
+
const { p2pIp, p2pPort } = this.config;
|
|
508
|
+
if (!p2pIp) {
|
|
296
509
|
throw new Error('Announce address not provided.');
|
|
297
510
|
}
|
|
298
|
-
const announceTcpMultiaddr = convertToMultiaddr(
|
|
299
|
-
|
|
300
|
-
// Start job queue, peer discovery service and libp2p node
|
|
301
|
-
this.jobQueue.start();
|
|
302
|
-
await this.peerDiscoveryService.start();
|
|
303
|
-
await this.node.start();
|
|
304
|
-
|
|
305
|
-
// Subscribe to standard GossipSub topics by default
|
|
306
|
-
for (const topic of getTopicTypeForClientType(this.clientType)) {
|
|
307
|
-
this.subscribeToTopic(TopicTypeMap[topic].p2pTopic);
|
|
308
|
-
}
|
|
511
|
+
const announceTcpMultiaddr = convertToMultiaddr(p2pIp, p2pPort, 'tcp');
|
|
309
512
|
|
|
310
513
|
// Create request response protocol handlers
|
|
311
514
|
const txHandler = reqRespTxHandler(this.mempools);
|
|
312
515
|
const goodbyeHandler = reqGoodbyeHandler(this.peerManager);
|
|
313
|
-
const blockHandler = reqRespBlockHandler(this.
|
|
516
|
+
const blockHandler = reqRespBlockHandler(this.archiver);
|
|
517
|
+
const statusHandler = reqRespStatusHandler(this.protocolVersion, this.worldStateSynchronizer, this.logger);
|
|
314
518
|
|
|
315
|
-
const requestResponseHandlers = {
|
|
519
|
+
const requestResponseHandlers: Partial<ReqRespSubProtocolHandlers> = {
|
|
316
520
|
[ReqRespSubProtocol.PING]: pingHandler,
|
|
317
|
-
[ReqRespSubProtocol.STATUS]: statusHandler,
|
|
318
|
-
[ReqRespSubProtocol.TX]: txHandler.bind(this),
|
|
521
|
+
[ReqRespSubProtocol.STATUS]: statusHandler.bind(this),
|
|
319
522
|
[ReqRespSubProtocol.GOODBYE]: goodbyeHandler.bind(this),
|
|
320
523
|
[ReqRespSubProtocol.BLOCK]: blockHandler.bind(this),
|
|
321
524
|
};
|
|
322
525
|
|
|
526
|
+
if (!this.config.disableTransactions) {
|
|
527
|
+
const blockTxsHandler = reqRespBlockTxsHandler(this.mempools.attestationPool, this.mempools.txPool);
|
|
528
|
+
requestResponseHandlers[ReqRespSubProtocol.BLOCK_TXS] = blockTxsHandler.bind(this);
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
if (!this.config.disableTransactions) {
|
|
532
|
+
requestResponseHandlers[ReqRespSubProtocol.TX] = txHandler.bind(this);
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
// Define the sub protocol validators - This is done within this start() method to gain a callback to the existing validateTx function
|
|
536
|
+
const reqrespSubProtocolValidators = {
|
|
537
|
+
...DEFAULT_SUB_PROTOCOL_VALIDATORS,
|
|
538
|
+
[ReqRespSubProtocol.TX]: this.validateRequestedTxs.bind(this),
|
|
539
|
+
[ReqRespSubProtocol.BLOCK_TXS]: this.validateRequestedBlockTxs.bind(this),
|
|
540
|
+
[ReqRespSubProtocol.BLOCK]: this.validateRequestedBlock.bind(this),
|
|
541
|
+
};
|
|
542
|
+
|
|
543
|
+
await this.peerManager.initializePeers();
|
|
544
|
+
|
|
545
|
+
await this.reqresp.start(requestResponseHandlers, reqrespSubProtocolValidators);
|
|
546
|
+
|
|
547
|
+
await this.node.start();
|
|
548
|
+
|
|
549
|
+
// Subscribe to standard GossipSub topics by default
|
|
550
|
+
for (const topic of getTopicsForClientAndConfig(this.clientType, this.config.disableTransactions)) {
|
|
551
|
+
this.subscribeToTopic(this.topicStrings[topic]);
|
|
552
|
+
}
|
|
553
|
+
|
|
323
554
|
// add GossipSub listener
|
|
324
|
-
this.node.services.pubsub.addEventListener(GossipSubEvent.MESSAGE, this.
|
|
555
|
+
this.node.services.pubsub.addEventListener(GossipSubEvent.MESSAGE, this.gossipSubEventHandler);
|
|
325
556
|
|
|
326
|
-
// Start running promise for peer discovery
|
|
557
|
+
// Start running promise for peer discovery and metrics collection
|
|
558
|
+
if (!this.config.p2pDiscoveryDisabled) {
|
|
559
|
+
await this.peerDiscoveryService.start();
|
|
560
|
+
}
|
|
327
561
|
this.discoveryRunningPromise = new RunningPromise(
|
|
328
|
-
() =>
|
|
562
|
+
async () => {
|
|
563
|
+
await this.peerManager.heartbeat();
|
|
564
|
+
},
|
|
329
565
|
this.logger,
|
|
330
566
|
this.config.peerCheckIntervalMS,
|
|
331
567
|
);
|
|
332
568
|
this.discoveryRunningPromise.start();
|
|
333
569
|
|
|
334
|
-
// Define the sub protocol validators - This is done within this start() method to gain a callback to the existing validateTx function
|
|
335
|
-
const reqrespSubProtocolValidators = {
|
|
336
|
-
...DEFAULT_SUB_PROTOCOL_VALIDATORS,
|
|
337
|
-
// TODO(#11336): A request validator for blocks
|
|
338
|
-
[ReqRespSubProtocol.TX]: this.validateRequestedTx.bind(this),
|
|
339
|
-
};
|
|
340
|
-
await this.reqresp.start(requestResponseHandlers, reqrespSubProtocolValidators);
|
|
341
570
|
this.logger.info(`Started P2P service`, {
|
|
342
|
-
listen:
|
|
571
|
+
listen: this.config.listenAddress,
|
|
572
|
+
port: this.config.p2pPort,
|
|
343
573
|
announce: announceTcpMultiaddr,
|
|
344
574
|
peerId: this.node.peerId.toString(),
|
|
345
575
|
});
|
|
@@ -351,14 +581,11 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
|
|
|
351
581
|
*/
|
|
352
582
|
public async stop() {
|
|
353
583
|
// Remove gossip sub listener
|
|
354
|
-
this.node.services.pubsub.removeEventListener(GossipSubEvent.MESSAGE, this.
|
|
584
|
+
this.node.services.pubsub.removeEventListener(GossipSubEvent.MESSAGE, this.gossipSubEventHandler);
|
|
355
585
|
|
|
356
586
|
// Stop peer manager
|
|
357
587
|
this.logger.debug('Stopping peer manager...');
|
|
358
588
|
await this.peerManager.stop();
|
|
359
|
-
|
|
360
|
-
this.logger.debug('Stopping job queue...');
|
|
361
|
-
await this.jobQueue.end();
|
|
362
589
|
this.logger.debug('Stopping running promise...');
|
|
363
590
|
await this.discoveryRunningPromise?.stop();
|
|
364
591
|
this.logger.debug('Stopping peer discovery service...');
|
|
@@ -370,6 +597,18 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
|
|
|
370
597
|
this.logger.info('LibP2P service stopped');
|
|
371
598
|
}
|
|
372
599
|
|
|
600
|
+
addReqRespSubProtocol(
|
|
601
|
+
subProtocol: ReqRespSubProtocol,
|
|
602
|
+
handler: ReqRespSubProtocolHandler,
|
|
603
|
+
validator?: ReqRespSubProtocolValidators[ReqRespSubProtocol],
|
|
604
|
+
): Promise<void> {
|
|
605
|
+
return this.reqresp.addSubProtocol(subProtocol, handler, validator);
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
public registerThisValidatorAddresses(address: EthAddress[]): void {
|
|
609
|
+
this.peerManager.registerThisValidatorAddresses(address);
|
|
610
|
+
}
|
|
611
|
+
|
|
373
612
|
public getPeers(includePending?: boolean): PeerInfo[] {
|
|
374
613
|
return this.peerManager.getPeers(includePending);
|
|
375
614
|
}
|
|
@@ -387,23 +626,6 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
|
|
|
387
626
|
setImmediate(() => void safeJob());
|
|
388
627
|
}
|
|
389
628
|
|
|
390
|
-
/**
|
|
391
|
-
* Send Request via the ReqResp service
|
|
392
|
-
* The subprotocol defined will determine the request and response types
|
|
393
|
-
*
|
|
394
|
-
* See the subProtocolMap for the mapping of subprotocols to request/response types in `interface.ts`
|
|
395
|
-
*
|
|
396
|
-
* @param protocol The request response protocol to use
|
|
397
|
-
* @param request The request type to send
|
|
398
|
-
* @returns
|
|
399
|
-
*/
|
|
400
|
-
sendRequest<SubProtocol extends ReqRespSubProtocol>(
|
|
401
|
-
protocol: SubProtocol,
|
|
402
|
-
request: InstanceType<SubProtocolMap[SubProtocol]['request']>,
|
|
403
|
-
): Promise<InstanceType<SubProtocolMap[SubProtocol]['response']> | undefined> {
|
|
404
|
-
return this.reqresp.sendRequest(protocol, request);
|
|
405
|
-
}
|
|
406
|
-
|
|
407
629
|
/**
|
|
408
630
|
* Send a batch of requests to peers, and return the responses
|
|
409
631
|
* @param protocol - The request response protocol to use
|
|
@@ -413,8 +635,18 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
|
|
|
413
635
|
sendBatchRequest<SubProtocol extends ReqRespSubProtocol>(
|
|
414
636
|
protocol: SubProtocol,
|
|
415
637
|
requests: InstanceType<SubProtocolMap[SubProtocol]['request']>[],
|
|
416
|
-
|
|
417
|
-
|
|
638
|
+
pinnedPeerId: PeerId | undefined,
|
|
639
|
+
): Promise<InstanceType<SubProtocolMap[SubProtocol]['response']>[]> {
|
|
640
|
+
return this.reqresp.sendBatchRequest(protocol, requests, pinnedPeerId);
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
public sendRequestToPeer(
|
|
644
|
+
peerId: PeerId,
|
|
645
|
+
subProtocol: ReqRespSubProtocol,
|
|
646
|
+
payload: Buffer,
|
|
647
|
+
dialTimeout?: number,
|
|
648
|
+
): Promise<ReqRespResponse> {
|
|
649
|
+
return this.reqresp.sendRequestToPeer(peerId, subProtocol, payload, dialTimeout);
|
|
418
650
|
}
|
|
419
651
|
|
|
420
652
|
/**
|
|
@@ -425,9 +657,12 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
|
|
|
425
657
|
return this.peerDiscoveryService.getEnr();
|
|
426
658
|
}
|
|
427
659
|
|
|
428
|
-
public registerBlockReceivedCallback(callback:
|
|
660
|
+
public registerBlockReceivedCallback(callback: P2PBlockReceivedCallback) {
|
|
429
661
|
this.blockReceivedCallback = callback;
|
|
430
|
-
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
public registerCheckpointReceivedCallback(callback: P2PCheckpointReceivedCallback) {
|
|
665
|
+
this.checkpointReceivedCallback = callback;
|
|
431
666
|
}
|
|
432
667
|
|
|
433
668
|
/**
|
|
@@ -444,175 +679,519 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
|
|
|
444
679
|
/**
|
|
445
680
|
* Publishes data to a topic.
|
|
446
681
|
* @param topic - The topic to publish to.
|
|
447
|
-
* @param data - The
|
|
682
|
+
* @param data - The message to publish.
|
|
448
683
|
* @returns The number of recipients the data was sent to.
|
|
449
684
|
*/
|
|
450
|
-
private async publishToTopic(topic: string,
|
|
685
|
+
private async publishToTopic(topic: string, message: Gossipable) {
|
|
451
686
|
if (!this.node.services.pubsub) {
|
|
452
687
|
throw new Error('Pubsub service not available.');
|
|
453
688
|
}
|
|
454
|
-
const
|
|
455
|
-
|
|
689
|
+
const isBlockProposal = topic === this.topicStrings[TopicType.block_proposal];
|
|
690
|
+
const traceContext =
|
|
691
|
+
this.config.debugP2PInstrumentMessages && isBlockProposal ? this.telemetry.getTraceContext() : undefined;
|
|
692
|
+
const p2pMessage = P2PMessage.fromGossipable(message, this.config.debugP2PInstrumentMessages, traceContext);
|
|
693
|
+
const result = await this.node.services.pubsub.publish(topic, p2pMessage.toMessageData());
|
|
456
694
|
return result.recipients.length;
|
|
457
695
|
}
|
|
458
696
|
|
|
697
|
+
/**
|
|
698
|
+
* Checks if this message has already been seen, based on its msgId computed from hashing the message data.
|
|
699
|
+
* Note that we do not rely on the seenCache from gossipsub since we want to keep a longer history of seen
|
|
700
|
+
* messages to avoid tx echoes across the network.
|
|
701
|
+
*/
|
|
702
|
+
protected preValidateReceivedMessage(
|
|
703
|
+
msg: Message,
|
|
704
|
+
msgId: string,
|
|
705
|
+
source: PeerId,
|
|
706
|
+
): { result: boolean; topicType?: TopicType } {
|
|
707
|
+
let topicType: TopicType | undefined;
|
|
708
|
+
|
|
709
|
+
switch (msg.topic) {
|
|
710
|
+
case this.topicStrings[TopicType.tx]:
|
|
711
|
+
topicType = TopicType.tx;
|
|
712
|
+
break;
|
|
713
|
+
case this.topicStrings[TopicType.block_proposal]:
|
|
714
|
+
topicType = TopicType.block_proposal;
|
|
715
|
+
break;
|
|
716
|
+
case this.topicStrings[TopicType.checkpoint_proposal]:
|
|
717
|
+
topicType = TopicType.checkpoint_proposal;
|
|
718
|
+
break;
|
|
719
|
+
case this.topicStrings[TopicType.checkpoint_attestation]:
|
|
720
|
+
topicType = TopicType.checkpoint_attestation;
|
|
721
|
+
break;
|
|
722
|
+
default:
|
|
723
|
+
this.logger.error(`Received message on unknown topic: ${msg.topic}`);
|
|
724
|
+
break;
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
const validator = topicType ? this.msgIdSeenValidators[topicType] : undefined;
|
|
728
|
+
|
|
729
|
+
if (!validator || !validator.addMessage(msgId)) {
|
|
730
|
+
this.instrumentation.incMessagePrevalidationStatus(false, topicType);
|
|
731
|
+
this.node.services.pubsub.reportMessageValidationResult(msgId, source.toString(), TopicValidatorResult.Ignore);
|
|
732
|
+
return { result: false, topicType };
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
this.instrumentation.incMessagePrevalidationStatus(true, topicType);
|
|
736
|
+
|
|
737
|
+
return { result: true, topicType };
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
/**
|
|
741
|
+
* Safely deserializes a P2PMessage from raw message data.
|
|
742
|
+
* @param msgId - The message ID.
|
|
743
|
+
* @param source - The peer ID of the message source.
|
|
744
|
+
* @param data - The raw message data.
|
|
745
|
+
* @returns The deserialized P2PMessage or undefined if deserialization fails.
|
|
746
|
+
*/
|
|
747
|
+
private safelyDeserializeP2PMessage(msgId: string, source: PeerId, data: Uint8Array): P2PMessage | undefined {
|
|
748
|
+
try {
|
|
749
|
+
return P2PMessage.fromMessageData(Buffer.from(data), this.config.debugP2PInstrumentMessages);
|
|
750
|
+
} catch (err) {
|
|
751
|
+
this.logger.error(`Error deserializing P2PMessage`, err, {
|
|
752
|
+
msgId,
|
|
753
|
+
source: source.toString(),
|
|
754
|
+
});
|
|
755
|
+
this.node.services.pubsub.reportMessageValidationResult(msgId, source.toString(), TopicValidatorResult.Reject);
|
|
756
|
+
this.peerManager.penalizePeer(source, PeerErrorSeverity.LowToleranceError);
|
|
757
|
+
return undefined;
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
|
|
459
761
|
/**
|
|
460
762
|
* Handles a new gossip message that was received by the client.
|
|
461
763
|
* @param topic - The message's topic.
|
|
462
764
|
* @param data - The message data
|
|
463
765
|
*/
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
766
|
+
protected async handleNewGossipMessage(msg: Message, msgId: string, source: PeerId) {
|
|
767
|
+
const msgReceivedTime = Date.now();
|
|
768
|
+
let topicType: TopicType | undefined;
|
|
769
|
+
const p2pMessage = this.safelyDeserializeP2PMessage(msgId, source, msg.data);
|
|
770
|
+
if (!p2pMessage) {
|
|
771
|
+
return;
|
|
467
772
|
}
|
|
468
|
-
|
|
469
|
-
|
|
773
|
+
|
|
774
|
+
const preValidationResult = this.preValidateReceivedMessage(msg, msgId, source);
|
|
775
|
+
|
|
776
|
+
if (!preValidationResult.result) {
|
|
777
|
+
return;
|
|
470
778
|
}
|
|
471
|
-
|
|
472
|
-
|
|
779
|
+
|
|
780
|
+
// Determine topic type for attributes
|
|
781
|
+
if (msg.topic === this.topicStrings[TopicType.tx]) {
|
|
782
|
+
topicType = TopicType.tx;
|
|
783
|
+
} else if (msg.topic === this.topicStrings[TopicType.checkpoint_attestation]) {
|
|
784
|
+
topicType = TopicType.checkpoint_attestation;
|
|
785
|
+
} else if (msg.topic === this.topicStrings[TopicType.block_proposal]) {
|
|
786
|
+
topicType = TopicType.block_proposal;
|
|
787
|
+
} else if (msg.topic === this.topicStrings[TopicType.checkpoint_proposal]) {
|
|
788
|
+
topicType = TopicType.checkpoint_proposal;
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
// Process the message, optionally within a linked span for trace propagation
|
|
792
|
+
const processMessage = async () => {
|
|
793
|
+
if (msg.topic === this.topicStrings[TopicType.tx]) {
|
|
794
|
+
await this.handleGossipedTx(p2pMessage.payload, msgId, source);
|
|
795
|
+
} else if (msg.topic === this.topicStrings[TopicType.checkpoint_attestation]) {
|
|
796
|
+
if (this.clientType === P2PClientType.Full) {
|
|
797
|
+
await this.processCheckpointAttestationFromPeer(p2pMessage.payload, msgId, source);
|
|
798
|
+
}
|
|
799
|
+
} else if (msg.topic === this.topicStrings[TopicType.block_proposal]) {
|
|
800
|
+
await this.processBlockFromPeer(p2pMessage.payload, msgId, source);
|
|
801
|
+
} else if (msg.topic === this.topicStrings[TopicType.checkpoint_proposal]) {
|
|
802
|
+
await this.handleGossipedCheckpointProposal(p2pMessage.payload, msgId, source);
|
|
803
|
+
} else {
|
|
804
|
+
this.logger.error(`Received message on unknown topic: ${msg.topic}`);
|
|
805
|
+
}
|
|
806
|
+
};
|
|
807
|
+
|
|
808
|
+
const latency = p2pMessage.timestamp !== undefined ? msgReceivedTime - p2pMessage.timestamp.getTime() : undefined;
|
|
809
|
+
const propagatedContext = p2pMessage.traceContext
|
|
810
|
+
? this.telemetry.extractPropagatedContext(p2pMessage.traceContext)
|
|
811
|
+
: undefined;
|
|
812
|
+
|
|
813
|
+
if (propagatedContext) {
|
|
814
|
+
await this.tracer.startActiveSpan(
|
|
815
|
+
'LibP2PService.processMessage',
|
|
816
|
+
{
|
|
817
|
+
attributes: {
|
|
818
|
+
[Attributes.TOPIC_NAME]: topicType!,
|
|
819
|
+
[Attributes.PEER_ID]: source.toString(),
|
|
820
|
+
},
|
|
821
|
+
},
|
|
822
|
+
propagatedContext,
|
|
823
|
+
async span => {
|
|
824
|
+
try {
|
|
825
|
+
await processMessage();
|
|
826
|
+
span.setStatus({
|
|
827
|
+
code: SpanStatusCode.OK,
|
|
828
|
+
});
|
|
829
|
+
} catch (err) {
|
|
830
|
+
span.setStatus({
|
|
831
|
+
code: SpanStatusCode.ERROR,
|
|
832
|
+
message: String(err),
|
|
833
|
+
});
|
|
834
|
+
if (typeof err === 'string' || (err && err instanceof Error)) {
|
|
835
|
+
span.recordException(err);
|
|
836
|
+
}
|
|
837
|
+
throw err;
|
|
838
|
+
} finally {
|
|
839
|
+
span.end();
|
|
840
|
+
}
|
|
841
|
+
},
|
|
842
|
+
);
|
|
843
|
+
} else {
|
|
844
|
+
await processMessage();
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
if (latency !== undefined && topicType !== undefined) {
|
|
848
|
+
this.instrumentation.recordMessageLatency(topicType, latency);
|
|
473
849
|
}
|
|
474
850
|
|
|
475
851
|
return;
|
|
476
852
|
}
|
|
477
853
|
|
|
478
|
-
|
|
479
|
-
validationFunc: () => Promise<
|
|
854
|
+
protected async validateReceivedMessage<T>(
|
|
855
|
+
validationFunc: () => Promise<ReceivedMessageValidationResult<T>>,
|
|
480
856
|
msgId: string,
|
|
481
857
|
source: PeerId,
|
|
482
|
-
|
|
483
|
-
|
|
858
|
+
topicType: TopicType,
|
|
859
|
+
): Promise<ReceivedMessageValidationResult<T>> {
|
|
860
|
+
let resultAndObj: ReceivedMessageValidationResult<T> = { result: TopicValidatorResult.Reject };
|
|
861
|
+
const timer = new Timer();
|
|
484
862
|
try {
|
|
485
863
|
resultAndObj = await validationFunc();
|
|
486
864
|
} catch (err) {
|
|
487
|
-
this.
|
|
865
|
+
this.peerManager.penalizePeer(source, PeerErrorSeverity.LowToleranceError);
|
|
866
|
+
this.logger.error(`Error deserializing and validating gossipsub message`, err, {
|
|
867
|
+
msgId,
|
|
868
|
+
source: source.toString(),
|
|
869
|
+
topicType,
|
|
870
|
+
});
|
|
488
871
|
}
|
|
489
872
|
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
);
|
|
873
|
+
if (resultAndObj.result === TopicValidatorResult.Accept) {
|
|
874
|
+
this.instrumentation.recordMessageValidation(topicType, timer);
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
this.node.services.pubsub.reportMessageValidationResult(msgId, source.toString(), resultAndObj.result);
|
|
495
878
|
return resultAndObj;
|
|
496
879
|
}
|
|
497
880
|
|
|
498
|
-
|
|
499
|
-
const validationFunc = async () => {
|
|
500
|
-
const tx = Tx.fromBuffer(
|
|
501
|
-
const
|
|
502
|
-
|
|
881
|
+
protected async handleGossipedTx(payloadData: Buffer, msgId: string, source: PeerId) {
|
|
882
|
+
const validationFunc: () => Promise<ReceivedMessageValidationResult<Tx>> = async () => {
|
|
883
|
+
const tx = Tx.fromBuffer(payloadData);
|
|
884
|
+
const isValid = await this.validatePropagatedTx(tx, source);
|
|
885
|
+
const exists = isValid && (await this.mempools.txPool.hasTx(tx.getTxHash()));
|
|
886
|
+
|
|
887
|
+
this.logger.trace(`Validate propagated tx`, {
|
|
888
|
+
isValid,
|
|
889
|
+
exists,
|
|
890
|
+
[Attributes.P2P_ID]: source.toString(),
|
|
891
|
+
});
|
|
892
|
+
|
|
893
|
+
if (!isValid) {
|
|
894
|
+
return { result: TopicValidatorResult.Reject };
|
|
895
|
+
} else if (exists) {
|
|
896
|
+
return { result: TopicValidatorResult.Ignore, obj: tx };
|
|
897
|
+
} else {
|
|
898
|
+
return { result: TopicValidatorResult.Accept, obj: tx };
|
|
899
|
+
}
|
|
503
900
|
};
|
|
504
901
|
|
|
505
|
-
const { result, obj: tx } = await this.validateReceivedMessage<Tx>(validationFunc, msgId, source);
|
|
506
|
-
if (
|
|
902
|
+
const { result, obj: tx } = await this.validateReceivedMessage<Tx>(validationFunc, msgId, source, TopicType.tx);
|
|
903
|
+
if (result !== TopicValidatorResult.Accept || !tx) {
|
|
507
904
|
return;
|
|
508
905
|
}
|
|
509
|
-
|
|
906
|
+
|
|
907
|
+
const txHash = tx.getTxHash();
|
|
510
908
|
const txHashString = txHash.toString();
|
|
511
|
-
this.logger.verbose(`Received tx ${txHashString} from external peer ${source.toString()}
|
|
909
|
+
this.logger.verbose(`Received tx ${txHashString} from external peer ${source.toString()} via gossip`, {
|
|
910
|
+
source: source.toString(),
|
|
911
|
+
txHash: txHashString,
|
|
912
|
+
});
|
|
913
|
+
|
|
914
|
+
if (this.config.dropTransactions && randomInt(1000) < this.config.dropTransactionsProbability * 1000) {
|
|
915
|
+
this.logger.warn(`Intentionally dropping tx ${txHashString} (probability rule)`);
|
|
916
|
+
return;
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
this.instrumentation.incrementTxReceived(1);
|
|
512
920
|
await this.mempools.txPool.addTxs([tx]);
|
|
513
921
|
}
|
|
514
922
|
|
|
515
|
-
/**
|
|
516
|
-
*
|
|
517
|
-
*
|
|
518
|
-
* @param attestation - The attestation to process.
|
|
923
|
+
/**
|
|
924
|
+
* Process a checkpoint attestation from a peer.
|
|
925
|
+
* Validates the attestation and adds it to the pool.
|
|
519
926
|
*/
|
|
520
|
-
private async
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
927
|
+
private async processCheckpointAttestationFromPeer(
|
|
928
|
+
payloadData: Buffer,
|
|
929
|
+
msgId: string,
|
|
930
|
+
source: PeerId,
|
|
931
|
+
): Promise<void> {
|
|
932
|
+
const validationFunc: () => Promise<ReceivedMessageValidationResult<CheckpointAttestation>> = async () => {
|
|
933
|
+
const attestation = CheckpointAttestation.fromBuffer(payloadData);
|
|
934
|
+
const pool = this.mempools.attestationPool;
|
|
935
|
+
const validationResult = await this.validateCheckpointAttestation(source, attestation);
|
|
936
|
+
const isValid = validationResult.result === 'accept';
|
|
937
|
+
const exists = isValid && (await pool.hasCheckpointAttestation(attestation));
|
|
938
|
+
|
|
939
|
+
let canAdd = true;
|
|
940
|
+
if (isValid && !exists) {
|
|
941
|
+
const slot = attestation.payload.header.slotNumber;
|
|
942
|
+
const { committee } = await this.epochCache.getCommittee(slot);
|
|
943
|
+
const committeeSize = committee?.length ?? 0;
|
|
944
|
+
canAdd = await pool.canAddCheckpointAttestation(attestation, committeeSize);
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
this.logger.trace(`Validate propagated checkpoint attestation`, {
|
|
948
|
+
isValid,
|
|
949
|
+
exists,
|
|
950
|
+
canAdd,
|
|
951
|
+
[Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber.toString(),
|
|
526
952
|
[Attributes.P2P_ID]: source.toString(),
|
|
527
953
|
});
|
|
528
|
-
|
|
954
|
+
|
|
955
|
+
if (validationResult.result === 'reject') {
|
|
956
|
+
return { result: TopicValidatorResult.Reject };
|
|
957
|
+
} else if (validationResult.result === 'ignore' || exists) {
|
|
958
|
+
return { result: TopicValidatorResult.Ignore, obj: attestation };
|
|
959
|
+
} else if (!canAdd) {
|
|
960
|
+
this.logger.warn(`Dropping checkpoint attestation due to per-(slot, proposalId) attestation cap`, {
|
|
961
|
+
slot: attestation.payload.header.slotNumber.toString(),
|
|
962
|
+
archive: attestation.archive.toString(),
|
|
963
|
+
source: source.toString(),
|
|
964
|
+
});
|
|
965
|
+
return { result: TopicValidatorResult.Ignore, obj: attestation };
|
|
966
|
+
} else {
|
|
967
|
+
return { result: TopicValidatorResult.Accept, obj: attestation };
|
|
968
|
+
}
|
|
529
969
|
};
|
|
530
970
|
|
|
531
|
-
const { result, obj: attestation } = await this.validateReceivedMessage<
|
|
971
|
+
const { result, obj: attestation } = await this.validateReceivedMessage<CheckpointAttestation>(
|
|
532
972
|
validationFunc,
|
|
533
973
|
msgId,
|
|
534
974
|
source,
|
|
975
|
+
TopicType.checkpoint_attestation,
|
|
535
976
|
);
|
|
536
|
-
|
|
977
|
+
|
|
978
|
+
if (result !== TopicValidatorResult.Accept || !attestation) {
|
|
537
979
|
return;
|
|
538
980
|
}
|
|
981
|
+
|
|
539
982
|
this.logger.debug(
|
|
540
|
-
`Received attestation for
|
|
983
|
+
`Received checkpoint attestation for slot ${attestation.slotNumber} from external peer ${source.toString()}`,
|
|
541
984
|
{
|
|
542
|
-
p2pMessageIdentifier: await attestation.
|
|
543
|
-
slot: attestation.slotNumber
|
|
985
|
+
p2pMessageIdentifier: await attestation.p2pMessageLoggingIdentifier(),
|
|
986
|
+
slot: attestation.slotNumber,
|
|
544
987
|
archive: attestation.archive.toString(),
|
|
545
|
-
|
|
988
|
+
source: source.toString(),
|
|
546
989
|
},
|
|
547
990
|
);
|
|
548
|
-
|
|
991
|
+
|
|
992
|
+
await this.mempools.attestationPool.addCheckpointAttestations([attestation]);
|
|
549
993
|
}
|
|
550
994
|
|
|
551
|
-
private async processBlockFromPeer(
|
|
552
|
-
const validationFunc = async () => {
|
|
553
|
-
const block = BlockProposal.fromBuffer(
|
|
554
|
-
const
|
|
555
|
-
|
|
556
|
-
|
|
995
|
+
private async processBlockFromPeer(payloadData: Buffer, msgId: string, source: PeerId): Promise<void> {
|
|
996
|
+
const validationFunc: () => Promise<ReceivedMessageValidationResult<BlockProposal>> = async () => {
|
|
997
|
+
const block = BlockProposal.fromBuffer(payloadData);
|
|
998
|
+
const validationResult = await this.validateBlockProposal(source, block);
|
|
999
|
+
const isValid = validationResult.result === 'accept';
|
|
1000
|
+
const pool = this.mempools.attestationPool;
|
|
1001
|
+
|
|
1002
|
+
const exists = isValid && (await pool.hasBlockProposal(block));
|
|
1003
|
+
const canAdd = isValid && (await pool.canAddProposal(block));
|
|
1004
|
+
|
|
1005
|
+
this.logger.trace(`Validate propagated block proposal`, {
|
|
1006
|
+
isValid,
|
|
1007
|
+
exists,
|
|
1008
|
+
canAdd,
|
|
1009
|
+
[Attributes.SLOT_NUMBER]: block.slotNumber.toString(),
|
|
557
1010
|
[Attributes.P2P_ID]: source.toString(),
|
|
558
1011
|
});
|
|
559
|
-
|
|
1012
|
+
|
|
1013
|
+
if (validationResult.result === 'reject') {
|
|
1014
|
+
return { result: TopicValidatorResult.Reject };
|
|
1015
|
+
} else if (validationResult.result === 'ignore' || exists) {
|
|
1016
|
+
return { result: TopicValidatorResult.Ignore, obj: block };
|
|
1017
|
+
} else if (!canAdd) {
|
|
1018
|
+
this.peerManager.penalizePeer(source, PeerErrorSeverity.MidToleranceError);
|
|
1019
|
+
this.logger.warn(`Penalizing peer for block proposal exceeding per-slot cap`, {
|
|
1020
|
+
slot: block.slotNumber.toString(),
|
|
1021
|
+
archive: block.archive.toString(),
|
|
1022
|
+
source: source.toString(),
|
|
1023
|
+
});
|
|
1024
|
+
return { result: TopicValidatorResult.Reject };
|
|
1025
|
+
} else {
|
|
1026
|
+
return { result: TopicValidatorResult.Accept, obj: block };
|
|
1027
|
+
}
|
|
560
1028
|
};
|
|
561
1029
|
|
|
562
|
-
const { result, obj: block } = await this.validateReceivedMessage<BlockProposal>(
|
|
1030
|
+
const { result, obj: block } = await this.validateReceivedMessage<BlockProposal>(
|
|
1031
|
+
validationFunc,
|
|
1032
|
+
msgId,
|
|
1033
|
+
source,
|
|
1034
|
+
TopicType.block_proposal,
|
|
1035
|
+
);
|
|
1036
|
+
|
|
563
1037
|
if (!result || !block) {
|
|
564
1038
|
return;
|
|
565
1039
|
}
|
|
566
|
-
|
|
1040
|
+
|
|
1041
|
+
await this.processValidBlockProposal(block, source);
|
|
567
1042
|
}
|
|
568
1043
|
|
|
569
1044
|
// REVIEW: callback pattern https://github.com/AztecProtocol/aztec-packages/issues/7963
|
|
1045
|
+
// REFACTOR(palla): This method should be moved to the p2p_client or to a separate component,
|
|
1046
|
+
// should not be here as it does not deal with p2p networking.
|
|
570
1047
|
@trackSpan('Libp2pService.processValidBlockProposal', async block => ({
|
|
571
|
-
[Attributes.
|
|
572
|
-
[Attributes.SLOT_NUMBER]: block.slotNumber.toNumber(),
|
|
1048
|
+
[Attributes.SLOT_NUMBER]: block.slotNumber,
|
|
573
1049
|
[Attributes.BLOCK_ARCHIVE]: block.archive.toString(),
|
|
574
|
-
[Attributes.P2P_ID]: await block.
|
|
1050
|
+
[Attributes.P2P_ID]: await block.p2pMessageLoggingIdentifier().then(i => i.toString()),
|
|
575
1051
|
}))
|
|
576
|
-
private async processValidBlockProposal(block: BlockProposal) {
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
1052
|
+
private async processValidBlockProposal(block: BlockProposal, sender: PeerId) {
|
|
1053
|
+
const slot = block.slotNumber;
|
|
1054
|
+
this.logger.verbose(`Received block proposal for slot ${slot} from external peer ${sender.toString()}.`, {
|
|
1055
|
+
p2pMessageIdentifier: await block.p2pMessageLoggingIdentifier(),
|
|
1056
|
+
source: sender.toString(),
|
|
1057
|
+
...block.toBlockInfo(),
|
|
1058
|
+
});
|
|
1059
|
+
|
|
1060
|
+
// Attempt to add proposal
|
|
1061
|
+
try {
|
|
1062
|
+
await this.mempools.attestationPool.addBlockProposal(block);
|
|
1063
|
+
} catch (err: unknown) {
|
|
1064
|
+
// Drop proposals if we hit per-slot cap in the attestation pool; rethrow unknown errors
|
|
1065
|
+
if (err instanceof ProposalSlotCapExceededError) {
|
|
1066
|
+
this.logger.warn(`Dropping block proposal due to per-slot proposal cap`, {
|
|
1067
|
+
slot: String(slot),
|
|
1068
|
+
archive: block.archive.toString(),
|
|
1069
|
+
error: (err as Error).message,
|
|
1070
|
+
});
|
|
1071
|
+
return;
|
|
1072
|
+
}
|
|
1073
|
+
throw err;
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1076
|
+
// Mark the txs in this proposal as non-evictable
|
|
1077
|
+
await this.mempools.txPool.markTxsAsNonEvictable(block.txHashes);
|
|
1078
|
+
|
|
1079
|
+
// Call the block received callback to validate the proposal.
|
|
1080
|
+
// Note: Validators do NOT attest to individual blocks, only to checkpoint proposals.
|
|
1081
|
+
const isValid = await this.blockReceivedCallback(block, sender);
|
|
1082
|
+
if (!isValid) {
|
|
1083
|
+
this.logger.warn(`Block proposal validation failed for block ${block.blockNumber}`, block.toBlockInfo());
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
/**
|
|
1088
|
+
* Handle a gossiped checkpoint proposal.
|
|
1089
|
+
* Validates and processes the checkpoint proposal, then triggers the callback for attestation.
|
|
1090
|
+
*/
|
|
1091
|
+
private async handleGossipedCheckpointProposal(payloadData: Buffer, msgId: string, source: PeerId): Promise<void> {
|
|
1092
|
+
// TODO(palla/mbps): This pattern is repeated across multiple message handlers, consider abstracting it.
|
|
1093
|
+
const validationFunc: () => Promise<ReceivedMessageValidationResult<CheckpointProposal>> = async () => {
|
|
1094
|
+
const checkpoint = CheckpointProposal.fromBuffer(payloadData);
|
|
1095
|
+
const validationResult = await this.validateCheckpointProposal(source, checkpoint);
|
|
1096
|
+
const isValid = validationResult.result === 'accept';
|
|
1097
|
+
const pool = this.mempools.attestationPool;
|
|
1098
|
+
|
|
1099
|
+
const exists = isValid && (await pool.hasCheckpointProposal(checkpoint));
|
|
1100
|
+
const canAdd = isValid && (await pool.canAddCheckpointProposal(checkpoint));
|
|
1101
|
+
|
|
1102
|
+
this.logger.trace(`Validate propagated checkpoint proposal`, {
|
|
1103
|
+
isValid,
|
|
1104
|
+
exists,
|
|
1105
|
+
canAdd,
|
|
1106
|
+
[Attributes.SLOT_NUMBER]: checkpoint.slotNumber.toString(),
|
|
1107
|
+
[Attributes.P2P_ID]: source.toString(),
|
|
1108
|
+
});
|
|
1109
|
+
|
|
1110
|
+
if (validationResult.result === 'reject') {
|
|
1111
|
+
return { result: TopicValidatorResult.Reject };
|
|
1112
|
+
} else if (validationResult.result === 'ignore' || exists) {
|
|
1113
|
+
return { result: TopicValidatorResult.Ignore, obj: checkpoint };
|
|
1114
|
+
} else if (!canAdd) {
|
|
1115
|
+
this.peerManager.penalizePeer(source, PeerErrorSeverity.MidToleranceError);
|
|
1116
|
+
this.logger.warn(`Penalizing peer for checkpoint proposal exceeding per-slot cap`, {
|
|
1117
|
+
slot: checkpoint.slotNumber.toString(),
|
|
1118
|
+
archive: checkpoint.archive.toString(),
|
|
1119
|
+
source: source.toString(),
|
|
1120
|
+
});
|
|
1121
|
+
return { result: TopicValidatorResult.Reject };
|
|
1122
|
+
} else {
|
|
1123
|
+
return { result: TopicValidatorResult.Accept, obj: checkpoint };
|
|
1124
|
+
}
|
|
1125
|
+
};
|
|
1126
|
+
|
|
1127
|
+
const { result, obj: checkpoint } = await this.validateReceivedMessage<CheckpointProposal>(
|
|
1128
|
+
validationFunc,
|
|
1129
|
+
msgId,
|
|
1130
|
+
source,
|
|
1131
|
+
TopicType.checkpoint_proposal,
|
|
585
1132
|
);
|
|
586
|
-
const attestation = await this.blockReceivedCallback(block);
|
|
587
1133
|
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
if (attestation != undefined) {
|
|
591
|
-
this.logger.verbose(
|
|
592
|
-
`Broadcasting attestation for block ${attestation.blockNumber.toNumber()} slot ${attestation.slotNumber.toNumber()}`,
|
|
593
|
-
{
|
|
594
|
-
p2pMessageIdentifier: await attestation.p2pMessageIdentifier(),
|
|
595
|
-
slot: attestation.slotNumber.toNumber(),
|
|
596
|
-
archive: attestation.archive.toString(),
|
|
597
|
-
block: attestation.blockNumber.toNumber(),
|
|
598
|
-
},
|
|
599
|
-
);
|
|
600
|
-
await this.broadcastAttestation(attestation);
|
|
1134
|
+
if (result !== TopicValidatorResult.Accept || !checkpoint) {
|
|
1135
|
+
return;
|
|
601
1136
|
}
|
|
1137
|
+
|
|
1138
|
+
await this.processValidCheckpointProposal(checkpoint, source);
|
|
602
1139
|
}
|
|
603
1140
|
|
|
604
1141
|
/**
|
|
605
|
-
*
|
|
606
|
-
*
|
|
1142
|
+
* Process a validated checkpoint proposal.
|
|
1143
|
+
* Extracts and processes the last block proposal (if present) first, then processes the checkpoint.
|
|
1144
|
+
* The block callback is invoked before the checkpoint callback.
|
|
607
1145
|
*/
|
|
608
|
-
@trackSpan('Libp2pService.
|
|
609
|
-
[Attributes.
|
|
610
|
-
[Attributes.
|
|
611
|
-
[Attributes.
|
|
612
|
-
[Attributes.P2P_ID]: await attestation.p2pMessageIdentifier().then(i => i.toString()),
|
|
1146
|
+
@trackSpan('Libp2pService.processValidCheckpointProposal', async checkpoint => ({
|
|
1147
|
+
[Attributes.SLOT_NUMBER]: checkpoint.slotNumber,
|
|
1148
|
+
[Attributes.BLOCK_ARCHIVE]: checkpoint.archive.toString(),
|
|
1149
|
+
[Attributes.P2P_ID]: await checkpoint.p2pMessageLoggingIdentifier().then(i => i.toString()),
|
|
613
1150
|
}))
|
|
614
|
-
private async
|
|
615
|
-
|
|
1151
|
+
private async processValidCheckpointProposal(checkpoint: CheckpointProposal, sender: PeerId) {
|
|
1152
|
+
const slot = checkpoint.slotNumber;
|
|
1153
|
+
this.logger.verbose(`Received checkpoint proposal for slot ${slot} from external peer ${sender.toString()}.`, {
|
|
1154
|
+
p2pMessageIdentifier: await checkpoint.p2pMessageLoggingIdentifier(),
|
|
1155
|
+
slot: checkpoint.slotNumber,
|
|
1156
|
+
archive: checkpoint.archive.toString(),
|
|
1157
|
+
source: sender.toString(),
|
|
1158
|
+
});
|
|
1159
|
+
|
|
1160
|
+
// Extract block proposal before adding to pool (pool stores them separately)
|
|
1161
|
+
const blockProposal = checkpoint.getBlockProposal();
|
|
1162
|
+
|
|
1163
|
+
// Add proposal to the pool (this extracts and stores block proposal separately)
|
|
1164
|
+
await this.mempools.attestationPool.addCheckpointProposal(checkpoint);
|
|
1165
|
+
|
|
1166
|
+
// Mark txs as non-evictable if present (from the last block)
|
|
1167
|
+
if (checkpoint.txHashes.length > 0) {
|
|
1168
|
+
await this.mempools.txPool.markTxsAsNonEvictable(checkpoint.txHashes);
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1171
|
+
// If there was a last block proposal, invoke the block callback first for validation.
|
|
1172
|
+
// Note: The block proposal is already stored in the pool by addCheckpointProposal.
|
|
1173
|
+
if (blockProposal) {
|
|
1174
|
+
const isValid = await this.blockReceivedCallback(blockProposal, sender);
|
|
1175
|
+
if (!isValid) {
|
|
1176
|
+
this.logger.warn(`Block proposal from checkpoint failed validation`, {
|
|
1177
|
+
slot: slot.toString(),
|
|
1178
|
+
archive: checkpoint.archive.toString(),
|
|
1179
|
+
blockNumber: blockProposal.blockNumber.toString(),
|
|
1180
|
+
});
|
|
1181
|
+
return;
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
// Call the checkpoint received callback with the core version (without lastBlock)
|
|
1186
|
+
// to validate and potentially generate attestations
|
|
1187
|
+
const attestations = await this.checkpointReceivedCallback(checkpoint.toCore(), sender);
|
|
1188
|
+
if (attestations && attestations.length > 0) {
|
|
1189
|
+
// If the callback returned attestations, add them to the pool and propagate them
|
|
1190
|
+
await this.mempools.attestationPool.addCheckpointAttestations(attestations);
|
|
1191
|
+
for (const attestation of attestations) {
|
|
1192
|
+
await this.propagate(attestation);
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
616
1195
|
}
|
|
617
1196
|
|
|
618
1197
|
/**
|
|
@@ -620,111 +1199,317 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
|
|
|
620
1199
|
* @param message - The message to propagate.
|
|
621
1200
|
*/
|
|
622
1201
|
public async propagate<T extends Gossipable>(message: T) {
|
|
623
|
-
const p2pMessageIdentifier = await message.
|
|
1202
|
+
const p2pMessageIdentifier = await message.p2pMessageLoggingIdentifier();
|
|
624
1203
|
this.logger.trace(`Message ${p2pMessageIdentifier} queued`, { p2pMessageIdentifier });
|
|
625
|
-
void this.
|
|
626
|
-
.
|
|
627
|
-
|
|
628
|
-
})
|
|
629
|
-
.catch(error => {
|
|
630
|
-
this.logger.error(`Error propagating message ${p2pMessageIdentifier}`, { error });
|
|
631
|
-
});
|
|
1204
|
+
void this.sendToPeers(message).catch(error => {
|
|
1205
|
+
this.logger.error(`Error propagating message ${p2pMessageIdentifier}`, { error });
|
|
1206
|
+
});
|
|
632
1207
|
}
|
|
633
1208
|
|
|
634
1209
|
/**
|
|
635
|
-
* Validate
|
|
1210
|
+
* Validate the requested block transactions. Allow partial returns.
|
|
1211
|
+
* @param request - The block transactions request.
|
|
1212
|
+
* @param response - The block transactions response.
|
|
1213
|
+
* @param peerId - The ID of the peer that made the request.
|
|
1214
|
+
* @returns True if the requested block transactions are valid, false otherwise.
|
|
1215
|
+
*/
|
|
1216
|
+
@trackSpan('Libp2pService.validateRequestedBlockTxs', request => ({
|
|
1217
|
+
[Attributes.BLOCK_ARCHIVE]: request.archiveRoot.toString(),
|
|
1218
|
+
}))
|
|
1219
|
+
private async validateRequestedBlockTxs(
|
|
1220
|
+
request: BlockTxsRequest,
|
|
1221
|
+
response: BlockTxsResponse,
|
|
1222
|
+
peerId: PeerId,
|
|
1223
|
+
): Promise<boolean> {
|
|
1224
|
+
const requestedTxValidator = this.createRequestedTxValidator();
|
|
1225
|
+
|
|
1226
|
+
try {
|
|
1227
|
+
if (!response.archiveRoot.equals(request.archiveRoot)) {
|
|
1228
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
1229
|
+
throw new ValidationError(
|
|
1230
|
+
`Received block txs for unexpected archive root: expected ${request.archiveRoot.toString()}, got ${response.archiveRoot.toString()}`,
|
|
1231
|
+
);
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1234
|
+
if (response.txIndices.getLength() !== request.txIndices.getLength()) {
|
|
1235
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
1236
|
+
throw new ValidationError(
|
|
1237
|
+
`Received block txs with mismatched bitvector length: expected ${request.txIndices.getLength()}, got ${response.txIndices.getLength()}`,
|
|
1238
|
+
);
|
|
1239
|
+
}
|
|
1240
|
+
|
|
1241
|
+
// Check no duplicates and not exceeding returnable count
|
|
1242
|
+
const requestedIndices = new Set(request.txIndices.getTrueIndices());
|
|
1243
|
+
const availableIndices = new Set(response.txIndices.getTrueIndices());
|
|
1244
|
+
const maxReturnable = [...requestedIndices].filter(i => availableIndices.has(i)).length;
|
|
1245
|
+
|
|
1246
|
+
const returnedHashes = await Promise.all(response.txs.map(tx => tx.getTxHash().toString()));
|
|
1247
|
+
const uniqueReturned = new Set(returnedHashes.map(h => h.toString()));
|
|
1248
|
+
if (uniqueReturned.size !== returnedHashes.length) {
|
|
1249
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
1250
|
+
throw new ValidationError(`Received duplicate txs in block txs response`);
|
|
1251
|
+
}
|
|
1252
|
+
if (response.txs.length > maxReturnable) {
|
|
1253
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
1254
|
+
throw new ValidationError(
|
|
1255
|
+
`Received more txs (${response.txs.length}) than requested-and-available (${maxReturnable})`,
|
|
1256
|
+
);
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1259
|
+
// Given proposal (should have locally), ensure returned txs are valid subset and match request indices
|
|
1260
|
+
const proposal = await this.mempools.attestationPool.getBlockProposal(request.archiveRoot.toString());
|
|
1261
|
+
if (proposal) {
|
|
1262
|
+
// Build intersected indices
|
|
1263
|
+
const intersectIdx = request.txIndices.getTrueIndices().filter(i => response.txIndices.isSet(i));
|
|
1264
|
+
|
|
1265
|
+
// Enforce subset membership and preserve increasing order by index.
|
|
1266
|
+
const hashToIndexInProposal = new Map<string, number>(
|
|
1267
|
+
proposal.txHashes.map((h, i) => [h.toString(), i] as [string, number]),
|
|
1268
|
+
);
|
|
1269
|
+
const allowedIndexSet = new Set(intersectIdx);
|
|
1270
|
+
const indices = returnedHashes.map(h => hashToIndexInProposal.get(h));
|
|
1271
|
+
const allAllowed = indices.every(idx => idx !== undefined && allowedIndexSet.has(idx));
|
|
1272
|
+
const strictlyIncreasing = indices.every((idx, i) => (i === 0 ? idx !== undefined : idx! > indices[i - 1]!));
|
|
1273
|
+
if (!allAllowed || !strictlyIncreasing) {
|
|
1274
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
|
|
1275
|
+
throw new ValidationError('Returned txs do not match expected subset/order for requested indices');
|
|
1276
|
+
}
|
|
1277
|
+
} else {
|
|
1278
|
+
// No local proposal, cannot check the membership/order of the returned txs
|
|
1279
|
+
this.logger.warn(
|
|
1280
|
+
`Block proposal not found for archive root ${request.archiveRoot.toString()}; cannot validate membership/order of returned txs`,
|
|
1281
|
+
);
|
|
1282
|
+
return false;
|
|
1283
|
+
}
|
|
1284
|
+
|
|
1285
|
+
await Promise.all(response.txs.map(tx => this.validateRequestedTx(tx, peerId, requestedTxValidator)));
|
|
1286
|
+
return true;
|
|
1287
|
+
} catch (e: any) {
|
|
1288
|
+
if (e instanceof ValidationError) {
|
|
1289
|
+
this.logger.warn(`Failed validation for requested block txs from peer ${peerId.toString()}`);
|
|
1290
|
+
} else {
|
|
1291
|
+
this.logger.error(`Error during validation of requested block txs`, e);
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1294
|
+
return false;
|
|
1295
|
+
}
|
|
1296
|
+
}
|
|
1297
|
+
|
|
1298
|
+
/**
|
|
1299
|
+
* Validate a collection of txs that has been requested from a peer.
|
|
636
1300
|
*
|
|
637
|
-
* The core component of this validator is that
|
|
1301
|
+
* The core component of this validator is that each tx hash MUST match the requested tx hash,
|
|
638
1302
|
* In order to perform this check, the tx proof must be verified.
|
|
639
1303
|
*
|
|
640
1304
|
* Note: This function is called from within `ReqResp.sendRequest` as part of the
|
|
641
1305
|
* ReqRespSubProtocol.TX subprotocol validation.
|
|
642
1306
|
*
|
|
643
|
-
* @param requestedTxHash - The
|
|
644
|
-
* @param responseTx - The
|
|
1307
|
+
* @param requestedTxHash - The collection of the txs that was requested.
|
|
1308
|
+
* @param responseTx - The collection of txs that was received as a response to the request.
|
|
645
1309
|
* @param peerId - The peer ID of the peer that sent the tx.
|
|
646
|
-
* @returns True if the
|
|
1310
|
+
* @returns True if the whole collection of txs is valid, false otherwise.
|
|
647
1311
|
*/
|
|
648
1312
|
@trackSpan('Libp2pService.validateRequestedTx', (requestedTxHash, _responseTx) => ({
|
|
649
1313
|
[Attributes.TX_HASH]: requestedTxHash.toString(),
|
|
650
1314
|
}))
|
|
651
|
-
private async
|
|
652
|
-
const
|
|
653
|
-
const
|
|
654
|
-
|
|
655
|
-
//
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
1315
|
+
private async validateRequestedTxs(requestedTxHash: TxHash[], responseTx: Tx[], peerId: PeerId): Promise<boolean> {
|
|
1316
|
+
const requested = new Set(requestedTxHash.map(h => h.toString()));
|
|
1317
|
+
const requestedTxValidator = this.createRequestedTxValidator();
|
|
1318
|
+
|
|
1319
|
+
//TODO: (mralj) - this is somewhat naive implementation, if single tx is invalid we consider the whole response invalid.
|
|
1320
|
+
// I think we should still extract the valid txs and return them, so that we can still use the response.
|
|
1321
|
+
try {
|
|
1322
|
+
await Promise.all(responseTx.map(tx => this.validateRequestedTx(tx, peerId, requestedTxValidator, requested)));
|
|
1323
|
+
return true;
|
|
1324
|
+
} catch (e: any) {
|
|
1325
|
+
if (e instanceof ValidationError) {
|
|
1326
|
+
this.logger.warn(`Failed to validate requested txs from peer ${peerId.toString()}, reason ${e.message}`);
|
|
1327
|
+
} else {
|
|
1328
|
+
this.logger.error(`Error during validation of requested txs`, e);
|
|
1329
|
+
}
|
|
1330
|
+
|
|
659
1331
|
return false;
|
|
660
1332
|
}
|
|
1333
|
+
}
|
|
1334
|
+
|
|
1335
|
+
/**
|
|
1336
|
+
* Validates a BLOCK response.
|
|
1337
|
+
*
|
|
1338
|
+
* If a local copy exists, enforces hash equality. If missing, rejects (no penalty) since the hash cannot be verified.
|
|
1339
|
+
* Penalizes on block number mismatch or hash mismatch.
|
|
1340
|
+
*
|
|
1341
|
+
* @param requestedBlockNumber - The requested block number.
|
|
1342
|
+
* @param responseBlock - The block returned by the peer.
|
|
1343
|
+
* @param peerId - The peer that returned the block.
|
|
1344
|
+
* @returns True if the response is valid, false otherwise.
|
|
1345
|
+
*/
|
|
1346
|
+
@trackSpan('Libp2pService.validateRequestedBlock', (requestedBlockNumber, _responseBlock) => ({
|
|
1347
|
+
[Attributes.BLOCK_NUMBER]: requestedBlockNumber.toString(),
|
|
1348
|
+
}))
|
|
1349
|
+
private async validateRequestedBlock(
|
|
1350
|
+
requestedBlockNumber: Fr,
|
|
1351
|
+
responseBlock: L2Block,
|
|
1352
|
+
peerId: PeerId,
|
|
1353
|
+
): Promise<boolean> {
|
|
1354
|
+
try {
|
|
1355
|
+
const reqNum = Number(requestedBlockNumber.toString());
|
|
1356
|
+
if (responseBlock.number !== reqNum) {
|
|
1357
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
|
|
1358
|
+
return false;
|
|
1359
|
+
}
|
|
661
1360
|
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
1361
|
+
const local = await this.archiver.getBlock(BlockNumber(reqNum));
|
|
1362
|
+
if (!local) {
|
|
1363
|
+
// We are missing the local block; we cannot verify the hash yet. Reject without penalizing.
|
|
1364
|
+
// TODO: Consider extending this validator to accept an expected hash or
|
|
1365
|
+
// performing quorum-based checks when using P2P syncing prior to L1 sync.
|
|
1366
|
+
this.logger.warn(`Local block ${reqNum} not found; rejecting BLOCK response without hash verification`);
|
|
1367
|
+
return false;
|
|
1368
|
+
}
|
|
1369
|
+
const [localHash, respHash] = await Promise.all([local.hash(), responseBlock.hash()]);
|
|
1370
|
+
if (!localHash.equals(respHash)) {
|
|
1371
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
1372
|
+
return false;
|
|
1373
|
+
}
|
|
1374
|
+
|
|
1375
|
+
return true;
|
|
1376
|
+
} catch (e) {
|
|
1377
|
+
this.logger.warn(`Error validating requested block`, e);
|
|
665
1378
|
return false;
|
|
666
1379
|
}
|
|
1380
|
+
}
|
|
667
1381
|
|
|
668
|
-
|
|
1382
|
+
private async validateRequestedTx(tx: Tx, peerId: PeerId, txValidator: TxValidator, requested?: Set<`0x${string}`>) {
|
|
1383
|
+
const penalize = (severity: PeerErrorSeverity) => this.peerManager.penalizePeer(peerId, severity);
|
|
1384
|
+
if (requested && !requested.has(tx.getTxHash().toString())) {
|
|
1385
|
+
penalize(PeerErrorSeverity.MidToleranceError);
|
|
1386
|
+
throw new ValidationError(`Received tx with hash ${tx.getTxHash().toString()} that was not requested.`);
|
|
1387
|
+
}
|
|
1388
|
+
|
|
1389
|
+
const { result } = await txValidator.validateTx(tx);
|
|
1390
|
+
if (result === 'invalid') {
|
|
1391
|
+
penalize(PeerErrorSeverity.LowToleranceError);
|
|
1392
|
+
throw new ValidationError(`Received tx with hash ${tx.getTxHash().toString()} that is invalid.`);
|
|
1393
|
+
}
|
|
1394
|
+
}
|
|
1395
|
+
|
|
1396
|
+
private createRequestedTxValidator(): TxValidator {
|
|
1397
|
+
return createTxReqRespValidator(this.proofVerifier, {
|
|
1398
|
+
l1ChainId: this.config.l1ChainId,
|
|
1399
|
+
rollupVersion: this.config.rollupVersion,
|
|
1400
|
+
});
|
|
669
1401
|
}
|
|
670
1402
|
|
|
671
|
-
@trackSpan('Libp2pService.validatePropagatedTx',
|
|
672
|
-
[Attributes.TX_HASH]:
|
|
1403
|
+
@trackSpan('Libp2pService.validatePropagatedTx', tx => ({
|
|
1404
|
+
[Attributes.TX_HASH]: tx.getTxHash().toString(),
|
|
673
1405
|
}))
|
|
674
1406
|
private async validatePropagatedTx(tx: Tx, peerId: PeerId): Promise<boolean> {
|
|
675
|
-
const
|
|
676
|
-
const messageValidators = this.createMessageValidators(blockNumber);
|
|
677
|
-
const outcome = await this.runValidations(tx, messageValidators);
|
|
1407
|
+
const currentBlockNumber = await this.archiver.getBlockNumber();
|
|
678
1408
|
|
|
679
|
-
if (
|
|
680
|
-
|
|
1409
|
+
// We accept transactions if they are not expired by the next slot (checked based on the IncludeByTimestamp field)
|
|
1410
|
+
const { ts: nextSlotTimestamp } = this.epochCache.getEpochAndSlotInNextL1Slot();
|
|
1411
|
+
const messageValidators = await this.createMessageValidators(currentBlockNumber, nextSlotTimestamp);
|
|
1412
|
+
|
|
1413
|
+
for (const validator of messageValidators) {
|
|
1414
|
+
const outcome = await this.runValidations(tx, validator);
|
|
1415
|
+
|
|
1416
|
+
if (outcome.allPassed) {
|
|
1417
|
+
continue;
|
|
1418
|
+
}
|
|
1419
|
+
const { name } = outcome.failure;
|
|
1420
|
+
let { severity } = outcome.failure;
|
|
1421
|
+
|
|
1422
|
+
// Double spend validator has a special case handler
|
|
1423
|
+
if (name === 'doubleSpendValidator') {
|
|
1424
|
+
const txBlockNumber = BlockNumber(currentBlockNumber + 1); // tx is expected to be in the next block
|
|
1425
|
+
severity = await this.handleDoubleSpendFailure(tx, txBlockNumber);
|
|
1426
|
+
}
|
|
1427
|
+
|
|
1428
|
+
this.peerManager.penalizePeer(peerId, severity);
|
|
1429
|
+
return false;
|
|
681
1430
|
}
|
|
682
|
-
|
|
683
|
-
|
|
1431
|
+
return true;
|
|
1432
|
+
}
|
|
684
1433
|
|
|
685
|
-
|
|
686
|
-
if (
|
|
687
|
-
|
|
1434
|
+
private async getGasFees(blockNumber: BlockNumber): Promise<GasFees> {
|
|
1435
|
+
if (blockNumber === this.feesCache?.blockNumber) {
|
|
1436
|
+
return this.feesCache.gasFees;
|
|
688
1437
|
}
|
|
689
1438
|
|
|
690
|
-
this.
|
|
691
|
-
|
|
1439
|
+
const header = await this.archiver.getBlockHeader(blockNumber);
|
|
1440
|
+
const gasFees = header?.globalVariables.gasFees ?? GasFees.empty();
|
|
1441
|
+
this.feesCache = { blockNumber, gasFees };
|
|
1442
|
+
return gasFees;
|
|
692
1443
|
}
|
|
693
1444
|
|
|
694
1445
|
/**
|
|
695
|
-
*
|
|
1446
|
+
* Get the BatchTxRequesterLibP2PService dependencies for creating BatchTxRequester instances
|
|
1447
|
+
*/
|
|
1448
|
+
public getBatchTxRequesterService(): BatchTxRequesterLibP2PService {
|
|
1449
|
+
return {
|
|
1450
|
+
reqResp: this.reqresp,
|
|
1451
|
+
connectionSampler: this.reqresp.getConnectionSampler(),
|
|
1452
|
+
txValidatorConfig: {
|
|
1453
|
+
l1ChainId: this.config.l1ChainId,
|
|
1454
|
+
rollupVersion: this.config.rollupVersion,
|
|
1455
|
+
proofVerifier: this.proofVerifier,
|
|
1456
|
+
},
|
|
1457
|
+
peerScoring: this.peerManager,
|
|
1458
|
+
};
|
|
1459
|
+
}
|
|
1460
|
+
|
|
1461
|
+
public async validate(txs: Tx[]): Promise<void> {
|
|
1462
|
+
const currentBlockNumber = await this.archiver.getBlockNumber();
|
|
1463
|
+
|
|
1464
|
+
// We accept transactions if they are not expired by the next slot (checked based on the IncludeByTimestamp field)
|
|
1465
|
+
const { ts: nextSlotTimestamp } = this.epochCache.getEpochAndSlotInNextL1Slot();
|
|
1466
|
+
const messageValidators = await this.createMessageValidators(currentBlockNumber, nextSlotTimestamp);
|
|
1467
|
+
|
|
1468
|
+
await Promise.all(
|
|
1469
|
+
txs.map(async tx => {
|
|
1470
|
+
for (const validator of messageValidators) {
|
|
1471
|
+
const outcome = await this.runValidations(tx, validator);
|
|
1472
|
+
if (!outcome.allPassed) {
|
|
1473
|
+
throw new Error('Invalid tx detected', { cause: { outcome } });
|
|
1474
|
+
}
|
|
1475
|
+
}
|
|
1476
|
+
}),
|
|
1477
|
+
);
|
|
1478
|
+
}
|
|
1479
|
+
|
|
1480
|
+
/**
|
|
1481
|
+
* Create message validators for the given block number and timestamp.
|
|
696
1482
|
*
|
|
697
1483
|
* Each validator is a pair of a validator and a severity.
|
|
698
1484
|
* If a validator fails, the peer is penalized with the severity of the validator.
|
|
699
1485
|
*
|
|
700
|
-
* @param
|
|
1486
|
+
* @param currentBlockNumber - The current synced block number.
|
|
1487
|
+
* @param nextSlotTimestamp - The timestamp of the next slot (used to validate txs are not expired).
|
|
701
1488
|
* @returns The message validators.
|
|
702
1489
|
*/
|
|
703
|
-
private createMessageValidators(
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
},
|
|
727
|
-
};
|
|
1490
|
+
private async createMessageValidators(
|
|
1491
|
+
currentBlockNumber: BlockNumber,
|
|
1492
|
+
nextSlotTimestamp: UInt64,
|
|
1493
|
+
): Promise<Record<string, MessageValidator>[]> {
|
|
1494
|
+
const gasFees = await this.getGasFees(currentBlockNumber);
|
|
1495
|
+
const allowedInSetup = this.config.txPublicSetupAllowList ?? (await getDefaultAllowedSetupFunctions());
|
|
1496
|
+
|
|
1497
|
+
const blockNumberInWhichTheTxIsConsideredToBeIncluded = BlockNumber(currentBlockNumber + 1);
|
|
1498
|
+
|
|
1499
|
+
return createTxMessageValidators(
|
|
1500
|
+
nextSlotTimestamp,
|
|
1501
|
+
blockNumberInWhichTheTxIsConsideredToBeIncluded,
|
|
1502
|
+
this.worldStateSynchronizer,
|
|
1503
|
+
gasFees,
|
|
1504
|
+
this.config.l1ChainId,
|
|
1505
|
+
this.config.rollupVersion,
|
|
1506
|
+
protocolContractsHash,
|
|
1507
|
+
this.archiver,
|
|
1508
|
+
this.proofVerifier,
|
|
1509
|
+
!this.config.disableTransactions,
|
|
1510
|
+
allowedInSetup,
|
|
1511
|
+
this.logger.getBindings(),
|
|
1512
|
+
);
|
|
728
1513
|
}
|
|
729
1514
|
|
|
730
1515
|
/**
|
|
@@ -739,28 +1524,26 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
|
|
|
739
1524
|
): Promise<ValidationOutcome> {
|
|
740
1525
|
const validationPromises = Object.entries(messageValidators).map(async ([name, { validator, severity }]) => {
|
|
741
1526
|
const { result } = await validator.validateTx(tx);
|
|
742
|
-
return { name, isValid: result
|
|
1527
|
+
return { name, isValid: result !== 'invalid', severity };
|
|
743
1528
|
});
|
|
744
1529
|
|
|
745
1530
|
// A promise that resolves when all validations have been run
|
|
746
|
-
const allValidations = Promise.all(validationPromises);
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
// If all validations pass, allPassed will be true, if failed, then the failure will be the first validation to fail
|
|
763
|
-
return result;
|
|
1531
|
+
const allValidations = await Promise.all(validationPromises);
|
|
1532
|
+
const failed = allValidations.find(x => !x.isValid);
|
|
1533
|
+
if (failed) {
|
|
1534
|
+
return {
|
|
1535
|
+
allPassed: false,
|
|
1536
|
+
failure: {
|
|
1537
|
+
isValid: { result: 'invalid' as const, reason: ['Failed validation'] },
|
|
1538
|
+
name: failed.name,
|
|
1539
|
+
severity: failed.severity,
|
|
1540
|
+
},
|
|
1541
|
+
};
|
|
1542
|
+
} else {
|
|
1543
|
+
return {
|
|
1544
|
+
allPassed: true,
|
|
1545
|
+
};
|
|
1546
|
+
}
|
|
764
1547
|
}
|
|
765
1548
|
|
|
766
1549
|
/**
|
|
@@ -774,20 +1557,23 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
|
|
|
774
1557
|
* @param peerId - The peer ID of the peer that sent the tx.
|
|
775
1558
|
* @returns Severity
|
|
776
1559
|
*/
|
|
777
|
-
private async handleDoubleSpendFailure(tx: Tx, blockNumber:
|
|
1560
|
+
private async handleDoubleSpendFailure(tx: Tx, blockNumber: BlockNumber): Promise<PeerErrorSeverity> {
|
|
778
1561
|
if (blockNumber <= this.config.doubleSpendSeverePeerPenaltyWindow) {
|
|
779
1562
|
return PeerErrorSeverity.HighToleranceError;
|
|
780
1563
|
}
|
|
781
1564
|
|
|
782
|
-
const snapshotValidator = new DoubleSpendTxValidator(
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
1565
|
+
const snapshotValidator = new DoubleSpendTxValidator(
|
|
1566
|
+
{
|
|
1567
|
+
nullifiersExist: async (nullifiers: Buffer[]) => {
|
|
1568
|
+
const merkleTree = this.worldStateSynchronizer.getSnapshot(
|
|
1569
|
+
BlockNumber(blockNumber - this.config.doubleSpendSeverePeerPenaltyWindow),
|
|
1570
|
+
);
|
|
1571
|
+
const indices = await merkleTree.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, nullifiers);
|
|
1572
|
+
return indices.map(index => index !== undefined);
|
|
1573
|
+
},
|
|
789
1574
|
},
|
|
790
|
-
|
|
1575
|
+
this.logger.getBindings(),
|
|
1576
|
+
);
|
|
791
1577
|
|
|
792
1578
|
const validSnapshot = await snapshotValidator.validateTx(tx);
|
|
793
1579
|
if (validSnapshot.result !== 'valid') {
|
|
@@ -798,25 +1584,28 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
|
|
|
798
1584
|
}
|
|
799
1585
|
|
|
800
1586
|
/**
|
|
801
|
-
* Validate
|
|
1587
|
+
* Validate a checkpoint attestation.
|
|
802
1588
|
*
|
|
803
|
-
* @param attestation - The attestation to validate.
|
|
804
|
-
* @returns True if the attestation is valid, false otherwise.
|
|
1589
|
+
* @param attestation - The checkpoint attestation to validate.
|
|
1590
|
+
* @returns True if the checkpoint attestation is valid, false otherwise.
|
|
805
1591
|
*/
|
|
806
|
-
@trackSpan('Libp2pService.
|
|
807
|
-
[Attributes.
|
|
808
|
-
[Attributes.SLOT_NUMBER]: attestation.payload.header.globalVariables.slotNumber.toNumber(),
|
|
1592
|
+
@trackSpan('Libp2pService.validateCheckpointAttestation', async (_, attestation) => ({
|
|
1593
|
+
[Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber,
|
|
809
1594
|
[Attributes.BLOCK_ARCHIVE]: attestation.archive.toString(),
|
|
810
|
-
[Attributes.P2P_ID]: await attestation.
|
|
1595
|
+
[Attributes.P2P_ID]: await attestation.p2pMessageLoggingIdentifier().then(i => i.toString()),
|
|
811
1596
|
}))
|
|
812
|
-
public async
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
1597
|
+
public async validateCheckpointAttestation(
|
|
1598
|
+
peerId: PeerId,
|
|
1599
|
+
attestation: CheckpointAttestation,
|
|
1600
|
+
): Promise<P2PValidationResult> {
|
|
1601
|
+
const result = await this.checkpointAttestationValidator.validate(attestation);
|
|
1602
|
+
|
|
1603
|
+
if (result.result === 'reject') {
|
|
1604
|
+
this.logger.debug(`Penalizing peer ${peerId} for checkpoint attestation validation failure`);
|
|
1605
|
+
this.peerManager.penalizePeer(peerId, result.severity);
|
|
817
1606
|
}
|
|
818
1607
|
|
|
819
|
-
return
|
|
1608
|
+
return result;
|
|
820
1609
|
}
|
|
821
1610
|
|
|
822
1611
|
/**
|
|
@@ -826,29 +1615,57 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
|
|
|
826
1615
|
* @returns True if the block proposal is valid, false otherwise.
|
|
827
1616
|
*/
|
|
828
1617
|
@trackSpan('Libp2pService.validateBlockProposal', (_peerId, block) => ({
|
|
829
|
-
[Attributes.SLOT_NUMBER]: block.
|
|
1618
|
+
[Attributes.SLOT_NUMBER]: block.slotNumber.toString(),
|
|
830
1619
|
}))
|
|
831
|
-
public async validateBlockProposal(peerId: PeerId, block: BlockProposal): Promise<
|
|
832
|
-
const
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
1620
|
+
public async validateBlockProposal(peerId: PeerId, block: BlockProposal): Promise<P2PValidationResult> {
|
|
1621
|
+
const result = await this.blockProposalValidator.validate(block);
|
|
1622
|
+
|
|
1623
|
+
if (result.result === 'reject') {
|
|
1624
|
+
this.logger.debug(`Penalizing peer ${peerId} for block proposal validation failure`);
|
|
1625
|
+
this.peerManager.penalizePeer(peerId, result.severity);
|
|
836
1626
|
}
|
|
837
1627
|
|
|
838
|
-
return
|
|
1628
|
+
return result;
|
|
1629
|
+
}
|
|
1630
|
+
|
|
1631
|
+
/**
|
|
1632
|
+
* Validate a checkpoint proposal.
|
|
1633
|
+
*
|
|
1634
|
+
* @param checkpoint - The checkpoint proposal to validate.
|
|
1635
|
+
* @returns True if the checkpoint proposal is valid, false otherwise.
|
|
1636
|
+
*/
|
|
1637
|
+
@trackSpan('Libp2pService.validateCheckpointProposal', (_peerId, checkpoint) => ({
|
|
1638
|
+
[Attributes.SLOT_NUMBER]: checkpoint.slotNumber.toString(),
|
|
1639
|
+
}))
|
|
1640
|
+
public async validateCheckpointProposal(
|
|
1641
|
+
peerId: PeerId,
|
|
1642
|
+
checkpoint: CheckpointProposal,
|
|
1643
|
+
): Promise<P2PValidationResult> {
|
|
1644
|
+
const result = await this.checkpointProposalValidator.validate(checkpoint);
|
|
1645
|
+
|
|
1646
|
+
if (result.result === 'reject') {
|
|
1647
|
+
this.logger.debug(`Penalizing peer ${peerId} for checkpoint proposal validation failure`);
|
|
1648
|
+
this.peerManager.penalizePeer(peerId, result.severity);
|
|
1649
|
+
}
|
|
1650
|
+
|
|
1651
|
+
return result;
|
|
839
1652
|
}
|
|
840
1653
|
|
|
841
1654
|
public getPeerScore(peerId: PeerId): number {
|
|
842
1655
|
return this.node.services.pubsub.score.score(peerId.toString());
|
|
843
1656
|
}
|
|
844
1657
|
|
|
1658
|
+
public handleAuthRequestFromPeer(authRequest: AuthRequest, peerId: PeerId): Promise<StatusMessage> {
|
|
1659
|
+
return this.peerManager.handleAuthRequestFromPeer(authRequest, peerId);
|
|
1660
|
+
}
|
|
1661
|
+
|
|
845
1662
|
private async sendToPeers<T extends Gossipable>(message: T) {
|
|
846
1663
|
const parent = message.constructor as typeof Gossipable;
|
|
847
1664
|
|
|
848
|
-
const identifier = await message.
|
|
1665
|
+
const identifier = await message.p2pMessageLoggingIdentifier().then(i => i.toString());
|
|
849
1666
|
this.logger.trace(`Sending message ${identifier}`, { p2pMessageIdentifier: identifier });
|
|
850
1667
|
|
|
851
|
-
const recipientsNum = await this.publishToTopic(parent.p2pTopic, message
|
|
1668
|
+
const recipientsNum = await this.publishToTopic(this.topicStrings[parent.p2pTopic], message);
|
|
852
1669
|
this.logger.debug(`Sent message ${identifier} to ${recipientsNum} peers`, {
|
|
853
1670
|
p2pMessageIdentifier: identifier,
|
|
854
1671
|
sourcePeer: this.node.peerId.toString(),
|