@aztec/p2p 0.0.1-commit.9b94fc1 → 0.0.1-commit.9badcec54
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +129 -3
- 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 +11 -11
- package/dest/client/factory.d.ts.map +1 -1
- package/dest/client/factory.js +60 -20
- package/dest/client/interface.d.ts +68 -35
- package/dest/client/interface.d.ts.map +1 -1
- package/dest/client/p2p_client.d.ts +53 -65
- package/dest/client/p2p_client.d.ts.map +1 -1
- package/dest/client/p2p_client.js +632 -335
- 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 +315 -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 +137 -87
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +124 -54
- package/dest/errors/p2p-service.error.d.ts +9 -0
- package/dest/errors/p2p-service.error.d.ts.map +1 -0
- package/dest/errors/p2p-service.error.js +10 -0
- package/dest/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 -2
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +1 -1
- package/dest/mem_pools/attestation_pool/attestation_pool.d.ts +113 -76
- package/dest/mem_pools/attestation_pool/attestation_pool.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/attestation_pool.js +448 -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 -289
- 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 +11 -8
- 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 -3
- 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 +33 -13
- 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_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 +94 -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 +180 -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 +75 -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 +215 -0
- package/dest/mem_pools/tx_pool_v2/interfaces.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/interfaces.js +10 -0
- package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts +134 -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 +220 -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 +337 -0
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts +62 -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 +167 -0
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts +78 -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 +923 -0
- package/dest/msg_validators/attestation_validator/attestation_validator.d.ts +8 -5
- package/dest/msg_validators/attestation_validator/attestation_validator.d.ts.map +1 -1
- package/dest/msg_validators/attestation_validator/attestation_validator.js +63 -21
- package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts +9 -7
- package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts.map +1 -1
- package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.js +24 -15
- package/dest/msg_validators/clock_tolerance.d.ts +32 -0
- package/dest/msg_validators/clock_tolerance.d.ts.map +1 -0
- package/dest/msg_validators/clock_tolerance.js +88 -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/proposal_validator/block_proposal_validator.d.ts +12 -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 +14 -0
- package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts +12 -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 +20 -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 +20 -0
- package/dest/msg_validators/proposal_validator/proposal_validator.d.ts.map +1 -0
- package/dest/msg_validators/proposal_validator/proposal_validator.js +124 -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 +2 -1
- package/dest/msg_validators/tx_validator/allowed_public_setup.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/allowed_public_setup.js +24 -20
- package/dest/msg_validators/tx_validator/allowed_setup_helpers.d.ts +17 -0
- package/dest/msg_validators/tx_validator/allowed_setup_helpers.d.ts.map +1 -0
- package/dest/msg_validators/tx_validator/allowed_setup_helpers.js +24 -0
- 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/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/contract_instance_validator.d.ts +9 -0
- package/dest/msg_validators/tx_validator/contract_instance_validator.d.ts.map +1 -0
- package/dest/msg_validators/tx_validator/contract_instance_validator.js +48 -0
- 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 +39 -3
- 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 +139 -6
- package/dest/msg_validators/tx_validator/factory.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/factory.js +255 -58
- 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 +24 -0
- package/dest/msg_validators/tx_validator/gas_validator.d.ts +68 -3
- package/dest/msg_validators/tx_validator/gas_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/gas_validator.js +122 -58
- package/dest/msg_validators/tx_validator/index.d.ts +4 -1
- package/dest/msg_validators/tx_validator/index.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/index.js +3 -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 +6 -6
- 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 +24 -3
- package/dest/msg_validators/tx_validator/phases_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/phases_validator.js +75 -27
- 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 +14 -10
- package/dest/services/discv5/discV5_service.js +1 -1
- package/dest/services/dummy_service.d.ts +31 -4
- package/dest/services/dummy_service.d.ts.map +1 -1
- package/dest/services/dummy_service.js +54 -1
- package/dest/services/encoding.d.ts +7 -3
- package/dest/services/encoding.d.ts.map +1 -1
- package/dest/services/encoding.js +23 -15
- 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 +184 -0
- package/dest/services/gossipsub/topic_score_params.d.ts.map +1 -0
- package/dest/services/gossipsub/topic_score_params.js +363 -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 +43 -71
- package/dest/services/libp2p/libp2p_service.d.ts +109 -44
- package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
- package/dest/services/libp2p/libp2p_service.js +1128 -431
- 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 -21
- package/dest/services/peer-manager/peer_manager.d.ts +7 -3
- package/dest/services/peer-manager/peer_manager.d.ts.map +1 -1
- package/dest/services/peer-manager/peer_manager.js +43 -23
- 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 +64 -16
- package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts +51 -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 +543 -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 +47 -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 +35 -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 +136 -0
- package/dest/services/reqresp/batch-tx-requester/peer_collection.d.ts +62 -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 +176 -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 +3 -3
- package/dest/services/reqresp/config.d.ts.map +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 -1
- 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/interface.d.ts +25 -9
- package/dest/services/reqresp/interface.d.ts.map +1 -1
- package/dest/services/reqresp/interface.js +23 -10
- 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 +16 -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_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 -7
- 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/index.d.ts +1 -2
- package/dest/services/reqresp/protocols/index.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/index.js +0 -1
- package/dest/services/reqresp/protocols/status.d.ts +5 -4
- 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 +21 -3
- package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts +5 -4
- package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts.map +1 -1
- package/dest/services/reqresp/rate-limiter/rate_limiter.js +10 -8
- package/dest/services/reqresp/rate-limiter/rate_limits.d.ts +1 -1
- package/dest/services/reqresp/rate-limiter/rate_limits.d.ts.map +1 -1
- package/dest/services/reqresp/rate-limiter/rate_limits.js +0 -10
- package/dest/services/reqresp/reqresp.d.ts +9 -2
- package/dest/services/reqresp/reqresp.d.ts.map +1 -1
- package/dest/services/reqresp/reqresp.js +497 -58
- package/dest/services/service.d.ts +59 -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 -9
- package/dest/services/tx_collection/fast_tx_collection.d.ts.map +1 -1
- package/dest/services/tx_collection/fast_tx_collection.js +95 -84
- 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 +38 -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 +100 -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/proposal_tx_collector.d.ts +48 -0
- package/dest/services/tx_collection/proposal_tx_collector.d.ts.map +1 -0
- package/dest/services/tx_collection/proposal_tx_collector.js +50 -0
- package/dest/services/tx_collection/request_tracker.d.ts +53 -0
- package/dest/services/tx_collection/request_tracker.d.ts.map +1 -0
- package/dest/services/tx_collection/request_tracker.js +84 -0
- package/dest/services/tx_collection/slow_tx_collection.d.ts +9 -4
- package/dest/services/tx_collection/slow_tx_collection.d.ts.map +1 -1
- package/dest/services/tx_collection/slow_tx_collection.js +60 -26
- package/dest/services/tx_collection/tx_collection.d.ts +31 -20
- 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 +18 -8
- 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 +13 -7
- package/dest/services/tx_collection/tx_source.d.ts.map +1 -1
- package/dest/services/tx_collection/tx_source.js +26 -7
- 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/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-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 +40 -6
- package/dest/test-helpers/mock-pubsub.d.ts.map +1 -1
- package/dest/test-helpers/mock-pubsub.js +139 -13
- 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 +5 -5
- 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 +386 -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 +281 -134
- package/dest/testbench/worker_client_manager.d.ts +60 -6
- package/dest/testbench/worker_client_manager.d.ts.map +1 -1
- package/dest/testbench/worker_client_manager.js +280 -41
- package/dest/util.d.ts +3 -3
- package/dest/util.d.ts.map +1 -1
- package/package.json +18 -18
- package/src/bootstrap/bootstrap.ts +7 -4
- package/src/client/factory.ts +116 -45
- package/src/client/interface.ts +81 -36
- package/src/client/p2p_client.ts +299 -396
- package/src/client/test/tx_proposal_collector/README.md +227 -0
- package/src/client/test/tx_proposal_collector/proposal_tx_collector_worker.ts +355 -0
- package/src/client/test/tx_proposal_collector/proposal_tx_collector_worker_protocol.ts +43 -0
- package/src/config.ts +196 -64
- package/src/errors/p2p-service.error.ts +11 -0
- package/src/errors/tx-pool.error.ts +12 -0
- package/src/index.ts +1 -1
- package/src/mem_pools/attestation_pool/attestation_pool.ts +515 -78
- package/src/mem_pools/attestation_pool/attestation_pool_test_suite.ts +614 -322
- 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 +2 -2
- package/src/mem_pools/instrumentation.ts +43 -14
- package/src/mem_pools/interface.ts +5 -7
- package/src/mem_pools/tx_pool_v2/README.md +283 -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 +122 -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 +219 -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 +99 -0
- package/src/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.ts +32 -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 +247 -0
- package/src/mem_pools/tx_pool_v2/tx_metadata.ts +343 -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 +430 -0
- package/src/mem_pools/tx_pool_v2/tx_pool_v2.ts +238 -0
- package/src/mem_pools/tx_pool_v2/tx_pool_v2_impl.ts +1105 -0
- package/src/msg_validators/attestation_validator/README.md +49 -0
- package/src/msg_validators/attestation_validator/attestation_validator.ts +51 -24
- package/src/msg_validators/attestation_validator/fisherman_attestation_validator.ts +25 -19
- package/src/msg_validators/clock_tolerance.ts +120 -0
- package/src/msg_validators/index.ts +1 -1
- package/src/msg_validators/proposal_validator/README.md +123 -0
- package/src/msg_validators/proposal_validator/block_proposal_validator.ts +23 -0
- package/src/msg_validators/proposal_validator/checkpoint_proposal_validator.ts +29 -0
- package/src/msg_validators/proposal_validator/index.ts +3 -0
- package/src/msg_validators/proposal_validator/proposal_validator.ts +122 -0
- package/src/msg_validators/tx_validator/README.md +119 -0
- package/src/msg_validators/tx_validator/aggregate_tx_validator.ts +5 -5
- package/src/msg_validators/tx_validator/allowed_public_setup.ts +22 -27
- package/src/msg_validators/tx_validator/allowed_setup_helpers.ts +31 -0
- package/src/msg_validators/tx_validator/archive_cache.ts +2 -2
- package/src/msg_validators/tx_validator/block_header_validator.ts +21 -8
- package/src/msg_validators/tx_validator/contract_instance_validator.ts +56 -0
- package/src/msg_validators/tx_validator/data_validator.ts +60 -7
- package/src/msg_validators/tx_validator/double_spend_validator.ts +15 -9
- package/src/msg_validators/tx_validator/factory.ts +416 -58
- package/src/msg_validators/tx_validator/fee_payer_balance.ts +44 -0
- package/src/msg_validators/tx_validator/gas_validator.ts +162 -61
- package/src/msg_validators/tx_validator/index.ts +3 -0
- package/src/msg_validators/tx_validator/metadata_validator.ts +31 -12
- package/src/msg_validators/tx_validator/nullifier_cache.ts +30 -0
- package/src/msg_validators/tx_validator/phases_validator.ts +87 -30
- 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 +14 -19
- package/src/services/discv5/discV5_service.ts +1 -1
- package/src/services/dummy_service.ts +71 -2
- package/src/services/encoding.ts +22 -13
- 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 +519 -0
- package/src/services/index.ts +1 -0
- package/src/services/libp2p/instrumentation.ts +48 -75
- package/src/services/libp2p/libp2p_service.ts +827 -461
- package/src/services/peer-manager/metrics.ts +46 -21
- package/src/services/peer-manager/peer_manager.ts +50 -15
- package/src/services/peer-manager/peer_scoring.ts +55 -9
- package/src/services/reqresp/README.md +229 -0
- package/src/services/reqresp/batch-tx-requester/README.md +344 -0
- package/src/services/reqresp/batch-tx-requester/batch_tx_requester.ts +673 -0
- package/src/services/reqresp/batch-tx-requester/config.ts +40 -0
- package/src/services/reqresp/batch-tx-requester/interface.ts +54 -0
- package/src/services/reqresp/batch-tx-requester/missing_txs.ts +168 -0
- package/src/services/reqresp/batch-tx-requester/peer_collection.ts +249 -0
- package/src/services/reqresp/batch-tx-requester/tx_validator.ts +37 -0
- package/src/services/reqresp/config.ts +2 -2
- 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 +48 -10
- package/src/services/reqresp/metrics.ts +35 -27
- package/src/services/reqresp/protocols/auth.ts +2 -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/index.ts +0 -1
- package/src/services/reqresp/protocols/status.ts +16 -12
- package/src/services/reqresp/protocols/tx.ts +24 -5
- package/src/services/reqresp/rate-limiter/rate_limiter.ts +13 -9
- package/src/services/reqresp/rate-limiter/rate_limits.ts +0 -10
- package/src/services/reqresp/reqresp.ts +116 -32
- package/src/services/service.ts +78 -5
- package/src/services/tx_collection/config.ts +84 -2
- package/src/services/tx_collection/fast_tx_collection.ts +114 -93
- package/src/services/tx_collection/file_store_tx_collection.ts +202 -0
- package/src/services/tx_collection/file_store_tx_source.ts +129 -0
- package/src/services/tx_collection/index.ts +6 -0
- package/src/services/tx_collection/instrumentation.ts +11 -13
- package/src/services/tx_collection/proposal_tx_collector.ts +108 -0
- package/src/services/tx_collection/request_tracker.ts +127 -0
- package/src/services/tx_collection/slow_tx_collection.ts +69 -36
- package/src/services/tx_collection/tx_collection.ts +123 -27
- package/src/services/tx_collection/tx_collection_sink.ts +30 -34
- package/src/services/tx_collection/tx_source.ts +28 -8
- 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 +4 -6
- package/src/test-helpers/mock-pubsub.ts +178 -15
- package/src/test-helpers/mock-tx-helpers.ts +1 -1
- package/src/test-helpers/reqresp-nodes.ts +8 -10
- package/src/test-helpers/test_tx_provider.ts +64 -0
- package/src/test-helpers/testbench-utils.ts +457 -0
- package/src/testbench/p2p_client_testbench_worker.ts +410 -131
- package/src/testbench/worker_client_manager.ts +367 -43
- package/src/util.ts +8 -2
- package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts +0 -37
- 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 -213
- package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts +0 -30
- 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 -219
- package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts +0 -115
- package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.js +0 -617
- package/dest/mem_pools/tx_pool/index.d.ts +0 -4
- package/dest/mem_pools/tx_pool/index.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/index.js +0 -3
- 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/mem_pools/tx_pool/priority.d.ts +0 -8
- package/dest/mem_pools/tx_pool/priority.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/priority.js +0 -10
- package/dest/mem_pools/tx_pool/tx_pool.d.ts +0 -122
- package/dest/mem_pools/tx_pool/tx_pool.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/tx_pool.js +0 -3
- package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts +0 -7
- package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/tx_pool_test_suite.js +0 -394
- 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 -82
- 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/dest/services/reqresp/protocols/block.d.ts +0 -9
- package/dest/services/reqresp/protocols/block.d.ts.map +0 -1
- package/dest/services/reqresp/protocols/block.js +0 -31
- package/src/mem_pools/attestation_pool/kv_attestation_pool.ts +0 -298
- package/src/mem_pools/attestation_pool/memory_attestation_pool.ts +0 -287
- package/src/mem_pools/tx_pool/aztec_kv_tx_pool.ts +0 -750
- package/src/mem_pools/tx_pool/index.ts +0 -3
- package/src/mem_pools/tx_pool/memory_tx_pool.ts +0 -283
- package/src/mem_pools/tx_pool/priority.ts +0 -13
- package/src/mem_pools/tx_pool/tx_pool.ts +0 -135
- package/src/mem_pools/tx_pool/tx_pool_test_suite.ts +0 -313
- package/src/msg_validators/block_proposal_validator/block_proposal_validator.ts +0 -97
- package/src/msg_validators/block_proposal_validator/index.ts +0 -1
- package/src/services/reqresp/protocols/block.ts +0 -36
|
@@ -1,34 +1,41 @@
|
|
|
1
1
|
import type { EpochCacheInterface } from '@aztec/epoch-cache';
|
|
2
|
-
import { SlotNumber } from '@aztec/foundation/branded-types';
|
|
3
|
-
import {
|
|
4
|
-
import { Fr } from '@aztec/foundation/fields';
|
|
2
|
+
import { BlockNumber, type SlotNumber } from '@aztec/foundation/branded-types';
|
|
3
|
+
import { maxBy } from '@aztec/foundation/collection';
|
|
5
4
|
import { type Logger, createLibp2pComponentLogger, createLogger } from '@aztec/foundation/log';
|
|
6
5
|
import { RunningPromise } from '@aztec/foundation/running-promise';
|
|
7
6
|
import { Timer } from '@aztec/foundation/timer';
|
|
8
7
|
import type { AztecAsyncKVStore } from '@aztec/kv-store';
|
|
9
|
-
import { getVKTreeRoot } from '@aztec/noir-protocol-circuits-types/vk-tree';
|
|
10
8
|
import { protocolContractsHash } from '@aztec/protocol-contracts';
|
|
11
|
-
import type { EthAddress,
|
|
9
|
+
import type { EthAddress, 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,
|
|
21
20
|
PeerErrorSeverity,
|
|
21
|
+
PeerErrorSeverityByHarshness,
|
|
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';
|
|
@@ -50,58 +57,65 @@ import { ENR } from '@nethermindeth/enr';
|
|
|
50
57
|
import { createLibp2p } from 'libp2p';
|
|
51
58
|
|
|
52
59
|
import type { P2PConfig } from '../../config.js';
|
|
53
|
-
import {
|
|
60
|
+
import { CheckpointProposalReceivedCallbackNotRegisteredError } from '../../errors/p2p-service.error.js';
|
|
54
61
|
import type { MemPools } from '../../mem_pools/interface.js';
|
|
55
62
|
import {
|
|
56
|
-
AttestationValidator,
|
|
57
63
|
BlockProposalValidator,
|
|
64
|
+
CheckpointAttestationValidator,
|
|
65
|
+
CheckpointProposalValidator,
|
|
66
|
+
DoubleSpendTxValidator,
|
|
58
67
|
FishermanAttestationValidator,
|
|
68
|
+
getDefaultAllowedSetupFunctions,
|
|
59
69
|
} from '../../msg_validators/index.js';
|
|
60
70
|
import { MessageSeenValidator } from '../../msg_validators/msg_seen_validator/msg_seen_validator.js';
|
|
61
|
-
import { getDefaultAllowedSetupFunctions } from '../../msg_validators/tx_validator/allowed_public_setup.js';
|
|
62
|
-
import { type MessageValidator, createTxMessageValidators } from '../../msg_validators/tx_validator/factory.js';
|
|
63
71
|
import {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
} from '../../msg_validators/tx_validator/
|
|
72
|
+
type TransactionValidator,
|
|
73
|
+
createFirstStageTxValidationsForGossipedTransactions,
|
|
74
|
+
createSecondStageTxValidationsForGossipedTransactions,
|
|
75
|
+
createTxValidatorForBlockProposalReceivedTxs,
|
|
76
|
+
createTxValidatorForReqResponseReceivedTxs,
|
|
77
|
+
} from '../../msg_validators/tx_validator/factory.js';
|
|
70
78
|
import { GossipSubEvent } from '../../types/index.js';
|
|
71
79
|
import { type PubSubLibp2p, convertToMultiaddr } from '../../util.js';
|
|
72
80
|
import { getVersions } from '../../versioning.js';
|
|
73
81
|
import { AztecDatastore } from '../data_store.js';
|
|
74
82
|
import { DiscV5Service } from '../discv5/discV5_service.js';
|
|
75
83
|
import { SnappyTransform, fastMsgIdFn, getMsgIdFn, msgIdToStrFn } from '../encoding.js';
|
|
76
|
-
import { gossipScoreThresholds } from '../gossipsub/scoring.js';
|
|
84
|
+
import { APP_SPECIFIC_WEIGHT, gossipScoreThresholds } from '../gossipsub/scoring.js';
|
|
85
|
+
import { createAllTopicScoreParams } from '../gossipsub/topic_score_params.js';
|
|
77
86
|
import type { PeerManagerInterface } from '../peer-manager/interface.js';
|
|
78
87
|
import { PeerManager } from '../peer-manager/peer_manager.js';
|
|
79
88
|
import { PeerScoring } from '../peer-manager/peer_scoring.js';
|
|
89
|
+
import type { BatchTxRequesterLibP2PService } from '../reqresp/batch-tx-requester/interface.js';
|
|
80
90
|
import type { P2PReqRespConfig } from '../reqresp/config.js';
|
|
81
91
|
import {
|
|
92
|
+
AuthRequest,
|
|
93
|
+
BlockTxsRequest,
|
|
94
|
+
BlockTxsResponse,
|
|
82
95
|
DEFAULT_SUB_PROTOCOL_VALIDATORS,
|
|
83
96
|
type ReqRespInterface,
|
|
97
|
+
type ReqRespResponse,
|
|
84
98
|
ReqRespSubProtocol,
|
|
85
99
|
type ReqRespSubProtocolHandler,
|
|
86
100
|
type ReqRespSubProtocolHandlers,
|
|
87
101
|
type ReqRespSubProtocolValidators,
|
|
102
|
+
StatusMessage,
|
|
88
103
|
type SubProtocolMap,
|
|
89
104
|
ValidationError,
|
|
90
|
-
} from '../reqresp/interface.js';
|
|
91
|
-
import { reqRespBlockTxsHandler } from '../reqresp/protocols/block_txs/block_txs_handler.js';
|
|
92
|
-
import { reqGoodbyeHandler } from '../reqresp/protocols/goodbye.js';
|
|
93
|
-
import {
|
|
94
|
-
AuthRequest,
|
|
95
|
-
BlockTxsRequest,
|
|
96
|
-
BlockTxsResponse,
|
|
97
|
-
StatusMessage,
|
|
98
105
|
pingHandler,
|
|
99
|
-
|
|
106
|
+
reqGoodbyeHandler,
|
|
107
|
+
reqRespBlockTxsHandler,
|
|
100
108
|
reqRespStatusHandler,
|
|
101
109
|
reqRespTxHandler,
|
|
102
|
-
} from '../reqresp/
|
|
110
|
+
} from '../reqresp/index.js';
|
|
103
111
|
import { ReqResp } from '../reqresp/reqresp.js';
|
|
104
|
-
import type {
|
|
112
|
+
import type {
|
|
113
|
+
P2PBlockReceivedCallback,
|
|
114
|
+
P2PCheckpointReceivedCallback,
|
|
115
|
+
P2PDuplicateAttestationCallback,
|
|
116
|
+
P2PService,
|
|
117
|
+
PeerDiscoveryService,
|
|
118
|
+
} from '../service.js';
|
|
105
119
|
import { P2PInstrumentation } from './instrumentation.js';
|
|
106
120
|
|
|
107
121
|
interface ValidationResult {
|
|
@@ -113,25 +127,36 @@ interface ValidationResult {
|
|
|
113
127
|
type ValidationOutcome = { allPassed: true } | { allPassed: false; failure: ValidationResult };
|
|
114
128
|
|
|
115
129
|
// REFACTOR: Unify with the type above
|
|
116
|
-
type ReceivedMessageValidationResult<T> =
|
|
117
|
-
| { obj: T; result: Exclude<TopicValidatorResult, TopicValidatorResult.Reject
|
|
118
|
-
| { 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; severity: PeerErrorSeverity };
|
|
119
133
|
|
|
120
134
|
/**
|
|
121
135
|
* Lib P2P implementation of the P2PService interface.
|
|
122
136
|
*/
|
|
123
|
-
export class LibP2PService
|
|
137
|
+
export class LibP2PService extends WithTracer implements P2PService {
|
|
124
138
|
private discoveryRunningPromise?: RunningPromise;
|
|
125
139
|
private msgIdSeenValidators: Record<TopicType, MessageSeenValidator> = {} as Record<TopicType, MessageSeenValidator>;
|
|
126
140
|
|
|
127
141
|
// Message validators
|
|
128
|
-
private attestationValidator: AttestationValidator;
|
|
129
142
|
private blockProposalValidator: BlockProposalValidator;
|
|
143
|
+
private checkpointProposalValidator: CheckpointProposalValidator;
|
|
144
|
+
private checkpointAttestationValidator: CheckpointAttestationValidator;
|
|
130
145
|
|
|
131
146
|
private protocolVersion = '';
|
|
132
147
|
private topicStrings: Record<TopicType, string> = {} as Record<TopicType, string>;
|
|
133
148
|
|
|
134
|
-
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;
|
|
135
160
|
|
|
136
161
|
/**
|
|
137
162
|
* Callback for when a block is received from a peer.
|
|
@@ -140,21 +165,35 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
140
165
|
*/
|
|
141
166
|
private blockReceivedCallback: P2PBlockReceivedCallback;
|
|
142
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 allNodesCheckpointReceivedCallback: P2PCheckpointReceivedCallback;
|
|
174
|
+
/**
|
|
175
|
+
* Callback for when a checkpoint proposal is received - specifically for validators - from a peer.
|
|
176
|
+
* @param checkpoint - The checkpoint proposal received from the peer.
|
|
177
|
+
* @returns The attestations for the checkpoint, if any.
|
|
178
|
+
*/
|
|
179
|
+
private validatorCheckpointReceivedCallback: P2PCheckpointReceivedCallback;
|
|
180
|
+
|
|
143
181
|
private gossipSubEventHandler: (e: CustomEvent<GossipsubMessage>) => void;
|
|
144
182
|
|
|
145
183
|
private instrumentation: P2PInstrumentation;
|
|
146
184
|
|
|
185
|
+
private telemetry: TelemetryClient;
|
|
186
|
+
|
|
147
187
|
protected logger: Logger;
|
|
148
188
|
|
|
149
189
|
constructor(
|
|
150
|
-
private clientType: T,
|
|
151
190
|
private config: P2PConfig,
|
|
152
191
|
protected node: PubSubLibp2p,
|
|
153
192
|
private peerDiscoveryService: PeerDiscoveryService,
|
|
154
193
|
private reqresp: ReqRespInterface,
|
|
155
|
-
|
|
156
|
-
protected mempools: MemPools
|
|
157
|
-
|
|
194
|
+
protected peerManager: PeerManagerInterface,
|
|
195
|
+
protected mempools: MemPools,
|
|
196
|
+
protected archiver: L2BlockSource & ContractDataSource,
|
|
158
197
|
private epochCache: EpochCacheInterface,
|
|
159
198
|
private proofVerifier: ClientProtocolCircuitVerifier,
|
|
160
199
|
private worldStateSynchronizer: WorldStateSynchronizer,
|
|
@@ -162,6 +201,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
162
201
|
logger: Logger = createLogger('p2p:libp2p_service'),
|
|
163
202
|
) {
|
|
164
203
|
super(telemetry, 'LibP2PService');
|
|
204
|
+
this.telemetry = telemetry;
|
|
165
205
|
|
|
166
206
|
// Create child logger with fisherman prefix if in fisherman mode
|
|
167
207
|
this.logger = config.fishermanMode ? logger.createChild('[FISHERMAN]') : logger;
|
|
@@ -170,7 +210,8 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
170
210
|
|
|
171
211
|
this.msgIdSeenValidators[TopicType.tx] = new MessageSeenValidator(config.seenMessageCacheSize);
|
|
172
212
|
this.msgIdSeenValidators[TopicType.block_proposal] = new MessageSeenValidator(config.seenMessageCacheSize);
|
|
173
|
-
this.msgIdSeenValidators[TopicType.
|
|
213
|
+
this.msgIdSeenValidators[TopicType.checkpoint_proposal] = new MessageSeenValidator(config.seenMessageCacheSize);
|
|
214
|
+
this.msgIdSeenValidators[TopicType.checkpoint_attestation] = new MessageSeenValidator(config.seenMessageCacheSize);
|
|
174
215
|
|
|
175
216
|
const versions = getVersions(config);
|
|
176
217
|
this.protocolVersion = compressComponentVersions(versions);
|
|
@@ -178,25 +219,49 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
178
219
|
|
|
179
220
|
this.topicStrings[TopicType.tx] = createTopicString(TopicType.tx, this.protocolVersion);
|
|
180
221
|
this.topicStrings[TopicType.block_proposal] = createTopicString(TopicType.block_proposal, this.protocolVersion);
|
|
181
|
-
this.topicStrings[TopicType.
|
|
182
|
-
TopicType.
|
|
222
|
+
this.topicStrings[TopicType.checkpoint_proposal] = createTopicString(
|
|
223
|
+
TopicType.checkpoint_proposal,
|
|
224
|
+
this.protocolVersion,
|
|
225
|
+
);
|
|
226
|
+
this.topicStrings[TopicType.checkpoint_attestation] = createTopicString(
|
|
227
|
+
TopicType.checkpoint_attestation,
|
|
183
228
|
this.protocolVersion,
|
|
184
229
|
);
|
|
185
230
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
:
|
|
190
|
-
|
|
231
|
+
const p2pPropagationTime = config.attestationPropagationTime;
|
|
232
|
+
const proposalValidatorOpts = {
|
|
233
|
+
txsPermitted: !config.disableTransactions,
|
|
234
|
+
maxTxsPerBlock: config.validateMaxTxsPerBlock ?? config.validateMaxTxsPerCheckpoint,
|
|
235
|
+
p2pPropagationTime,
|
|
236
|
+
};
|
|
237
|
+
this.blockProposalValidator = new BlockProposalValidator(epochCache, proposalValidatorOpts);
|
|
238
|
+
this.checkpointProposalValidator = new CheckpointProposalValidator(epochCache, proposalValidatorOpts);
|
|
239
|
+
this.checkpointAttestationValidator = config.fishermanMode
|
|
240
|
+
? new FishermanAttestationValidator(epochCache, mempools.attestationPool, telemetry, {
|
|
241
|
+
l1PublishingTime: config.l1PublishingTime,
|
|
242
|
+
})
|
|
243
|
+
: new CheckpointAttestationValidator(epochCache, { l1PublishingTime: config.l1PublishingTime });
|
|
191
244
|
|
|
192
245
|
this.gossipSubEventHandler = this.handleGossipSubEvent.bind(this);
|
|
193
246
|
|
|
194
|
-
this.blockReceivedCallback = async (block: BlockProposal): Promise<
|
|
195
|
-
this.logger.
|
|
196
|
-
`Handler not yet registered
|
|
247
|
+
this.blockReceivedCallback = async (block: BlockProposal): Promise<boolean> => {
|
|
248
|
+
this.logger.warn(
|
|
249
|
+
`Handler for block received not yet registered on P2P service. Received block ${block.blockNumber} for slot ${block.slotNumber} from peer.`,
|
|
197
250
|
{ p2pMessageIdentifier: await block.p2pMessageLoggingIdentifier() },
|
|
198
251
|
);
|
|
199
|
-
return
|
|
252
|
+
return true;
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
this.allNodesCheckpointReceivedCallback = (
|
|
256
|
+
_checkpoint: CheckpointProposalCore,
|
|
257
|
+
): Promise<CheckpointAttestation[] | undefined> => {
|
|
258
|
+
throw new CheckpointProposalReceivedCallbackNotRegisteredError();
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
this.validatorCheckpointReceivedCallback = (
|
|
262
|
+
_checkpoint: CheckpointProposalCore,
|
|
263
|
+
): Promise<CheckpointAttestation[] | undefined> => {
|
|
264
|
+
return Promise.resolve(undefined);
|
|
200
265
|
};
|
|
201
266
|
}
|
|
202
267
|
|
|
@@ -210,12 +275,11 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
210
275
|
* @param txPool - The transaction pool to be accessed by the service.
|
|
211
276
|
* @returns The new service.
|
|
212
277
|
*/
|
|
213
|
-
public static async new
|
|
214
|
-
clientType: T,
|
|
278
|
+
public static async new(
|
|
215
279
|
config: P2PConfig,
|
|
216
280
|
peerId: PeerId,
|
|
217
281
|
deps: {
|
|
218
|
-
mempools: MemPools
|
|
282
|
+
mempools: MemPools;
|
|
219
283
|
l2BlockSource: L2BlockSource & ContractDataSource;
|
|
220
284
|
epochCache: EpochCacheInterface;
|
|
221
285
|
proofVerifier: ClientProtocolCircuitVerifier;
|
|
@@ -242,14 +306,14 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
242
306
|
|
|
243
307
|
const datastore = new AztecDatastore(peerStore);
|
|
244
308
|
|
|
245
|
-
const otelMetricsAdapter = new OtelMetricsAdapter(telemetry);
|
|
309
|
+
const otelMetricsAdapter = new OtelMetricsAdapter(telemetry, logger.getBindings());
|
|
246
310
|
|
|
247
311
|
const peerDiscoveryService = new DiscV5Service(
|
|
248
312
|
peerId,
|
|
249
313
|
config,
|
|
250
314
|
packageVersion,
|
|
251
315
|
telemetry,
|
|
252
|
-
createLogger(`${logger.module}:discv5_service
|
|
316
|
+
createLogger(`${logger.module}:discv5_service`, logger.getBindings()),
|
|
253
317
|
);
|
|
254
318
|
|
|
255
319
|
// Seed libp2p's bootstrap discovery with private and trusted peers
|
|
@@ -263,10 +327,6 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
263
327
|
const versions = getVersions(config);
|
|
264
328
|
const protocolVersion = compressComponentVersions(versions);
|
|
265
329
|
|
|
266
|
-
const txTopic = createTopicString(TopicType.tx, protocolVersion);
|
|
267
|
-
const blockProposalTopic = createTopicString(TopicType.block_proposal, protocolVersion);
|
|
268
|
-
const blockAttestationTopic = createTopicString(TopicType.block_attestation, protocolVersion);
|
|
269
|
-
|
|
270
330
|
const preferredPeersEnrs: ENR[] = config.preferredPeers.map(enr => ENR.decodeTxt(enr));
|
|
271
331
|
const directPeers = (
|
|
272
332
|
await Promise.all(
|
|
@@ -286,6 +346,19 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
286
346
|
|
|
287
347
|
const announceTcpMultiaddr = config.p2pIp ? [convertToMultiaddr(config.p2pIp, p2pPort, 'tcp')] : [];
|
|
288
348
|
|
|
349
|
+
// Create dynamic topic score params based on network configuration
|
|
350
|
+
const l1Constants = epochCache.getL1Constants();
|
|
351
|
+
const topicScoreParams = createAllTopicScoreParams(protocolVersion, {
|
|
352
|
+
slotDurationMs: l1Constants.slotDuration * 1000,
|
|
353
|
+
ethereumSlotDuration: l1Constants.ethereumSlotDuration,
|
|
354
|
+
heartbeatIntervalMs: config.gossipsubInterval,
|
|
355
|
+
targetCommitteeSize: l1Constants.targetCommitteeSize,
|
|
356
|
+
blockDurationMs: config.blockDurationMs,
|
|
357
|
+
l1PublishingTime: config.l1PublishingTime,
|
|
358
|
+
p2pPropagationTime: config.attestationPropagationTime,
|
|
359
|
+
expectedBlockProposalsPerSlot: config.expectedBlockProposalsPerSlot,
|
|
360
|
+
});
|
|
361
|
+
|
|
289
362
|
const node = await createLibp2p({
|
|
290
363
|
start: false,
|
|
291
364
|
peerId,
|
|
@@ -381,30 +454,14 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
381
454
|
scoreParams: createPeerScoreParams({
|
|
382
455
|
// IPColocation factor can be disabled for local testing - default to -5
|
|
383
456
|
IPColocationFactorWeight: config.debugDisableColocationPenalty ? 0 : -5.0,
|
|
384
|
-
topics:
|
|
385
|
-
[txTopic]: createTopicScoreParams({
|
|
386
|
-
topicWeight: 1,
|
|
387
|
-
invalidMessageDeliveriesWeight: -20,
|
|
388
|
-
invalidMessageDeliveriesDecay: 0.5,
|
|
389
|
-
}),
|
|
390
|
-
[blockAttestationTopic]: createTopicScoreParams({
|
|
391
|
-
topicWeight: 1,
|
|
392
|
-
invalidMessageDeliveriesWeight: -20,
|
|
393
|
-
invalidMessageDeliveriesDecay: 0.5,
|
|
394
|
-
}),
|
|
395
|
-
[blockProposalTopic]: createTopicScoreParams({
|
|
396
|
-
topicWeight: 1,
|
|
397
|
-
invalidMessageDeliveriesWeight: -20,
|
|
398
|
-
invalidMessageDeliveriesDecay: 0.5,
|
|
399
|
-
}),
|
|
400
|
-
},
|
|
457
|
+
topics: topicScoreParams,
|
|
401
458
|
}),
|
|
402
459
|
}) as (components: GossipSubComponents) => GossipSub,
|
|
403
460
|
components: (components: { connectionManager: ConnectionManager }) => ({
|
|
404
461
|
connectionManager: components.connectionManager,
|
|
405
462
|
}),
|
|
406
463
|
},
|
|
407
|
-
logger: createLibp2pComponentLogger(logger.module),
|
|
464
|
+
logger: createLibp2pComponentLogger(logger.module, logger.getBindings()),
|
|
408
465
|
});
|
|
409
466
|
|
|
410
467
|
const peerScoring = new PeerScoring(config, telemetry);
|
|
@@ -423,13 +480,19 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
423
480
|
epochCache,
|
|
424
481
|
);
|
|
425
482
|
|
|
426
|
-
//
|
|
427
|
-
|
|
483
|
+
// Gate req/resp data protocols for unauthenticated peers when p2pAllowOnlyValidators is enabled
|
|
484
|
+
reqresp.setShouldRejectPeer(peerId => peerManager.shouldDisableP2PGossip(peerId));
|
|
485
|
+
|
|
486
|
+
// Configure application-specific scoring for gossipsub.
|
|
487
|
+
// The weight scales app score to align with gossipsub thresholds:
|
|
488
|
+
// - Disconnect (-50) × 10 = -500 = gossipThreshold (stops receiving gossip)
|
|
489
|
+
// - Ban (-100) × 10 = -1000 = publishThreshold (cannot publish)
|
|
490
|
+
// Note: positive topic scores can offset penalties, so alignment is best-effort.
|
|
491
|
+
node.services.pubsub.score.params.appSpecificWeight = APP_SPECIFIC_WEIGHT;
|
|
428
492
|
node.services.pubsub.score.params.appSpecificScore = (peerId: string) =>
|
|
429
493
|
peerManager.shouldDisableP2PGossip(peerId) ? -Infinity : peerManager.getPeerScore(peerId);
|
|
430
494
|
|
|
431
495
|
return new LibP2PService(
|
|
432
|
-
clientType,
|
|
433
496
|
config,
|
|
434
497
|
node,
|
|
435
498
|
peerDiscoveryService,
|
|
@@ -462,33 +525,23 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
462
525
|
}
|
|
463
526
|
const announceTcpMultiaddr = convertToMultiaddr(p2pIp, p2pPort, 'tcp');
|
|
464
527
|
|
|
465
|
-
await this.peerManager.initializePeers();
|
|
466
|
-
if (!this.config.p2pDiscoveryDisabled) {
|
|
467
|
-
await this.peerDiscoveryService.start();
|
|
468
|
-
}
|
|
469
|
-
await this.node.start();
|
|
470
|
-
|
|
471
|
-
// Subscribe to standard GossipSub topics by default
|
|
472
|
-
for (const topic of getTopicsForClientAndConfig(this.clientType, this.config.disableTransactions)) {
|
|
473
|
-
this.subscribeToTopic(this.topicStrings[topic]);
|
|
474
|
-
}
|
|
475
|
-
|
|
476
528
|
// Create request response protocol handlers
|
|
477
529
|
const txHandler = reqRespTxHandler(this.mempools);
|
|
478
530
|
const goodbyeHandler = reqGoodbyeHandler(this.peerManager);
|
|
479
|
-
const blockHandler = reqRespBlockHandler(this.archiver);
|
|
480
531
|
const statusHandler = reqRespStatusHandler(this.protocolVersion, this.worldStateSynchronizer, this.logger);
|
|
481
532
|
|
|
482
533
|
const requestResponseHandlers: Partial<ReqRespSubProtocolHandlers> = {
|
|
483
534
|
[ReqRespSubProtocol.PING]: pingHandler,
|
|
484
535
|
[ReqRespSubProtocol.STATUS]: statusHandler.bind(this),
|
|
485
536
|
[ReqRespSubProtocol.GOODBYE]: goodbyeHandler.bind(this),
|
|
486
|
-
[ReqRespSubProtocol.BLOCK]: blockHandler.bind(this),
|
|
487
537
|
};
|
|
488
538
|
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
539
|
+
if (!this.config.disableTransactions) {
|
|
540
|
+
const blockTxsHandler = reqRespBlockTxsHandler(
|
|
541
|
+
this.mempools.attestationPool,
|
|
542
|
+
this.archiver,
|
|
543
|
+
this.mempools.txPool,
|
|
544
|
+
);
|
|
492
545
|
requestResponseHandlers[ReqRespSubProtocol.BLOCK_TXS] = blockTxsHandler.bind(this);
|
|
493
546
|
}
|
|
494
547
|
|
|
@@ -496,10 +549,31 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
496
549
|
requestResponseHandlers[ReqRespSubProtocol.TX] = txHandler.bind(this);
|
|
497
550
|
}
|
|
498
551
|
|
|
552
|
+
// Define the sub protocol validators - This is done within this start() method to gain a callback to the existing validateTx function
|
|
553
|
+
const reqrespSubProtocolValidators = {
|
|
554
|
+
...DEFAULT_SUB_PROTOCOL_VALIDATORS,
|
|
555
|
+
[ReqRespSubProtocol.TX]: this.validateRequestedTxs.bind(this),
|
|
556
|
+
[ReqRespSubProtocol.BLOCK_TXS]: this.validateRequestedBlockTxs.bind(this),
|
|
557
|
+
};
|
|
558
|
+
|
|
559
|
+
await this.peerManager.initializePeers();
|
|
560
|
+
|
|
561
|
+
await this.reqresp.start(requestResponseHandlers, reqrespSubProtocolValidators);
|
|
562
|
+
|
|
563
|
+
await this.node.start();
|
|
564
|
+
|
|
565
|
+
// Subscribe to standard GossipSub topics by default
|
|
566
|
+
for (const topic of getTopicsForConfig(this.config.disableTransactions)) {
|
|
567
|
+
this.subscribeToTopic(this.topicStrings[topic]);
|
|
568
|
+
}
|
|
569
|
+
|
|
499
570
|
// add GossipSub listener
|
|
500
571
|
this.node.services.pubsub.addEventListener(GossipSubEvent.MESSAGE, this.gossipSubEventHandler);
|
|
501
572
|
|
|
502
573
|
// Start running promise for peer discovery and metrics collection
|
|
574
|
+
if (!this.config.p2pDiscoveryDisabled) {
|
|
575
|
+
await this.peerDiscoveryService.start();
|
|
576
|
+
}
|
|
503
577
|
this.discoveryRunningPromise = new RunningPromise(
|
|
504
578
|
async () => {
|
|
505
579
|
await this.peerManager.heartbeat();
|
|
@@ -509,14 +583,6 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
509
583
|
);
|
|
510
584
|
this.discoveryRunningPromise.start();
|
|
511
585
|
|
|
512
|
-
// Define the sub protocol validators - This is done within this start() method to gain a callback to the existing validateTx function
|
|
513
|
-
const reqrespSubProtocolValidators = {
|
|
514
|
-
...DEFAULT_SUB_PROTOCOL_VALIDATORS,
|
|
515
|
-
[ReqRespSubProtocol.TX]: this.validateRequestedTxs.bind(this),
|
|
516
|
-
[ReqRespSubProtocol.BLOCK_TXS]: this.validateRequestedBlockTxs.bind(this),
|
|
517
|
-
[ReqRespSubProtocol.BLOCK]: this.validateRequestedBlock.bind(this),
|
|
518
|
-
};
|
|
519
|
-
await this.reqresp.start(requestResponseHandlers, reqrespSubProtocolValidators);
|
|
520
586
|
this.logger.info(`Started P2P service`, {
|
|
521
587
|
listen: this.config.listenAddress,
|
|
522
588
|
port: this.config.p2pPort,
|
|
@@ -563,6 +629,10 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
563
629
|
return this.peerManager.getPeers(includePending);
|
|
564
630
|
}
|
|
565
631
|
|
|
632
|
+
public getGossipMeshPeerCount(topicType: TopicType): number {
|
|
633
|
+
return this.node.services.pubsub.getMeshPeers(this.topicStrings[topicType]).length;
|
|
634
|
+
}
|
|
635
|
+
|
|
566
636
|
private handleGossipSubEvent(e: CustomEvent<GossipsubMessage>) {
|
|
567
637
|
this.logger.trace(`Received PUBSUB message.`);
|
|
568
638
|
|
|
@@ -590,6 +660,15 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
590
660
|
return this.reqresp.sendBatchRequest(protocol, requests, pinnedPeerId);
|
|
591
661
|
}
|
|
592
662
|
|
|
663
|
+
public sendRequestToPeer(
|
|
664
|
+
peerId: PeerId,
|
|
665
|
+
subProtocol: ReqRespSubProtocol,
|
|
666
|
+
payload: Buffer,
|
|
667
|
+
dialTimeout?: number,
|
|
668
|
+
): Promise<ReqRespResponse> {
|
|
669
|
+
return this.reqresp.sendRequestToPeer(peerId, subProtocol, payload, dialTimeout);
|
|
670
|
+
}
|
|
671
|
+
|
|
593
672
|
/**
|
|
594
673
|
* Get the ENR of the node
|
|
595
674
|
* @returns The ENR of the node
|
|
@@ -602,6 +681,37 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
602
681
|
this.blockReceivedCallback = callback;
|
|
603
682
|
}
|
|
604
683
|
|
|
684
|
+
public registerValidatorCheckpointReceivedCallback(callback: P2PCheckpointReceivedCallback) {
|
|
685
|
+
this.validatorCheckpointReceivedCallback = callback;
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
public registerAllNodesCheckpointReceivedCallback(callback: P2PCheckpointReceivedCallback) {
|
|
689
|
+
this.allNodesCheckpointReceivedCallback = callback;
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
public async notifyOwnCheckpointProposal(checkpoint: CheckpointProposalCore): Promise<void> {
|
|
693
|
+
await this.allNodesCheckpointReceivedCallback(checkpoint, this.node.peerId);
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
/**
|
|
697
|
+
* Registers a callback to be invoked when a duplicate proposal is detected.
|
|
698
|
+
* This callback is triggered on the first duplicate (when count goes from 1 to 2).
|
|
699
|
+
*/
|
|
700
|
+
public registerDuplicateProposalCallback(
|
|
701
|
+
callback: (info: { slot: SlotNumber; proposer: EthAddress; type: 'checkpoint' | 'block' }) => void,
|
|
702
|
+
): void {
|
|
703
|
+
this.duplicateProposalCallback = callback;
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
/**
|
|
707
|
+
* Registers a callback to be invoked when a duplicate attestation is detected.
|
|
708
|
+
* A validator signing attestations for different proposals at the same slot.
|
|
709
|
+
* This callback is triggered on the first duplicate (when count goes from 1 to 2).
|
|
710
|
+
*/
|
|
711
|
+
public registerDuplicateAttestationCallback(callback: P2PDuplicateAttestationCallback): void {
|
|
712
|
+
this.duplicateAttestationCallback = callback;
|
|
713
|
+
}
|
|
714
|
+
|
|
605
715
|
/**
|
|
606
716
|
* Subscribes to a topic.
|
|
607
717
|
* @param topic - The topic to subscribe to.
|
|
@@ -623,7 +733,10 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
623
733
|
if (!this.node.services.pubsub) {
|
|
624
734
|
throw new Error('Pubsub service not available.');
|
|
625
735
|
}
|
|
626
|
-
const
|
|
736
|
+
const isBlockProposal = topic === this.topicStrings[TopicType.block_proposal];
|
|
737
|
+
const traceContext =
|
|
738
|
+
this.config.debugP2PInstrumentMessages && isBlockProposal ? this.telemetry.getTraceContext() : undefined;
|
|
739
|
+
const p2pMessage = P2PMessage.fromGossipable(message, this.config.debugP2PInstrumentMessages, traceContext);
|
|
627
740
|
const result = await this.node.services.pubsub.publish(topic, p2pMessage.toMessageData());
|
|
628
741
|
return result.recipients.length;
|
|
629
742
|
}
|
|
@@ -644,12 +757,15 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
644
757
|
case this.topicStrings[TopicType.tx]:
|
|
645
758
|
topicType = TopicType.tx;
|
|
646
759
|
break;
|
|
647
|
-
case this.topicStrings[TopicType.block_attestation]:
|
|
648
|
-
topicType = TopicType.block_attestation;
|
|
649
|
-
break;
|
|
650
760
|
case this.topicStrings[TopicType.block_proposal]:
|
|
651
761
|
topicType = TopicType.block_proposal;
|
|
652
762
|
break;
|
|
763
|
+
case this.topicStrings[TopicType.checkpoint_proposal]:
|
|
764
|
+
topicType = TopicType.checkpoint_proposal;
|
|
765
|
+
break;
|
|
766
|
+
case this.topicStrings[TopicType.checkpoint_attestation]:
|
|
767
|
+
topicType = TopicType.checkpoint_attestation;
|
|
768
|
+
break;
|
|
653
769
|
default:
|
|
654
770
|
this.logger.error(`Received message on unknown topic: ${msg.topic}`);
|
|
655
771
|
break;
|
|
@@ -660,6 +776,9 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
660
776
|
if (!validator || !validator.addMessage(msgId)) {
|
|
661
777
|
this.instrumentation.incMessagePrevalidationStatus(false, topicType);
|
|
662
778
|
this.node.services.pubsub.reportMessageValidationResult(msgId, source.toString(), TopicValidatorResult.Ignore);
|
|
779
|
+
if (topicType === TopicType.tx) {
|
|
780
|
+
this.logger.verbose(`Ignoring already-seen tx gossip message`, { msgId, source: source.toString() });
|
|
781
|
+
}
|
|
663
782
|
return { result: false, topicType };
|
|
664
783
|
}
|
|
665
784
|
|
|
@@ -708,74 +827,217 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
708
827
|
return;
|
|
709
828
|
}
|
|
710
829
|
|
|
830
|
+
// Determine topic type for attributes
|
|
711
831
|
if (msg.topic === this.topicStrings[TopicType.tx]) {
|
|
712
832
|
topicType = TopicType.tx;
|
|
713
|
-
|
|
833
|
+
} else if (msg.topic === this.topicStrings[TopicType.checkpoint_attestation]) {
|
|
834
|
+
topicType = TopicType.checkpoint_attestation;
|
|
835
|
+
} else if (msg.topic === this.topicStrings[TopicType.block_proposal]) {
|
|
836
|
+
topicType = TopicType.block_proposal;
|
|
837
|
+
} else if (msg.topic === this.topicStrings[TopicType.checkpoint_proposal]) {
|
|
838
|
+
topicType = TopicType.checkpoint_proposal;
|
|
714
839
|
}
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
840
|
+
|
|
841
|
+
// Process the message, optionally within a linked span for trace propagation
|
|
842
|
+
const processMessage = async () => {
|
|
843
|
+
if (msg.topic === this.topicStrings[TopicType.tx]) {
|
|
844
|
+
await this.handleGossipedTx(p2pMessage.payload, msgId, source);
|
|
845
|
+
} else if (msg.topic === this.topicStrings[TopicType.checkpoint_attestation]) {
|
|
846
|
+
await this.processCheckpointAttestationFromPeer(p2pMessage.payload, msgId, source);
|
|
847
|
+
} else if (msg.topic === this.topicStrings[TopicType.block_proposal]) {
|
|
848
|
+
await this.processBlockFromPeer(p2pMessage.payload, msgId, source);
|
|
849
|
+
} else if (msg.topic === this.topicStrings[TopicType.checkpoint_proposal]) {
|
|
850
|
+
await this.handleGossipedCheckpointProposal(p2pMessage.payload, msgId, source);
|
|
851
|
+
} else {
|
|
852
|
+
this.logger.error(`Received message on unknown topic: ${msg.topic}`);
|
|
719
853
|
}
|
|
720
|
-
}
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
854
|
+
};
|
|
855
|
+
|
|
856
|
+
const latency = p2pMessage.timestamp !== undefined ? msgReceivedTime - p2pMessage.timestamp.getTime() : undefined;
|
|
857
|
+
const propagatedContext = p2pMessage.traceContext
|
|
858
|
+
? this.telemetry.extractPropagatedContext(p2pMessage.traceContext)
|
|
859
|
+
: undefined;
|
|
860
|
+
|
|
861
|
+
if (propagatedContext) {
|
|
862
|
+
await this.tracer.startActiveSpan(
|
|
863
|
+
'LibP2PService.processMessage',
|
|
864
|
+
{
|
|
865
|
+
attributes: {
|
|
866
|
+
[Attributes.TOPIC_NAME]: topicType!,
|
|
867
|
+
[Attributes.PEER_ID]: source.toString(),
|
|
868
|
+
},
|
|
869
|
+
},
|
|
870
|
+
propagatedContext,
|
|
871
|
+
async span => {
|
|
872
|
+
try {
|
|
873
|
+
await processMessage();
|
|
874
|
+
span.setStatus({
|
|
875
|
+
code: SpanStatusCode.OK,
|
|
876
|
+
});
|
|
877
|
+
} catch (err) {
|
|
878
|
+
span.setStatus({
|
|
879
|
+
code: SpanStatusCode.ERROR,
|
|
880
|
+
message: String(err),
|
|
881
|
+
});
|
|
882
|
+
if (typeof err === 'string' || (err && err instanceof Error)) {
|
|
883
|
+
span.recordException(err);
|
|
884
|
+
}
|
|
885
|
+
throw err;
|
|
886
|
+
} finally {
|
|
887
|
+
span.end();
|
|
888
|
+
}
|
|
889
|
+
},
|
|
890
|
+
);
|
|
891
|
+
} else {
|
|
892
|
+
await processMessage();
|
|
724
893
|
}
|
|
725
894
|
|
|
726
|
-
if (
|
|
727
|
-
const latency = msgReceivedTime - p2pMessage.timestamp.getTime();
|
|
895
|
+
if (latency !== undefined && topicType !== undefined) {
|
|
728
896
|
this.instrumentation.recordMessageLatency(topicType, latency);
|
|
729
897
|
}
|
|
730
898
|
|
|
731
899
|
return;
|
|
732
900
|
}
|
|
733
901
|
|
|
734
|
-
protected async validateReceivedMessage<T>(
|
|
735
|
-
validationFunc: () => Promise<ReceivedMessageValidationResult<T>>,
|
|
902
|
+
protected async validateReceivedMessage<T, M = undefined>(
|
|
903
|
+
validationFunc: () => Promise<ReceivedMessageValidationResult<T, M>>,
|
|
736
904
|
msgId: string,
|
|
737
905
|
source: PeerId,
|
|
738
906
|
topicType: TopicType,
|
|
739
|
-
): Promise<ReceivedMessageValidationResult<T>> {
|
|
740
|
-
|
|
907
|
+
): Promise<ReceivedMessageValidationResult<T, M>> {
|
|
908
|
+
// Default to reject result with a penalty if validation function throws an error
|
|
909
|
+
let resultAndObj: ReceivedMessageValidationResult<T, M> = {
|
|
910
|
+
result: TopicValidatorResult.Reject,
|
|
911
|
+
severity: PeerErrorSeverity.MidToleranceError,
|
|
912
|
+
};
|
|
741
913
|
const timer = new Timer();
|
|
742
914
|
try {
|
|
743
915
|
resultAndObj = await validationFunc();
|
|
744
916
|
} catch (err) {
|
|
745
|
-
this.
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
917
|
+
this.logger.error(`Error validating gossipsub message`, err, { msgId, source: source.toString(), topicType });
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
const validationTimeMs = timer.ms();
|
|
921
|
+
const mcacheWindowMs = this.config.gossipsubMcacheLength * this.config.gossipsubInterval;
|
|
922
|
+
if (validationTimeMs > mcacheWindowMs * 0.75) {
|
|
923
|
+
this.instrumentation.incSlowValidation(topicType);
|
|
924
|
+
this.logger.warn(
|
|
925
|
+
`Gossip validation for ${topicType} took ${validationTimeMs}ms, approaching mcache eviction window of ${mcacheWindowMs}ms. ` +
|
|
926
|
+
`Message forwarding may be skipped if validation exceeds the window.`,
|
|
927
|
+
{ msgId, source: source.toString(), topicType, validationTimeMs, mcacheWindowMs },
|
|
928
|
+
);
|
|
751
929
|
}
|
|
752
930
|
|
|
753
931
|
if (resultAndObj.result === TopicValidatorResult.Accept) {
|
|
932
|
+
this.logger.debug(`Message ${topicType} accepted by validator`, { msgId, source: source.toString(), topicType });
|
|
754
933
|
this.instrumentation.recordMessageValidation(topicType, timer);
|
|
934
|
+
} else if (resultAndObj.result === TopicValidatorResult.Reject) {
|
|
935
|
+
this.logger.warn(`Message ${topicType} rejected by validator with severity ${resultAndObj.severity}`, {
|
|
936
|
+
msgId,
|
|
937
|
+
source: source.toString(),
|
|
938
|
+
topicType,
|
|
939
|
+
severity: resultAndObj.severity,
|
|
940
|
+
});
|
|
941
|
+
this.peerManager.penalizePeer(source, resultAndObj.severity);
|
|
942
|
+
} else {
|
|
943
|
+
this.logger.trace(`Message ${topicType} ignored by validator`, { msgId, source: source.toString(), topicType });
|
|
755
944
|
}
|
|
756
945
|
|
|
757
946
|
this.node.services.pubsub.reportMessageValidationResult(msgId, source.toString(), resultAndObj.result);
|
|
758
947
|
return resultAndObj;
|
|
759
948
|
}
|
|
760
949
|
|
|
950
|
+
private tryDeserialize<T>(deserializeFunc: () => T, msgId: string, source: PeerId): T | undefined {
|
|
951
|
+
try {
|
|
952
|
+
return deserializeFunc();
|
|
953
|
+
} catch (err) {
|
|
954
|
+
this.logger.warn(`Failed to deserialize gossipsub message from buffer`, {
|
|
955
|
+
err,
|
|
956
|
+
msgId,
|
|
957
|
+
source: source.toString(),
|
|
958
|
+
});
|
|
959
|
+
return undefined;
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
|
|
761
963
|
protected async handleGossipedTx(payloadData: Buffer, msgId: string, source: PeerId) {
|
|
762
964
|
const validationFunc: () => Promise<ReceivedMessageValidationResult<Tx>> = async () => {
|
|
763
|
-
const tx = Tx.fromBuffer(payloadData);
|
|
764
|
-
|
|
765
|
-
|
|
965
|
+
const tx = this.tryDeserialize(() => Tx.fromBuffer(payloadData), msgId, source);
|
|
966
|
+
if (!tx) {
|
|
967
|
+
return { result: TopicValidatorResult.Reject, severity: PeerErrorSeverity.LowToleranceError };
|
|
968
|
+
}
|
|
766
969
|
|
|
767
|
-
this.
|
|
768
|
-
|
|
769
|
-
|
|
970
|
+
const currentBlockNumber = await this.archiver.getBlockNumber();
|
|
971
|
+
const { ts: nextSlotTimestamp } = this.epochCache.getEpochAndSlotInNextL1Slot();
|
|
972
|
+
|
|
973
|
+
// Stage 1: fast validators (metadata, data, timestamps, double-spend, gas, phases, block header)
|
|
974
|
+
const firstStageValidators = await this.createFirstStageMessageValidators(currentBlockNumber, nextSlotTimestamp);
|
|
975
|
+
const firstStageOutcome = await this.runValidations(tx, firstStageValidators);
|
|
976
|
+
if (!firstStageOutcome.allPassed) {
|
|
977
|
+
const { name } = firstStageOutcome.failure;
|
|
978
|
+
let { severity } = firstStageOutcome.failure;
|
|
979
|
+
|
|
980
|
+
// Double spend validator has a special case handler. We perform more detailed examination
|
|
981
|
+
// as to how recently the nullifier was entered into the tree and if the transaction should
|
|
982
|
+
// have 'known' the nullifier existed. This determines the severity of the penalty applied to the peer.
|
|
983
|
+
if (name === 'doubleSpendValidator') {
|
|
984
|
+
const txBlockNumber = BlockNumber(currentBlockNumber + 1);
|
|
985
|
+
severity = await this.handleDoubleSpendFailure(tx, txBlockNumber);
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
this.logger.verbose(`Rejecting gossiped tx ${tx.getTxHash().toString()}: stage 1 validation failed`, {
|
|
989
|
+
validator: name,
|
|
990
|
+
severity,
|
|
991
|
+
source: source.toString(),
|
|
992
|
+
});
|
|
993
|
+
return { result: TopicValidatorResult.Reject, severity };
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
// Pool pre-check: see if the pool would accept this tx before doing expensive proof verification
|
|
997
|
+
const canAdd = await this.mempools.txPool.canAddPendingTx(tx);
|
|
998
|
+
if (canAdd === 'ignored') {
|
|
999
|
+
this.logger.verbose(`Ignoring gossiped tx ${tx.getTxHash().toString()}: pool pre-check returned ignored`, {
|
|
1000
|
+
source: source.toString(),
|
|
1001
|
+
});
|
|
1002
|
+
return { result: TopicValidatorResult.Ignore, obj: tx };
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
// Stage 2: expensive proof verification
|
|
1006
|
+
const secondStageValidators = this.createSecondStageMessageValidators();
|
|
1007
|
+
const secondStageOutcome = await this.runValidations(tx, secondStageValidators);
|
|
1008
|
+
if (!secondStageOutcome.allPassed) {
|
|
1009
|
+
const { severity, name } = secondStageOutcome.failure;
|
|
1010
|
+
this.logger.verbose(`Rejecting gossiped tx ${tx.getTxHash().toString()}: stage 2 validation failed`, {
|
|
1011
|
+
validator: name,
|
|
1012
|
+
severity,
|
|
1013
|
+
source: source.toString(),
|
|
1014
|
+
});
|
|
1015
|
+
return { result: TopicValidatorResult.Reject, severity };
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
// Pool add: persist the tx
|
|
1019
|
+
const txHash = tx.getTxHash();
|
|
1020
|
+
const addResult = await this.mempools.txPool.addPendingTxs([tx], { source: 'gossip' });
|
|
1021
|
+
|
|
1022
|
+
const wasAccepted = addResult.accepted.some(h => h.equals(txHash));
|
|
1023
|
+
const wasIgnored = addResult.ignored.some(h => h.equals(txHash));
|
|
1024
|
+
|
|
1025
|
+
this.logger.verbose(`Validate propagated tx ${txHash.toString()}`, {
|
|
1026
|
+
wasAccepted,
|
|
1027
|
+
wasIgnored,
|
|
770
1028
|
[Attributes.P2P_ID]: source.toString(),
|
|
771
1029
|
});
|
|
772
1030
|
|
|
773
|
-
if (
|
|
774
|
-
return { result: TopicValidatorResult.
|
|
775
|
-
} else if (
|
|
1031
|
+
if (wasAccepted) {
|
|
1032
|
+
return { result: TopicValidatorResult.Accept, obj: tx };
|
|
1033
|
+
} else if (wasIgnored) {
|
|
776
1034
|
return { result: TopicValidatorResult.Ignore, obj: tx };
|
|
777
1035
|
} else {
|
|
778
|
-
|
|
1036
|
+
this.logger.warn(`Gossiped tx ${txHash.toString()} unexpectedly rejected by pool`, {
|
|
1037
|
+
source: source.toString(),
|
|
1038
|
+
txHash: txHash.toString(),
|
|
1039
|
+
});
|
|
1040
|
+
return { result: TopicValidatorResult.Reject, severity: PeerErrorSeverity.HighToleranceError };
|
|
779
1041
|
}
|
|
780
1042
|
};
|
|
781
1043
|
|
|
@@ -784,6 +1046,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
784
1046
|
return;
|
|
785
1047
|
}
|
|
786
1048
|
|
|
1049
|
+
// Tx was accepted into pool and will be propagated - just log and record metrics
|
|
787
1050
|
const txHash = tx.getTxHash();
|
|
788
1051
|
const txHashString = txHash.toString();
|
|
789
1052
|
this.logger.verbose(`Received tx ${txHashString} from external peer ${source.toString()} via gossip`, {
|
|
@@ -791,73 +1054,40 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
791
1054
|
txHash: txHashString,
|
|
792
1055
|
});
|
|
793
1056
|
|
|
794
|
-
if (this.config.dropTransactions && randomInt(1000) < this.config.dropTransactionsProbability * 1000) {
|
|
795
|
-
this.logger.warn(`Intentionally dropping tx ${txHashString} (probability rule)`);
|
|
796
|
-
return;
|
|
797
|
-
}
|
|
798
|
-
|
|
799
1057
|
this.instrumentation.incrementTxReceived(1);
|
|
800
|
-
await this.mempools.txPool.addTxs([tx]);
|
|
801
1058
|
}
|
|
802
1059
|
|
|
803
1060
|
/**
|
|
804
|
-
* Process
|
|
805
|
-
*
|
|
806
|
-
*
|
|
807
|
-
* @param attestation - The attestation to process.
|
|
1061
|
+
* Process a checkpoint attestation from a peer.
|
|
1062
|
+
* Validates the attestation and adds it to the pool.
|
|
808
1063
|
*/
|
|
809
|
-
private async
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
isValid,
|
|
826
|
-
exists,
|
|
827
|
-
canAdd,
|
|
828
|
-
[Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber.toString(),
|
|
829
|
-
[Attributes.P2P_ID]: source.toString(),
|
|
830
|
-
});
|
|
831
|
-
|
|
832
|
-
if (!isValid) {
|
|
833
|
-
return { result: TopicValidatorResult.Reject };
|
|
834
|
-
} else if (exists) {
|
|
835
|
-
return { result: TopicValidatorResult.Ignore, obj: attestation };
|
|
836
|
-
} else if (!canAdd) {
|
|
837
|
-
this.logger.warn(`Dropping block attestation due to per-(slot, proposalId) attestation cap`, {
|
|
838
|
-
slot: attestation.payload.header.slotNumber.toString(),
|
|
839
|
-
archive: attestation.archive.toString(),
|
|
840
|
-
source: source.toString(),
|
|
841
|
-
});
|
|
842
|
-
return { result: TopicValidatorResult.Ignore, obj: attestation };
|
|
843
|
-
} else {
|
|
844
|
-
return { result: TopicValidatorResult.Accept, obj: attestation };
|
|
845
|
-
}
|
|
846
|
-
};
|
|
847
|
-
|
|
848
|
-
const { result, obj: attestation } = await this.validateReceivedMessage<BlockAttestation>(
|
|
849
|
-
validationFunc,
|
|
1064
|
+
private async processCheckpointAttestationFromPeer(
|
|
1065
|
+
payloadData: Buffer,
|
|
1066
|
+
msgId: string,
|
|
1067
|
+
source: PeerId,
|
|
1068
|
+
): Promise<void> {
|
|
1069
|
+
const { result, obj: attestation } = await this.validateReceivedMessage<CheckpointAttestation>(
|
|
1070
|
+
() => {
|
|
1071
|
+
const attestation = this.tryDeserialize(() => CheckpointAttestation.fromBuffer(payloadData), msgId, source);
|
|
1072
|
+
if (!attestation) {
|
|
1073
|
+
return Promise.resolve({
|
|
1074
|
+
result: TopicValidatorResult.Reject,
|
|
1075
|
+
severity: PeerErrorSeverity.LowToleranceError,
|
|
1076
|
+
});
|
|
1077
|
+
}
|
|
1078
|
+
return this.validateAndStoreCheckpointAttestation(source, attestation);
|
|
1079
|
+
},
|
|
850
1080
|
msgId,
|
|
851
1081
|
source,
|
|
852
|
-
TopicType.
|
|
1082
|
+
TopicType.checkpoint_attestation,
|
|
853
1083
|
);
|
|
854
1084
|
|
|
855
1085
|
if (result !== TopicValidatorResult.Accept || !attestation) {
|
|
856
1086
|
return;
|
|
857
1087
|
}
|
|
858
1088
|
|
|
859
|
-
this.logger.
|
|
860
|
-
`Received attestation for slot ${attestation.slotNumber} from external peer ${source.toString()}`,
|
|
1089
|
+
this.logger.verbose(
|
|
1090
|
+
`Received valid checkpoint attestation for slot ${attestation.slotNumber} from external peer ${source.toString()}`,
|
|
861
1091
|
{
|
|
862
1092
|
p2pMessageIdentifier: await attestation.p2pMessageLoggingIdentifier(),
|
|
863
1093
|
slot: attestation.slotNumber,
|
|
@@ -865,123 +1095,361 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
865
1095
|
source: source.toString(),
|
|
866
1096
|
},
|
|
867
1097
|
);
|
|
868
|
-
|
|
869
|
-
await this.mempools.attestationPool!.addAttestations([attestation]);
|
|
870
1098
|
}
|
|
871
1099
|
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
this.logger.
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
1100
|
+
/** Validates a checkpoint attestation and adds it to the pool. Penalizes the peer if validation fails. */
|
|
1101
|
+
@trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId, attestation) => ({
|
|
1102
|
+
[Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber.toString(),
|
|
1103
|
+
}))
|
|
1104
|
+
protected async validateAndStoreCheckpointAttestation(
|
|
1105
|
+
peerId: PeerId,
|
|
1106
|
+
attestation: CheckpointAttestation,
|
|
1107
|
+
): Promise<ReceivedMessageValidationResult<CheckpointAttestation>> {
|
|
1108
|
+
const validationResult = await this.checkpointAttestationValidator.validate(attestation);
|
|
1109
|
+
|
|
1110
|
+
if (validationResult.result === 'reject') {
|
|
1111
|
+
this.logger.warn(`Penalizing peer ${peerId} for checkpoint attestation validation failure`);
|
|
1112
|
+
return { result: TopicValidatorResult.Reject, severity: validationResult.severity };
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1115
|
+
if (validationResult.result === 'ignore') {
|
|
1116
|
+
return { result: TopicValidatorResult.Ignore, obj: attestation };
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
// Try to add the attestation: this handles existence check, cap check, and adding in one call
|
|
1120
|
+
// count is the number of attestations by this signer for this slot (for duplicate detection)
|
|
1121
|
+
const slot = attestation.payload.header.slotNumber;
|
|
1122
|
+
const { added, alreadyExists, count } =
|
|
1123
|
+
await this.mempools.attestationPool.tryAddCheckpointAttestation(attestation);
|
|
1124
|
+
|
|
1125
|
+
this.logger.trace(`Validate propagated checkpoint attestation`, {
|
|
1126
|
+
added,
|
|
1127
|
+
alreadyExists,
|
|
1128
|
+
count,
|
|
1129
|
+
[Attributes.SLOT_NUMBER]: slot.toString(),
|
|
1130
|
+
[Attributes.P2P_ID]: peerId.toString(),
|
|
1131
|
+
});
|
|
1132
|
+
|
|
1133
|
+
// Exact same attestation received, no need to re-broadcast
|
|
1134
|
+
if (alreadyExists) {
|
|
1135
|
+
return { result: TopicValidatorResult.Ignore, obj: attestation };
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
// Could not add (cap reached for signer), penalize and do not re-broadcast
|
|
1139
|
+
if (!added) {
|
|
1140
|
+
this.logger.warn(`Rejecting checkpoint attestation due to cap`, {
|
|
1141
|
+
slot: slot.toString(),
|
|
1142
|
+
archive: attestation.archive.toString(),
|
|
1143
|
+
source: peerId.toString(),
|
|
1144
|
+
attester: attestation.getSender()?.toString(),
|
|
1145
|
+
count,
|
|
889
1146
|
});
|
|
1147
|
+
return { result: TopicValidatorResult.Reject, severity: PeerErrorSeverity.HighToleranceError };
|
|
1148
|
+
}
|
|
890
1149
|
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
this.
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
1150
|
+
// Check if this is a duplicate attestation (signer attested to a different proposal at the same slot)
|
|
1151
|
+
// count is the number of attestations by this signer for this slot
|
|
1152
|
+
if (count === 2) {
|
|
1153
|
+
const attester = attestation.getSender();
|
|
1154
|
+
if (attester) {
|
|
1155
|
+
this.logger.warn(`Detected duplicate attestation (equivocation) at slot ${slot}`, {
|
|
1156
|
+
slot: slot.toString(),
|
|
1157
|
+
archive: attestation.archive.toString(),
|
|
1158
|
+
source: peerId.toString(),
|
|
1159
|
+
attester: attester.toString(),
|
|
901
1160
|
});
|
|
902
|
-
|
|
903
|
-
} else {
|
|
904
|
-
return { result: TopicValidatorResult.Accept, obj: block };
|
|
1161
|
+
this.duplicateAttestationCallback?.({ slot, attester });
|
|
905
1162
|
}
|
|
906
|
-
}
|
|
1163
|
+
}
|
|
907
1164
|
|
|
908
|
-
|
|
909
|
-
|
|
1165
|
+
// Attestation was added successfully - accept it so other nodes can also detect the equivocation
|
|
1166
|
+
return { result: TopicValidatorResult.Accept, obj: attestation };
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
protected async processBlockFromPeer(payloadData: Buffer, msgId: string, source: PeerId): Promise<void> {
|
|
1170
|
+
const {
|
|
1171
|
+
result,
|
|
1172
|
+
obj: block,
|
|
1173
|
+
metadata: { isEquivocated } = {},
|
|
1174
|
+
} = await this.validateReceivedMessage<BlockProposal, { isEquivocated: boolean }>(
|
|
1175
|
+
() => this.validateAndStoreBlockProposal(source, BlockProposal.fromBuffer(payloadData)),
|
|
910
1176
|
msgId,
|
|
911
1177
|
source,
|
|
912
1178
|
TopicType.block_proposal,
|
|
913
1179
|
);
|
|
914
1180
|
|
|
915
|
-
|
|
1181
|
+
// If not accepted or equivocated, return
|
|
1182
|
+
if (result !== TopicValidatorResult.Accept || !block || isEquivocated) {
|
|
916
1183
|
return;
|
|
917
1184
|
}
|
|
918
1185
|
|
|
919
1186
|
await this.processValidBlockProposal(block, source);
|
|
920
1187
|
}
|
|
921
1188
|
|
|
922
|
-
|
|
1189
|
+
/** Validates a block proposal. Triggers a penalization to the peer that sent it if invalid. Adds to the mempool if valid. */
|
|
1190
|
+
@trackSpan('Libp2pService.validateAndStoreBlockProposal', (_peerId, block) => ({
|
|
1191
|
+
[Attributes.BLOCK_NUMBER]: block.blockNumber.toString(),
|
|
1192
|
+
[Attributes.SLOT_NUMBER]: block.slotNumber.toString(),
|
|
1193
|
+
}))
|
|
1194
|
+
protected async validateAndStoreBlockProposal(
|
|
1195
|
+
peerId: PeerId,
|
|
1196
|
+
block: BlockProposal,
|
|
1197
|
+
): Promise<ReceivedMessageValidationResult<BlockProposal, { isEquivocated: boolean }>> {
|
|
1198
|
+
const validationResult = await this.blockProposalValidator.validate(block);
|
|
1199
|
+
|
|
1200
|
+
if (validationResult.result === 'reject') {
|
|
1201
|
+
this.logger.warn(`Penalizing peer ${peerId} for block proposal validation failure`);
|
|
1202
|
+
return { result: TopicValidatorResult.Reject, severity: validationResult.severity };
|
|
1203
|
+
}
|
|
1204
|
+
|
|
1205
|
+
if (validationResult.result === 'ignore') {
|
|
1206
|
+
return { result: TopicValidatorResult.Ignore, obj: block };
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1209
|
+
// Try to add the proposal: this handles existence check, cap check, and adding in one call
|
|
1210
|
+
const { added, alreadyExists, count } = await this.mempools.attestationPool.tryAddBlockProposal(block);
|
|
1211
|
+
const isEquivocated = count !== undefined && count > 1;
|
|
1212
|
+
|
|
1213
|
+
// Duplicate proposal received, no need to re-broadcast
|
|
1214
|
+
if (alreadyExists) {
|
|
1215
|
+
this.logger.debug(`Ignoring duplicate block proposal received`, {
|
|
1216
|
+
...block.toBlockInfo(),
|
|
1217
|
+
indexWithinCheckpoint: block.indexWithinCheckpoint,
|
|
1218
|
+
proposer: block.getSender()?.toString(),
|
|
1219
|
+
source: peerId.toString(),
|
|
1220
|
+
});
|
|
1221
|
+
return { result: TopicValidatorResult.Ignore, obj: block, metadata: { isEquivocated } };
|
|
1222
|
+
}
|
|
1223
|
+
|
|
1224
|
+
// Too many blocks received for this slot and index, penalize peer and do not re-broadcast
|
|
1225
|
+
if (!added) {
|
|
1226
|
+
this.logger.warn(`Penalizing peer for block proposal exceeding per-position cap`, {
|
|
1227
|
+
...block.toBlockInfo(),
|
|
1228
|
+
indexWithinCheckpoint: block.indexWithinCheckpoint,
|
|
1229
|
+
count,
|
|
1230
|
+
proposer: block.getSender()?.toString(),
|
|
1231
|
+
source: peerId.toString(),
|
|
1232
|
+
});
|
|
1233
|
+
return {
|
|
1234
|
+
result: TopicValidatorResult.Reject,
|
|
1235
|
+
metadata: { isEquivocated },
|
|
1236
|
+
severity: PeerErrorSeverity.HighToleranceError,
|
|
1237
|
+
};
|
|
1238
|
+
}
|
|
1239
|
+
|
|
1240
|
+
// If this was a duplicate proposal, do not process it, but do invoke the duplicate callback,
|
|
1241
|
+
// and do re-broadcast it so other nodes in the network know to slash the proposer
|
|
1242
|
+
if (isEquivocated) {
|
|
1243
|
+
const proposer = block.getSender();
|
|
1244
|
+
this.logger.warn(`Detected duplicate block proposal (equivocation) at slot ${block.slotNumber}`, {
|
|
1245
|
+
...block.toBlockInfo(),
|
|
1246
|
+
source: peerId.toString(),
|
|
1247
|
+
proposer: proposer?.toString(),
|
|
1248
|
+
});
|
|
1249
|
+
// Invoke the duplicate callback on the first duplicate spotted only
|
|
1250
|
+
if (proposer && count === 2) {
|
|
1251
|
+
this.duplicateProposalCallback?.({ slot: block.slotNumber, proposer, type: 'block' });
|
|
1252
|
+
}
|
|
1253
|
+
return { result: TopicValidatorResult.Accept, obj: block, metadata: { isEquivocated } };
|
|
1254
|
+
}
|
|
1255
|
+
|
|
1256
|
+
// Otherwise, we're good to go!
|
|
1257
|
+
return { result: TopicValidatorResult.Accept, obj: block };
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1260
|
+
// REFACTOR(palla): This method should be moved to the p2p_client or to a separate component,
|
|
1261
|
+
// should not be here as it does not deal with p2p networking.
|
|
923
1262
|
@trackSpan('Libp2pService.processValidBlockProposal', async block => ({
|
|
924
1263
|
[Attributes.SLOT_NUMBER]: block.slotNumber,
|
|
925
1264
|
[Attributes.BLOCK_ARCHIVE]: block.archive.toString(),
|
|
926
1265
|
[Attributes.P2P_ID]: await block.p2pMessageLoggingIdentifier().then(i => i.toString()),
|
|
927
1266
|
}))
|
|
928
|
-
|
|
1267
|
+
protected async processValidBlockProposal(block: BlockProposal, sender: PeerId) {
|
|
929
1268
|
const slot = block.slotNumber;
|
|
930
|
-
const previousSlot = SlotNumber(slot - 1);
|
|
931
1269
|
this.logger.verbose(`Received block proposal for slot ${slot} from external peer ${sender.toString()}.`, {
|
|
932
1270
|
p2pMessageIdentifier: await block.p2pMessageLoggingIdentifier(),
|
|
933
|
-
slot: block.slotNumber,
|
|
934
|
-
archive: block.archive.toString(),
|
|
935
1271
|
source: sender.toString(),
|
|
1272
|
+
...block.toBlockInfo(),
|
|
936
1273
|
});
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
1274
|
+
|
|
1275
|
+
// Mark the txs in this proposal as protected
|
|
1276
|
+
await this.mempools.txPool.protectTxs(block.txHashes, block.blockHeader);
|
|
1277
|
+
|
|
1278
|
+
// Call the block received callback to validate the proposal.
|
|
1279
|
+
// Note: Validators do NOT attest to individual blocks, only to checkpoint proposals.
|
|
1280
|
+
const isValid = await this.blockReceivedCallback(block, sender);
|
|
1281
|
+
if (!isValid) {
|
|
1282
|
+
this.logger.info(`Block proposal validation failed for block ${block.blockNumber}`, block.toBlockInfo());
|
|
940
1283
|
}
|
|
1284
|
+
}
|
|
941
1285
|
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
1286
|
+
/**
|
|
1287
|
+
* Handle a gossiped checkpoint proposal.
|
|
1288
|
+
* Validates and processes the checkpoint proposal, then triggers the callback for attestation.
|
|
1289
|
+
*/
|
|
1290
|
+
protected async handleGossipedCheckpointProposal(payloadData: Buffer, msgId: string, source: PeerId): Promise<void> {
|
|
1291
|
+
const {
|
|
1292
|
+
result,
|
|
1293
|
+
obj: checkpoint,
|
|
1294
|
+
metadata: { isEquivocated, processBlock } = {},
|
|
1295
|
+
} = await this.validateReceivedMessage<CheckpointProposal, { isEquivocated: boolean; processBlock: boolean }>(
|
|
1296
|
+
() => this.validateAndStoreCheckpointProposal(source, CheckpointProposal.fromBuffer(payloadData)),
|
|
1297
|
+
msgId,
|
|
1298
|
+
source,
|
|
1299
|
+
TopicType.checkpoint_proposal,
|
|
1300
|
+
);
|
|
1301
|
+
|
|
1302
|
+
// If the checkpoint contained a valid last block, we process it even if the checkpoint itself is to be rejected
|
|
1303
|
+
// TODO(palla/mbps): Is this ok? Should we be considering a block from a checkpoint that was equivocated?
|
|
1304
|
+
if (processBlock && checkpoint?.getBlockProposal()) {
|
|
1305
|
+
await this.processValidBlockProposal(checkpoint.getBlockProposal()!, source);
|
|
1306
|
+
}
|
|
1307
|
+
|
|
1308
|
+
if (result !== TopicValidatorResult.Accept || !checkpoint || isEquivocated) {
|
|
1309
|
+
return;
|
|
1310
|
+
}
|
|
1311
|
+
|
|
1312
|
+
await this.processValidCheckpointProposal(checkpoint.toCore(), source);
|
|
1313
|
+
}
|
|
1314
|
+
|
|
1315
|
+
/**
|
|
1316
|
+
* Validates a checkpoint proposal. Penalizes peer if validation fails. Adds the checkpoint and
|
|
1317
|
+
* its last block (if present) to the mempool if valid. Triggers equivocation detection on both.
|
|
1318
|
+
*/
|
|
1319
|
+
@trackSpan('Libp2pService.validateAndStoreCheckpointProposal', (_peerId, checkpoint) => ({
|
|
1320
|
+
[Attributes.SLOT_NUMBER]: checkpoint.slotNumber.toString(),
|
|
1321
|
+
}))
|
|
1322
|
+
protected async validateAndStoreCheckpointProposal(
|
|
1323
|
+
peerId: PeerId,
|
|
1324
|
+
checkpoint: CheckpointProposal,
|
|
1325
|
+
): Promise<ReceivedMessageValidationResult<CheckpointProposal, { isEquivocated: boolean; processBlock: boolean }>> {
|
|
1326
|
+
const validationResult = await this.checkpointProposalValidator.validate(checkpoint);
|
|
1327
|
+
|
|
1328
|
+
if (validationResult.result === 'reject') {
|
|
1329
|
+
this.logger.warn(`Penalizing peer ${peerId} for checkpoint proposal validation failure`);
|
|
1330
|
+
return { result: TopicValidatorResult.Reject, severity: validationResult.severity };
|
|
1331
|
+
}
|
|
1332
|
+
|
|
1333
|
+
if (validationResult.result === 'ignore') {
|
|
1334
|
+
return { result: TopicValidatorResult.Ignore, obj: checkpoint };
|
|
1335
|
+
}
|
|
1336
|
+
|
|
1337
|
+
// Extract and try to add the block proposal first if present
|
|
1338
|
+
const blockProposal = checkpoint.getBlockProposal();
|
|
1339
|
+
let processBlock = false;
|
|
1340
|
+
if (blockProposal) {
|
|
1341
|
+
this.logger.debug(`Validating block proposal from propagated checkpoint`, {
|
|
1342
|
+
[Attributes.SLOT_NUMBER]: checkpoint.slotNumber.toString(),
|
|
1343
|
+
[Attributes.P2P_ID]: peerId.toString(),
|
|
1344
|
+
});
|
|
1345
|
+
const blockProposalResult = await this.validateAndStoreBlockProposal(peerId, blockProposal);
|
|
1346
|
+
const { obj, metadata: { isEquivocated } = {} } = blockProposalResult;
|
|
1347
|
+
if (blockProposalResult.result === TopicValidatorResult.Reject || !obj || isEquivocated) {
|
|
1348
|
+
this.logger.debug(`Rejecting checkpoint due to invalid last block proposal`, {
|
|
1349
|
+
[Attributes.SLOT_NUMBER]: checkpoint.slotNumber.toString(),
|
|
1350
|
+
[Attributes.P2P_ID]: peerId.toString(),
|
|
1351
|
+
isEquivocated,
|
|
1352
|
+
result: blockProposalResult.result,
|
|
952
1353
|
});
|
|
953
|
-
return
|
|
1354
|
+
return {
|
|
1355
|
+
result: TopicValidatorResult.Reject,
|
|
1356
|
+
severity:
|
|
1357
|
+
'severity' in blockProposalResult ? blockProposalResult.severity : PeerErrorSeverity.MidToleranceError,
|
|
1358
|
+
};
|
|
1359
|
+
} else if (blockProposalResult.result === TopicValidatorResult.Accept && obj && !isEquivocated) {
|
|
1360
|
+
processBlock = true;
|
|
954
1361
|
}
|
|
955
|
-
throw err;
|
|
956
1362
|
}
|
|
957
|
-
await this.mempools.txPool.markTxsAsNonEvictable(block.txHashes);
|
|
958
|
-
const attestations = await this.blockReceivedCallback(block, sender);
|
|
959
1363
|
|
|
960
|
-
//
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
1364
|
+
// Try to add the checkpoint proposal core: this handles existence check, cap check, and adding in one call
|
|
1365
|
+
const checkpointCore = checkpoint.toCore();
|
|
1366
|
+
const tryAddResult = await this.mempools.attestationPool.tryAddCheckpointProposal(checkpointCore);
|
|
1367
|
+
const { added, alreadyExists, count } = tryAddResult;
|
|
1368
|
+
const isEquivocated = count !== undefined && count > 1;
|
|
1369
|
+
|
|
1370
|
+
// Duplicate proposal received, do not re-broadcast
|
|
1371
|
+
if (alreadyExists) {
|
|
1372
|
+
this.logger.debug(`Ignoring duplicate checkpoint proposal received`, {
|
|
1373
|
+
...checkpoint.toCheckpointInfo(),
|
|
1374
|
+
source: peerId.toString(),
|
|
1375
|
+
});
|
|
1376
|
+
return {
|
|
1377
|
+
result: TopicValidatorResult.Ignore,
|
|
1378
|
+
obj: checkpoint,
|
|
1379
|
+
metadata: { isEquivocated, processBlock },
|
|
1380
|
+
};
|
|
1381
|
+
}
|
|
1382
|
+
|
|
1383
|
+
// Too many checkpoint proposals received for this slot, penalize peer and do not re-broadcast
|
|
1384
|
+
// Note: We still return the checkpoint obj so the lastBlock can be processed if valid
|
|
1385
|
+
if (!added) {
|
|
1386
|
+
this.logger.warn(`Penalizing peer for checkpoint proposal exceeding per-slot cap`, {
|
|
1387
|
+
...checkpoint.toCheckpointInfo(),
|
|
1388
|
+
count,
|
|
1389
|
+
source: peerId.toString(),
|
|
1390
|
+
});
|
|
1391
|
+
return {
|
|
1392
|
+
result: TopicValidatorResult.Reject,
|
|
1393
|
+
obj: checkpoint,
|
|
1394
|
+
metadata: { isEquivocated, processBlock },
|
|
1395
|
+
severity: PeerErrorSeverity.HighToleranceError,
|
|
1396
|
+
};
|
|
1397
|
+
}
|
|
1398
|
+
|
|
1399
|
+
// If this was a duplicate proposal, do not process it, but do invoke the duplicate callback,
|
|
1400
|
+
// and do re-broadcast it so other nodes in the network know to slash the proposer
|
|
1401
|
+
if (isEquivocated) {
|
|
1402
|
+
const proposer = checkpoint.getSender();
|
|
1403
|
+
this.logger.warn(`Detected duplicate checkpoint proposal (equivocation) at slot ${checkpoint.slotNumber}`, {
|
|
1404
|
+
...checkpoint.toCheckpointInfo(),
|
|
1405
|
+
source: peerId.toString(),
|
|
1406
|
+
proposer: proposer?.toString(),
|
|
1407
|
+
});
|
|
1408
|
+
// Invoke the duplicate callback on the first duplicate spotted only
|
|
1409
|
+
if (proposer && count === 2) {
|
|
1410
|
+
this.duplicateProposalCallback?.({ slot: checkpoint.slotNumber, proposer, type: 'checkpoint' });
|
|
970
1411
|
}
|
|
1412
|
+
return {
|
|
1413
|
+
result: TopicValidatorResult.Accept,
|
|
1414
|
+
obj: checkpoint,
|
|
1415
|
+
metadata: { isEquivocated, processBlock },
|
|
1416
|
+
};
|
|
971
1417
|
}
|
|
1418
|
+
|
|
1419
|
+
// Otherwise, we're good to go!
|
|
1420
|
+
return { result: TopicValidatorResult.Accept, obj: checkpoint, metadata: { processBlock, isEquivocated } };
|
|
972
1421
|
}
|
|
973
1422
|
|
|
974
1423
|
/**
|
|
975
|
-
*
|
|
976
|
-
*
|
|
1424
|
+
* Process a validated checkpoint proposal.
|
|
1425
|
+
* Note: The proposal was already added to the pool by tryAddCheckpointProposal in handleGossipedCheckpointProposal.
|
|
977
1426
|
*/
|
|
978
|
-
@trackSpan('Libp2pService.
|
|
979
|
-
[Attributes.SLOT_NUMBER]:
|
|
980
|
-
[Attributes.BLOCK_ARCHIVE]:
|
|
981
|
-
[Attributes.P2P_ID]: await
|
|
1427
|
+
@trackSpan('Libp2pService.processValidCheckpointProposal', async checkpoint => ({
|
|
1428
|
+
[Attributes.SLOT_NUMBER]: checkpoint.slotNumber,
|
|
1429
|
+
[Attributes.BLOCK_ARCHIVE]: checkpoint.archive.toString(),
|
|
1430
|
+
[Attributes.P2P_ID]: await checkpoint.p2pMessageLoggingIdentifier().then(i => i.toString()),
|
|
982
1431
|
}))
|
|
983
|
-
|
|
984
|
-
|
|
1432
|
+
protected async processValidCheckpointProposal(checkpoint: CheckpointProposalCore, sender: PeerId) {
|
|
1433
|
+
const slot = checkpoint.slotNumber;
|
|
1434
|
+
this.logger.verbose(`Received checkpoint proposal for slot ${slot} from external peer ${sender.toString()}.`, {
|
|
1435
|
+
p2pMessageIdentifier: await checkpoint.p2pMessageLoggingIdentifier(),
|
|
1436
|
+
slot: checkpoint.slotNumber,
|
|
1437
|
+
archive: checkpoint.archive.toString(),
|
|
1438
|
+
source: sender.toString(),
|
|
1439
|
+
});
|
|
1440
|
+
|
|
1441
|
+
await this.allNodesCheckpointReceivedCallback(checkpoint, sender);
|
|
1442
|
+
|
|
1443
|
+
// Call the checkpoint received callback with the core version (without lastBlock)
|
|
1444
|
+
// to validate and potentially generate attestations
|
|
1445
|
+
const attestations = await this.validatorCheckpointReceivedCallback(checkpoint, sender);
|
|
1446
|
+
if (attestations && attestations.length > 0) {
|
|
1447
|
+
// If the callback returned attestations, add them to the pool and propagate them
|
|
1448
|
+
await this.mempools.attestationPool.addOwnCheckpointAttestations(attestations);
|
|
1449
|
+
for (const attestation of attestations) {
|
|
1450
|
+
await this.propagate(attestation);
|
|
1451
|
+
}
|
|
1452
|
+
}
|
|
985
1453
|
}
|
|
986
1454
|
|
|
987
1455
|
/**
|
|
@@ -1004,9 +1472,9 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1004
1472
|
* @returns True if the requested block transactions are valid, false otherwise.
|
|
1005
1473
|
*/
|
|
1006
1474
|
@trackSpan('Libp2pService.validateRequestedBlockTxs', request => ({
|
|
1007
|
-
[Attributes.
|
|
1475
|
+
[Attributes.BLOCK_ARCHIVE]: request.archiveRoot.toString(),
|
|
1008
1476
|
}))
|
|
1009
|
-
|
|
1477
|
+
protected async validateRequestedBlockTxs(
|
|
1010
1478
|
request: BlockTxsRequest,
|
|
1011
1479
|
response: BlockTxsResponse,
|
|
1012
1480
|
peerId: PeerId,
|
|
@@ -1014,10 +1482,10 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1014
1482
|
const requestedTxValidator = this.createRequestedTxValidator();
|
|
1015
1483
|
|
|
1016
1484
|
try {
|
|
1017
|
-
if (!response.
|
|
1485
|
+
if (!response.archiveRoot.equals(request.archiveRoot)) {
|
|
1018
1486
|
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
1019
1487
|
throw new ValidationError(
|
|
1020
|
-
`Received block txs for unexpected
|
|
1488
|
+
`Received block txs for unexpected archive root: expected ${request.archiveRoot.toString()}, got ${response.archiveRoot.toString()}`,
|
|
1021
1489
|
);
|
|
1022
1490
|
}
|
|
1023
1491
|
|
|
@@ -1047,7 +1515,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1047
1515
|
}
|
|
1048
1516
|
|
|
1049
1517
|
// Given proposal (should have locally), ensure returned txs are valid subset and match request indices
|
|
1050
|
-
const proposal = await this.mempools.attestationPool
|
|
1518
|
+
const proposal = await this.mempools.attestationPool.getBlockProposal(request.archiveRoot.toString());
|
|
1051
1519
|
if (proposal) {
|
|
1052
1520
|
// Build intersected indices
|
|
1053
1521
|
const intersectIdx = request.txIndices.getTrueIndices().filter(i => response.txIndices.isSet(i));
|
|
@@ -1067,7 +1535,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1067
1535
|
} else {
|
|
1068
1536
|
// No local proposal, cannot check the membership/order of the returned txs
|
|
1069
1537
|
this.logger.warn(
|
|
1070
|
-
`Block proposal not found for
|
|
1538
|
+
`Block proposal not found for archive root ${request.archiveRoot.toString()}; cannot validate membership/order of returned txs`,
|
|
1071
1539
|
);
|
|
1072
1540
|
return false;
|
|
1073
1541
|
}
|
|
@@ -1106,7 +1574,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1106
1574
|
const requested = new Set(requestedTxHash.map(h => h.toString()));
|
|
1107
1575
|
const requestedTxValidator = this.createRequestedTxValidator();
|
|
1108
1576
|
|
|
1109
|
-
//TODO: (mralj) - this is somewhat naive implementation, if single tx is
|
|
1577
|
+
//TODO: (mralj) - this is somewhat naive implementation, if single tx is invalid we consider the whole response invalid.
|
|
1110
1578
|
// I think we should still extract the valid txs and return them, so that we can still use the response.
|
|
1111
1579
|
try {
|
|
1112
1580
|
await Promise.all(responseTx.map(tx => this.validateRequestedTx(tx, peerId, requestedTxValidator, requested)));
|
|
@@ -1122,74 +1590,13 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1122
1590
|
}
|
|
1123
1591
|
}
|
|
1124
1592
|
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
*
|
|
1128
|
-
* If a local copy exists, enforces hash equality. If missing, rejects (no penalty) since the hash cannot be verified.
|
|
1129
|
-
* Penalizes on block number mismatch or hash mismatch.
|
|
1130
|
-
*
|
|
1131
|
-
* @param requestedBlockNumber - The requested block number.
|
|
1132
|
-
* @param responseBlock - The block returned by the peer.
|
|
1133
|
-
* @param peerId - The peer that returned the block.
|
|
1134
|
-
* @returns True if the response is valid, false otherwise.
|
|
1135
|
-
*/
|
|
1136
|
-
@trackSpan('Libp2pService.validateRequestedBlock', (requestedBlockNumber, _responseBlock) => ({
|
|
1137
|
-
[Attributes.BLOCK_NUMBER]: requestedBlockNumber.toString(),
|
|
1138
|
-
}))
|
|
1139
|
-
private async validateRequestedBlock(
|
|
1140
|
-
requestedBlockNumber: Fr,
|
|
1141
|
-
responseBlock: L2Block,
|
|
1593
|
+
protected async validateRequestedTx(
|
|
1594
|
+
tx: Tx,
|
|
1142
1595
|
peerId: PeerId,
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
if (responseBlock.number !== reqNum) {
|
|
1147
|
-
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
|
|
1148
|
-
return false;
|
|
1149
|
-
}
|
|
1150
|
-
|
|
1151
|
-
const local = await this.archiver.getBlock(reqNum);
|
|
1152
|
-
if (!local) {
|
|
1153
|
-
// We are missing the local block; we cannot verify the hash yet. Reject without penalizing.
|
|
1154
|
-
// TODO: Consider extending this validator to accept an expected hash or
|
|
1155
|
-
// performing quorum-based checks when using P2P syncing prior to L1 sync.
|
|
1156
|
-
this.logger.warn(`Local block ${reqNum} not found; rejecting BLOCK response without hash verification`);
|
|
1157
|
-
return false;
|
|
1158
|
-
}
|
|
1159
|
-
const [localHash, respHash] = await Promise.all([local.hash(), responseBlock.hash()]);
|
|
1160
|
-
if (!localHash.equals(respHash)) {
|
|
1161
|
-
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
1162
|
-
return false;
|
|
1163
|
-
}
|
|
1164
|
-
|
|
1165
|
-
return true;
|
|
1166
|
-
} catch (e) {
|
|
1167
|
-
this.logger.warn(`Error validating requested block`, e);
|
|
1168
|
-
return false;
|
|
1169
|
-
}
|
|
1170
|
-
}
|
|
1171
|
-
|
|
1172
|
-
private createRequestedTxValidator(): TxValidator {
|
|
1173
|
-
return new AggregateTxValidator(
|
|
1174
|
-
new DataTxValidator(),
|
|
1175
|
-
new MetadataTxValidator({
|
|
1176
|
-
l1ChainId: new Fr(this.config.l1ChainId),
|
|
1177
|
-
rollupVersion: new Fr(this.config.rollupVersion),
|
|
1178
|
-
protocolContractsHash,
|
|
1179
|
-
vkTreeRoot: getVKTreeRoot(),
|
|
1180
|
-
}),
|
|
1181
|
-
new TxProofValidator(this.proofVerifier),
|
|
1182
|
-
);
|
|
1183
|
-
}
|
|
1184
|
-
|
|
1185
|
-
private async validateRequestedTx(tx: Tx, peerId: PeerId, txValidator: TxValidator, requested?: Set<`0x${string}`>) {
|
|
1596
|
+
txValidator: TxValidator,
|
|
1597
|
+
requested?: Set<`0x${string}`>,
|
|
1598
|
+
) {
|
|
1186
1599
|
const penalize = (severity: PeerErrorSeverity) => this.peerManager.penalizePeer(peerId, severity);
|
|
1187
|
-
|
|
1188
|
-
if (!(await tx.validateTxHash())) {
|
|
1189
|
-
penalize(PeerErrorSeverity.MidToleranceError);
|
|
1190
|
-
throw new ValidationError(`Received tx with invalid hash ${tx.getTxHash().toString()}.`);
|
|
1191
|
-
}
|
|
1192
|
-
|
|
1193
1600
|
if (requested && !requested.has(tx.getTxHash().toString())) {
|
|
1194
1601
|
penalize(PeerErrorSeverity.MidToleranceError);
|
|
1195
1602
|
throw new ValidationError(`Received tx with hash ${tx.getTxHash().toString()} that was not requested.`);
|
|
@@ -1202,38 +1609,14 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1202
1609
|
}
|
|
1203
1610
|
}
|
|
1204
1611
|
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
// We accept transactions if they are not expired by the next slot (checked based on the IncludeByTimestamp field)
|
|
1212
|
-
const { ts: nextSlotTimestamp } = this.epochCache.getEpochAndSlotInNextL1Slot();
|
|
1213
|
-
const messageValidators = await this.createMessageValidators(currentBlockNumber, nextSlotTimestamp);
|
|
1214
|
-
|
|
1215
|
-
for (const validator of messageValidators) {
|
|
1216
|
-
const outcome = await this.runValidations(tx, validator);
|
|
1217
|
-
|
|
1218
|
-
if (outcome.allPassed) {
|
|
1219
|
-
continue;
|
|
1220
|
-
}
|
|
1221
|
-
const { name } = outcome.failure;
|
|
1222
|
-
let { severity } = outcome.failure;
|
|
1223
|
-
|
|
1224
|
-
// Double spend validator has a special case handler
|
|
1225
|
-
if (name === 'doubleSpendValidator') {
|
|
1226
|
-
const txBlockNumber = currentBlockNumber + 1; // tx is expected to be in the next block
|
|
1227
|
-
severity = await this.handleDoubleSpendFailure(tx, txBlockNumber);
|
|
1228
|
-
}
|
|
1229
|
-
|
|
1230
|
-
this.peerManager.penalizePeer(peerId, severity);
|
|
1231
|
-
return false;
|
|
1232
|
-
}
|
|
1233
|
-
return true;
|
|
1612
|
+
protected createRequestedTxValidator(): TxValidator {
|
|
1613
|
+
return createTxValidatorForReqResponseReceivedTxs(this.proofVerifier, {
|
|
1614
|
+
l1ChainId: this.config.l1ChainId,
|
|
1615
|
+
rollupVersion: this.config.rollupVersion,
|
|
1616
|
+
});
|
|
1234
1617
|
}
|
|
1235
1618
|
|
|
1236
|
-
private async getGasFees(blockNumber:
|
|
1619
|
+
private async getGasFees(blockNumber: BlockNumber): Promise<GasFees> {
|
|
1237
1620
|
if (blockNumber === this.feesCache?.blockNumber) {
|
|
1238
1621
|
return this.feesCache.gasFees;
|
|
1239
1622
|
}
|
|
@@ -1244,59 +1627,78 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1244
1627
|
return gasFees;
|
|
1245
1628
|
}
|
|
1246
1629
|
|
|
1247
|
-
|
|
1248
|
-
|
|
1630
|
+
/**
|
|
1631
|
+
* Get the BatchTxRequesterLibP2PService dependencies for creating BatchTxRequester instances
|
|
1632
|
+
*/
|
|
1633
|
+
public getBatchTxRequesterService(): BatchTxRequesterLibP2PService {
|
|
1634
|
+
return {
|
|
1635
|
+
reqResp: this.reqresp,
|
|
1636
|
+
connectionSampler: this.reqresp.getConnectionSampler(),
|
|
1637
|
+
txValidatorConfig: {
|
|
1638
|
+
l1ChainId: this.config.l1ChainId,
|
|
1639
|
+
rollupVersion: this.config.rollupVersion,
|
|
1640
|
+
proofVerifier: this.proofVerifier,
|
|
1641
|
+
},
|
|
1642
|
+
peerScoring: this.peerManager,
|
|
1643
|
+
};
|
|
1644
|
+
}
|
|
1249
1645
|
|
|
1250
|
-
|
|
1251
|
-
const
|
|
1252
|
-
|
|
1646
|
+
public async validateTxsReceivedInBlockProposal(txs: Tx[]): Promise<void> {
|
|
1647
|
+
const validator = createTxValidatorForBlockProposalReceivedTxs(
|
|
1648
|
+
this.proofVerifier,
|
|
1649
|
+
{ l1ChainId: this.config.l1ChainId, rollupVersion: this.config.rollupVersion },
|
|
1650
|
+
this.logger.getBindings(),
|
|
1651
|
+
);
|
|
1253
1652
|
|
|
1254
|
-
await Promise.all(
|
|
1653
|
+
const results = await Promise.all(
|
|
1255
1654
|
txs.map(async tx => {
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
if (!outcome.allPassed) {
|
|
1259
|
-
throw new Error('Invalid tx detected', { cause: { outcome } });
|
|
1260
|
-
}
|
|
1261
|
-
}
|
|
1655
|
+
const result = await validator.validateTx(tx);
|
|
1656
|
+
return result.result !== 'invalid';
|
|
1262
1657
|
}),
|
|
1263
1658
|
);
|
|
1659
|
+
if (results.some(value => value === false)) {
|
|
1660
|
+
throw new Error('Invalid tx detected');
|
|
1661
|
+
}
|
|
1264
1662
|
}
|
|
1265
1663
|
|
|
1266
|
-
/**
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
* Each validator is a pair of a validator and a severity.
|
|
1270
|
-
* If a validator fails, the peer is penalized with the severity of the validator.
|
|
1271
|
-
*
|
|
1272
|
-
* @param currentBlockNumber - The current synced block number.
|
|
1273
|
-
* @param nextSlotTimestamp - The timestamp of the next slot (used to validate txs are not expired).
|
|
1274
|
-
* @returns The message validators.
|
|
1275
|
-
*/
|
|
1276
|
-
private async createMessageValidators(
|
|
1277
|
-
currentBlockNumber: number,
|
|
1664
|
+
/** Creates the first stage (fast) validators for gossiped transactions. */
|
|
1665
|
+
protected async createFirstStageMessageValidators(
|
|
1666
|
+
currentBlockNumber: BlockNumber,
|
|
1278
1667
|
nextSlotTimestamp: UInt64,
|
|
1279
|
-
): Promise<Record<string,
|
|
1668
|
+
): Promise<Record<string, TransactionValidator>> {
|
|
1280
1669
|
const gasFees = await this.getGasFees(currentBlockNumber);
|
|
1281
|
-
const allowedInSetup =
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1670
|
+
const allowedInSetup = [
|
|
1671
|
+
...(await getDefaultAllowedSetupFunctions()),
|
|
1672
|
+
...(this.config.txPublicSetupAllowListExtend ?? []),
|
|
1673
|
+
];
|
|
1674
|
+
const blockNumber = BlockNumber(currentBlockNumber + 1);
|
|
1675
|
+
const l1Constants = await this.archiver.getL1Constants();
|
|
1676
|
+
|
|
1677
|
+
return createFirstStageTxValidationsForGossipedTransactions(
|
|
1286
1678
|
nextSlotTimestamp,
|
|
1287
|
-
|
|
1679
|
+
blockNumber,
|
|
1288
1680
|
this.worldStateSynchronizer,
|
|
1289
1681
|
gasFees,
|
|
1290
1682
|
this.config.l1ChainId,
|
|
1291
1683
|
this.config.rollupVersion,
|
|
1292
1684
|
protocolContractsHash,
|
|
1293
1685
|
this.archiver,
|
|
1294
|
-
this.proofVerifier,
|
|
1295
1686
|
!this.config.disableTransactions,
|
|
1296
1687
|
allowedInSetup,
|
|
1688
|
+
this.logger.getBindings(),
|
|
1689
|
+
{
|
|
1690
|
+
rollupManaLimit: l1Constants.rollupManaLimit,
|
|
1691
|
+
maxBlockL2Gas: this.config.validateMaxL2BlockGas,
|
|
1692
|
+
maxBlockDAGas: this.config.validateMaxDABlockGas,
|
|
1693
|
+
},
|
|
1297
1694
|
);
|
|
1298
1695
|
}
|
|
1299
1696
|
|
|
1697
|
+
/** Creates the second stage (expensive proof verification) validators for gossiped transactions. */
|
|
1698
|
+
protected createSecondStageMessageValidators(): Record<string, TransactionValidator> {
|
|
1699
|
+
return createSecondStageTxValidationsForGossipedTransactions(this.proofVerifier, this.logger.getBindings());
|
|
1700
|
+
}
|
|
1701
|
+
|
|
1300
1702
|
/**
|
|
1301
1703
|
* Run validations on a tx.
|
|
1302
1704
|
* @param tx - The tx to validate.
|
|
@@ -1305,7 +1707,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1305
1707
|
*/
|
|
1306
1708
|
private async runValidations(
|
|
1307
1709
|
tx: Tx,
|
|
1308
|
-
messageValidators: Record<string,
|
|
1710
|
+
messageValidators: Record<string, TransactionValidator>,
|
|
1309
1711
|
): Promise<ValidationOutcome> {
|
|
1310
1712
|
const validationPromises = Object.entries(messageValidators).map(async ([name, { validator, severity }]) => {
|
|
1311
1713
|
const { result } = await validator.validateTx(tx);
|
|
@@ -1314,8 +1716,10 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1314
1716
|
|
|
1315
1717
|
// A promise that resolves when all validations have been run
|
|
1316
1718
|
const allValidations = await Promise.all(validationPromises);
|
|
1317
|
-
const
|
|
1318
|
-
if (
|
|
1719
|
+
const failures = allValidations.filter(x => !x.isValid);
|
|
1720
|
+
if (failures.length > 0) {
|
|
1721
|
+
// Pick the most severe failure (lowest tolerance = harshest penalty)
|
|
1722
|
+
const failed = maxBy(failures, f => PeerErrorSeverityByHarshness.indexOf(f.severity))!;
|
|
1319
1723
|
return {
|
|
1320
1724
|
allPassed: false,
|
|
1321
1725
|
failure: {
|
|
@@ -1342,20 +1746,23 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1342
1746
|
* @param peerId - The peer ID of the peer that sent the tx.
|
|
1343
1747
|
* @returns Severity
|
|
1344
1748
|
*/
|
|
1345
|
-
private async handleDoubleSpendFailure(tx: Tx, blockNumber:
|
|
1749
|
+
private async handleDoubleSpendFailure(tx: Tx, blockNumber: BlockNumber): Promise<PeerErrorSeverity> {
|
|
1346
1750
|
if (blockNumber <= this.config.doubleSpendSeverePeerPenaltyWindow) {
|
|
1347
1751
|
return PeerErrorSeverity.HighToleranceError;
|
|
1348
1752
|
}
|
|
1349
1753
|
|
|
1350
|
-
const snapshotValidator = new DoubleSpendTxValidator(
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1754
|
+
const snapshotValidator = new DoubleSpendTxValidator(
|
|
1755
|
+
{
|
|
1756
|
+
nullifiersExist: async (nullifiers: Buffer[]) => {
|
|
1757
|
+
const merkleTree = this.worldStateSynchronizer.getSnapshot(
|
|
1758
|
+
BlockNumber(blockNumber - this.config.doubleSpendSeverePeerPenaltyWindow),
|
|
1759
|
+
);
|
|
1760
|
+
const indices = await merkleTree.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, nullifiers);
|
|
1761
|
+
return indices.map(index => index !== undefined);
|
|
1762
|
+
},
|
|
1357
1763
|
},
|
|
1358
|
-
|
|
1764
|
+
this.logger.getBindings(),
|
|
1765
|
+
);
|
|
1359
1766
|
|
|
1360
1767
|
const validSnapshot = await snapshotValidator.validateTx(tx);
|
|
1361
1768
|
if (validSnapshot.result !== 'valid') {
|
|
@@ -1365,47 +1772,6 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1365
1772
|
return PeerErrorSeverity.HighToleranceError;
|
|
1366
1773
|
}
|
|
1367
1774
|
|
|
1368
|
-
/**
|
|
1369
|
-
* Validate an attestation.
|
|
1370
|
-
*
|
|
1371
|
-
* @param attestation - The attestation to validate.
|
|
1372
|
-
* @returns True if the attestation is valid, false otherwise.
|
|
1373
|
-
*/
|
|
1374
|
-
@trackSpan('Libp2pService.validateAttestation', async (_, attestation) => ({
|
|
1375
|
-
[Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber,
|
|
1376
|
-
[Attributes.BLOCK_ARCHIVE]: attestation.archive.toString(),
|
|
1377
|
-
[Attributes.P2P_ID]: await attestation.p2pMessageLoggingIdentifier().then(i => i.toString()),
|
|
1378
|
-
}))
|
|
1379
|
-
public async validateAttestation(peerId: PeerId, attestation: BlockAttestation): Promise<boolean> {
|
|
1380
|
-
const severity = await this.attestationValidator.validate(attestation);
|
|
1381
|
-
if (severity) {
|
|
1382
|
-
this.peerManager.penalizePeer(peerId, severity);
|
|
1383
|
-
return false;
|
|
1384
|
-
}
|
|
1385
|
-
|
|
1386
|
-
return true;
|
|
1387
|
-
}
|
|
1388
|
-
|
|
1389
|
-
/**
|
|
1390
|
-
* Validate a block proposal.
|
|
1391
|
-
*
|
|
1392
|
-
* @param block - The block proposal to validate.
|
|
1393
|
-
* @returns True if the block proposal is valid, false otherwise.
|
|
1394
|
-
*/
|
|
1395
|
-
@trackSpan('Libp2pService.validateBlockProposal', (_peerId, block) => ({
|
|
1396
|
-
[Attributes.SLOT_NUMBER]: block.payload.header.slotNumber.toString(),
|
|
1397
|
-
}))
|
|
1398
|
-
public async validateBlockProposal(peerId: PeerId, block: BlockProposal): Promise<boolean> {
|
|
1399
|
-
const severity = await this.blockProposalValidator.validate(block);
|
|
1400
|
-
if (severity) {
|
|
1401
|
-
this.logger.debug(`Penalizing peer ${peerId} for block proposal validation failure`);
|
|
1402
|
-
this.peerManager.penalizePeer(peerId, severity);
|
|
1403
|
-
return false;
|
|
1404
|
-
}
|
|
1405
|
-
|
|
1406
|
-
return true;
|
|
1407
|
-
}
|
|
1408
|
-
|
|
1409
1775
|
public getPeerScore(peerId: PeerId): number {
|
|
1410
1776
|
return this.node.services.pubsub.score.score(peerId.toString());
|
|
1411
1777
|
}
|