@aztec/p2p 0.0.1-commit.b655e406 → 0.0.1-commit.c0b82b2
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 +4 -4
- package/dest/client/factory.d.ts +10 -10
- package/dest/client/factory.d.ts.map +1 -1
- package/dest/client/factory.js +45 -19
- package/dest/client/index.d.ts +1 -1
- package/dest/client/interface.d.ts +61 -33
- package/dest/client/interface.d.ts.map +1 -1
- package/dest/client/p2p_client.d.ts +52 -83
- package/dest/client/p2p_client.d.ts.map +1 -1
- package/dest/client/p2p_client.js +612 -318
- 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 +304 -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 +95 -64
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +42 -21
- package/dest/enr/generate-enr.d.ts +1 -1
- 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/errors/tx-pool.error.d.ts +8 -0
- package/dest/errors/tx-pool.error.d.ts.map +1 -0
- package/dest/errors/tx-pool.error.js +9 -0
- package/dest/index.d.ts +2 -1
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +1 -0
- package/dest/mem_pools/attestation_pool/attestation_pool.d.ts +114 -57
- package/dest/mem_pools/attestation_pool/attestation_pool.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/attestation_pool.js +441 -3
- package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.d.ts +2 -2
- 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 +529 -288
- package/dest/mem_pools/attestation_pool/index.d.ts +2 -3
- package/dest/mem_pools/attestation_pool/index.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/index.js +1 -2
- package/dest/mem_pools/attestation_pool/mocks.d.ts +234 -10
- package/dest/mem_pools/attestation_pool/mocks.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/mocks.js +17 -13
- package/dest/mem_pools/index.d.ts +3 -2
- package/dest/mem_pools/index.d.ts.map +1 -1
- package/dest/mem_pools/index.js +1 -1
- package/dest/mem_pools/instrumentation.d.ts +9 -1
- package/dest/mem_pools/instrumentation.d.ts.map +1 -1
- package/dest/mem_pools/instrumentation.js +37 -10
- package/dest/mem_pools/interface.d.ts +6 -7
- package/dest/mem_pools/interface.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts +33 -58
- 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 +314 -335
- 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 +6 -1
- package/dest/mem_pools/tx_pool/tx_pool.d.ts +11 -6
- 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 +30 -24
- package/dest/mem_pools/tx_pool_v2/archive/index.d.ts +2 -0
- package/dest/mem_pools/tx_pool_v2/archive/index.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/archive/index.js +1 -0
- package/dest/mem_pools/tx_pool_v2/archive/tx_archive.d.ts +43 -0
- package/dest/mem_pools/tx_pool_v2/archive/tx_archive.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/archive/tx_archive.js +103 -0
- package/dest/mem_pools/tx_pool_v2/deleted_pool.d.ts +104 -0
- package/dest/mem_pools/tx_pool_v2/deleted_pool.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/deleted_pool.js +251 -0
- package/dest/mem_pools/tx_pool_v2/eviction/eviction_manager.d.ts +47 -0
- package/dest/mem_pools/tx_pool_v2/eviction/eviction_manager.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/eviction/eviction_manager.js +128 -0
- package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.d.ts +17 -0
- package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.js +93 -0
- package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.d.ts +19 -0
- package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.js +97 -0
- package/dest/mem_pools/tx_pool_v2/eviction/index.d.ts +10 -0
- package/dest/mem_pools/tx_pool_v2/eviction/index.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/eviction/index.js +11 -0
- package/dest/mem_pools/tx_pool_v2/eviction/interfaces.d.ts +174 -0
- package/dest/mem_pools/tx_pool_v2/eviction/interfaces.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/eviction/interfaces.js +25 -0
- package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_mining_rule.d.ts +15 -0
- package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_mining_rule.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_mining_rule.js +65 -0
- package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.d.ts +17 -0
- package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.js +93 -0
- package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.d.ts +16 -0
- package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.js +78 -0
- package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.d.ts +20 -0
- package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.js +73 -0
- package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.d.ts +15 -0
- package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.js +19 -0
- package/dest/mem_pools/tx_pool_v2/index.d.ts +6 -0
- package/dest/mem_pools/tx_pool_v2/index.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/index.js +5 -0
- package/dest/mem_pools/tx_pool_v2/instrumentation.d.ts +15 -0
- package/dest/mem_pools/tx_pool_v2/instrumentation.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/instrumentation.js +43 -0
- package/dest/mem_pools/tx_pool_v2/interfaces.d.ts +211 -0
- package/dest/mem_pools/tx_pool_v2/interfaces.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/interfaces.js +9 -0
- package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts +119 -0
- package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/tx_metadata.js +193 -0
- package/dest/mem_pools/tx_pool_v2/tx_pool_bench_metrics.d.ts +26 -0
- package/dest/mem_pools/tx_pool_v2/tx_pool_bench_metrics.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/tx_pool_bench_metrics.js +70 -0
- package/dest/mem_pools/tx_pool_v2/tx_pool_indices.d.ts +108 -0
- package/dest/mem_pools/tx_pool_v2/tx_pool_indices.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/tx_pool_indices.js +354 -0
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts +60 -0
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2.js +161 -0
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts +77 -0
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.js +905 -0
- package/dest/msg_validators/attestation_validator/attestation_validator.d.ts +7 -6
- package/dest/msg_validators/attestation_validator/attestation_validator.d.ts.map +1 -1
- package/dest/msg_validators/attestation_validator/attestation_validator.js +57 -24
- 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 +1 -1
- package/dest/msg_validators/msg_seen_validator/msg_seen_validator.d.ts.map +1 -1
- 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 +4 -4
- package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/aggregate_tx_validator.js +3 -3
- package/dest/msg_validators/tx_validator/allowed_public_setup.d.ts +1 -1
- package/dest/msg_validators/tx_validator/archive_cache.d.ts +3 -3
- package/dest/msg_validators/tx_validator/archive_cache.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/archive_cache.js +1 -1
- package/dest/msg_validators/tx_validator/block_header_validator.d.ts +20 -6
- package/dest/msg_validators/tx_validator/block_header_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/block_header_validator.js +4 -3
- 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 +4 -1
- package/dest/msg_validators/tx_validator/double_spend_validator.d.ts +15 -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 +7 -6
- package/dest/msg_validators/tx_validator/factory.d.ts +120 -6
- package/dest/msg_validators/tx_validator/factory.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/factory.js +228 -57
- 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 +59 -3
- package/dest/msg_validators/tx_validator/gas_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/gas_validator.js +84 -52
- package/dest/msg_validators/tx_validator/index.d.ts +3 -1
- package/dest/msg_validators/tx_validator/index.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/index.js +2 -0
- package/dest/msg_validators/tx_validator/metadata_validator.d.ts +4 -3
- package/dest/msg_validators/tx_validator/metadata_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/metadata_validator.js +2 -2
- package/dest/msg_validators/tx_validator/nullifier_cache.d.ts +14 -0
- package/dest/msg_validators/tx_validator/nullifier_cache.d.ts.map +1 -0
- package/dest/msg_validators/tx_validator/nullifier_cache.js +24 -0
- package/dest/msg_validators/tx_validator/phases_validator.d.ts +3 -2
- package/dest/msg_validators/tx_validator/phases_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/phases_validator.js +6 -4
- 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 +2 -2
- package/dest/msg_validators/tx_validator/test_utils.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/timestamp_validator.d.ts +23 -5
- package/dest/msg_validators/tx_validator/timestamp_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/timestamp_validator.js +8 -8
- package/dest/msg_validators/tx_validator/tx_permitted_validator.d.ts +3 -2
- package/dest/msg_validators/tx_validator/tx_permitted_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/tx_permitted_validator.js +2 -2
- 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 +2 -2
- 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 +1 -1
- package/dest/services/discv5/discV5_service.d.ts.map +1 -1
- package/dest/services/discv5/discV5_service.js +1 -1
- package/dest/services/dummy_service.d.ts +28 -4
- package/dest/services/dummy_service.d.ts.map +1 -1
- package/dest/services/dummy_service.js +49 -1
- package/dest/services/encoding.d.ts +3 -3
- package/dest/services/encoding.d.ts.map +1 -1
- package/dest/services/encoding.js +16 -14
- package/dest/services/gossipsub/index.d.ts +3 -0
- package/dest/services/gossipsub/index.d.ts.map +1 -0
- package/dest/services/gossipsub/index.js +2 -0
- package/dest/services/gossipsub/scoring.d.ts +21 -3
- package/dest/services/gossipsub/scoring.d.ts.map +1 -1
- package/dest/services/gossipsub/scoring.js +24 -7
- package/dest/services/gossipsub/topic_score_params.d.ts +173 -0
- package/dest/services/gossipsub/topic_score_params.d.ts.map +1 -0
- package/dest/services/gossipsub/topic_score_params.js +346 -0
- package/dest/services/index.d.ts +2 -1
- package/dest/services/index.d.ts.map +1 -1
- package/dest/services/index.js +1 -0
- package/dest/services/libp2p/instrumentation.d.ts +3 -1
- package/dest/services/libp2p/instrumentation.d.ts.map +1 -1
- package/dest/services/libp2p/instrumentation.js +36 -71
- package/dest/services/libp2p/libp2p_service.d.ts +112 -93
- package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
- package/dest/services/libp2p/libp2p_service.js +1158 -342
- package/dest/services/peer-manager/interface.d.ts +1 -1
- package/dest/services/peer-manager/metrics.d.ts +9 -2
- package/dest/services/peer-manager/metrics.d.ts.map +1 -1
- package/dest/services/peer-manager/metrics.js +39 -16
- package/dest/services/peer-manager/peer_manager.d.ts +2 -33
- package/dest/services/peer-manager/peer_manager.d.ts.map +1 -1
- package/dest/services/peer-manager/peer_manager.js +6 -12
- 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 +68 -4
- package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts +48 -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 +539 -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 +46 -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 +34 -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 +130 -0
- package/dest/services/reqresp/batch-tx-requester/peer_collection.d.ts +60 -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 +173 -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 +1 -1
- package/dest/services/reqresp/connection-sampler/batch_connection_sampler.d.ts +22 -3
- package/dest/services/reqresp/connection-sampler/batch_connection_sampler.d.ts.map +1 -1
- package/dest/services/reqresp/connection-sampler/batch_connection_sampler.js +63 -4
- package/dest/services/reqresp/connection-sampler/connection_sampler.d.ts +2 -4
- package/dest/services/reqresp/connection-sampler/connection_sampler.d.ts.map +1 -1
- package/dest/services/reqresp/connection-sampler/connection_sampler.js +12 -0
- 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 +1 -1
- package/dest/services/reqresp/interface.d.ts +13 -2
- package/dest/services/reqresp/interface.d.ts.map +1 -1
- package/dest/services/reqresp/interface.js +16 -2
- 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 +2 -2
- package/dest/services/reqresp/protocols/auth.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/auth.js +2 -2
- package/dest/services/reqresp/protocols/block.d.ts +1 -1
- package/dest/services/reqresp/protocols/block.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/block.js +3 -2
- package/dest/services/reqresp/protocols/block_txs/bitvector.d.ts +5 -1
- package/dest/services/reqresp/protocols/block_txs/bitvector.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/block_txs/bitvector.js +12 -0
- package/dest/services/reqresp/protocols/block_txs/block_txs_handler.d.ts +7 -5
- package/dest/services/reqresp/protocols/block_txs/block_txs_handler.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/block_txs/block_txs_handler.js +27 -9
- package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.d.ts +30 -9
- package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.js +60 -14
- package/dest/services/reqresp/protocols/block_txs/index.d.ts +1 -1
- package/dest/services/reqresp/protocols/goodbye.d.ts +1 -1
- package/dest/services/reqresp/protocols/goodbye.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/index.d.ts +1 -1
- package/dest/services/reqresp/protocols/ping.d.ts +1 -1
- package/dest/services/reqresp/protocols/status.d.ts +6 -5
- package/dest/services/reqresp/protocols/status.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/status.js +7 -3
- package/dest/services/reqresp/protocols/tx.d.ts +8 -3
- package/dest/services/reqresp/protocols/tx.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/tx.js +20 -0
- package/dest/services/reqresp/rate-limiter/index.d.ts +1 -1
- package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts +2 -2
- package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts.map +1 -1
- package/dest/services/reqresp/rate-limiter/rate_limits.d.ts +1 -1
- package/dest/services/reqresp/reqresp.d.ts +6 -41
- package/dest/services/reqresp/reqresp.d.ts.map +1 -1
- package/dest/services/reqresp/reqresp.js +473 -51
- package/dest/services/reqresp/status.d.ts +2 -2
- package/dest/services/reqresp/status.d.ts.map +1 -1
- package/dest/services/service.d.ts +56 -4
- package/dest/services/service.d.ts.map +1 -1
- package/dest/services/tx_collection/config.d.ts +22 -1
- package/dest/services/tx_collection/config.d.ts.map +1 -1
- package/dest/services/tx_collection/config.js +56 -2
- package/dest/services/tx_collection/fast_tx_collection.d.ts +10 -12
- package/dest/services/tx_collection/fast_tx_collection.d.ts.map +1 -1
- package/dest/services/tx_collection/fast_tx_collection.js +71 -44
- package/dest/services/tx_collection/file_store_tx_collection.d.ts +53 -0
- package/dest/services/tx_collection/file_store_tx_collection.d.ts.map +1 -0
- package/dest/services/tx_collection/file_store_tx_collection.js +167 -0
- package/dest/services/tx_collection/file_store_tx_source.d.ts +37 -0
- package/dest/services/tx_collection/file_store_tx_source.d.ts.map +1 -0
- package/dest/services/tx_collection/file_store_tx_source.js +90 -0
- package/dest/services/tx_collection/index.d.ts +3 -1
- package/dest/services/tx_collection/index.d.ts.map +1 -1
- package/dest/services/tx_collection/index.js +2 -0
- package/dest/services/tx_collection/instrumentation.d.ts +1 -1
- package/dest/services/tx_collection/instrumentation.d.ts.map +1 -1
- package/dest/services/tx_collection/instrumentation.js +11 -13
- package/dest/services/tx_collection/missing_txs_tracker.d.ts +32 -0
- package/dest/services/tx_collection/missing_txs_tracker.d.ts.map +1 -0
- package/dest/services/tx_collection/missing_txs_tracker.js +27 -0
- package/dest/services/tx_collection/proposal_tx_collector.d.ts +49 -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 +9 -6
- package/dest/services/tx_collection/slow_tx_collection.d.ts.map +1 -1
- package/dest/services/tx_collection/slow_tx_collection.js +61 -26
- package/dest/services/tx_collection/tx_collection.d.ts +31 -18
- package/dest/services/tx_collection/tx_collection.d.ts.map +1 -1
- package/dest/services/tx_collection/tx_collection.js +79 -7
- package/dest/services/tx_collection/tx_collection_sink.d.ts +19 -9
- package/dest/services/tx_collection/tx_collection_sink.d.ts.map +1 -1
- package/dest/services/tx_collection/tx_collection_sink.js +26 -29
- package/dest/services/tx_collection/tx_source.d.ts +8 -3
- package/dest/services/tx_collection/tx_source.d.ts.map +1 -1
- package/dest/services/tx_collection/tx_source.js +19 -2
- package/dest/services/tx_file_store/config.d.ts +16 -0
- package/dest/services/tx_file_store/config.d.ts.map +1 -0
- package/dest/services/tx_file_store/config.js +22 -0
- package/dest/services/tx_file_store/index.d.ts +4 -0
- package/dest/services/tx_file_store/index.d.ts.map +1 -0
- package/dest/services/tx_file_store/index.js +3 -0
- package/dest/services/tx_file_store/instrumentation.d.ts +15 -0
- package/dest/services/tx_file_store/instrumentation.d.ts.map +1 -0
- package/dest/services/tx_file_store/instrumentation.js +29 -0
- package/dest/services/tx_file_store/tx_file_store.d.ts +48 -0
- package/dest/services/tx_file_store/tx_file_store.d.ts.map +1 -0
- package/dest/services/tx_file_store/tx_file_store.js +152 -0
- package/dest/services/tx_provider.d.ts +7 -5
- package/dest/services/tx_provider.d.ts.map +1 -1
- package/dest/services/tx_provider.js +20 -10
- package/dest/services/tx_provider_instrumentation.d.ts +5 -2
- package/dest/services/tx_provider_instrumentation.d.ts.map +1 -1
- package/dest/services/tx_provider_instrumentation.js +14 -14
- 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 +3 -1
- package/dest/test-helpers/index.d.ts.map +1 -1
- package/dest/test-helpers/index.js +2 -0
- package/dest/test-helpers/make-enrs.d.ts +1 -1
- package/dest/test-helpers/make-test-p2p-clients.d.ts +7 -8
- package/dest/test-helpers/make-test-p2p-clients.d.ts.map +1 -1
- package/dest/test-helpers/make-test-p2p-clients.js +1 -2
- package/dest/test-helpers/mock-pubsub.d.ts +32 -6
- package/dest/test-helpers/mock-pubsub.d.ts.map +1 -1
- package/dest/test-helpers/mock-pubsub.js +105 -4
- package/dest/test-helpers/mock-tx-helpers.d.ts +2 -2
- package/dest/test-helpers/mock-tx-helpers.d.ts.map +1 -1
- package/dest/test-helpers/mock-tx-helpers.js +1 -1
- package/dest/test-helpers/reqresp-nodes.d.ts +2 -3
- package/dest/test-helpers/reqresp-nodes.d.ts.map +1 -1
- package/dest/test-helpers/reqresp-nodes.js +4 -3
- 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 +163 -0
- package/dest/test-helpers/testbench-utils.d.ts.map +1 -0
- package/dest/test-helpers/testbench-utils.js +366 -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 +225 -127
- package/dest/testbench/parse_log_file.d.ts +1 -1
- package/dest/testbench/testbench.d.ts +1 -1
- package/dest/testbench/worker_client_manager.d.ts +51 -6
- package/dest/testbench/worker_client_manager.d.ts.map +1 -1
- package/dest/testbench/worker_client_manager.js +226 -39
- package/dest/types/index.d.ts +1 -1
- package/dest/util.d.ts +3 -2
- package/dest/util.d.ts.map +1 -1
- package/dest/util.js +11 -2
- package/dest/versioning.d.ts +1 -1
- package/package.json +19 -18
- package/src/bootstrap/bootstrap.ts +7 -4
- package/src/client/factory.ts +85 -43
- package/src/client/interface.ts +74 -34
- package/src/client/p2p_client.ts +281 -383
- package/src/client/test/tx_proposal_collector/README.md +227 -0
- package/src/client/test/tx_proposal_collector/proposal_tx_collector_worker.ts +345 -0
- package/src/client/test/tx_proposal_collector/proposal_tx_collector_worker_protocol.ts +43 -0
- package/src/config.ts +77 -30
- package/src/errors/attestation-pool.error.ts +13 -0
- package/src/errors/tx-pool.error.ts +12 -0
- package/src/index.ts +1 -0
- package/src/mem_pools/attestation_pool/attestation_pool.ts +514 -58
- package/src/mem_pools/attestation_pool/attestation_pool_test_suite.ts +614 -309
- package/src/mem_pools/attestation_pool/index.ts +9 -2
- package/src/mem_pools/attestation_pool/mocks.ts +22 -15
- package/src/mem_pools/index.ts +4 -1
- package/src/mem_pools/instrumentation.ts +48 -10
- package/src/mem_pools/interface.ts +5 -7
- package/src/mem_pools/tx_pool/README.md +270 -0
- package/src/mem_pools/tx_pool/aztec_kv_tx_pool.ts +367 -371
- 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 +8 -1
- package/src/mem_pools/tx_pool/tx_pool.ts +11 -5
- package/src/mem_pools/tx_pool/tx_pool_test_suite.ts +23 -17
- package/src/mem_pools/tx_pool_v2/README.md +275 -0
- package/src/mem_pools/tx_pool_v2/archive/index.ts +1 -0
- package/src/mem_pools/tx_pool_v2/archive/tx_archive.ts +120 -0
- package/src/mem_pools/tx_pool_v2/deleted_pool.ts +321 -0
- package/src/mem_pools/tx_pool_v2/eviction/eviction_manager.ts +160 -0
- package/src/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.ts +121 -0
- package/src/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.ts +125 -0
- package/src/mem_pools/tx_pool_v2/eviction/index.ts +27 -0
- package/src/mem_pools/tx_pool_v2/eviction/interfaces.ts +209 -0
- package/src/mem_pools/tx_pool_v2/eviction/invalid_txs_after_mining_rule.ts +74 -0
- package/src/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.ts +101 -0
- package/src/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.ts +91 -0
- package/src/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.ts +90 -0
- package/src/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.ts +31 -0
- package/src/mem_pools/tx_pool_v2/index.ts +12 -0
- package/src/mem_pools/tx_pool_v2/instrumentation.ts +69 -0
- package/src/mem_pools/tx_pool_v2/interfaces.ts +242 -0
- package/src/mem_pools/tx_pool_v2/tx_metadata.ts +297 -0
- package/src/mem_pools/tx_pool_v2/tx_pool_bench_metrics.ts +77 -0
- package/src/mem_pools/tx_pool_v2/tx_pool_indices.ts +444 -0
- package/src/mem_pools/tx_pool_v2/tx_pool_v2.ts +223 -0
- package/src/mem_pools/tx_pool_v2/tx_pool_v2_impl.ts +1083 -0
- package/src/msg_validators/attestation_validator/attestation_validator.ts +45 -32
- 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/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/README.md +115 -0
- package/src/msg_validators/tx_validator/aggregate_tx_validator.ts +5 -5
- package/src/msg_validators/tx_validator/archive_cache.ts +3 -3
- package/src/msg_validators/tx_validator/block_header_validator.ts +21 -8
- package/src/msg_validators/tx_validator/data_validator.ts +18 -6
- package/src/msg_validators/tx_validator/double_spend_validator.ts +15 -9
- package/src/msg_validators/tx_validator/factory.ts +375 -57
- package/src/msg_validators/tx_validator/fee_payer_balance.ts +40 -0
- package/src/msg_validators/tx_validator/gas_validator.ts +106 -54
- package/src/msg_validators/tx_validator/index.ts +2 -0
- package/src/msg_validators/tx_validator/metadata_validator.ts +19 -8
- package/src/msg_validators/tx_validator/nullifier_cache.ts +30 -0
- package/src/msg_validators/tx_validator/phases_validator.ts +8 -4
- package/src/msg_validators/tx_validator/size_validator.ts +22 -0
- package/src/msg_validators/tx_validator/test_utils.ts +1 -1
- package/src/msg_validators/tx_validator/timestamp_validator.ts +30 -19
- package/src/msg_validators/tx_validator/tx_permitted_validator.ts +8 -3
- package/src/msg_validators/tx_validator/tx_proof_validator.ts +8 -3
- package/src/services/data_store.ts +10 -7
- package/src/services/discv5/discV5_service.ts +1 -1
- package/src/services/dummy_service.ts +65 -2
- package/src/services/encoding.ts +13 -12
- package/src/services/gossipsub/README.md +641 -0
- package/src/services/gossipsub/index.ts +2 -0
- package/src/services/gossipsub/scoring.ts +29 -5
- package/src/services/gossipsub/topic_score_params.ts +487 -0
- package/src/services/index.ts +1 -0
- package/src/services/libp2p/instrumentation.ts +39 -71
- package/src/services/libp2p/libp2p_service.ts +883 -364
- package/src/services/peer-manager/metrics.ts +44 -16
- package/src/services/peer-manager/peer_manager.ts +7 -4
- package/src/services/peer-manager/peer_scoring.ts +70 -3
- package/src/services/reqresp/batch-tx-requester/README.md +305 -0
- package/src/services/reqresp/batch-tx-requester/batch_tx_requester.ts +678 -0
- package/src/services/reqresp/batch-tx-requester/config.ts +40 -0
- package/src/services/reqresp/batch-tx-requester/interface.ts +53 -0
- package/src/services/reqresp/batch-tx-requester/missing_txs.ts +161 -0
- package/src/services/reqresp/batch-tx-requester/peer_collection.ts +244 -0
- package/src/services/reqresp/batch-tx-requester/tx_validator.ts +37 -0
- package/src/services/reqresp/connection-sampler/batch_connection_sampler.ts +65 -4
- package/src/services/reqresp/connection-sampler/connection_sampler.ts +19 -1
- package/src/services/reqresp/constants.ts +14 -0
- package/src/services/reqresp/interface.ts +30 -2
- package/src/services/reqresp/metrics.ts +36 -27
- package/src/services/reqresp/protocols/auth.ts +2 -2
- package/src/services/reqresp/protocols/block.ts +3 -2
- package/src/services/reqresp/protocols/block_txs/bitvector.ts +16 -0
- package/src/services/reqresp/protocols/block_txs/block_txs_handler.ts +35 -12
- package/src/services/reqresp/protocols/block_txs/block_txs_reqresp.ts +75 -10
- package/src/services/reqresp/protocols/status.ts +16 -12
- package/src/services/reqresp/protocols/tx.ts +23 -2
- package/src/services/reqresp/reqresp.ts +82 -23
- package/src/services/service.ts +73 -5
- package/src/services/tx_collection/config.ts +84 -2
- package/src/services/tx_collection/fast_tx_collection.ts +96 -49
- package/src/services/tx_collection/file_store_tx_collection.ts +202 -0
- package/src/services/tx_collection/file_store_tx_source.ts +117 -0
- package/src/services/tx_collection/index.ts +6 -0
- package/src/services/tx_collection/instrumentation.ts +11 -13
- package/src/services/tx_collection/missing_txs_tracker.ts +52 -0
- package/src/services/tx_collection/proposal_tx_collector.ts +113 -0
- package/src/services/tx_collection/slow_tx_collection.ts +70 -36
- package/src/services/tx_collection/tx_collection.ts +122 -24
- package/src/services/tx_collection/tx_collection_sink.ts +30 -34
- package/src/services/tx_collection/tx_source.ts +22 -3
- package/src/services/tx_file_store/config.ts +37 -0
- package/src/services/tx_file_store/index.ts +3 -0
- package/src/services/tx_file_store/instrumentation.ts +36 -0
- package/src/services/tx_file_store/tx_file_store.ts +175 -0
- package/src/services/tx_provider.ts +29 -12
- package/src/services/tx_provider_instrumentation.ts +24 -14
- package/src/test-helpers/index.ts +2 -0
- package/src/test-helpers/make-test-p2p-clients.ts +3 -5
- package/src/test-helpers/mock-pubsub.ts +147 -10
- package/src/test-helpers/mock-tx-helpers.ts +1 -1
- package/src/test-helpers/reqresp-nodes.ts +5 -7
- package/src/test-helpers/test_tx_provider.ts +64 -0
- package/src/test-helpers/testbench-utils.ts +430 -0
- package/src/testbench/p2p_client_testbench_worker.ts +350 -125
- package/src/testbench/worker_client_manager.ts +304 -42
- package/src/util.ts +19 -3
- package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts +0 -30
- package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts.map +0 -1
- package/dest/mem_pools/attestation_pool/kv_attestation_pool.js +0 -190
- package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts +0 -25
- package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts.map +0 -1
- package/dest/mem_pools/attestation_pool/memory_attestation_pool.js +0 -197
- package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts +0 -80
- 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 -238
- package/dest/msg_validators/block_proposal_validator/block_proposal_validator.d.ts +0 -12
- 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 -70
- 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/attestation_pool/kv_attestation_pool.ts +0 -256
- package/src/mem_pools/attestation_pool/memory_attestation_pool.ts +0 -253
- package/src/mem_pools/tx_pool/memory_tx_pool.ts +0 -283
- package/src/msg_validators/block_proposal_validator/block_proposal_validator.ts +0 -81
- package/src/msg_validators/block_proposal_validator/index.ts +0 -1
|
@@ -1,34 +1,41 @@
|
|
|
1
1
|
import type { EpochCacheInterface } from '@aztec/epoch-cache';
|
|
2
|
-
import {
|
|
3
|
-
import { Fr } from '@aztec/foundation/
|
|
2
|
+
import { BlockNumber, type SlotNumber } from '@aztec/foundation/branded-types';
|
|
3
|
+
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
4
4
|
import { type Logger, createLibp2pComponentLogger, createLogger } from '@aztec/foundation/log';
|
|
5
|
-
import { SerialQueue } from '@aztec/foundation/queue';
|
|
6
5
|
import { RunningPromise } from '@aztec/foundation/running-promise';
|
|
7
6
|
import { Timer } from '@aztec/foundation/timer';
|
|
8
7
|
import type { AztecAsyncKVStore } from '@aztec/kv-store';
|
|
9
|
-
import { getVKTreeRoot } from '@aztec/noir-protocol-circuits-types/vk-tree';
|
|
10
8
|
import { protocolContractsHash } from '@aztec/protocol-contracts';
|
|
11
|
-
import type { EthAddress, L2BlockSource } from '@aztec/stdlib/block';
|
|
9
|
+
import type { EthAddress, L2Block, L2BlockSource } from '@aztec/stdlib/block';
|
|
12
10
|
import type { ContractDataSource } from '@aztec/stdlib/contract';
|
|
13
11
|
import { GasFees } from '@aztec/stdlib/gas';
|
|
14
12
|
import type { ClientProtocolCircuitVerifier, PeerInfo, WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
|
|
15
13
|
import {
|
|
16
|
-
BlockAttestation,
|
|
17
14
|
BlockProposal,
|
|
15
|
+
CheckpointAttestation,
|
|
16
|
+
CheckpointProposal,
|
|
17
|
+
type CheckpointProposalCore,
|
|
18
18
|
type Gossipable,
|
|
19
|
-
P2PClientType,
|
|
20
19
|
P2PMessage,
|
|
20
|
+
type ValidationResult as P2PValidationResult,
|
|
21
21
|
PeerErrorSeverity,
|
|
22
22
|
TopicType,
|
|
23
23
|
createTopicString,
|
|
24
|
-
|
|
24
|
+
getTopicsForConfig,
|
|
25
25
|
metricsTopicStrToLabels,
|
|
26
26
|
} from '@aztec/stdlib/p2p';
|
|
27
27
|
import { MerkleTreeId } from '@aztec/stdlib/trees';
|
|
28
28
|
import { Tx, type TxHash, type TxValidationResult, type TxValidator } from '@aztec/stdlib/tx';
|
|
29
29
|
import type { UInt64 } from '@aztec/stdlib/types';
|
|
30
30
|
import { compressComponentVersions } from '@aztec/stdlib/versioning';
|
|
31
|
-
import {
|
|
31
|
+
import {
|
|
32
|
+
Attributes,
|
|
33
|
+
OtelMetricsAdapter,
|
|
34
|
+
SpanStatusCode,
|
|
35
|
+
type TelemetryClient,
|
|
36
|
+
WithTracer,
|
|
37
|
+
trackSpan,
|
|
38
|
+
} from '@aztec/telemetry-client';
|
|
32
39
|
|
|
33
40
|
import {
|
|
34
41
|
type GossipSub,
|
|
@@ -36,7 +43,7 @@ import {
|
|
|
36
43
|
type GossipsubMessage,
|
|
37
44
|
gossipsub,
|
|
38
45
|
} from '@chainsafe/libp2p-gossipsub';
|
|
39
|
-
import { createPeerScoreParams
|
|
46
|
+
import { createPeerScoreParams } from '@chainsafe/libp2p-gossipsub/score';
|
|
40
47
|
import { SignaturePolicy } from '@chainsafe/libp2p-gossipsub/types';
|
|
41
48
|
import { noise } from '@chainsafe/libp2p-noise';
|
|
42
49
|
import { yamux } from '@chainsafe/libp2p-yamux';
|
|
@@ -51,52 +58,64 @@ import { createLibp2p } from 'libp2p';
|
|
|
51
58
|
|
|
52
59
|
import type { P2PConfig } from '../../config.js';
|
|
53
60
|
import type { MemPools } from '../../mem_pools/interface.js';
|
|
54
|
-
import { AttestationValidator, BlockProposalValidator } from '../../msg_validators/index.js';
|
|
55
|
-
import { MessageSeenValidator } from '../../msg_validators/msg_seen_validator/msg_seen_validator.js';
|
|
56
|
-
import { getDefaultAllowedSetupFunctions } from '../../msg_validators/tx_validator/allowed_public_setup.js';
|
|
57
|
-
import { type MessageValidator, createTxMessageValidators } from '../../msg_validators/tx_validator/factory.js';
|
|
58
61
|
import {
|
|
59
|
-
|
|
60
|
-
|
|
62
|
+
BlockProposalValidator,
|
|
63
|
+
CheckpointAttestationValidator,
|
|
64
|
+
CheckpointProposalValidator,
|
|
61
65
|
DoubleSpendTxValidator,
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
} from '../../msg_validators/
|
|
66
|
+
FishermanAttestationValidator,
|
|
67
|
+
getDefaultAllowedSetupFunctions,
|
|
68
|
+
} from '../../msg_validators/index.js';
|
|
69
|
+
import { MessageSeenValidator } from '../../msg_validators/msg_seen_validator/msg_seen_validator.js';
|
|
70
|
+
import {
|
|
71
|
+
type TransactionValidator,
|
|
72
|
+
createFirstStageTxValidationsForGossipedTransactions,
|
|
73
|
+
createSecondStageTxValidationsForGossipedTransactions,
|
|
74
|
+
createTxValidatorForBlockProposalReceivedTxs,
|
|
75
|
+
createTxValidatorForReqResponseReceivedTxs,
|
|
76
|
+
} from '../../msg_validators/tx_validator/factory.js';
|
|
65
77
|
import { GossipSubEvent } from '../../types/index.js';
|
|
66
78
|
import { type PubSubLibp2p, convertToMultiaddr } from '../../util.js';
|
|
67
79
|
import { getVersions } from '../../versioning.js';
|
|
68
80
|
import { AztecDatastore } from '../data_store.js';
|
|
69
81
|
import { DiscV5Service } from '../discv5/discV5_service.js';
|
|
70
82
|
import { SnappyTransform, fastMsgIdFn, getMsgIdFn, msgIdToStrFn } from '../encoding.js';
|
|
71
|
-
import { gossipScoreThresholds } from '../gossipsub/scoring.js';
|
|
83
|
+
import { APP_SPECIFIC_WEIGHT, gossipScoreThresholds } from '../gossipsub/scoring.js';
|
|
84
|
+
import { createAllTopicScoreParams } from '../gossipsub/topic_score_params.js';
|
|
72
85
|
import type { PeerManagerInterface } from '../peer-manager/interface.js';
|
|
73
86
|
import { PeerManager } from '../peer-manager/peer_manager.js';
|
|
74
87
|
import { PeerScoring } from '../peer-manager/peer_scoring.js';
|
|
88
|
+
import type { BatchTxRequesterLibP2PService } from '../reqresp/batch-tx-requester/interface.js';
|
|
75
89
|
import type { P2PReqRespConfig } from '../reqresp/config.js';
|
|
76
90
|
import {
|
|
91
|
+
AuthRequest,
|
|
92
|
+
BlockTxsRequest,
|
|
93
|
+
BlockTxsResponse,
|
|
77
94
|
DEFAULT_SUB_PROTOCOL_VALIDATORS,
|
|
78
95
|
type ReqRespInterface,
|
|
96
|
+
type ReqRespResponse,
|
|
79
97
|
ReqRespSubProtocol,
|
|
80
98
|
type ReqRespSubProtocolHandler,
|
|
81
99
|
type ReqRespSubProtocolHandlers,
|
|
82
100
|
type ReqRespSubProtocolValidators,
|
|
101
|
+
StatusMessage,
|
|
83
102
|
type SubProtocolMap,
|
|
84
103
|
ValidationError,
|
|
85
|
-
} from '../reqresp/interface.js';
|
|
86
|
-
import { reqRespBlockTxsHandler } from '../reqresp/protocols/block_txs/block_txs_handler.js';
|
|
87
|
-
import { reqGoodbyeHandler } from '../reqresp/protocols/goodbye.js';
|
|
88
|
-
import {
|
|
89
|
-
AuthRequest,
|
|
90
|
-
BlockTxsRequest,
|
|
91
|
-
BlockTxsResponse,
|
|
92
|
-
StatusMessage,
|
|
93
104
|
pingHandler,
|
|
105
|
+
reqGoodbyeHandler,
|
|
94
106
|
reqRespBlockHandler,
|
|
107
|
+
reqRespBlockTxsHandler,
|
|
95
108
|
reqRespStatusHandler,
|
|
96
109
|
reqRespTxHandler,
|
|
97
|
-
} from '../reqresp/
|
|
110
|
+
} from '../reqresp/index.js';
|
|
98
111
|
import { ReqResp } from '../reqresp/reqresp.js';
|
|
99
|
-
import type {
|
|
112
|
+
import type {
|
|
113
|
+
P2PBlockReceivedCallback,
|
|
114
|
+
P2PCheckpointReceivedCallback,
|
|
115
|
+
P2PDuplicateAttestationCallback,
|
|
116
|
+
P2PService,
|
|
117
|
+
PeerDiscoveryService,
|
|
118
|
+
} from '../service.js';
|
|
100
119
|
import { P2PInstrumentation } from './instrumentation.js';
|
|
101
120
|
|
|
102
121
|
interface ValidationResult {
|
|
@@ -108,26 +127,36 @@ interface ValidationResult {
|
|
|
108
127
|
type ValidationOutcome = { allPassed: true } | { allPassed: false; failure: ValidationResult };
|
|
109
128
|
|
|
110
129
|
// REFACTOR: Unify with the type above
|
|
111
|
-
type ReceivedMessageValidationResult<T> =
|
|
112
|
-
| { obj: T; result: Exclude<TopicValidatorResult, TopicValidatorResult.Reject
|
|
113
|
-
| { obj?:
|
|
130
|
+
type ReceivedMessageValidationResult<T, M = undefined> =
|
|
131
|
+
| { obj: T; result: Exclude<TopicValidatorResult, TopicValidatorResult.Reject>; metadata?: M }
|
|
132
|
+
| { obj?: T; result: TopicValidatorResult.Reject; metadata?: M };
|
|
114
133
|
|
|
115
134
|
/**
|
|
116
135
|
* Lib P2P implementation of the P2PService interface.
|
|
117
136
|
*/
|
|
118
|
-
export class LibP2PService
|
|
119
|
-
private jobQueue: SerialQueue = new SerialQueue();
|
|
137
|
+
export class LibP2PService extends WithTracer implements P2PService {
|
|
120
138
|
private discoveryRunningPromise?: RunningPromise;
|
|
121
139
|
private msgIdSeenValidators: Record<TopicType, MessageSeenValidator> = {} as Record<TopicType, MessageSeenValidator>;
|
|
122
140
|
|
|
123
141
|
// Message validators
|
|
124
|
-
private attestationValidator: AttestationValidator;
|
|
125
142
|
private blockProposalValidator: BlockProposalValidator;
|
|
143
|
+
private checkpointProposalValidator: CheckpointProposalValidator;
|
|
144
|
+
private checkpointAttestationValidator: CheckpointAttestationValidator;
|
|
126
145
|
|
|
127
146
|
private protocolVersion = '';
|
|
128
147
|
private topicStrings: Record<TopicType, string> = {} as Record<TopicType, string>;
|
|
129
148
|
|
|
130
|
-
private feesCache: { blockNumber:
|
|
149
|
+
private feesCache: { blockNumber: BlockNumber; gasFees: GasFees } | undefined;
|
|
150
|
+
|
|
151
|
+
/** Callback invoked when a duplicate proposal is detected (triggers slashing). */
|
|
152
|
+
private duplicateProposalCallback?: (info: {
|
|
153
|
+
slot: SlotNumber;
|
|
154
|
+
proposer: EthAddress;
|
|
155
|
+
type: 'checkpoint' | 'block';
|
|
156
|
+
}) => void;
|
|
157
|
+
|
|
158
|
+
/** Callback invoked when a duplicate attestation is detected (triggers slashing). */
|
|
159
|
+
private duplicateAttestationCallback?: P2PDuplicateAttestationCallback;
|
|
131
160
|
|
|
132
161
|
/**
|
|
133
162
|
* Callback for when a block is received from a peer.
|
|
@@ -136,32 +165,47 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
136
165
|
*/
|
|
137
166
|
private blockReceivedCallback: P2PBlockReceivedCallback;
|
|
138
167
|
|
|
168
|
+
/**
|
|
169
|
+
* Callback for when a checkpoint proposal is received from a peer.
|
|
170
|
+
* @param checkpoint - The checkpoint proposal received from the peer.
|
|
171
|
+
* @returns The attestations for the checkpoint, if any.
|
|
172
|
+
*/
|
|
173
|
+
private checkpointReceivedCallback: P2PCheckpointReceivedCallback;
|
|
174
|
+
|
|
139
175
|
private gossipSubEventHandler: (e: CustomEvent<GossipsubMessage>) => void;
|
|
140
176
|
|
|
141
177
|
private instrumentation: P2PInstrumentation;
|
|
142
178
|
|
|
179
|
+
private telemetry: TelemetryClient;
|
|
180
|
+
|
|
181
|
+
protected logger: Logger;
|
|
182
|
+
|
|
143
183
|
constructor(
|
|
144
|
-
private clientType: T,
|
|
145
184
|
private config: P2PConfig,
|
|
146
185
|
protected node: PubSubLibp2p,
|
|
147
186
|
private peerDiscoveryService: PeerDiscoveryService,
|
|
148
187
|
private reqresp: ReqRespInterface,
|
|
149
|
-
|
|
150
|
-
protected mempools: MemPools
|
|
151
|
-
|
|
188
|
+
protected peerManager: PeerManagerInterface,
|
|
189
|
+
protected mempools: MemPools,
|
|
190
|
+
protected archiver: L2BlockSource & ContractDataSource,
|
|
152
191
|
private epochCache: EpochCacheInterface,
|
|
153
192
|
private proofVerifier: ClientProtocolCircuitVerifier,
|
|
154
193
|
private worldStateSynchronizer: WorldStateSynchronizer,
|
|
155
194
|
telemetry: TelemetryClient,
|
|
156
|
-
|
|
195
|
+
logger: Logger = createLogger('p2p:libp2p_service'),
|
|
157
196
|
) {
|
|
158
197
|
super(telemetry, 'LibP2PService');
|
|
198
|
+
this.telemetry = telemetry;
|
|
199
|
+
|
|
200
|
+
// Create child logger with fisherman prefix if in fisherman mode
|
|
201
|
+
this.logger = config.fishermanMode ? logger.createChild('[FISHERMAN]') : logger;
|
|
159
202
|
|
|
160
203
|
this.instrumentation = new P2PInstrumentation(telemetry, 'LibP2PService');
|
|
161
204
|
|
|
162
205
|
this.msgIdSeenValidators[TopicType.tx] = new MessageSeenValidator(config.seenMessageCacheSize);
|
|
163
206
|
this.msgIdSeenValidators[TopicType.block_proposal] = new MessageSeenValidator(config.seenMessageCacheSize);
|
|
164
|
-
this.msgIdSeenValidators[TopicType.
|
|
207
|
+
this.msgIdSeenValidators[TopicType.checkpoint_proposal] = new MessageSeenValidator(config.seenMessageCacheSize);
|
|
208
|
+
this.msgIdSeenValidators[TopicType.checkpoint_attestation] = new MessageSeenValidator(config.seenMessageCacheSize);
|
|
165
209
|
|
|
166
210
|
const versions = getVersions(config);
|
|
167
211
|
this.protocolVersion = compressComponentVersions(versions);
|
|
@@ -169,22 +213,40 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
169
213
|
|
|
170
214
|
this.topicStrings[TopicType.tx] = createTopicString(TopicType.tx, this.protocolVersion);
|
|
171
215
|
this.topicStrings[TopicType.block_proposal] = createTopicString(TopicType.block_proposal, this.protocolVersion);
|
|
172
|
-
this.topicStrings[TopicType.
|
|
173
|
-
TopicType.
|
|
216
|
+
this.topicStrings[TopicType.checkpoint_proposal] = createTopicString(
|
|
217
|
+
TopicType.checkpoint_proposal,
|
|
218
|
+
this.protocolVersion,
|
|
219
|
+
);
|
|
220
|
+
this.topicStrings[TopicType.checkpoint_attestation] = createTopicString(
|
|
221
|
+
TopicType.checkpoint_attestation,
|
|
174
222
|
this.protocolVersion,
|
|
175
223
|
);
|
|
176
224
|
|
|
177
|
-
this.attestationValidator = new AttestationValidator(epochCache);
|
|
178
225
|
this.blockProposalValidator = new BlockProposalValidator(epochCache, { txsPermitted: !config.disableTransactions });
|
|
226
|
+
this.checkpointProposalValidator = new CheckpointProposalValidator(epochCache, {
|
|
227
|
+
txsPermitted: !config.disableTransactions,
|
|
228
|
+
});
|
|
229
|
+
this.checkpointAttestationValidator = config.fishermanMode
|
|
230
|
+
? new FishermanAttestationValidator(epochCache, mempools.attestationPool, telemetry)
|
|
231
|
+
: new CheckpointAttestationValidator(epochCache);
|
|
179
232
|
|
|
180
233
|
this.gossipSubEventHandler = this.handleGossipSubEvent.bind(this);
|
|
181
234
|
|
|
182
|
-
this.blockReceivedCallback = async (block: BlockProposal): Promise<
|
|
235
|
+
this.blockReceivedCallback = async (block: BlockProposal): Promise<boolean> => {
|
|
183
236
|
this.logger.debug(
|
|
184
|
-
`Handler not yet registered: Block received callback not set. Received block for slot ${block.slotNumber
|
|
185
|
-
{ p2pMessageIdentifier: await block.
|
|
237
|
+
`Handler not yet registered: Block received callback not set. Received block for slot ${block.slotNumber} from peer.`,
|
|
238
|
+
{ p2pMessageIdentifier: await block.p2pMessageLoggingIdentifier() },
|
|
186
239
|
);
|
|
187
|
-
return
|
|
240
|
+
return false;
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
this.checkpointReceivedCallback = (
|
|
244
|
+
checkpoint: CheckpointProposalCore,
|
|
245
|
+
): Promise<CheckpointAttestation[] | undefined> => {
|
|
246
|
+
this.logger.debug(
|
|
247
|
+
`Handler not yet registered: Checkpoint received callback not set. Received checkpoint for slot ${checkpoint.slotNumber} from peer.`,
|
|
248
|
+
);
|
|
249
|
+
return Promise.resolve(undefined);
|
|
188
250
|
};
|
|
189
251
|
}
|
|
190
252
|
|
|
@@ -198,12 +260,11 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
198
260
|
* @param txPool - The transaction pool to be accessed by the service.
|
|
199
261
|
* @returns The new service.
|
|
200
262
|
*/
|
|
201
|
-
public static async new
|
|
202
|
-
clientType: T,
|
|
263
|
+
public static async new(
|
|
203
264
|
config: P2PConfig,
|
|
204
265
|
peerId: PeerId,
|
|
205
266
|
deps: {
|
|
206
|
-
mempools: MemPools
|
|
267
|
+
mempools: MemPools;
|
|
207
268
|
l2BlockSource: L2BlockSource & ContractDataSource;
|
|
208
269
|
epochCache: EpochCacheInterface;
|
|
209
270
|
proofVerifier: ClientProtocolCircuitVerifier;
|
|
@@ -230,14 +291,14 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
230
291
|
|
|
231
292
|
const datastore = new AztecDatastore(peerStore);
|
|
232
293
|
|
|
233
|
-
const otelMetricsAdapter = new OtelMetricsAdapter(telemetry);
|
|
294
|
+
const otelMetricsAdapter = new OtelMetricsAdapter(telemetry, logger.getBindings());
|
|
234
295
|
|
|
235
296
|
const peerDiscoveryService = new DiscV5Service(
|
|
236
297
|
peerId,
|
|
237
298
|
config,
|
|
238
299
|
packageVersion,
|
|
239
300
|
telemetry,
|
|
240
|
-
createLogger(`${logger.module}:discv5_service
|
|
301
|
+
createLogger(`${logger.module}:discv5_service`, logger.getBindings()),
|
|
241
302
|
);
|
|
242
303
|
|
|
243
304
|
// Seed libp2p's bootstrap discovery with private and trusted peers
|
|
@@ -251,10 +312,6 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
251
312
|
const versions = getVersions(config);
|
|
252
313
|
const protocolVersion = compressComponentVersions(versions);
|
|
253
314
|
|
|
254
|
-
const txTopic = createTopicString(TopicType.tx, protocolVersion);
|
|
255
|
-
const blockProposalTopic = createTopicString(TopicType.block_proposal, protocolVersion);
|
|
256
|
-
const blockAttestationTopic = createTopicString(TopicType.block_attestation, protocolVersion);
|
|
257
|
-
|
|
258
315
|
const preferredPeersEnrs: ENR[] = config.preferredPeers.map(enr => ENR.decodeTxt(enr));
|
|
259
316
|
const directPeers = (
|
|
260
317
|
await Promise.all(
|
|
@@ -274,6 +331,16 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
274
331
|
|
|
275
332
|
const announceTcpMultiaddr = config.p2pIp ? [convertToMultiaddr(config.p2pIp, p2pPort, 'tcp')] : [];
|
|
276
333
|
|
|
334
|
+
// Create dynamic topic score params based on network configuration
|
|
335
|
+
const l1Constants = epochCache.getL1Constants();
|
|
336
|
+
const topicScoreParams = createAllTopicScoreParams(protocolVersion, {
|
|
337
|
+
slotDurationMs: l1Constants.slotDuration * 1000,
|
|
338
|
+
heartbeatIntervalMs: config.gossipsubInterval,
|
|
339
|
+
targetCommitteeSize: l1Constants.targetCommitteeSize,
|
|
340
|
+
blockDurationMs: config.blockDurationMs,
|
|
341
|
+
expectedBlockProposalsPerSlot: config.expectedBlockProposalsPerSlot,
|
|
342
|
+
});
|
|
343
|
+
|
|
277
344
|
const node = await createLibp2p({
|
|
278
345
|
start: false,
|
|
279
346
|
peerId,
|
|
@@ -369,33 +436,17 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
369
436
|
scoreParams: createPeerScoreParams({
|
|
370
437
|
// IPColocation factor can be disabled for local testing - default to -5
|
|
371
438
|
IPColocationFactorWeight: config.debugDisableColocationPenalty ? 0 : -5.0,
|
|
372
|
-
topics:
|
|
373
|
-
[txTopic]: createTopicScoreParams({
|
|
374
|
-
topicWeight: 1,
|
|
375
|
-
invalidMessageDeliveriesWeight: -20,
|
|
376
|
-
invalidMessageDeliveriesDecay: 0.5,
|
|
377
|
-
}),
|
|
378
|
-
[blockAttestationTopic]: createTopicScoreParams({
|
|
379
|
-
topicWeight: 1,
|
|
380
|
-
invalidMessageDeliveriesWeight: -20,
|
|
381
|
-
invalidMessageDeliveriesDecay: 0.5,
|
|
382
|
-
}),
|
|
383
|
-
[blockProposalTopic]: createTopicScoreParams({
|
|
384
|
-
topicWeight: 1,
|
|
385
|
-
invalidMessageDeliveriesWeight: -20,
|
|
386
|
-
invalidMessageDeliveriesDecay: 0.5,
|
|
387
|
-
}),
|
|
388
|
-
},
|
|
439
|
+
topics: topicScoreParams,
|
|
389
440
|
}),
|
|
390
441
|
}) as (components: GossipSubComponents) => GossipSub,
|
|
391
442
|
components: (components: { connectionManager: ConnectionManager }) => ({
|
|
392
443
|
connectionManager: components.connectionManager,
|
|
393
444
|
}),
|
|
394
445
|
},
|
|
395
|
-
logger: createLibp2pComponentLogger(logger.module),
|
|
446
|
+
logger: createLibp2pComponentLogger(logger.module, logger.getBindings()),
|
|
396
447
|
});
|
|
397
448
|
|
|
398
|
-
const peerScoring = new PeerScoring(config);
|
|
449
|
+
const peerScoring = new PeerScoring(config, telemetry);
|
|
399
450
|
const reqresp = new ReqResp(config, node, peerScoring, createLogger(`${logger.module}:reqresp`));
|
|
400
451
|
|
|
401
452
|
const peerManager = new PeerManager(
|
|
@@ -411,13 +462,16 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
411
462
|
epochCache,
|
|
412
463
|
);
|
|
413
464
|
|
|
414
|
-
//
|
|
415
|
-
|
|
465
|
+
// Configure application-specific scoring for gossipsub.
|
|
466
|
+
// The weight scales app score to align with gossipsub thresholds:
|
|
467
|
+
// - Disconnect (-50) × 10 = -500 = gossipThreshold (stops receiving gossip)
|
|
468
|
+
// - Ban (-100) × 10 = -1000 = publishThreshold (cannot publish)
|
|
469
|
+
// Note: positive topic scores can offset penalties, so alignment is best-effort.
|
|
470
|
+
node.services.pubsub.score.params.appSpecificWeight = APP_SPECIFIC_WEIGHT;
|
|
416
471
|
node.services.pubsub.score.params.appSpecificScore = (peerId: string) =>
|
|
417
472
|
peerManager.shouldDisableP2PGossip(peerId) ? -Infinity : peerManager.getPeerScore(peerId);
|
|
418
473
|
|
|
419
474
|
return new LibP2PService(
|
|
420
|
-
clientType,
|
|
421
475
|
config,
|
|
422
476
|
node,
|
|
423
477
|
peerDiscoveryService,
|
|
@@ -450,20 +504,6 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
450
504
|
}
|
|
451
505
|
const announceTcpMultiaddr = convertToMultiaddr(p2pIp, p2pPort, 'tcp');
|
|
452
506
|
|
|
453
|
-
// Start job queue, peer discovery service and libp2p node
|
|
454
|
-
this.jobQueue.start();
|
|
455
|
-
|
|
456
|
-
await this.peerManager.initializePeers();
|
|
457
|
-
if (!this.config.p2pDiscoveryDisabled) {
|
|
458
|
-
await this.peerDiscoveryService.start();
|
|
459
|
-
}
|
|
460
|
-
await this.node.start();
|
|
461
|
-
|
|
462
|
-
// Subscribe to standard GossipSub topics by default
|
|
463
|
-
for (const topic of getTopicsForClientAndConfig(this.clientType, this.config.disableTransactions)) {
|
|
464
|
-
this.subscribeToTopic(this.topicStrings[topic]);
|
|
465
|
-
}
|
|
466
|
-
|
|
467
507
|
// Create request response protocol handlers
|
|
468
508
|
const txHandler = reqRespTxHandler(this.mempools);
|
|
469
509
|
const goodbyeHandler = reqGoodbyeHandler(this.peerManager);
|
|
@@ -477,9 +517,12 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
477
517
|
[ReqRespSubProtocol.BLOCK]: blockHandler.bind(this),
|
|
478
518
|
};
|
|
479
519
|
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
520
|
+
if (!this.config.disableTransactions) {
|
|
521
|
+
const blockTxsHandler = reqRespBlockTxsHandler(
|
|
522
|
+
this.mempools.attestationPool,
|
|
523
|
+
this.archiver,
|
|
524
|
+
this.mempools.txPool,
|
|
525
|
+
);
|
|
483
526
|
requestResponseHandlers[ReqRespSubProtocol.BLOCK_TXS] = blockTxsHandler.bind(this);
|
|
484
527
|
}
|
|
485
528
|
|
|
@@ -487,25 +530,41 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
487
530
|
requestResponseHandlers[ReqRespSubProtocol.TX] = txHandler.bind(this);
|
|
488
531
|
}
|
|
489
532
|
|
|
533
|
+
// Define the sub protocol validators - This is done within this start() method to gain a callback to the existing validateTx function
|
|
534
|
+
const reqrespSubProtocolValidators = {
|
|
535
|
+
...DEFAULT_SUB_PROTOCOL_VALIDATORS,
|
|
536
|
+
[ReqRespSubProtocol.TX]: this.validateRequestedTxs.bind(this),
|
|
537
|
+
[ReqRespSubProtocol.BLOCK_TXS]: this.validateRequestedBlockTxs.bind(this),
|
|
538
|
+
[ReqRespSubProtocol.BLOCK]: this.validateRequestedBlock.bind(this),
|
|
539
|
+
};
|
|
540
|
+
|
|
541
|
+
await this.peerManager.initializePeers();
|
|
542
|
+
|
|
543
|
+
await this.reqresp.start(requestResponseHandlers, reqrespSubProtocolValidators);
|
|
544
|
+
|
|
545
|
+
await this.node.start();
|
|
546
|
+
|
|
547
|
+
// Subscribe to standard GossipSub topics by default
|
|
548
|
+
for (const topic of getTopicsForConfig(this.config.disableTransactions)) {
|
|
549
|
+
this.subscribeToTopic(this.topicStrings[topic]);
|
|
550
|
+
}
|
|
551
|
+
|
|
490
552
|
// add GossipSub listener
|
|
491
553
|
this.node.services.pubsub.addEventListener(GossipSubEvent.MESSAGE, this.gossipSubEventHandler);
|
|
492
554
|
|
|
493
|
-
// Start running promise for peer discovery
|
|
555
|
+
// Start running promise for peer discovery and metrics collection
|
|
556
|
+
if (!this.config.p2pDiscoveryDisabled) {
|
|
557
|
+
await this.peerDiscoveryService.start();
|
|
558
|
+
}
|
|
494
559
|
this.discoveryRunningPromise = new RunningPromise(
|
|
495
|
-
() =>
|
|
560
|
+
async () => {
|
|
561
|
+
await this.peerManager.heartbeat();
|
|
562
|
+
},
|
|
496
563
|
this.logger,
|
|
497
564
|
this.config.peerCheckIntervalMS,
|
|
498
565
|
);
|
|
499
566
|
this.discoveryRunningPromise.start();
|
|
500
567
|
|
|
501
|
-
// Define the sub protocol validators - This is done within this start() method to gain a callback to the existing validateTx function
|
|
502
|
-
const reqrespSubProtocolValidators = {
|
|
503
|
-
...DEFAULT_SUB_PROTOCOL_VALIDATORS,
|
|
504
|
-
// TODO(#11336): A request validator for blocks
|
|
505
|
-
[ReqRespSubProtocol.TX]: this.validateRequestedTxs.bind(this),
|
|
506
|
-
[ReqRespSubProtocol.BLOCK_TXS]: this.validateRequestedBlockTxs.bind(this),
|
|
507
|
-
};
|
|
508
|
-
await this.reqresp.start(requestResponseHandlers, reqrespSubProtocolValidators);
|
|
509
568
|
this.logger.info(`Started P2P service`, {
|
|
510
569
|
listen: this.config.listenAddress,
|
|
511
570
|
port: this.config.p2pPort,
|
|
@@ -525,9 +584,6 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
525
584
|
// Stop peer manager
|
|
526
585
|
this.logger.debug('Stopping peer manager...');
|
|
527
586
|
await this.peerManager.stop();
|
|
528
|
-
|
|
529
|
-
this.logger.debug('Stopping job queue...');
|
|
530
|
-
await this.jobQueue.end();
|
|
531
587
|
this.logger.debug('Stopping running promise...');
|
|
532
588
|
await this.discoveryRunningPromise?.stop();
|
|
533
589
|
this.logger.debug('Stopping peer discovery service...');
|
|
@@ -555,6 +611,10 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
555
611
|
return this.peerManager.getPeers(includePending);
|
|
556
612
|
}
|
|
557
613
|
|
|
614
|
+
public getGossipMeshPeerCount(topicType: TopicType): number {
|
|
615
|
+
return this.node.services.pubsub.getMeshPeers(this.topicStrings[topicType]).length;
|
|
616
|
+
}
|
|
617
|
+
|
|
558
618
|
private handleGossipSubEvent(e: CustomEvent<GossipsubMessage>) {
|
|
559
619
|
this.logger.trace(`Received PUBSUB message.`);
|
|
560
620
|
|
|
@@ -582,6 +642,15 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
582
642
|
return this.reqresp.sendBatchRequest(protocol, requests, pinnedPeerId);
|
|
583
643
|
}
|
|
584
644
|
|
|
645
|
+
public sendRequestToPeer(
|
|
646
|
+
peerId: PeerId,
|
|
647
|
+
subProtocol: ReqRespSubProtocol,
|
|
648
|
+
payload: Buffer,
|
|
649
|
+
dialTimeout?: number,
|
|
650
|
+
): Promise<ReqRespResponse> {
|
|
651
|
+
return this.reqresp.sendRequestToPeer(peerId, subProtocol, payload, dialTimeout);
|
|
652
|
+
}
|
|
653
|
+
|
|
585
654
|
/**
|
|
586
655
|
* Get the ENR of the node
|
|
587
656
|
* @returns The ENR of the node
|
|
@@ -594,6 +663,29 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
594
663
|
this.blockReceivedCallback = callback;
|
|
595
664
|
}
|
|
596
665
|
|
|
666
|
+
public registerCheckpointReceivedCallback(callback: P2PCheckpointReceivedCallback) {
|
|
667
|
+
this.checkpointReceivedCallback = callback;
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
/**
|
|
671
|
+
* Registers a callback to be invoked when a duplicate proposal is detected.
|
|
672
|
+
* This callback is triggered on the first duplicate (when count goes from 1 to 2).
|
|
673
|
+
*/
|
|
674
|
+
public registerDuplicateProposalCallback(
|
|
675
|
+
callback: (info: { slot: SlotNumber; proposer: EthAddress; type: 'checkpoint' | 'block' }) => void,
|
|
676
|
+
): void {
|
|
677
|
+
this.duplicateProposalCallback = callback;
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
/**
|
|
681
|
+
* Registers a callback to be invoked when a duplicate attestation is detected.
|
|
682
|
+
* A validator signing attestations for different proposals at the same slot.
|
|
683
|
+
* This callback is triggered on the first duplicate (when count goes from 1 to 2).
|
|
684
|
+
*/
|
|
685
|
+
public registerDuplicateAttestationCallback(callback: P2PDuplicateAttestationCallback): void {
|
|
686
|
+
this.duplicateAttestationCallback = callback;
|
|
687
|
+
}
|
|
688
|
+
|
|
597
689
|
/**
|
|
598
690
|
* Subscribes to a topic.
|
|
599
691
|
* @param topic - The topic to subscribe to.
|
|
@@ -615,7 +707,10 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
615
707
|
if (!this.node.services.pubsub) {
|
|
616
708
|
throw new Error('Pubsub service not available.');
|
|
617
709
|
}
|
|
618
|
-
const
|
|
710
|
+
const isBlockProposal = topic === this.topicStrings[TopicType.block_proposal];
|
|
711
|
+
const traceContext =
|
|
712
|
+
this.config.debugP2PInstrumentMessages && isBlockProposal ? this.telemetry.getTraceContext() : undefined;
|
|
713
|
+
const p2pMessage = P2PMessage.fromGossipable(message, this.config.debugP2PInstrumentMessages, traceContext);
|
|
619
714
|
const result = await this.node.services.pubsub.publish(topic, p2pMessage.toMessageData());
|
|
620
715
|
return result.recipients.length;
|
|
621
716
|
}
|
|
@@ -636,12 +731,15 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
636
731
|
case this.topicStrings[TopicType.tx]:
|
|
637
732
|
topicType = TopicType.tx;
|
|
638
733
|
break;
|
|
639
|
-
case this.topicStrings[TopicType.block_attestation]:
|
|
640
|
-
topicType = TopicType.block_attestation;
|
|
641
|
-
break;
|
|
642
734
|
case this.topicStrings[TopicType.block_proposal]:
|
|
643
735
|
topicType = TopicType.block_proposal;
|
|
644
736
|
break;
|
|
737
|
+
case this.topicStrings[TopicType.checkpoint_proposal]:
|
|
738
|
+
topicType = TopicType.checkpoint_proposal;
|
|
739
|
+
break;
|
|
740
|
+
case this.topicStrings[TopicType.checkpoint_attestation]:
|
|
741
|
+
topicType = TopicType.checkpoint_attestation;
|
|
742
|
+
break;
|
|
645
743
|
default:
|
|
646
744
|
this.logger.error(`Received message on unknown topic: ${msg.topic}`);
|
|
647
745
|
break;
|
|
@@ -660,13 +758,39 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
660
758
|
return { result: true, topicType };
|
|
661
759
|
}
|
|
662
760
|
|
|
761
|
+
/**
|
|
762
|
+
* Safely deserializes a P2PMessage from raw message data.
|
|
763
|
+
* @param msgId - The message ID.
|
|
764
|
+
* @param source - The peer ID of the message source.
|
|
765
|
+
* @param data - The raw message data.
|
|
766
|
+
* @returns The deserialized P2PMessage or undefined if deserialization fails.
|
|
767
|
+
*/
|
|
768
|
+
private safelyDeserializeP2PMessage(msgId: string, source: PeerId, data: Uint8Array): P2PMessage | undefined {
|
|
769
|
+
try {
|
|
770
|
+
return P2PMessage.fromMessageData(Buffer.from(data), this.config.debugP2PInstrumentMessages);
|
|
771
|
+
} catch (err) {
|
|
772
|
+
this.logger.error(`Error deserializing P2PMessage`, err, {
|
|
773
|
+
msgId,
|
|
774
|
+
source: source.toString(),
|
|
775
|
+
});
|
|
776
|
+
this.node.services.pubsub.reportMessageValidationResult(msgId, source.toString(), TopicValidatorResult.Reject);
|
|
777
|
+
this.peerManager.penalizePeer(source, PeerErrorSeverity.LowToleranceError);
|
|
778
|
+
return undefined;
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
|
|
663
782
|
/**
|
|
664
783
|
* Handles a new gossip message that was received by the client.
|
|
665
784
|
* @param topic - The message's topic.
|
|
666
785
|
* @param data - The message data
|
|
667
786
|
*/
|
|
668
787
|
protected async handleNewGossipMessage(msg: Message, msgId: string, source: PeerId) {
|
|
669
|
-
const
|
|
788
|
+
const msgReceivedTime = Date.now();
|
|
789
|
+
let topicType: TopicType | undefined;
|
|
790
|
+
const p2pMessage = this.safelyDeserializeP2PMessage(msgId, source, msg.data);
|
|
791
|
+
if (!p2pMessage) {
|
|
792
|
+
return;
|
|
793
|
+
}
|
|
670
794
|
|
|
671
795
|
const preValidationResult = this.preValidateReceivedMessage(msg, msgId, source);
|
|
672
796
|
|
|
@@ -674,30 +798,90 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
674
798
|
return;
|
|
675
799
|
}
|
|
676
800
|
|
|
801
|
+
// Determine topic type for attributes
|
|
677
802
|
if (msg.topic === this.topicStrings[TopicType.tx]) {
|
|
678
|
-
|
|
803
|
+
topicType = TopicType.tx;
|
|
804
|
+
} else if (msg.topic === this.topicStrings[TopicType.checkpoint_attestation]) {
|
|
805
|
+
topicType = TopicType.checkpoint_attestation;
|
|
806
|
+
} else if (msg.topic === this.topicStrings[TopicType.block_proposal]) {
|
|
807
|
+
topicType = TopicType.block_proposal;
|
|
808
|
+
} else if (msg.topic === this.topicStrings[TopicType.checkpoint_proposal]) {
|
|
809
|
+
topicType = TopicType.checkpoint_proposal;
|
|
679
810
|
}
|
|
680
|
-
|
|
681
|
-
|
|
811
|
+
|
|
812
|
+
// Process the message, optionally within a linked span for trace propagation
|
|
813
|
+
const processMessage = async () => {
|
|
814
|
+
if (msg.topic === this.topicStrings[TopicType.tx]) {
|
|
815
|
+
await this.handleGossipedTx(p2pMessage.payload, msgId, source);
|
|
816
|
+
} else if (msg.topic === this.topicStrings[TopicType.checkpoint_attestation]) {
|
|
817
|
+
await this.processCheckpointAttestationFromPeer(p2pMessage.payload, msgId, source);
|
|
818
|
+
} else if (msg.topic === this.topicStrings[TopicType.block_proposal]) {
|
|
819
|
+
await this.processBlockFromPeer(p2pMessage.payload, msgId, source);
|
|
820
|
+
} else if (msg.topic === this.topicStrings[TopicType.checkpoint_proposal]) {
|
|
821
|
+
await this.handleGossipedCheckpointProposal(p2pMessage.payload, msgId, source);
|
|
822
|
+
} else {
|
|
823
|
+
this.logger.error(`Received message on unknown topic: ${msg.topic}`);
|
|
824
|
+
}
|
|
825
|
+
};
|
|
826
|
+
|
|
827
|
+
const latency = p2pMessage.timestamp !== undefined ? msgReceivedTime - p2pMessage.timestamp.getTime() : undefined;
|
|
828
|
+
const propagatedContext = p2pMessage.traceContext
|
|
829
|
+
? this.telemetry.extractPropagatedContext(p2pMessage.traceContext)
|
|
830
|
+
: undefined;
|
|
831
|
+
|
|
832
|
+
if (propagatedContext) {
|
|
833
|
+
await this.tracer.startActiveSpan(
|
|
834
|
+
'LibP2PService.processMessage',
|
|
835
|
+
{
|
|
836
|
+
attributes: {
|
|
837
|
+
[Attributes.TOPIC_NAME]: topicType!,
|
|
838
|
+
[Attributes.PEER_ID]: source.toString(),
|
|
839
|
+
},
|
|
840
|
+
},
|
|
841
|
+
propagatedContext,
|
|
842
|
+
async span => {
|
|
843
|
+
try {
|
|
844
|
+
await processMessage();
|
|
845
|
+
span.setStatus({
|
|
846
|
+
code: SpanStatusCode.OK,
|
|
847
|
+
});
|
|
848
|
+
} catch (err) {
|
|
849
|
+
span.setStatus({
|
|
850
|
+
code: SpanStatusCode.ERROR,
|
|
851
|
+
message: String(err),
|
|
852
|
+
});
|
|
853
|
+
if (typeof err === 'string' || (err && err instanceof Error)) {
|
|
854
|
+
span.recordException(err);
|
|
855
|
+
}
|
|
856
|
+
throw err;
|
|
857
|
+
} finally {
|
|
858
|
+
span.end();
|
|
859
|
+
}
|
|
860
|
+
},
|
|
861
|
+
);
|
|
862
|
+
} else {
|
|
863
|
+
await processMessage();
|
|
682
864
|
}
|
|
683
|
-
|
|
684
|
-
|
|
865
|
+
|
|
866
|
+
if (latency !== undefined && topicType !== undefined) {
|
|
867
|
+
this.instrumentation.recordMessageLatency(topicType, latency);
|
|
685
868
|
}
|
|
686
869
|
|
|
687
870
|
return;
|
|
688
871
|
}
|
|
689
872
|
|
|
690
|
-
protected async validateReceivedMessage<T>(
|
|
691
|
-
validationFunc: () => Promise<ReceivedMessageValidationResult<T>>,
|
|
873
|
+
protected async validateReceivedMessage<T, M = undefined>(
|
|
874
|
+
validationFunc: () => Promise<ReceivedMessageValidationResult<T, M>>,
|
|
692
875
|
msgId: string,
|
|
693
876
|
source: PeerId,
|
|
694
877
|
topicType: TopicType,
|
|
695
|
-
): Promise<ReceivedMessageValidationResult<T>> {
|
|
696
|
-
let resultAndObj: ReceivedMessageValidationResult<T> = { result: TopicValidatorResult.Reject };
|
|
878
|
+
): Promise<ReceivedMessageValidationResult<T, M>> {
|
|
879
|
+
let resultAndObj: ReceivedMessageValidationResult<T, M> = { result: TopicValidatorResult.Reject };
|
|
697
880
|
const timer = new Timer();
|
|
698
881
|
try {
|
|
699
882
|
resultAndObj = await validationFunc();
|
|
700
883
|
} catch (err) {
|
|
884
|
+
this.peerManager.penalizePeer(source, PeerErrorSeverity.LowToleranceError);
|
|
701
885
|
this.logger.error(`Error deserializing and validating gossipsub message`, err, {
|
|
702
886
|
msgId,
|
|
703
887
|
source: source.toString(),
|
|
@@ -716,21 +900,63 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
716
900
|
protected async handleGossipedTx(payloadData: Buffer, msgId: string, source: PeerId) {
|
|
717
901
|
const validationFunc: () => Promise<ReceivedMessageValidationResult<Tx>> = async () => {
|
|
718
902
|
const tx = Tx.fromBuffer(payloadData);
|
|
719
|
-
|
|
720
|
-
const
|
|
903
|
+
|
|
904
|
+
const currentBlockNumber = await this.archiver.getBlockNumber();
|
|
905
|
+
const { ts: nextSlotTimestamp } = this.epochCache.getEpochAndSlotInNextL1Slot();
|
|
906
|
+
|
|
907
|
+
// Stage 1: fast validators (metadata, data, timestamps, double-spend, gas, phases, block header)
|
|
908
|
+
const firstStageValidators = await this.createFirstStageMessageValidators(currentBlockNumber, nextSlotTimestamp);
|
|
909
|
+
const firstStageOutcome = await this.runValidations(tx, firstStageValidators);
|
|
910
|
+
if (!firstStageOutcome.allPassed) {
|
|
911
|
+
const { name } = firstStageOutcome.failure;
|
|
912
|
+
let { severity } = firstStageOutcome.failure;
|
|
913
|
+
|
|
914
|
+
// Double spend validator has a special case handler. We perform more detailed examination
|
|
915
|
+
// as to how recently the nullifier was entered into the tree and if the transaction should
|
|
916
|
+
// have 'known' the nullifier existed. This determines the severity of the penalty applied to the peer.
|
|
917
|
+
if (name === 'doubleSpendValidator') {
|
|
918
|
+
const txBlockNumber = BlockNumber(currentBlockNumber + 1);
|
|
919
|
+
severity = await this.handleDoubleSpendFailure(tx, txBlockNumber);
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
this.peerManager.penalizePeer(source, severity);
|
|
923
|
+
return { result: TopicValidatorResult.Reject };
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
// Pool pre-check: see if the pool would accept this tx before doing expensive proof verification
|
|
927
|
+
const canAdd = await this.mempools.txPool.canAddPendingTx(tx);
|
|
928
|
+
if (canAdd === 'ignored') {
|
|
929
|
+
return { result: TopicValidatorResult.Ignore, obj: tx };
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
// Stage 2: expensive proof verification
|
|
933
|
+
const secondStageValidators = this.createSecondStageMessageValidators();
|
|
934
|
+
const secondStageOutcome = await this.runValidations(tx, secondStageValidators);
|
|
935
|
+
if (!secondStageOutcome.allPassed) {
|
|
936
|
+
const { severity } = secondStageOutcome.failure;
|
|
937
|
+
this.peerManager.penalizePeer(source, severity);
|
|
938
|
+
return { result: TopicValidatorResult.Reject };
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
// Pool add: persist the tx
|
|
942
|
+
const txHash = tx.getTxHash();
|
|
943
|
+
const addResult = await this.mempools.txPool.addPendingTxs([tx], { source: 'gossip' });
|
|
944
|
+
|
|
945
|
+
const wasAccepted = addResult.accepted.some(h => h.equals(txHash));
|
|
946
|
+
const wasIgnored = addResult.ignored.some(h => h.equals(txHash));
|
|
721
947
|
|
|
722
948
|
this.logger.trace(`Validate propagated tx`, {
|
|
723
|
-
|
|
724
|
-
|
|
949
|
+
wasAccepted,
|
|
950
|
+
wasIgnored,
|
|
725
951
|
[Attributes.P2P_ID]: source.toString(),
|
|
726
952
|
});
|
|
727
953
|
|
|
728
|
-
if (
|
|
729
|
-
return { result: TopicValidatorResult.
|
|
730
|
-
} else if (
|
|
954
|
+
if (wasAccepted) {
|
|
955
|
+
return { result: TopicValidatorResult.Accept, obj: tx };
|
|
956
|
+
} else if (wasIgnored) {
|
|
731
957
|
return { result: TopicValidatorResult.Ignore, obj: tx };
|
|
732
958
|
} else {
|
|
733
|
-
return { result: TopicValidatorResult.
|
|
959
|
+
return { result: TopicValidatorResult.Reject };
|
|
734
960
|
}
|
|
735
961
|
};
|
|
736
962
|
|
|
@@ -739,6 +965,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
739
965
|
return;
|
|
740
966
|
}
|
|
741
967
|
|
|
968
|
+
// Tx was accepted into pool and will be propagated - just log and record metrics
|
|
742
969
|
const txHash = tx.getTxHash();
|
|
743
970
|
const txHashString = txHash.toString();
|
|
744
971
|
this.logger.verbose(`Received tx ${txHashString} from external peer ${source.toString()} via gossip`, {
|
|
@@ -746,155 +973,386 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
746
973
|
txHash: txHashString,
|
|
747
974
|
});
|
|
748
975
|
|
|
749
|
-
|
|
750
|
-
this.logger.warn(`Intentionally dropping tx ${txHashString} (probability rule)`);
|
|
751
|
-
return;
|
|
752
|
-
}
|
|
753
|
-
|
|
754
|
-
await this.mempools.txPool.addTxs([tx]);
|
|
976
|
+
this.instrumentation.incrementTxReceived(1);
|
|
755
977
|
}
|
|
756
978
|
|
|
757
979
|
/**
|
|
758
|
-
* Process
|
|
759
|
-
*
|
|
760
|
-
*
|
|
761
|
-
* @param attestation - The attestation to process.
|
|
980
|
+
* Process a checkpoint attestation from a peer.
|
|
981
|
+
* Validates the attestation and adds it to the pool.
|
|
762
982
|
*/
|
|
763
|
-
private async
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
this.
|
|
770
|
-
isValid,
|
|
771
|
-
exists,
|
|
772
|
-
[Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber.toString(),
|
|
773
|
-
[Attributes.P2P_ID]: source.toString(),
|
|
774
|
-
});
|
|
775
|
-
|
|
776
|
-
if (!isValid) {
|
|
777
|
-
return { result: TopicValidatorResult.Reject };
|
|
778
|
-
} else if (exists) {
|
|
779
|
-
return { result: TopicValidatorResult.Ignore, obj: attestation };
|
|
780
|
-
} else {
|
|
781
|
-
return { result: TopicValidatorResult.Accept, obj: attestation };
|
|
782
|
-
}
|
|
783
|
-
};
|
|
784
|
-
|
|
785
|
-
const { result, obj: attestation } = await this.validateReceivedMessage<BlockAttestation>(
|
|
786
|
-
validationFunc,
|
|
983
|
+
private async processCheckpointAttestationFromPeer(
|
|
984
|
+
payloadData: Buffer,
|
|
985
|
+
msgId: string,
|
|
986
|
+
source: PeerId,
|
|
987
|
+
): Promise<void> {
|
|
988
|
+
const { result, obj: attestation } = await this.validateReceivedMessage<CheckpointAttestation>(
|
|
989
|
+
() => this.validateAndStoreCheckpointAttestation(source, CheckpointAttestation.fromBuffer(payloadData)),
|
|
787
990
|
msgId,
|
|
788
991
|
source,
|
|
789
|
-
TopicType.
|
|
992
|
+
TopicType.checkpoint_attestation,
|
|
790
993
|
);
|
|
791
994
|
|
|
792
995
|
if (result !== TopicValidatorResult.Accept || !attestation) {
|
|
793
996
|
return;
|
|
794
997
|
}
|
|
795
998
|
|
|
796
|
-
this.logger.
|
|
797
|
-
`Received attestation for slot ${attestation.slotNumber
|
|
999
|
+
this.logger.verbose(
|
|
1000
|
+
`Received valid checkpoint attestation for slot ${attestation.slotNumber} from external peer ${source.toString()}`,
|
|
798
1001
|
{
|
|
799
|
-
p2pMessageIdentifier: await attestation.
|
|
800
|
-
slot: attestation.slotNumber
|
|
1002
|
+
p2pMessageIdentifier: await attestation.p2pMessageLoggingIdentifier(),
|
|
1003
|
+
slot: attestation.slotNumber,
|
|
801
1004
|
archive: attestation.archive.toString(),
|
|
802
1005
|
source: source.toString(),
|
|
803
1006
|
},
|
|
804
1007
|
);
|
|
805
|
-
|
|
806
|
-
await this.mempools.attestationPool!.addAttestations([attestation]);
|
|
807
1008
|
}
|
|
808
1009
|
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
1010
|
+
/** Validates a checkpoint attestation and adds it to the pool. Penalizes the peer if validation fails. */
|
|
1011
|
+
@trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId, attestation) => ({
|
|
1012
|
+
[Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber.toString(),
|
|
1013
|
+
}))
|
|
1014
|
+
protected async validateAndStoreCheckpointAttestation(
|
|
1015
|
+
peerId: PeerId,
|
|
1016
|
+
attestation: CheckpointAttestation,
|
|
1017
|
+
): Promise<ReceivedMessageValidationResult<CheckpointAttestation>> {
|
|
1018
|
+
const validationResult = await this.checkpointAttestationValidator.validate(attestation);
|
|
1019
|
+
|
|
1020
|
+
if (validationResult.result === 'reject') {
|
|
1021
|
+
this.logger.warn(`Penalizing peer ${peerId} for checkpoint attestation validation failure`);
|
|
1022
|
+
this.peerManager.penalizePeer(peerId, validationResult.severity);
|
|
1023
|
+
return { result: TopicValidatorResult.Reject };
|
|
1024
|
+
}
|
|
813
1025
|
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
1026
|
+
if (validationResult.result === 'ignore') {
|
|
1027
|
+
return { result: TopicValidatorResult.Ignore, obj: attestation };
|
|
1028
|
+
}
|
|
817
1029
|
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
1030
|
+
// Try to add the attestation: this handles existence check, cap check, and adding in one call
|
|
1031
|
+
// count is the number of attestations by this signer for this slot (for duplicate detection)
|
|
1032
|
+
const slot = attestation.payload.header.slotNumber;
|
|
1033
|
+
const { added, alreadyExists, count } =
|
|
1034
|
+
await this.mempools.attestationPool.tryAddCheckpointAttestation(attestation);
|
|
1035
|
+
|
|
1036
|
+
this.logger.trace(`Validate propagated checkpoint attestation`, {
|
|
1037
|
+
added,
|
|
1038
|
+
alreadyExists,
|
|
1039
|
+
count,
|
|
1040
|
+
[Attributes.SLOT_NUMBER]: slot.toString(),
|
|
1041
|
+
[Attributes.P2P_ID]: peerId.toString(),
|
|
1042
|
+
});
|
|
1043
|
+
|
|
1044
|
+
// Exact same attestation received, no need to re-broadcast
|
|
1045
|
+
if (alreadyExists) {
|
|
1046
|
+
return { result: TopicValidatorResult.Ignore, obj: attestation };
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
// Could not add (cap reached for signer), no need to re-broadcast
|
|
1050
|
+
if (!added) {
|
|
1051
|
+
this.logger.warn(`Dropping checkpoint attestation due to cap`, {
|
|
1052
|
+
slot: slot.toString(),
|
|
1053
|
+
archive: attestation.archive.toString(),
|
|
1054
|
+
source: peerId.toString(),
|
|
1055
|
+
attester: attestation.getSender()?.toString(),
|
|
1056
|
+
count,
|
|
823
1057
|
});
|
|
1058
|
+
return { result: TopicValidatorResult.Ignore, obj: attestation };
|
|
1059
|
+
}
|
|
824
1060
|
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
1061
|
+
// Check if this is a duplicate attestation (signer attested to a different proposal at the same slot)
|
|
1062
|
+
// count is the number of attestations by this signer for this slot
|
|
1063
|
+
if (count === 2) {
|
|
1064
|
+
const attester = attestation.getSender();
|
|
1065
|
+
if (attester) {
|
|
1066
|
+
this.logger.warn(`Detected duplicate attestation (equivocation) at slot ${slot}`, {
|
|
1067
|
+
slot: slot.toString(),
|
|
1068
|
+
archive: attestation.archive.toString(),
|
|
1069
|
+
source: peerId.toString(),
|
|
1070
|
+
attester: attester.toString(),
|
|
1071
|
+
});
|
|
1072
|
+
this.duplicateAttestationCallback?.({ slot, attester });
|
|
831
1073
|
}
|
|
832
|
-
}
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1076
|
+
// Attestation was added successfully - accept it so other nodes can also detect the equivocation
|
|
1077
|
+
return { result: TopicValidatorResult.Accept, obj: attestation };
|
|
1078
|
+
}
|
|
833
1079
|
|
|
834
|
-
|
|
835
|
-
|
|
1080
|
+
protected async processBlockFromPeer(payloadData: Buffer, msgId: string, source: PeerId): Promise<void> {
|
|
1081
|
+
const {
|
|
1082
|
+
result,
|
|
1083
|
+
obj: block,
|
|
1084
|
+
metadata: { isEquivocated } = {},
|
|
1085
|
+
} = await this.validateReceivedMessage<BlockProposal, { isEquivocated: boolean }>(
|
|
1086
|
+
() => this.validateAndStoreBlockProposal(source, BlockProposal.fromBuffer(payloadData)),
|
|
836
1087
|
msgId,
|
|
837
1088
|
source,
|
|
838
1089
|
TopicType.block_proposal,
|
|
839
1090
|
);
|
|
840
1091
|
|
|
841
|
-
|
|
1092
|
+
// If not accepted or equivocated, return
|
|
1093
|
+
if (result !== TopicValidatorResult.Accept || !block || isEquivocated) {
|
|
842
1094
|
return;
|
|
843
1095
|
}
|
|
844
1096
|
|
|
845
1097
|
await this.processValidBlockProposal(block, source);
|
|
846
1098
|
}
|
|
847
1099
|
|
|
848
|
-
|
|
1100
|
+
/** Validates a block proposal. Triggers a penalization to the peer that sent it if invalid. Adds to the mempool if valid. */
|
|
1101
|
+
@trackSpan('Libp2pService.validateAndStoreBlockProposal', (_peerId, block) => ({
|
|
1102
|
+
[Attributes.BLOCK_NUMBER]: block.blockNumber.toString(),
|
|
1103
|
+
[Attributes.SLOT_NUMBER]: block.slotNumber.toString(),
|
|
1104
|
+
}))
|
|
1105
|
+
protected async validateAndStoreBlockProposal(
|
|
1106
|
+
peerId: PeerId,
|
|
1107
|
+
block: BlockProposal,
|
|
1108
|
+
): Promise<ReceivedMessageValidationResult<BlockProposal, { isEquivocated: boolean }>> {
|
|
1109
|
+
const validationResult = await this.blockProposalValidator.validate(block);
|
|
1110
|
+
|
|
1111
|
+
if (validationResult.result === 'reject') {
|
|
1112
|
+
this.logger.warn(`Penalizing peer ${peerId} for block proposal validation failure`);
|
|
1113
|
+
this.peerManager.penalizePeer(peerId, validationResult.severity);
|
|
1114
|
+
return { result: TopicValidatorResult.Reject };
|
|
1115
|
+
}
|
|
1116
|
+
|
|
1117
|
+
if (validationResult.result === 'ignore') {
|
|
1118
|
+
return { result: TopicValidatorResult.Ignore, obj: block };
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1121
|
+
// Try to add the proposal: this handles existence check, cap check, and adding in one call
|
|
1122
|
+
const { added, alreadyExists, count } = await this.mempools.attestationPool.tryAddBlockProposal(block);
|
|
1123
|
+
const isEquivocated = count !== undefined && count > 1;
|
|
1124
|
+
|
|
1125
|
+
// Duplicate proposal received, no need to re-broadcast
|
|
1126
|
+
if (alreadyExists) {
|
|
1127
|
+
this.logger.debug(`Ignoring duplicate block proposal received`, {
|
|
1128
|
+
...block.toBlockInfo(),
|
|
1129
|
+
indexWithinCheckpoint: block.indexWithinCheckpoint,
|
|
1130
|
+
proposer: block.getSender()?.toString(),
|
|
1131
|
+
source: peerId.toString(),
|
|
1132
|
+
});
|
|
1133
|
+
return { result: TopicValidatorResult.Ignore, obj: block, metadata: { isEquivocated } };
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
// Too many blocks received for this slot and index, penalize peer and do not re-broadcast
|
|
1137
|
+
if (!added) {
|
|
1138
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.HighToleranceError);
|
|
1139
|
+
this.logger.warn(`Penalizing peer for block proposal exceeding per-position cap`, {
|
|
1140
|
+
...block.toBlockInfo(),
|
|
1141
|
+
indexWithinCheckpoint: block.indexWithinCheckpoint,
|
|
1142
|
+
count,
|
|
1143
|
+
proposer: block.getSender()?.toString(),
|
|
1144
|
+
source: peerId.toString(),
|
|
1145
|
+
});
|
|
1146
|
+
return { result: TopicValidatorResult.Reject, metadata: { isEquivocated } };
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1149
|
+
// If this was a duplicate proposal, do not process it, but do invoke the duplicate callback,
|
|
1150
|
+
// and do re-broadcast it so other nodes in the network know to slash the proposer
|
|
1151
|
+
if (isEquivocated) {
|
|
1152
|
+
const proposer = block.getSender();
|
|
1153
|
+
this.logger.warn(`Detected duplicate block proposal (equivocation) at slot ${block.slotNumber}`, {
|
|
1154
|
+
...block.toBlockInfo(),
|
|
1155
|
+
source: peerId.toString(),
|
|
1156
|
+
proposer: proposer?.toString(),
|
|
1157
|
+
});
|
|
1158
|
+
// Invoke the duplicate callback on the first duplicate spotted only
|
|
1159
|
+
if (proposer && count === 2) {
|
|
1160
|
+
this.duplicateProposalCallback?.({ slot: block.slotNumber, proposer, type: 'block' });
|
|
1161
|
+
}
|
|
1162
|
+
return { result: TopicValidatorResult.Accept, obj: block, metadata: { isEquivocated } };
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
// Otherwise, we're good to go!
|
|
1166
|
+
return { result: TopicValidatorResult.Accept, obj: block };
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
// REFACTOR(palla): This method should be moved to the p2p_client or to a separate component,
|
|
1170
|
+
// should not be here as it does not deal with p2p networking.
|
|
849
1171
|
@trackSpan('Libp2pService.processValidBlockProposal', async block => ({
|
|
850
|
-
[Attributes.SLOT_NUMBER]: block.slotNumber
|
|
1172
|
+
[Attributes.SLOT_NUMBER]: block.slotNumber,
|
|
851
1173
|
[Attributes.BLOCK_ARCHIVE]: block.archive.toString(),
|
|
852
|
-
[Attributes.P2P_ID]: await block.
|
|
1174
|
+
[Attributes.P2P_ID]: await block.p2pMessageLoggingIdentifier().then(i => i.toString()),
|
|
853
1175
|
}))
|
|
854
|
-
|
|
855
|
-
const slot = block.slotNumber
|
|
856
|
-
const previousSlot = slot - 1n;
|
|
1176
|
+
protected async processValidBlockProposal(block: BlockProposal, sender: PeerId) {
|
|
1177
|
+
const slot = block.slotNumber;
|
|
857
1178
|
this.logger.verbose(`Received block proposal for slot ${slot} from external peer ${sender.toString()}.`, {
|
|
858
|
-
p2pMessageIdentifier: await block.
|
|
859
|
-
slot: block.slotNumber.toNumber(),
|
|
860
|
-
archive: block.archive.toString(),
|
|
1179
|
+
p2pMessageIdentifier: await block.p2pMessageLoggingIdentifier(),
|
|
861
1180
|
source: sender.toString(),
|
|
1181
|
+
...block.toBlockInfo(),
|
|
862
1182
|
});
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
1183
|
+
|
|
1184
|
+
// Mark the txs in this proposal as protected
|
|
1185
|
+
await this.mempools.txPool.protectTxs(block.txHashes, block.blockHeader);
|
|
1186
|
+
|
|
1187
|
+
// Call the block received callback to validate the proposal.
|
|
1188
|
+
// Note: Validators do NOT attest to individual blocks, only to checkpoint proposals.
|
|
1189
|
+
const isValid = await this.blockReceivedCallback(block, sender);
|
|
1190
|
+
if (!isValid) {
|
|
1191
|
+
this.logger.warn(`Block proposal validation failed for block ${block.blockNumber}`, block.toBlockInfo());
|
|
866
1192
|
}
|
|
1193
|
+
}
|
|
867
1194
|
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
1195
|
+
/**
|
|
1196
|
+
* Handle a gossiped checkpoint proposal.
|
|
1197
|
+
* Validates and processes the checkpoint proposal, then triggers the callback for attestation.
|
|
1198
|
+
*/
|
|
1199
|
+
protected async handleGossipedCheckpointProposal(payloadData: Buffer, msgId: string, source: PeerId): Promise<void> {
|
|
1200
|
+
const {
|
|
1201
|
+
result,
|
|
1202
|
+
obj: checkpoint,
|
|
1203
|
+
metadata: { isEquivocated, processBlock } = {},
|
|
1204
|
+
} = await this.validateReceivedMessage<CheckpointProposal, { isEquivocated: boolean; processBlock: boolean }>(
|
|
1205
|
+
() => this.validateAndStoreCheckpointProposal(source, CheckpointProposal.fromBuffer(payloadData)),
|
|
1206
|
+
msgId,
|
|
1207
|
+
source,
|
|
1208
|
+
TopicType.checkpoint_proposal,
|
|
1209
|
+
);
|
|
872
1210
|
|
|
873
|
-
//
|
|
874
|
-
//
|
|
875
|
-
if (
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
1211
|
+
// If the checkpoint contained a valid last block, we process it even if the checkpoint itself is to be rejected
|
|
1212
|
+
// TODO(palla/mbps): Is this ok? Should we be considering a block from a checkpoint that was equivocated?
|
|
1213
|
+
if (processBlock && checkpoint?.getBlockProposal()) {
|
|
1214
|
+
await this.processValidBlockProposal(checkpoint.getBlockProposal()!, source);
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1217
|
+
if (result !== TopicValidatorResult.Accept || !checkpoint || isEquivocated) {
|
|
1218
|
+
return;
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
await this.processValidCheckpointProposal(checkpoint.toCore(), source);
|
|
1222
|
+
}
|
|
1223
|
+
|
|
1224
|
+
/**
|
|
1225
|
+
* Validates a checkpoint proposal. Penalizes peer if validation fails. Adds the checkpoint and
|
|
1226
|
+
* its last block (if present) to the mempool if valid. Triggers equivocation detection on both.
|
|
1227
|
+
*/
|
|
1228
|
+
@trackSpan('Libp2pService.validateAndStoreCheckpointProposal', (_peerId, checkpoint) => ({
|
|
1229
|
+
[Attributes.SLOT_NUMBER]: checkpoint.slotNumber.toString(),
|
|
1230
|
+
}))
|
|
1231
|
+
protected async validateAndStoreCheckpointProposal(
|
|
1232
|
+
peerId: PeerId,
|
|
1233
|
+
checkpoint: CheckpointProposal,
|
|
1234
|
+
): Promise<ReceivedMessageValidationResult<CheckpointProposal, { isEquivocated: boolean; processBlock: boolean }>> {
|
|
1235
|
+
const validationResult = await this.checkpointProposalValidator.validate(checkpoint);
|
|
1236
|
+
|
|
1237
|
+
if (validationResult.result === 'reject') {
|
|
1238
|
+
this.logger.warn(`Penalizing peer ${peerId} for checkpoint proposal validation failure`);
|
|
1239
|
+
this.peerManager.penalizePeer(peerId, validationResult.severity);
|
|
1240
|
+
return { result: TopicValidatorResult.Reject };
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1243
|
+
if (validationResult.result === 'ignore') {
|
|
1244
|
+
return { result: TopicValidatorResult.Ignore, obj: checkpoint };
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1247
|
+
// Extract and try to add the block proposal first if present
|
|
1248
|
+
const blockProposal = checkpoint.getBlockProposal();
|
|
1249
|
+
let processBlock = false;
|
|
1250
|
+
if (blockProposal) {
|
|
1251
|
+
this.logger.debug(`Validating block proposal from propagated checkpoint`, {
|
|
1252
|
+
[Attributes.SLOT_NUMBER]: checkpoint.slotNumber.toString(),
|
|
1253
|
+
[Attributes.P2P_ID]: peerId.toString(),
|
|
1254
|
+
});
|
|
1255
|
+
const {
|
|
1256
|
+
result,
|
|
1257
|
+
obj,
|
|
1258
|
+
metadata: { isEquivocated } = {},
|
|
1259
|
+
} = await this.validateAndStoreBlockProposal(peerId, blockProposal);
|
|
1260
|
+
if (result === TopicValidatorResult.Reject || !obj || isEquivocated) {
|
|
1261
|
+
this.logger.debug(`Rejecting checkpoint due to invalid last block proposal`, {
|
|
1262
|
+
[Attributes.SLOT_NUMBER]: checkpoint.slotNumber.toString(),
|
|
1263
|
+
[Attributes.P2P_ID]: peerId.toString(),
|
|
1264
|
+
isEquivocated,
|
|
1265
|
+
result,
|
|
881
1266
|
});
|
|
882
|
-
|
|
1267
|
+
return { result: TopicValidatorResult.Reject };
|
|
1268
|
+
} else if (result === TopicValidatorResult.Accept && obj && !isEquivocated) {
|
|
1269
|
+
processBlock = true;
|
|
883
1270
|
}
|
|
884
1271
|
}
|
|
1272
|
+
|
|
1273
|
+
// Try to add the checkpoint proposal core: this handles existence check, cap check, and adding in one call
|
|
1274
|
+
const checkpointCore = checkpoint.toCore();
|
|
1275
|
+
const tryAddResult = await this.mempools.attestationPool.tryAddCheckpointProposal(checkpointCore);
|
|
1276
|
+
const { added, alreadyExists, count } = tryAddResult;
|
|
1277
|
+
const isEquivocated = count !== undefined && count > 1;
|
|
1278
|
+
|
|
1279
|
+
// Duplicate proposal received, do not re-broadcast
|
|
1280
|
+
if (alreadyExists) {
|
|
1281
|
+
this.logger.debug(`Ignoring duplicate checkpoint proposal received`, {
|
|
1282
|
+
...checkpoint.toCheckpointInfo(),
|
|
1283
|
+
source: peerId.toString(),
|
|
1284
|
+
});
|
|
1285
|
+
return {
|
|
1286
|
+
result: TopicValidatorResult.Ignore,
|
|
1287
|
+
obj: checkpoint,
|
|
1288
|
+
metadata: { isEquivocated, processBlock },
|
|
1289
|
+
};
|
|
1290
|
+
}
|
|
1291
|
+
|
|
1292
|
+
// Too many checkpoint proposals received for this slot, penalize peer and do not re-broadcast
|
|
1293
|
+
// Note: We still return the checkpoint obj so the lastBlock can be processed if valid
|
|
1294
|
+
if (!added) {
|
|
1295
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.HighToleranceError);
|
|
1296
|
+
this.logger.warn(`Penalizing peer for checkpoint proposal exceeding per-slot cap`, {
|
|
1297
|
+
...checkpoint.toCheckpointInfo(),
|
|
1298
|
+
count,
|
|
1299
|
+
source: peerId.toString(),
|
|
1300
|
+
});
|
|
1301
|
+
return { result: TopicValidatorResult.Reject, obj: checkpoint, metadata: { isEquivocated, processBlock } };
|
|
1302
|
+
}
|
|
1303
|
+
|
|
1304
|
+
// If this was a duplicate proposal, do not process it, but do invoke the duplicate callback,
|
|
1305
|
+
// and do re-broadcast it so other nodes in the network know to slash the proposer
|
|
1306
|
+
if (isEquivocated) {
|
|
1307
|
+
const proposer = checkpoint.getSender();
|
|
1308
|
+
this.logger.warn(`Detected duplicate checkpoint proposal (equivocation) at slot ${checkpoint.slotNumber}`, {
|
|
1309
|
+
...checkpoint.toCheckpointInfo(),
|
|
1310
|
+
source: peerId.toString(),
|
|
1311
|
+
proposer: proposer?.toString(),
|
|
1312
|
+
});
|
|
1313
|
+
// Invoke the duplicate callback on the first duplicate spotted only
|
|
1314
|
+
if (proposer && count === 2) {
|
|
1315
|
+
this.duplicateProposalCallback?.({ slot: checkpoint.slotNumber, proposer, type: 'checkpoint' });
|
|
1316
|
+
}
|
|
1317
|
+
return {
|
|
1318
|
+
result: TopicValidatorResult.Accept,
|
|
1319
|
+
obj: checkpoint,
|
|
1320
|
+
metadata: { isEquivocated, processBlock },
|
|
1321
|
+
};
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1324
|
+
// Otherwise, we're good to go!
|
|
1325
|
+
return { result: TopicValidatorResult.Accept, obj: checkpoint, metadata: { processBlock, isEquivocated } };
|
|
885
1326
|
}
|
|
886
1327
|
|
|
887
1328
|
/**
|
|
888
|
-
*
|
|
889
|
-
*
|
|
1329
|
+
* Process a validated checkpoint proposal.
|
|
1330
|
+
* Note: The proposal was already added to the pool by tryAddCheckpointProposal in handleGossipedCheckpointProposal.
|
|
890
1331
|
*/
|
|
891
|
-
@trackSpan('Libp2pService.
|
|
892
|
-
[Attributes.SLOT_NUMBER]:
|
|
893
|
-
[Attributes.BLOCK_ARCHIVE]:
|
|
894
|
-
[Attributes.P2P_ID]: await
|
|
1332
|
+
@trackSpan('Libp2pService.processValidCheckpointProposal', async checkpoint => ({
|
|
1333
|
+
[Attributes.SLOT_NUMBER]: checkpoint.slotNumber,
|
|
1334
|
+
[Attributes.BLOCK_ARCHIVE]: checkpoint.archive.toString(),
|
|
1335
|
+
[Attributes.P2P_ID]: await checkpoint.p2pMessageLoggingIdentifier().then(i => i.toString()),
|
|
895
1336
|
}))
|
|
896
|
-
|
|
897
|
-
|
|
1337
|
+
protected async processValidCheckpointProposal(checkpoint: CheckpointProposalCore, sender: PeerId) {
|
|
1338
|
+
const slot = checkpoint.slotNumber;
|
|
1339
|
+
this.logger.verbose(`Received checkpoint proposal for slot ${slot} from external peer ${sender.toString()}.`, {
|
|
1340
|
+
p2pMessageIdentifier: await checkpoint.p2pMessageLoggingIdentifier(),
|
|
1341
|
+
slot: checkpoint.slotNumber,
|
|
1342
|
+
archive: checkpoint.archive.toString(),
|
|
1343
|
+
source: sender.toString(),
|
|
1344
|
+
});
|
|
1345
|
+
|
|
1346
|
+
// Call the checkpoint received callback with the core version (without lastBlock)
|
|
1347
|
+
// to validate and potentially generate attestations
|
|
1348
|
+
const attestations = await this.checkpointReceivedCallback(checkpoint, sender);
|
|
1349
|
+
if (attestations && attestations.length > 0) {
|
|
1350
|
+
// If the callback returned attestations, add them to the pool and propagate them
|
|
1351
|
+
await this.mempools.attestationPool.addOwnCheckpointAttestations(attestations);
|
|
1352
|
+
for (const attestation of attestations) {
|
|
1353
|
+
await this.propagate(attestation);
|
|
1354
|
+
}
|
|
1355
|
+
}
|
|
898
1356
|
}
|
|
899
1357
|
|
|
900
1358
|
/**
|
|
@@ -902,36 +1360,89 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
902
1360
|
* @param message - The message to propagate.
|
|
903
1361
|
*/
|
|
904
1362
|
public async propagate<T extends Gossipable>(message: T) {
|
|
905
|
-
const p2pMessageIdentifier = await message.
|
|
1363
|
+
const p2pMessageIdentifier = await message.p2pMessageLoggingIdentifier();
|
|
906
1364
|
this.logger.trace(`Message ${p2pMessageIdentifier} queued`, { p2pMessageIdentifier });
|
|
907
|
-
void this.
|
|
908
|
-
.
|
|
909
|
-
|
|
910
|
-
})
|
|
911
|
-
.catch(error => {
|
|
912
|
-
this.logger.error(`Error propagating message ${p2pMessageIdentifier}`, { error });
|
|
913
|
-
});
|
|
1365
|
+
void this.sendToPeers(message).catch(error => {
|
|
1366
|
+
this.logger.error(`Error propagating message ${p2pMessageIdentifier}`, { error });
|
|
1367
|
+
});
|
|
914
1368
|
}
|
|
915
1369
|
|
|
916
1370
|
/**
|
|
917
|
-
* Validate the requested block transactions.
|
|
1371
|
+
* Validate the requested block transactions. Allow partial returns.
|
|
918
1372
|
* @param request - The block transactions request.
|
|
919
1373
|
* @param response - The block transactions response.
|
|
920
1374
|
* @param peerId - The ID of the peer that made the request.
|
|
921
1375
|
* @returns True if the requested block transactions are valid, false otherwise.
|
|
922
1376
|
*/
|
|
923
1377
|
@trackSpan('Libp2pService.validateRequestedBlockTxs', request => ({
|
|
924
|
-
[Attributes.
|
|
1378
|
+
[Attributes.BLOCK_ARCHIVE]: request.archiveRoot.toString(),
|
|
925
1379
|
}))
|
|
926
|
-
|
|
927
|
-
|
|
1380
|
+
protected async validateRequestedBlockTxs(
|
|
1381
|
+
request: BlockTxsRequest,
|
|
928
1382
|
response: BlockTxsResponse,
|
|
929
1383
|
peerId: PeerId,
|
|
930
1384
|
): Promise<boolean> {
|
|
931
1385
|
const requestedTxValidator = this.createRequestedTxValidator();
|
|
932
1386
|
|
|
933
1387
|
try {
|
|
934
|
-
|
|
1388
|
+
if (!response.archiveRoot.equals(request.archiveRoot)) {
|
|
1389
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
1390
|
+
throw new ValidationError(
|
|
1391
|
+
`Received block txs for unexpected archive root: expected ${request.archiveRoot.toString()}, got ${response.archiveRoot.toString()}`,
|
|
1392
|
+
);
|
|
1393
|
+
}
|
|
1394
|
+
|
|
1395
|
+
if (response.txIndices.getLength() !== request.txIndices.getLength()) {
|
|
1396
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
1397
|
+
throw new ValidationError(
|
|
1398
|
+
`Received block txs with mismatched bitvector length: expected ${request.txIndices.getLength()}, got ${response.txIndices.getLength()}`,
|
|
1399
|
+
);
|
|
1400
|
+
}
|
|
1401
|
+
|
|
1402
|
+
// Check no duplicates and not exceeding returnable count
|
|
1403
|
+
const requestedIndices = new Set(request.txIndices.getTrueIndices());
|
|
1404
|
+
const availableIndices = new Set(response.txIndices.getTrueIndices());
|
|
1405
|
+
const maxReturnable = [...requestedIndices].filter(i => availableIndices.has(i)).length;
|
|
1406
|
+
|
|
1407
|
+
const returnedHashes = await Promise.all(response.txs.map(tx => tx.getTxHash().toString()));
|
|
1408
|
+
const uniqueReturned = new Set(returnedHashes.map(h => h.toString()));
|
|
1409
|
+
if (uniqueReturned.size !== returnedHashes.length) {
|
|
1410
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
1411
|
+
throw new ValidationError(`Received duplicate txs in block txs response`);
|
|
1412
|
+
}
|
|
1413
|
+
if (response.txs.length > maxReturnable) {
|
|
1414
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
1415
|
+
throw new ValidationError(
|
|
1416
|
+
`Received more txs (${response.txs.length}) than requested-and-available (${maxReturnable})`,
|
|
1417
|
+
);
|
|
1418
|
+
}
|
|
1419
|
+
|
|
1420
|
+
// Given proposal (should have locally), ensure returned txs are valid subset and match request indices
|
|
1421
|
+
const proposal = await this.mempools.attestationPool.getBlockProposal(request.archiveRoot.toString());
|
|
1422
|
+
if (proposal) {
|
|
1423
|
+
// Build intersected indices
|
|
1424
|
+
const intersectIdx = request.txIndices.getTrueIndices().filter(i => response.txIndices.isSet(i));
|
|
1425
|
+
|
|
1426
|
+
// Enforce subset membership and preserve increasing order by index.
|
|
1427
|
+
const hashToIndexInProposal = new Map<string, number>(
|
|
1428
|
+
proposal.txHashes.map((h, i) => [h.toString(), i] as [string, number]),
|
|
1429
|
+
);
|
|
1430
|
+
const allowedIndexSet = new Set(intersectIdx);
|
|
1431
|
+
const indices = returnedHashes.map(h => hashToIndexInProposal.get(h));
|
|
1432
|
+
const allAllowed = indices.every(idx => idx !== undefined && allowedIndexSet.has(idx));
|
|
1433
|
+
const strictlyIncreasing = indices.every((idx, i) => (i === 0 ? idx !== undefined : idx! > indices[i - 1]!));
|
|
1434
|
+
if (!allAllowed || !strictlyIncreasing) {
|
|
1435
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
|
|
1436
|
+
throw new ValidationError('Returned txs do not match expected subset/order for requested indices');
|
|
1437
|
+
}
|
|
1438
|
+
} else {
|
|
1439
|
+
// No local proposal, cannot check the membership/order of the returned txs
|
|
1440
|
+
this.logger.warn(
|
|
1441
|
+
`Block proposal not found for archive root ${request.archiveRoot.toString()}; cannot validate membership/order of returned txs`,
|
|
1442
|
+
);
|
|
1443
|
+
return false;
|
|
1444
|
+
}
|
|
1445
|
+
|
|
935
1446
|
await Promise.all(response.txs.map(tx => this.validateRequestedTx(tx, peerId, requestedTxValidator)));
|
|
936
1447
|
return true;
|
|
937
1448
|
} catch (e: any) {
|
|
@@ -955,7 +1466,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
955
1466
|
* ReqRespSubProtocol.TX subprotocol validation.
|
|
956
1467
|
*
|
|
957
1468
|
* @param requestedTxHash - The collection of the txs that was requested.
|
|
958
|
-
* @param responseTx - The
|
|
1469
|
+
* @param responseTx - The collection of txs that was received as a response to the request.
|
|
959
1470
|
* @param peerId - The peer ID of the peer that sent the tx.
|
|
960
1471
|
* @returns True if the whole collection of txs is valid, false otherwise.
|
|
961
1472
|
*/
|
|
@@ -966,7 +1477,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
966
1477
|
const requested = new Set(requestedTxHash.map(h => h.toString()));
|
|
967
1478
|
const requestedTxValidator = this.createRequestedTxValidator();
|
|
968
1479
|
|
|
969
|
-
//TODO: (mralj) - this is somewhat naive implementation, if single tx is
|
|
1480
|
+
//TODO: (mralj) - this is somewhat naive implementation, if single tx is invalid we consider the whole response invalid.
|
|
970
1481
|
// I think we should still extract the valid txs and return them, so that we can still use the response.
|
|
971
1482
|
try {
|
|
972
1483
|
await Promise.all(responseTx.map(tx => this.validateRequestedTx(tx, peerId, requestedTxValidator, requested)));
|
|
@@ -982,69 +1493,80 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
982
1493
|
}
|
|
983
1494
|
}
|
|
984
1495
|
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
1496
|
+
/**
|
|
1497
|
+
* Validates a BLOCK response.
|
|
1498
|
+
*
|
|
1499
|
+
* If a local copy exists, enforces hash equality. If missing, rejects (no penalty) since the hash cannot be verified.
|
|
1500
|
+
* Penalizes on block number mismatch or hash mismatch.
|
|
1501
|
+
*
|
|
1502
|
+
* @param requestedBlockNumber - The requested block number.
|
|
1503
|
+
* @param responseBlock - The block returned by the peer.
|
|
1504
|
+
* @param peerId - The peer that returned the block.
|
|
1505
|
+
* @returns True if the response is valid, false otherwise.
|
|
1506
|
+
*/
|
|
1507
|
+
@trackSpan('Libp2pService.validateRequestedBlock', (requestedBlockNumber, _responseBlock) => ({
|
|
1508
|
+
[Attributes.BLOCK_NUMBER]: requestedBlockNumber.toString(),
|
|
1509
|
+
}))
|
|
1510
|
+
protected async validateRequestedBlock(
|
|
1511
|
+
requestedBlockNumber: Fr,
|
|
1512
|
+
responseBlock: L2Block,
|
|
1513
|
+
peerId: PeerId,
|
|
1514
|
+
): Promise<boolean> {
|
|
1515
|
+
try {
|
|
1516
|
+
const reqNum = Number(requestedBlockNumber.toString());
|
|
1517
|
+
if (responseBlock.number !== reqNum) {
|
|
1518
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
|
|
1519
|
+
return false;
|
|
1520
|
+
}
|
|
1521
|
+
|
|
1522
|
+
const local = await this.archiver.getBlock(BlockNumber(reqNum));
|
|
1523
|
+
if (!local) {
|
|
1524
|
+
// We are missing the local block; we cannot verify the hash yet. Reject without penalizing.
|
|
1525
|
+
// TODO: Consider extending this validator to accept an expected hash or
|
|
1526
|
+
// performing quorum-based checks when using P2P syncing prior to L1 sync.
|
|
1527
|
+
this.logger.warn(`Local block ${reqNum} not found; rejecting BLOCK response without hash verification`);
|
|
1528
|
+
return false;
|
|
1529
|
+
}
|
|
1530
|
+
const [localHash, respHash] = await Promise.all([local.hash(), responseBlock.hash()]);
|
|
1531
|
+
if (!localHash.equals(respHash)) {
|
|
1532
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
1533
|
+
return false;
|
|
1534
|
+
}
|
|
997
1535
|
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
this.
|
|
1001
|
-
|
|
1536
|
+
return true;
|
|
1537
|
+
} catch (e) {
|
|
1538
|
+
this.logger.warn(`Error validating requested block`, e);
|
|
1539
|
+
return false;
|
|
1002
1540
|
}
|
|
1541
|
+
}
|
|
1003
1542
|
|
|
1543
|
+
protected async validateRequestedTx(
|
|
1544
|
+
tx: Tx,
|
|
1545
|
+
peerId: PeerId,
|
|
1546
|
+
txValidator: TxValidator,
|
|
1547
|
+
requested?: Set<`0x${string}`>,
|
|
1548
|
+
) {
|
|
1549
|
+
const penalize = (severity: PeerErrorSeverity) => this.peerManager.penalizePeer(peerId, severity);
|
|
1004
1550
|
if (requested && !requested.has(tx.getTxHash().toString())) {
|
|
1005
|
-
|
|
1551
|
+
penalize(PeerErrorSeverity.MidToleranceError);
|
|
1006
1552
|
throw new ValidationError(`Received tx with hash ${tx.getTxHash().toString()} that was not requested.`);
|
|
1007
1553
|
}
|
|
1008
1554
|
|
|
1009
1555
|
const { result } = await txValidator.validateTx(tx);
|
|
1010
1556
|
if (result === 'invalid') {
|
|
1011
|
-
|
|
1557
|
+
penalize(PeerErrorSeverity.LowToleranceError);
|
|
1012
1558
|
throw new ValidationError(`Received tx with hash ${tx.getTxHash().toString()} that is invalid.`);
|
|
1013
1559
|
}
|
|
1014
1560
|
}
|
|
1015
1561
|
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
// We accept transactions if they are not expired by the next slot (checked based on the IncludeByTimestamp field)
|
|
1023
|
-
const { ts: nextSlotTimestamp } = this.epochCache.getEpochAndSlotInNextL1Slot();
|
|
1024
|
-
const messageValidators = await this.createMessageValidators(currentBlockNumber, nextSlotTimestamp);
|
|
1025
|
-
|
|
1026
|
-
for (const validator of messageValidators) {
|
|
1027
|
-
const outcome = await this.runValidations(tx, validator);
|
|
1028
|
-
|
|
1029
|
-
if (outcome.allPassed) {
|
|
1030
|
-
continue;
|
|
1031
|
-
}
|
|
1032
|
-
const { name } = outcome.failure;
|
|
1033
|
-
let { severity } = outcome.failure;
|
|
1034
|
-
|
|
1035
|
-
// Double spend validator has a special case handler
|
|
1036
|
-
if (name === 'doubleSpendValidator') {
|
|
1037
|
-
const txBlockNumber = currentBlockNumber + 1; // tx is expected to be in the next block
|
|
1038
|
-
severity = await this.handleDoubleSpendFailure(tx, txBlockNumber);
|
|
1039
|
-
}
|
|
1040
|
-
|
|
1041
|
-
this.peerManager.penalizePeer(peerId, severity);
|
|
1042
|
-
return false;
|
|
1043
|
-
}
|
|
1044
|
-
return true;
|
|
1562
|
+
protected createRequestedTxValidator(): TxValidator {
|
|
1563
|
+
return createTxValidatorForReqResponseReceivedTxs(this.proofVerifier, {
|
|
1564
|
+
l1ChainId: this.config.l1ChainId,
|
|
1565
|
+
rollupVersion: this.config.rollupVersion,
|
|
1566
|
+
});
|
|
1045
1567
|
}
|
|
1046
1568
|
|
|
1047
|
-
private async getGasFees(blockNumber:
|
|
1569
|
+
private async getGasFees(blockNumber: BlockNumber): Promise<GasFees> {
|
|
1048
1570
|
if (blockNumber === this.feesCache?.blockNumber) {
|
|
1049
1571
|
return this.feesCache.gasFees;
|
|
1050
1572
|
}
|
|
@@ -1055,59 +1577,69 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1055
1577
|
return gasFees;
|
|
1056
1578
|
}
|
|
1057
1579
|
|
|
1058
|
-
|
|
1059
|
-
|
|
1580
|
+
/**
|
|
1581
|
+
* Get the BatchTxRequesterLibP2PService dependencies for creating BatchTxRequester instances
|
|
1582
|
+
*/
|
|
1583
|
+
public getBatchTxRequesterService(): BatchTxRequesterLibP2PService {
|
|
1584
|
+
return {
|
|
1585
|
+
reqResp: this.reqresp,
|
|
1586
|
+
connectionSampler: this.reqresp.getConnectionSampler(),
|
|
1587
|
+
txValidatorConfig: {
|
|
1588
|
+
l1ChainId: this.config.l1ChainId,
|
|
1589
|
+
rollupVersion: this.config.rollupVersion,
|
|
1590
|
+
proofVerifier: this.proofVerifier,
|
|
1591
|
+
},
|
|
1592
|
+
peerScoring: this.peerManager,
|
|
1593
|
+
};
|
|
1594
|
+
}
|
|
1060
1595
|
|
|
1061
|
-
|
|
1062
|
-
const
|
|
1063
|
-
|
|
1596
|
+
public async validateTxsReceivedInBlockProposal(txs: Tx[]): Promise<void> {
|
|
1597
|
+
const validator = createTxValidatorForBlockProposalReceivedTxs(
|
|
1598
|
+
this.proofVerifier,
|
|
1599
|
+
{ l1ChainId: this.config.l1ChainId, rollupVersion: this.config.rollupVersion },
|
|
1600
|
+
this.logger.getBindings(),
|
|
1601
|
+
);
|
|
1064
1602
|
|
|
1065
|
-
await Promise.all(
|
|
1603
|
+
const results = await Promise.all(
|
|
1066
1604
|
txs.map(async tx => {
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
if (!outcome.allPassed) {
|
|
1070
|
-
throw new Error('Invalid tx detected', { cause: { outcome } });
|
|
1071
|
-
}
|
|
1072
|
-
}
|
|
1605
|
+
const result = await validator.validateTx(tx);
|
|
1606
|
+
return result.result !== 'invalid';
|
|
1073
1607
|
}),
|
|
1074
1608
|
);
|
|
1609
|
+
if (results.some(value => value === false)) {
|
|
1610
|
+
throw new Error('Invalid tx detected');
|
|
1611
|
+
}
|
|
1075
1612
|
}
|
|
1076
1613
|
|
|
1077
|
-
/**
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
* Each validator is a pair of a validator and a severity.
|
|
1081
|
-
* If a validator fails, the peer is penalized with the severity of the validator.
|
|
1082
|
-
*
|
|
1083
|
-
* @param currentBlockNumber - The current synced block number.
|
|
1084
|
-
* @param nextSlotTimestamp - The timestamp of the next slot (used to validate txs are not expired).
|
|
1085
|
-
* @returns The message validators.
|
|
1086
|
-
*/
|
|
1087
|
-
private async createMessageValidators(
|
|
1088
|
-
currentBlockNumber: number,
|
|
1614
|
+
/** Creates the first stage (fast) validators for gossiped transactions. */
|
|
1615
|
+
protected async createFirstStageMessageValidators(
|
|
1616
|
+
currentBlockNumber: BlockNumber,
|
|
1089
1617
|
nextSlotTimestamp: UInt64,
|
|
1090
|
-
): Promise<Record<string,
|
|
1618
|
+
): Promise<Record<string, TransactionValidator>> {
|
|
1091
1619
|
const gasFees = await this.getGasFees(currentBlockNumber);
|
|
1092
1620
|
const allowedInSetup = this.config.txPublicSetupAllowList ?? (await getDefaultAllowedSetupFunctions());
|
|
1621
|
+
const blockNumber = BlockNumber(currentBlockNumber + 1);
|
|
1093
1622
|
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
return createTxMessageValidators(
|
|
1623
|
+
return createFirstStageTxValidationsForGossipedTransactions(
|
|
1097
1624
|
nextSlotTimestamp,
|
|
1098
|
-
|
|
1625
|
+
blockNumber,
|
|
1099
1626
|
this.worldStateSynchronizer,
|
|
1100
1627
|
gasFees,
|
|
1101
1628
|
this.config.l1ChainId,
|
|
1102
1629
|
this.config.rollupVersion,
|
|
1103
1630
|
protocolContractsHash,
|
|
1104
1631
|
this.archiver,
|
|
1105
|
-
this.proofVerifier,
|
|
1106
1632
|
!this.config.disableTransactions,
|
|
1107
1633
|
allowedInSetup,
|
|
1634
|
+
this.logger.getBindings(),
|
|
1108
1635
|
);
|
|
1109
1636
|
}
|
|
1110
1637
|
|
|
1638
|
+
/** Creates the second stage (expensive proof verification) validators for gossiped transactions. */
|
|
1639
|
+
protected createSecondStageMessageValidators(): Record<string, TransactionValidator> {
|
|
1640
|
+
return createSecondStageTxValidationsForGossipedTransactions(this.proofVerifier, this.logger.getBindings());
|
|
1641
|
+
}
|
|
1642
|
+
|
|
1111
1643
|
/**
|
|
1112
1644
|
* Run validations on a tx.
|
|
1113
1645
|
* @param tx - The tx to validate.
|
|
@@ -1116,7 +1648,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1116
1648
|
*/
|
|
1117
1649
|
private async runValidations(
|
|
1118
1650
|
tx: Tx,
|
|
1119
|
-
messageValidators: Record<string,
|
|
1651
|
+
messageValidators: Record<string, TransactionValidator>,
|
|
1120
1652
|
): Promise<ValidationOutcome> {
|
|
1121
1653
|
const validationPromises = Object.entries(messageValidators).map(async ([name, { validator, severity }]) => {
|
|
1122
1654
|
const { result } = await validator.validateTx(tx);
|
|
@@ -1153,20 +1685,23 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1153
1685
|
* @param peerId - The peer ID of the peer that sent the tx.
|
|
1154
1686
|
* @returns Severity
|
|
1155
1687
|
*/
|
|
1156
|
-
private async handleDoubleSpendFailure(tx: Tx, blockNumber:
|
|
1688
|
+
private async handleDoubleSpendFailure(tx: Tx, blockNumber: BlockNumber): Promise<PeerErrorSeverity> {
|
|
1157
1689
|
if (blockNumber <= this.config.doubleSpendSeverePeerPenaltyWindow) {
|
|
1158
1690
|
return PeerErrorSeverity.HighToleranceError;
|
|
1159
1691
|
}
|
|
1160
1692
|
|
|
1161
|
-
const snapshotValidator = new DoubleSpendTxValidator(
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1693
|
+
const snapshotValidator = new DoubleSpendTxValidator(
|
|
1694
|
+
{
|
|
1695
|
+
nullifiersExist: async (nullifiers: Buffer[]) => {
|
|
1696
|
+
const merkleTree = this.worldStateSynchronizer.getSnapshot(
|
|
1697
|
+
BlockNumber(blockNumber - this.config.doubleSpendSeverePeerPenaltyWindow),
|
|
1698
|
+
);
|
|
1699
|
+
const indices = await merkleTree.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, nullifiers);
|
|
1700
|
+
return indices.map(index => index !== undefined);
|
|
1701
|
+
},
|
|
1168
1702
|
},
|
|
1169
|
-
|
|
1703
|
+
this.logger.getBindings(),
|
|
1704
|
+
);
|
|
1170
1705
|
|
|
1171
1706
|
const validSnapshot = await snapshotValidator.validateTx(tx);
|
|
1172
1707
|
if (validSnapshot.result !== 'valid') {
|
|
@@ -1177,44 +1712,28 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1177
1712
|
}
|
|
1178
1713
|
|
|
1179
1714
|
/**
|
|
1180
|
-
* Validate
|
|
1715
|
+
* Validate a checkpoint attestation.
|
|
1181
1716
|
*
|
|
1182
|
-
* @param attestation - The attestation to validate.
|
|
1183
|
-
* @returns True if the attestation is valid, false otherwise.
|
|
1717
|
+
* @param attestation - The checkpoint attestation to validate.
|
|
1718
|
+
* @returns True if the checkpoint attestation is valid, false otherwise.
|
|
1184
1719
|
*/
|
|
1185
|
-
@trackSpan('Libp2pService.
|
|
1186
|
-
[Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber
|
|
1720
|
+
@trackSpan('Libp2pService.validateCheckpointAttestation', async (_, attestation) => ({
|
|
1721
|
+
[Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber,
|
|
1187
1722
|
[Attributes.BLOCK_ARCHIVE]: attestation.archive.toString(),
|
|
1188
|
-
[Attributes.P2P_ID]: await attestation.
|
|
1723
|
+
[Attributes.P2P_ID]: await attestation.p2pMessageLoggingIdentifier().then(i => i.toString()),
|
|
1189
1724
|
}))
|
|
1190
|
-
public async
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
}
|
|
1196
|
-
|
|
1197
|
-
return true;
|
|
1198
|
-
}
|
|
1725
|
+
public async validateCheckpointAttestation(
|
|
1726
|
+
peerId: PeerId,
|
|
1727
|
+
attestation: CheckpointAttestation,
|
|
1728
|
+
): Promise<P2PValidationResult> {
|
|
1729
|
+
const result = await this.checkpointAttestationValidator.validate(attestation);
|
|
1199
1730
|
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
* @param block - The block proposal to validate.
|
|
1204
|
-
* @returns True if the block proposal is valid, false otherwise.
|
|
1205
|
-
*/
|
|
1206
|
-
@trackSpan('Libp2pService.validateBlockProposal', (_peerId, block) => ({
|
|
1207
|
-
[Attributes.SLOT_NUMBER]: block.payload.header.slotNumber.toString(),
|
|
1208
|
-
}))
|
|
1209
|
-
public async validateBlockProposal(peerId: PeerId, block: BlockProposal): Promise<boolean> {
|
|
1210
|
-
const severity = await this.blockProposalValidator.validate(block);
|
|
1211
|
-
if (severity) {
|
|
1212
|
-
this.logger.debug(`Penalizing peer ${peerId} for block proposal validation failure`);
|
|
1213
|
-
this.peerManager.penalizePeer(peerId, severity);
|
|
1214
|
-
return false;
|
|
1731
|
+
if (result.result === 'reject') {
|
|
1732
|
+
this.logger.warn(`Penalizing peer ${peerId} for checkpoint attestation validation failure`);
|
|
1733
|
+
this.peerManager.penalizePeer(peerId, result.severity);
|
|
1215
1734
|
}
|
|
1216
1735
|
|
|
1217
|
-
return
|
|
1736
|
+
return result;
|
|
1218
1737
|
}
|
|
1219
1738
|
|
|
1220
1739
|
public getPeerScore(peerId: PeerId): number {
|
|
@@ -1228,7 +1747,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1228
1747
|
private async sendToPeers<T extends Gossipable>(message: T) {
|
|
1229
1748
|
const parent = message.constructor as typeof Gossipable;
|
|
1230
1749
|
|
|
1231
|
-
const identifier = await message.
|
|
1750
|
+
const identifier = await message.p2pMessageLoggingIdentifier().then(i => i.toString());
|
|
1232
1751
|
this.logger.trace(`Sending message ${identifier}`, { p2pMessageIdentifier: identifier });
|
|
1233
1752
|
|
|
1234
1753
|
const recipientsNum = await this.publishToTopic(this.topicStrings[parent.p2pTopic], message);
|