@aztec/p2p 0.0.1-commit.5daedc8 → 0.0.1-commit.6201a7b05
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 +12 -11
- package/dest/client/factory.d.ts.map +1 -1
- package/dest/client/factory.js +61 -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 +318 -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 +140 -87
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +128 -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 +19 -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 +48 -12
- 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 +11 -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 +12 -0
- package/dest/mem_pools/tx_pool_v2/eviction/insufficient_fee_per_gas_eviction_rule.d.ts +16 -0
- package/dest/mem_pools/tx_pool_v2/eviction/insufficient_fee_per_gas_eviction_rule.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/eviction/insufficient_fee_per_gas_eviction_rule.js +62 -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 +218 -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 +137 -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 +223 -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 +924 -0
- package/dest/msg_validators/attestation_validator/attestation_validator.d.ts +11 -5
- package/dest/msg_validators/attestation_validator/attestation_validator.d.ts.map +1 -1
- package/dest/msg_validators/attestation_validator/attestation_validator.js +80 -22
- package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts +11 -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 +95 -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 +13 -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 +13 -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 +22 -0
- package/dest/msg_validators/proposal_validator/proposal_validator.d.ts.map +1 -0
- package/dest/msg_validators/proposal_validator/proposal_validator.js +139 -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 +100 -3
- package/dest/msg_validators/tx_validator/gas_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/gas_validator.js +146 -67
- 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 +113 -46
- package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
- package/dest/services/libp2p/libp2p_service.js +1146 -446
- 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 +4 -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 +8 -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 +286 -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 +121 -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 +357 -0
- package/src/client/test/tx_proposal_collector/proposal_tx_collector_worker_protocol.ts +43 -0
- package/src/config.ts +204 -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 +29 -17
- package/src/mem_pools/index.ts +2 -2
- package/src/mem_pools/instrumentation.ts +46 -13
- 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 +28 -0
- package/src/mem_pools/tx_pool_v2/eviction/insufficient_fee_per_gas_eviction_rule.ts +65 -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 +250 -0
- package/src/mem_pools/tx_pool_v2/tx_metadata.ts +349 -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 +1107 -0
- package/src/msg_validators/attestation_validator/README.md +49 -0
- package/src/msg_validators/attestation_validator/attestation_validator.ts +71 -24
- package/src/msg_validators/attestation_validator/fisherman_attestation_validator.ts +32 -19
- package/src/msg_validators/clock_tolerance.ts +127 -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 +28 -0
- package/src/msg_validators/proposal_validator/checkpoint_proposal_validator.ts +39 -0
- package/src/msg_validators/proposal_validator/index.ts +3 -0
- package/src/msg_validators/proposal_validator/proposal_validator.ts +142 -0
- package/src/msg_validators/tx_validator/README.md +127 -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 +418 -58
- package/src/msg_validators/tx_validator/fee_payer_balance.ts +44 -0
- package/src/msg_validators/tx_validator/gas_validator.ts +211 -77
- 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 +850 -472
- 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 +6 -6
- package/src/test-helpers/mock-pubsub.ts +181 -15
- package/src/test-helpers/mock-tx-helpers.ts +1 -1
- package/src/test-helpers/reqresp-nodes.ts +10 -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 +413 -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, merge } 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
|
-
import { GasFees } from '@aztec/stdlib/gas';
|
|
11
|
+
import { type BlockMinFeesProvider, 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,34 @@ 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
|
-
|
|
149
|
+
/** Callback invoked when a duplicate proposal is detected (triggers slashing). */
|
|
150
|
+
private duplicateProposalCallback?: (info: {
|
|
151
|
+
slot: SlotNumber;
|
|
152
|
+
proposer: EthAddress;
|
|
153
|
+
type: 'checkpoint' | 'block';
|
|
154
|
+
}) => void;
|
|
155
|
+
|
|
156
|
+
/** Callback invoked when a duplicate attestation is detected (triggers slashing). */
|
|
157
|
+
private duplicateAttestationCallback?: P2PDuplicateAttestationCallback;
|
|
135
158
|
|
|
136
159
|
/**
|
|
137
160
|
* Callback for when a block is received from a peer.
|
|
@@ -140,28 +163,44 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
140
163
|
*/
|
|
141
164
|
private blockReceivedCallback: P2PBlockReceivedCallback;
|
|
142
165
|
|
|
166
|
+
/**
|
|
167
|
+
* Callback for when a checkpoint proposal is received from a peer.
|
|
168
|
+
* @param checkpoint - The checkpoint proposal received from the peer.
|
|
169
|
+
* @returns The attestations for the checkpoint, if any.
|
|
170
|
+
*/
|
|
171
|
+
private allNodesCheckpointReceivedCallback: P2PCheckpointReceivedCallback;
|
|
172
|
+
/**
|
|
173
|
+
* Callback for when a checkpoint proposal is received - specifically for validators - from a peer.
|
|
174
|
+
* @param checkpoint - The checkpoint proposal received from the peer.
|
|
175
|
+
* @returns The attestations for the checkpoint, if any.
|
|
176
|
+
*/
|
|
177
|
+
private validatorCheckpointReceivedCallback: P2PCheckpointReceivedCallback;
|
|
178
|
+
|
|
143
179
|
private gossipSubEventHandler: (e: CustomEvent<GossipsubMessage>) => void;
|
|
144
180
|
|
|
145
181
|
private instrumentation: P2PInstrumentation;
|
|
146
182
|
|
|
183
|
+
private telemetry: TelemetryClient;
|
|
184
|
+
|
|
147
185
|
protected logger: Logger;
|
|
148
186
|
|
|
149
187
|
constructor(
|
|
150
|
-
private clientType: T,
|
|
151
188
|
private config: P2PConfig,
|
|
152
189
|
protected node: PubSubLibp2p,
|
|
153
190
|
private peerDiscoveryService: PeerDiscoveryService,
|
|
154
191
|
private reqresp: ReqRespInterface,
|
|
155
|
-
|
|
156
|
-
protected mempools: MemPools
|
|
157
|
-
|
|
192
|
+
protected peerManager: PeerManagerInterface,
|
|
193
|
+
protected mempools: MemPools,
|
|
194
|
+
protected archiver: L2BlockSource & ContractDataSource,
|
|
158
195
|
private epochCache: EpochCacheInterface,
|
|
159
196
|
private proofVerifier: ClientProtocolCircuitVerifier,
|
|
160
197
|
private worldStateSynchronizer: WorldStateSynchronizer,
|
|
198
|
+
private blockMinFeesProvider: BlockMinFeesProvider,
|
|
161
199
|
telemetry: TelemetryClient,
|
|
162
200
|
logger: Logger = createLogger('p2p:libp2p_service'),
|
|
163
201
|
) {
|
|
164
202
|
super(telemetry, 'LibP2PService');
|
|
203
|
+
this.telemetry = telemetry;
|
|
165
204
|
|
|
166
205
|
// Create child logger with fisherman prefix if in fisherman mode
|
|
167
206
|
this.logger = config.fishermanMode ? logger.createChild('[FISHERMAN]') : logger;
|
|
@@ -170,7 +209,8 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
170
209
|
|
|
171
210
|
this.msgIdSeenValidators[TopicType.tx] = new MessageSeenValidator(config.seenMessageCacheSize);
|
|
172
211
|
this.msgIdSeenValidators[TopicType.block_proposal] = new MessageSeenValidator(config.seenMessageCacheSize);
|
|
173
|
-
this.msgIdSeenValidators[TopicType.
|
|
212
|
+
this.msgIdSeenValidators[TopicType.checkpoint_proposal] = new MessageSeenValidator(config.seenMessageCacheSize);
|
|
213
|
+
this.msgIdSeenValidators[TopicType.checkpoint_attestation] = new MessageSeenValidator(config.seenMessageCacheSize);
|
|
174
214
|
|
|
175
215
|
const versions = getVersions(config);
|
|
176
216
|
this.protocolVersion = compressComponentVersions(versions);
|
|
@@ -178,30 +218,62 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
178
218
|
|
|
179
219
|
this.topicStrings[TopicType.tx] = createTopicString(TopicType.tx, this.protocolVersion);
|
|
180
220
|
this.topicStrings[TopicType.block_proposal] = createTopicString(TopicType.block_proposal, this.protocolVersion);
|
|
181
|
-
this.topicStrings[TopicType.
|
|
182
|
-
TopicType.
|
|
221
|
+
this.topicStrings[TopicType.checkpoint_proposal] = createTopicString(
|
|
222
|
+
TopicType.checkpoint_proposal,
|
|
223
|
+
this.protocolVersion,
|
|
224
|
+
);
|
|
225
|
+
this.topicStrings[TopicType.checkpoint_attestation] = createTopicString(
|
|
226
|
+
TopicType.checkpoint_attestation,
|
|
183
227
|
this.protocolVersion,
|
|
184
228
|
);
|
|
185
229
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
:
|
|
190
|
-
|
|
230
|
+
const p2pPropagationTime = config.attestationPropagationTime;
|
|
231
|
+
const proposalValidatorOpts = {
|
|
232
|
+
txsPermitted: !config.disableTransactions,
|
|
233
|
+
maxTxsPerBlock: config.validateMaxTxsPerBlock ?? config.validateMaxTxsPerCheckpoint,
|
|
234
|
+
p2pPropagationTime,
|
|
235
|
+
signatureContext: {
|
|
236
|
+
chainId: config.l1ChainId,
|
|
237
|
+
rollupAddress: config.l1Contracts.rollupAddress,
|
|
238
|
+
},
|
|
239
|
+
};
|
|
240
|
+
this.blockProposalValidator = new BlockProposalValidator(epochCache, proposalValidatorOpts);
|
|
241
|
+
this.checkpointProposalValidator = new CheckpointProposalValidator(epochCache, proposalValidatorOpts);
|
|
242
|
+
const attestationValidatorOpts = {
|
|
243
|
+
l1PublishingTime: config.l1PublishingTime,
|
|
244
|
+
p2pPropagationTime,
|
|
245
|
+
signatureContext: proposalValidatorOpts.signatureContext,
|
|
246
|
+
};
|
|
247
|
+
this.checkpointAttestationValidator = config.fishermanMode
|
|
248
|
+
? new FishermanAttestationValidator(epochCache, mempools.attestationPool, telemetry, attestationValidatorOpts)
|
|
249
|
+
: new CheckpointAttestationValidator(epochCache, attestationValidatorOpts);
|
|
191
250
|
|
|
192
251
|
this.gossipSubEventHandler = this.handleGossipSubEvent.bind(this);
|
|
193
252
|
|
|
194
|
-
this.blockReceivedCallback = async (block: BlockProposal): Promise<
|
|
195
|
-
this.logger.
|
|
196
|
-
`Handler not yet registered
|
|
253
|
+
this.blockReceivedCallback = async (block: BlockProposal): Promise<boolean> => {
|
|
254
|
+
this.logger.warn(
|
|
255
|
+
`Handler for block received not yet registered on P2P service. Received block ${block.blockNumber} for slot ${block.slotNumber} from peer.`,
|
|
197
256
|
{ p2pMessageIdentifier: await block.p2pMessageLoggingIdentifier() },
|
|
198
257
|
);
|
|
199
|
-
return
|
|
258
|
+
return true;
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
this.allNodesCheckpointReceivedCallback = (
|
|
262
|
+
_checkpoint: CheckpointProposalCore,
|
|
263
|
+
): Promise<CheckpointAttestation[] | undefined> => {
|
|
264
|
+
throw new CheckpointProposalReceivedCallbackNotRegisteredError();
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
this.validatorCheckpointReceivedCallback = (
|
|
268
|
+
_checkpoint: CheckpointProposalCore,
|
|
269
|
+
): Promise<CheckpointAttestation[] | undefined> => {
|
|
270
|
+
return Promise.resolve(undefined);
|
|
200
271
|
};
|
|
201
272
|
}
|
|
202
273
|
|
|
203
|
-
public updateConfig(config: Partial<P2PReqRespConfig
|
|
274
|
+
public updateConfig(config: Partial<P2PReqRespConfig & Pick<P2PConfig, 'skipIncomingProposals'>>) {
|
|
204
275
|
this.reqresp.updateConfig(config);
|
|
276
|
+
this.config = merge(this.config, config);
|
|
205
277
|
}
|
|
206
278
|
|
|
207
279
|
/**
|
|
@@ -210,17 +282,17 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
210
282
|
* @param txPool - The transaction pool to be accessed by the service.
|
|
211
283
|
* @returns The new service.
|
|
212
284
|
*/
|
|
213
|
-
public static async new
|
|
214
|
-
clientType: T,
|
|
285
|
+
public static async new(
|
|
215
286
|
config: P2PConfig,
|
|
216
287
|
peerId: PeerId,
|
|
217
288
|
deps: {
|
|
218
|
-
mempools: MemPools
|
|
289
|
+
mempools: MemPools;
|
|
219
290
|
l2BlockSource: L2BlockSource & ContractDataSource;
|
|
220
291
|
epochCache: EpochCacheInterface;
|
|
221
292
|
proofVerifier: ClientProtocolCircuitVerifier;
|
|
222
293
|
worldStateSynchronizer: WorldStateSynchronizer;
|
|
223
294
|
peerStore: AztecAsyncKVStore;
|
|
295
|
+
blockMinFeesProvider: BlockMinFeesProvider;
|
|
224
296
|
telemetry: TelemetryClient;
|
|
225
297
|
logger: Logger;
|
|
226
298
|
packageVersion: string;
|
|
@@ -233,6 +305,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
233
305
|
mempools,
|
|
234
306
|
proofVerifier,
|
|
235
307
|
peerStore,
|
|
308
|
+
blockMinFeesProvider,
|
|
236
309
|
telemetry,
|
|
237
310
|
logger,
|
|
238
311
|
packageVersion,
|
|
@@ -242,14 +315,14 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
242
315
|
|
|
243
316
|
const datastore = new AztecDatastore(peerStore);
|
|
244
317
|
|
|
245
|
-
const otelMetricsAdapter = new OtelMetricsAdapter(telemetry);
|
|
318
|
+
const otelMetricsAdapter = new OtelMetricsAdapter(telemetry, logger.getBindings());
|
|
246
319
|
|
|
247
320
|
const peerDiscoveryService = new DiscV5Service(
|
|
248
321
|
peerId,
|
|
249
322
|
config,
|
|
250
323
|
packageVersion,
|
|
251
324
|
telemetry,
|
|
252
|
-
createLogger(`${logger.module}:discv5_service
|
|
325
|
+
createLogger(`${logger.module}:discv5_service`, logger.getBindings()),
|
|
253
326
|
);
|
|
254
327
|
|
|
255
328
|
// Seed libp2p's bootstrap discovery with private and trusted peers
|
|
@@ -263,10 +336,6 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
263
336
|
const versions = getVersions(config);
|
|
264
337
|
const protocolVersion = compressComponentVersions(versions);
|
|
265
338
|
|
|
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
339
|
const preferredPeersEnrs: ENR[] = config.preferredPeers.map(enr => ENR.decodeTxt(enr));
|
|
271
340
|
const directPeers = (
|
|
272
341
|
await Promise.all(
|
|
@@ -286,6 +355,19 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
286
355
|
|
|
287
356
|
const announceTcpMultiaddr = config.p2pIp ? [convertToMultiaddr(config.p2pIp, p2pPort, 'tcp')] : [];
|
|
288
357
|
|
|
358
|
+
// Create dynamic topic score params based on network configuration
|
|
359
|
+
const l1Constants = epochCache.getL1Constants();
|
|
360
|
+
const topicScoreParams = createAllTopicScoreParams(protocolVersion, {
|
|
361
|
+
slotDurationMs: l1Constants.slotDuration * 1000,
|
|
362
|
+
ethereumSlotDuration: l1Constants.ethereumSlotDuration,
|
|
363
|
+
heartbeatIntervalMs: config.gossipsubInterval,
|
|
364
|
+
targetCommitteeSize: l1Constants.targetCommitteeSize,
|
|
365
|
+
blockDurationMs: config.blockDurationMs,
|
|
366
|
+
l1PublishingTime: config.l1PublishingTime,
|
|
367
|
+
p2pPropagationTime: config.attestationPropagationTime,
|
|
368
|
+
expectedBlockProposalsPerSlot: config.expectedBlockProposalsPerSlot,
|
|
369
|
+
});
|
|
370
|
+
|
|
289
371
|
const node = await createLibp2p({
|
|
290
372
|
start: false,
|
|
291
373
|
peerId,
|
|
@@ -381,30 +463,14 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
381
463
|
scoreParams: createPeerScoreParams({
|
|
382
464
|
// IPColocation factor can be disabled for local testing - default to -5
|
|
383
465
|
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
|
-
},
|
|
466
|
+
topics: topicScoreParams,
|
|
401
467
|
}),
|
|
402
468
|
}) as (components: GossipSubComponents) => GossipSub,
|
|
403
469
|
components: (components: { connectionManager: ConnectionManager }) => ({
|
|
404
470
|
connectionManager: components.connectionManager,
|
|
405
471
|
}),
|
|
406
472
|
},
|
|
407
|
-
logger: createLibp2pComponentLogger(logger.module),
|
|
473
|
+
logger: createLibp2pComponentLogger(logger.module, logger.getBindings()),
|
|
408
474
|
});
|
|
409
475
|
|
|
410
476
|
const peerScoring = new PeerScoring(config, telemetry);
|
|
@@ -423,13 +489,19 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
423
489
|
epochCache,
|
|
424
490
|
);
|
|
425
491
|
|
|
426
|
-
//
|
|
427
|
-
|
|
492
|
+
// Gate req/resp data protocols for unauthenticated peers when p2pAllowOnlyValidators is enabled
|
|
493
|
+
reqresp.setShouldRejectPeer(peerId => peerManager.shouldDisableP2PGossip(peerId));
|
|
494
|
+
|
|
495
|
+
// Configure application-specific scoring for gossipsub.
|
|
496
|
+
// The weight scales app score to align with gossipsub thresholds:
|
|
497
|
+
// - Disconnect (-50) × 10 = -500 = gossipThreshold (stops receiving gossip)
|
|
498
|
+
// - Ban (-100) × 10 = -1000 = publishThreshold (cannot publish)
|
|
499
|
+
// Note: positive topic scores can offset penalties, so alignment is best-effort.
|
|
500
|
+
node.services.pubsub.score.params.appSpecificWeight = APP_SPECIFIC_WEIGHT;
|
|
428
501
|
node.services.pubsub.score.params.appSpecificScore = (peerId: string) =>
|
|
429
502
|
peerManager.shouldDisableP2PGossip(peerId) ? -Infinity : peerManager.getPeerScore(peerId);
|
|
430
503
|
|
|
431
504
|
return new LibP2PService(
|
|
432
|
-
clientType,
|
|
433
505
|
config,
|
|
434
506
|
node,
|
|
435
507
|
peerDiscoveryService,
|
|
@@ -440,6 +512,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
440
512
|
epochCache,
|
|
441
513
|
proofVerifier,
|
|
442
514
|
worldStateSynchronizer,
|
|
515
|
+
blockMinFeesProvider,
|
|
443
516
|
telemetry,
|
|
444
517
|
logger,
|
|
445
518
|
);
|
|
@@ -462,33 +535,23 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
462
535
|
}
|
|
463
536
|
const announceTcpMultiaddr = convertToMultiaddr(p2pIp, p2pPort, 'tcp');
|
|
464
537
|
|
|
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
538
|
// Create request response protocol handlers
|
|
477
539
|
const txHandler = reqRespTxHandler(this.mempools);
|
|
478
540
|
const goodbyeHandler = reqGoodbyeHandler(this.peerManager);
|
|
479
|
-
const blockHandler = reqRespBlockHandler(this.archiver);
|
|
480
541
|
const statusHandler = reqRespStatusHandler(this.protocolVersion, this.worldStateSynchronizer, this.logger);
|
|
481
542
|
|
|
482
543
|
const requestResponseHandlers: Partial<ReqRespSubProtocolHandlers> = {
|
|
483
544
|
[ReqRespSubProtocol.PING]: pingHandler,
|
|
484
545
|
[ReqRespSubProtocol.STATUS]: statusHandler.bind(this),
|
|
485
546
|
[ReqRespSubProtocol.GOODBYE]: goodbyeHandler.bind(this),
|
|
486
|
-
[ReqRespSubProtocol.BLOCK]: blockHandler.bind(this),
|
|
487
547
|
};
|
|
488
548
|
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
549
|
+
if (!this.config.disableTransactions) {
|
|
550
|
+
const blockTxsHandler = reqRespBlockTxsHandler(
|
|
551
|
+
this.mempools.attestationPool,
|
|
552
|
+
this.archiver,
|
|
553
|
+
this.mempools.txPool,
|
|
554
|
+
);
|
|
492
555
|
requestResponseHandlers[ReqRespSubProtocol.BLOCK_TXS] = blockTxsHandler.bind(this);
|
|
493
556
|
}
|
|
494
557
|
|
|
@@ -496,10 +559,31 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
496
559
|
requestResponseHandlers[ReqRespSubProtocol.TX] = txHandler.bind(this);
|
|
497
560
|
}
|
|
498
561
|
|
|
562
|
+
// Define the sub protocol validators - This is done within this start() method to gain a callback to the existing validateTx function
|
|
563
|
+
const reqrespSubProtocolValidators = {
|
|
564
|
+
...DEFAULT_SUB_PROTOCOL_VALIDATORS,
|
|
565
|
+
[ReqRespSubProtocol.TX]: this.validateRequestedTxs.bind(this),
|
|
566
|
+
[ReqRespSubProtocol.BLOCK_TXS]: this.validateRequestedBlockTxs.bind(this),
|
|
567
|
+
};
|
|
568
|
+
|
|
569
|
+
await this.peerManager.initializePeers();
|
|
570
|
+
|
|
571
|
+
await this.reqresp.start(requestResponseHandlers, reqrespSubProtocolValidators);
|
|
572
|
+
|
|
573
|
+
await this.node.start();
|
|
574
|
+
|
|
575
|
+
// Subscribe to standard GossipSub topics by default
|
|
576
|
+
for (const topic of getTopicsForConfig(this.config.disableTransactions)) {
|
|
577
|
+
this.subscribeToTopic(this.topicStrings[topic]);
|
|
578
|
+
}
|
|
579
|
+
|
|
499
580
|
// add GossipSub listener
|
|
500
581
|
this.node.services.pubsub.addEventListener(GossipSubEvent.MESSAGE, this.gossipSubEventHandler);
|
|
501
582
|
|
|
502
583
|
// Start running promise for peer discovery and metrics collection
|
|
584
|
+
if (!this.config.p2pDiscoveryDisabled) {
|
|
585
|
+
await this.peerDiscoveryService.start();
|
|
586
|
+
}
|
|
503
587
|
this.discoveryRunningPromise = new RunningPromise(
|
|
504
588
|
async () => {
|
|
505
589
|
await this.peerManager.heartbeat();
|
|
@@ -509,14 +593,6 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
509
593
|
);
|
|
510
594
|
this.discoveryRunningPromise.start();
|
|
511
595
|
|
|
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
596
|
this.logger.info(`Started P2P service`, {
|
|
521
597
|
listen: this.config.listenAddress,
|
|
522
598
|
port: this.config.p2pPort,
|
|
@@ -563,6 +639,10 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
563
639
|
return this.peerManager.getPeers(includePending);
|
|
564
640
|
}
|
|
565
641
|
|
|
642
|
+
public getGossipMeshPeerCount(topicType: TopicType): number {
|
|
643
|
+
return this.node.services.pubsub.getMeshPeers(this.topicStrings[topicType]).length;
|
|
644
|
+
}
|
|
645
|
+
|
|
566
646
|
private handleGossipSubEvent(e: CustomEvent<GossipsubMessage>) {
|
|
567
647
|
this.logger.trace(`Received PUBSUB message.`);
|
|
568
648
|
|
|
@@ -590,6 +670,15 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
590
670
|
return this.reqresp.sendBatchRequest(protocol, requests, pinnedPeerId);
|
|
591
671
|
}
|
|
592
672
|
|
|
673
|
+
public sendRequestToPeer(
|
|
674
|
+
peerId: PeerId,
|
|
675
|
+
subProtocol: ReqRespSubProtocol,
|
|
676
|
+
payload: Buffer,
|
|
677
|
+
dialTimeout?: number,
|
|
678
|
+
): Promise<ReqRespResponse> {
|
|
679
|
+
return this.reqresp.sendRequestToPeer(peerId, subProtocol, payload, dialTimeout);
|
|
680
|
+
}
|
|
681
|
+
|
|
593
682
|
/**
|
|
594
683
|
* Get the ENR of the node
|
|
595
684
|
* @returns The ENR of the node
|
|
@@ -602,6 +691,37 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
602
691
|
this.blockReceivedCallback = callback;
|
|
603
692
|
}
|
|
604
693
|
|
|
694
|
+
public registerValidatorCheckpointReceivedCallback(callback: P2PCheckpointReceivedCallback) {
|
|
695
|
+
this.validatorCheckpointReceivedCallback = callback;
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
public registerAllNodesCheckpointReceivedCallback(callback: P2PCheckpointReceivedCallback) {
|
|
699
|
+
this.allNodesCheckpointReceivedCallback = callback;
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
public async notifyOwnCheckpointProposal(checkpoint: CheckpointProposalCore): Promise<void> {
|
|
703
|
+
await this.allNodesCheckpointReceivedCallback(checkpoint, this.node.peerId);
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
/**
|
|
707
|
+
* Registers a callback to be invoked when a duplicate proposal is detected.
|
|
708
|
+
* This callback is triggered on the first duplicate (when count goes from 1 to 2).
|
|
709
|
+
*/
|
|
710
|
+
public registerDuplicateProposalCallback(
|
|
711
|
+
callback: (info: { slot: SlotNumber; proposer: EthAddress; type: 'checkpoint' | 'block' }) => void,
|
|
712
|
+
): void {
|
|
713
|
+
this.duplicateProposalCallback = callback;
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
/**
|
|
717
|
+
* Registers a callback to be invoked when a duplicate attestation is detected.
|
|
718
|
+
* A validator signing attestations for different proposals at the same slot.
|
|
719
|
+
* This callback is triggered on the first duplicate (when count goes from 1 to 2).
|
|
720
|
+
*/
|
|
721
|
+
public registerDuplicateAttestationCallback(callback: P2PDuplicateAttestationCallback): void {
|
|
722
|
+
this.duplicateAttestationCallback = callback;
|
|
723
|
+
}
|
|
724
|
+
|
|
605
725
|
/**
|
|
606
726
|
* Subscribes to a topic.
|
|
607
727
|
* @param topic - The topic to subscribe to.
|
|
@@ -623,7 +743,10 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
623
743
|
if (!this.node.services.pubsub) {
|
|
624
744
|
throw new Error('Pubsub service not available.');
|
|
625
745
|
}
|
|
626
|
-
const
|
|
746
|
+
const isBlockProposal = topic === this.topicStrings[TopicType.block_proposal];
|
|
747
|
+
const traceContext =
|
|
748
|
+
this.config.debugP2PInstrumentMessages && isBlockProposal ? this.telemetry.getTraceContext() : undefined;
|
|
749
|
+
const p2pMessage = P2PMessage.fromGossipable(message, this.config.debugP2PInstrumentMessages, traceContext);
|
|
627
750
|
const result = await this.node.services.pubsub.publish(topic, p2pMessage.toMessageData());
|
|
628
751
|
return result.recipients.length;
|
|
629
752
|
}
|
|
@@ -644,12 +767,15 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
644
767
|
case this.topicStrings[TopicType.tx]:
|
|
645
768
|
topicType = TopicType.tx;
|
|
646
769
|
break;
|
|
647
|
-
case this.topicStrings[TopicType.block_attestation]:
|
|
648
|
-
topicType = TopicType.block_attestation;
|
|
649
|
-
break;
|
|
650
770
|
case this.topicStrings[TopicType.block_proposal]:
|
|
651
771
|
topicType = TopicType.block_proposal;
|
|
652
772
|
break;
|
|
773
|
+
case this.topicStrings[TopicType.checkpoint_proposal]:
|
|
774
|
+
topicType = TopicType.checkpoint_proposal;
|
|
775
|
+
break;
|
|
776
|
+
case this.topicStrings[TopicType.checkpoint_attestation]:
|
|
777
|
+
topicType = TopicType.checkpoint_attestation;
|
|
778
|
+
break;
|
|
653
779
|
default:
|
|
654
780
|
this.logger.error(`Received message on unknown topic: ${msg.topic}`);
|
|
655
781
|
break;
|
|
@@ -660,6 +786,9 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
660
786
|
if (!validator || !validator.addMessage(msgId)) {
|
|
661
787
|
this.instrumentation.incMessagePrevalidationStatus(false, topicType);
|
|
662
788
|
this.node.services.pubsub.reportMessageValidationResult(msgId, source.toString(), TopicValidatorResult.Ignore);
|
|
789
|
+
if (topicType === TopicType.tx) {
|
|
790
|
+
this.logger.verbose(`Ignoring already-seen tx gossip message`, { msgId, source: source.toString() });
|
|
791
|
+
}
|
|
663
792
|
return { result: false, topicType };
|
|
664
793
|
}
|
|
665
794
|
|
|
@@ -708,74 +837,226 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
708
837
|
return;
|
|
709
838
|
}
|
|
710
839
|
|
|
840
|
+
// Determine topic type for attributes
|
|
711
841
|
if (msg.topic === this.topicStrings[TopicType.tx]) {
|
|
712
842
|
topicType = TopicType.tx;
|
|
713
|
-
|
|
843
|
+
} else if (msg.topic === this.topicStrings[TopicType.checkpoint_attestation]) {
|
|
844
|
+
topicType = TopicType.checkpoint_attestation;
|
|
845
|
+
} else if (msg.topic === this.topicStrings[TopicType.block_proposal]) {
|
|
846
|
+
topicType = TopicType.block_proposal;
|
|
847
|
+
} else if (msg.topic === this.topicStrings[TopicType.checkpoint_proposal]) {
|
|
848
|
+
topicType = TopicType.checkpoint_proposal;
|
|
714
849
|
}
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
850
|
+
|
|
851
|
+
// Process the message, optionally within a linked span for trace propagation
|
|
852
|
+
const processMessage = async () => {
|
|
853
|
+
if (
|
|
854
|
+
this.config.skipIncomingProposals &&
|
|
855
|
+
(msg.topic === this.topicStrings[TopicType.block_proposal] ||
|
|
856
|
+
msg.topic === this.topicStrings[TopicType.checkpoint_proposal])
|
|
857
|
+
) {
|
|
858
|
+
this.logger.warn(`Ignoring incoming proposal (skipIncomingProposals is set)`, { topic: msg.topic });
|
|
859
|
+
this.node.services.pubsub.reportMessageValidationResult(msgId, source.toString(), TopicValidatorResult.Ignore);
|
|
860
|
+
return;
|
|
719
861
|
}
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
862
|
+
if (msg.topic === this.topicStrings[TopicType.tx]) {
|
|
863
|
+
await this.handleGossipedTx(p2pMessage.payload, msgId, source);
|
|
864
|
+
} else if (msg.topic === this.topicStrings[TopicType.checkpoint_attestation]) {
|
|
865
|
+
await this.processCheckpointAttestationFromPeer(p2pMessage.payload, msgId, source);
|
|
866
|
+
} else if (msg.topic === this.topicStrings[TopicType.block_proposal]) {
|
|
867
|
+
await this.processBlockFromPeer(p2pMessage.payload, msgId, source);
|
|
868
|
+
} else if (msg.topic === this.topicStrings[TopicType.checkpoint_proposal]) {
|
|
869
|
+
await this.handleGossipedCheckpointProposal(p2pMessage.payload, msgId, source);
|
|
870
|
+
} else {
|
|
871
|
+
this.logger.error(`Received message on unknown topic: ${msg.topic}`);
|
|
872
|
+
}
|
|
873
|
+
};
|
|
874
|
+
|
|
875
|
+
const latency = p2pMessage.timestamp !== undefined ? msgReceivedTime - p2pMessage.timestamp.getTime() : undefined;
|
|
876
|
+
const propagatedContext = p2pMessage.traceContext
|
|
877
|
+
? this.telemetry.extractPropagatedContext(p2pMessage.traceContext)
|
|
878
|
+
: undefined;
|
|
879
|
+
|
|
880
|
+
if (propagatedContext) {
|
|
881
|
+
await this.tracer.startActiveSpan(
|
|
882
|
+
'LibP2PService.processMessage',
|
|
883
|
+
{
|
|
884
|
+
attributes: {
|
|
885
|
+
[Attributes.TOPIC_NAME]: topicType!,
|
|
886
|
+
[Attributes.PEER_ID]: source.toString(),
|
|
887
|
+
},
|
|
888
|
+
},
|
|
889
|
+
propagatedContext,
|
|
890
|
+
async span => {
|
|
891
|
+
try {
|
|
892
|
+
await processMessage();
|
|
893
|
+
span.setStatus({
|
|
894
|
+
code: SpanStatusCode.OK,
|
|
895
|
+
});
|
|
896
|
+
} catch (err) {
|
|
897
|
+
span.setStatus({
|
|
898
|
+
code: SpanStatusCode.ERROR,
|
|
899
|
+
message: String(err),
|
|
900
|
+
});
|
|
901
|
+
if (typeof err === 'string' || (err && err instanceof Error)) {
|
|
902
|
+
span.recordException(err);
|
|
903
|
+
}
|
|
904
|
+
throw err;
|
|
905
|
+
} finally {
|
|
906
|
+
span.end();
|
|
907
|
+
}
|
|
908
|
+
},
|
|
909
|
+
);
|
|
910
|
+
} else {
|
|
911
|
+
await processMessage();
|
|
724
912
|
}
|
|
725
913
|
|
|
726
|
-
if (
|
|
727
|
-
const latency = msgReceivedTime - p2pMessage.timestamp.getTime();
|
|
914
|
+
if (latency !== undefined && topicType !== undefined) {
|
|
728
915
|
this.instrumentation.recordMessageLatency(topicType, latency);
|
|
729
916
|
}
|
|
730
917
|
|
|
731
918
|
return;
|
|
732
919
|
}
|
|
733
920
|
|
|
734
|
-
protected async validateReceivedMessage<T>(
|
|
735
|
-
validationFunc: () => Promise<ReceivedMessageValidationResult<T>>,
|
|
921
|
+
protected async validateReceivedMessage<T, M = undefined>(
|
|
922
|
+
validationFunc: () => Promise<ReceivedMessageValidationResult<T, M>>,
|
|
736
923
|
msgId: string,
|
|
737
924
|
source: PeerId,
|
|
738
925
|
topicType: TopicType,
|
|
739
|
-
): Promise<ReceivedMessageValidationResult<T>> {
|
|
740
|
-
|
|
926
|
+
): Promise<ReceivedMessageValidationResult<T, M>> {
|
|
927
|
+
// Default to reject result with a penalty if validation function throws an error
|
|
928
|
+
let resultAndObj: ReceivedMessageValidationResult<T, M> = {
|
|
929
|
+
result: TopicValidatorResult.Reject,
|
|
930
|
+
severity: PeerErrorSeverity.MidToleranceError,
|
|
931
|
+
};
|
|
741
932
|
const timer = new Timer();
|
|
742
933
|
try {
|
|
743
934
|
resultAndObj = await validationFunc();
|
|
744
935
|
} catch (err) {
|
|
745
|
-
this.
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
936
|
+
this.logger.error(`Error validating gossipsub message`, err, { msgId, source: source.toString(), topicType });
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
const validationTimeMs = timer.ms();
|
|
940
|
+
const mcacheWindowMs = this.config.gossipsubMcacheLength * this.config.gossipsubInterval;
|
|
941
|
+
if (validationTimeMs > mcacheWindowMs * 0.75) {
|
|
942
|
+
this.instrumentation.incSlowValidation(topicType);
|
|
943
|
+
this.logger.warn(
|
|
944
|
+
`Gossip validation for ${topicType} took ${validationTimeMs}ms, approaching mcache eviction window of ${mcacheWindowMs}ms. ` +
|
|
945
|
+
`Message forwarding may be skipped if validation exceeds the window.`,
|
|
946
|
+
{ msgId, source: source.toString(), topicType, validationTimeMs, mcacheWindowMs },
|
|
947
|
+
);
|
|
751
948
|
}
|
|
752
949
|
|
|
753
950
|
if (resultAndObj.result === TopicValidatorResult.Accept) {
|
|
951
|
+
this.logger.debug(`Message ${topicType} accepted by validator`, { msgId, source: source.toString(), topicType });
|
|
754
952
|
this.instrumentation.recordMessageValidation(topicType, timer);
|
|
953
|
+
} else if (resultAndObj.result === TopicValidatorResult.Reject) {
|
|
954
|
+
this.logger.warn(`Message ${topicType} rejected by validator with severity ${resultAndObj.severity}`, {
|
|
955
|
+
msgId,
|
|
956
|
+
source: source.toString(),
|
|
957
|
+
topicType,
|
|
958
|
+
severity: resultAndObj.severity,
|
|
959
|
+
});
|
|
960
|
+
this.peerManager.penalizePeer(source, resultAndObj.severity);
|
|
961
|
+
} else {
|
|
962
|
+
this.logger.trace(`Message ${topicType} ignored by validator`, { msgId, source: source.toString(), topicType });
|
|
755
963
|
}
|
|
756
964
|
|
|
757
965
|
this.node.services.pubsub.reportMessageValidationResult(msgId, source.toString(), resultAndObj.result);
|
|
758
966
|
return resultAndObj;
|
|
759
967
|
}
|
|
760
968
|
|
|
969
|
+
private tryDeserialize<T>(deserializeFunc: () => T, msgId: string, source: PeerId): T | undefined {
|
|
970
|
+
try {
|
|
971
|
+
return deserializeFunc();
|
|
972
|
+
} catch (err) {
|
|
973
|
+
this.logger.warn(`Failed to deserialize gossipsub message from buffer`, {
|
|
974
|
+
err,
|
|
975
|
+
msgId,
|
|
976
|
+
source: source.toString(),
|
|
977
|
+
});
|
|
978
|
+
return undefined;
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
|
|
761
982
|
protected async handleGossipedTx(payloadData: Buffer, msgId: string, source: PeerId) {
|
|
762
983
|
const validationFunc: () => Promise<ReceivedMessageValidationResult<Tx>> = async () => {
|
|
763
|
-
const tx = Tx.fromBuffer(payloadData);
|
|
764
|
-
|
|
765
|
-
|
|
984
|
+
const tx = this.tryDeserialize(() => Tx.fromBuffer(payloadData), msgId, source);
|
|
985
|
+
if (!tx) {
|
|
986
|
+
return { result: TopicValidatorResult.Reject, severity: PeerErrorSeverity.LowToleranceError };
|
|
987
|
+
}
|
|
766
988
|
|
|
767
|
-
this.
|
|
768
|
-
|
|
769
|
-
|
|
989
|
+
const currentBlockNumber = await this.archiver.getBlockNumber();
|
|
990
|
+
const { ts: nextSlotTimestamp } = this.epochCache.getEpochAndSlotInNextL1Slot();
|
|
991
|
+
|
|
992
|
+
// Stage 1: fast validators (metadata, data, timestamps, double-spend, gas, phases, block header)
|
|
993
|
+
const firstStageValidators = await this.createFirstStageMessageValidators(currentBlockNumber, nextSlotTimestamp);
|
|
994
|
+
const firstStageOutcome = await this.runValidations(tx, firstStageValidators);
|
|
995
|
+
if (!firstStageOutcome.allPassed) {
|
|
996
|
+
const { name } = firstStageOutcome.failure;
|
|
997
|
+
let { severity } = firstStageOutcome.failure;
|
|
998
|
+
|
|
999
|
+
// Double spend validator has a special case handler. We perform more detailed examination
|
|
1000
|
+
// as to how recently the nullifier was entered into the tree and if the transaction should
|
|
1001
|
+
// have 'known' the nullifier existed. This determines the severity of the penalty applied to the peer.
|
|
1002
|
+
if (name === 'doubleSpendValidator') {
|
|
1003
|
+
const txBlockNumber = BlockNumber(currentBlockNumber + 1);
|
|
1004
|
+
severity = await this.handleDoubleSpendFailure(tx, txBlockNumber);
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
this.logger.verbose(`Rejecting gossiped tx ${tx.getTxHash().toString()}: stage 1 validation failed`, {
|
|
1008
|
+
validator: name,
|
|
1009
|
+
severity,
|
|
1010
|
+
source: source.toString(),
|
|
1011
|
+
});
|
|
1012
|
+
return { result: TopicValidatorResult.Reject, severity };
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
// Pool pre-check: see if the pool would accept this tx before doing expensive proof verification
|
|
1016
|
+
const canAdd = await this.mempools.txPool.canAddPendingTx(tx);
|
|
1017
|
+
if (canAdd === 'ignored') {
|
|
1018
|
+
this.logger.verbose(`Ignoring gossiped tx ${tx.getTxHash().toString()}: pool pre-check returned ignored`, {
|
|
1019
|
+
source: source.toString(),
|
|
1020
|
+
});
|
|
1021
|
+
return { result: TopicValidatorResult.Ignore, obj: tx };
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
// Stage 2: expensive proof verification
|
|
1025
|
+
const secondStageValidators = this.createSecondStageMessageValidators();
|
|
1026
|
+
const secondStageOutcome = await this.runValidations(tx, secondStageValidators);
|
|
1027
|
+
if (!secondStageOutcome.allPassed) {
|
|
1028
|
+
const { severity, name } = secondStageOutcome.failure;
|
|
1029
|
+
this.logger.verbose(`Rejecting gossiped tx ${tx.getTxHash().toString()}: stage 2 validation failed`, {
|
|
1030
|
+
validator: name,
|
|
1031
|
+
severity,
|
|
1032
|
+
source: source.toString(),
|
|
1033
|
+
});
|
|
1034
|
+
return { result: TopicValidatorResult.Reject, severity };
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
// Pool add: persist the tx
|
|
1038
|
+
const txHash = tx.getTxHash();
|
|
1039
|
+
const addResult = await this.mempools.txPool.addPendingTxs([tx], { source: 'gossip' });
|
|
1040
|
+
|
|
1041
|
+
const wasAccepted = addResult.accepted.some(h => h.equals(txHash));
|
|
1042
|
+
const wasIgnored = addResult.ignored.some(h => h.equals(txHash));
|
|
1043
|
+
|
|
1044
|
+
this.logger.verbose(`Validate propagated tx ${txHash.toString()}`, {
|
|
1045
|
+
wasAccepted,
|
|
1046
|
+
wasIgnored,
|
|
770
1047
|
[Attributes.P2P_ID]: source.toString(),
|
|
771
1048
|
});
|
|
772
1049
|
|
|
773
|
-
if (
|
|
774
|
-
return { result: TopicValidatorResult.
|
|
775
|
-
} else if (
|
|
1050
|
+
if (wasAccepted) {
|
|
1051
|
+
return { result: TopicValidatorResult.Accept, obj: tx };
|
|
1052
|
+
} else if (wasIgnored) {
|
|
776
1053
|
return { result: TopicValidatorResult.Ignore, obj: tx };
|
|
777
1054
|
} else {
|
|
778
|
-
|
|
1055
|
+
this.logger.warn(`Gossiped tx ${txHash.toString()} unexpectedly rejected by pool`, {
|
|
1056
|
+
source: source.toString(),
|
|
1057
|
+
txHash: txHash.toString(),
|
|
1058
|
+
});
|
|
1059
|
+
return { result: TopicValidatorResult.Reject, severity: PeerErrorSeverity.HighToleranceError };
|
|
779
1060
|
}
|
|
780
1061
|
};
|
|
781
1062
|
|
|
@@ -784,6 +1065,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
784
1065
|
return;
|
|
785
1066
|
}
|
|
786
1067
|
|
|
1068
|
+
// Tx was accepted into pool and will be propagated - just log and record metrics
|
|
787
1069
|
const txHash = tx.getTxHash();
|
|
788
1070
|
const txHashString = txHash.toString();
|
|
789
1071
|
this.logger.verbose(`Received tx ${txHashString} from external peer ${source.toString()} via gossip`, {
|
|
@@ -791,73 +1073,40 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
791
1073
|
txHash: txHashString,
|
|
792
1074
|
});
|
|
793
1075
|
|
|
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
1076
|
this.instrumentation.incrementTxReceived(1);
|
|
800
|
-
await this.mempools.txPool.addTxs([tx]);
|
|
801
1077
|
}
|
|
802
1078
|
|
|
803
1079
|
/**
|
|
804
|
-
* Process
|
|
805
|
-
*
|
|
806
|
-
*
|
|
807
|
-
* @param attestation - The attestation to process.
|
|
1080
|
+
* Process a checkpoint attestation from a peer.
|
|
1081
|
+
* Validates the attestation and adds it to the pool.
|
|
808
1082
|
*/
|
|
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,
|
|
1083
|
+
private async processCheckpointAttestationFromPeer(
|
|
1084
|
+
payloadData: Buffer,
|
|
1085
|
+
msgId: string,
|
|
1086
|
+
source: PeerId,
|
|
1087
|
+
): Promise<void> {
|
|
1088
|
+
const { result, obj: attestation } = await this.validateReceivedMessage<CheckpointAttestation>(
|
|
1089
|
+
() => {
|
|
1090
|
+
const attestation = this.tryDeserialize(() => CheckpointAttestation.fromBuffer(payloadData), msgId, source);
|
|
1091
|
+
if (!attestation) {
|
|
1092
|
+
return Promise.resolve({
|
|
1093
|
+
result: TopicValidatorResult.Reject,
|
|
1094
|
+
severity: PeerErrorSeverity.LowToleranceError,
|
|
1095
|
+
});
|
|
1096
|
+
}
|
|
1097
|
+
return this.validateAndStoreCheckpointAttestation(source, attestation);
|
|
1098
|
+
},
|
|
850
1099
|
msgId,
|
|
851
1100
|
source,
|
|
852
|
-
TopicType.
|
|
1101
|
+
TopicType.checkpoint_attestation,
|
|
853
1102
|
);
|
|
854
1103
|
|
|
855
1104
|
if (result !== TopicValidatorResult.Accept || !attestation) {
|
|
856
1105
|
return;
|
|
857
1106
|
}
|
|
858
1107
|
|
|
859
|
-
this.logger.
|
|
860
|
-
`Received attestation for slot ${attestation.slotNumber} from external peer ${source.toString()}`,
|
|
1108
|
+
this.logger.verbose(
|
|
1109
|
+
`Received valid checkpoint attestation for slot ${attestation.slotNumber} from external peer ${source.toString()}`,
|
|
861
1110
|
{
|
|
862
1111
|
p2pMessageIdentifier: await attestation.p2pMessageLoggingIdentifier(),
|
|
863
1112
|
slot: attestation.slotNumber,
|
|
@@ -865,123 +1114,361 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
865
1114
|
source: source.toString(),
|
|
866
1115
|
},
|
|
867
1116
|
);
|
|
868
|
-
|
|
869
|
-
await this.mempools.attestationPool!.addAttestations([attestation]);
|
|
870
1117
|
}
|
|
871
1118
|
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
this.logger.
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
1119
|
+
/** Validates a checkpoint attestation and adds it to the pool. Penalizes the peer if validation fails. */
|
|
1120
|
+
@trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId, attestation) => ({
|
|
1121
|
+
[Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber.toString(),
|
|
1122
|
+
}))
|
|
1123
|
+
protected async validateAndStoreCheckpointAttestation(
|
|
1124
|
+
peerId: PeerId,
|
|
1125
|
+
attestation: CheckpointAttestation,
|
|
1126
|
+
): Promise<ReceivedMessageValidationResult<CheckpointAttestation>> {
|
|
1127
|
+
const validationResult = await this.checkpointAttestationValidator.validate(attestation);
|
|
1128
|
+
|
|
1129
|
+
if (validationResult.result === 'reject') {
|
|
1130
|
+
this.logger.warn(`Penalizing peer ${peerId} for checkpoint attestation validation failure`);
|
|
1131
|
+
return { result: TopicValidatorResult.Reject, severity: validationResult.severity };
|
|
1132
|
+
}
|
|
1133
|
+
|
|
1134
|
+
if (validationResult.result === 'ignore') {
|
|
1135
|
+
return { result: TopicValidatorResult.Ignore, obj: attestation };
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
// Try to add the attestation: this handles existence check, cap check, and adding in one call
|
|
1139
|
+
// count is the number of attestations by this signer for this slot (for duplicate detection)
|
|
1140
|
+
const slot = attestation.payload.header.slotNumber;
|
|
1141
|
+
const { added, alreadyExists, count } =
|
|
1142
|
+
await this.mempools.attestationPool.tryAddCheckpointAttestation(attestation);
|
|
1143
|
+
|
|
1144
|
+
this.logger.trace(`Validate propagated checkpoint attestation`, {
|
|
1145
|
+
added,
|
|
1146
|
+
alreadyExists,
|
|
1147
|
+
count,
|
|
1148
|
+
[Attributes.SLOT_NUMBER]: slot.toString(),
|
|
1149
|
+
[Attributes.P2P_ID]: peerId.toString(),
|
|
1150
|
+
});
|
|
1151
|
+
|
|
1152
|
+
// Exact same attestation received, no need to re-broadcast
|
|
1153
|
+
if (alreadyExists) {
|
|
1154
|
+
return { result: TopicValidatorResult.Ignore, obj: attestation };
|
|
1155
|
+
}
|
|
1156
|
+
|
|
1157
|
+
// Could not add (cap reached for signer), penalize and do not re-broadcast
|
|
1158
|
+
if (!added) {
|
|
1159
|
+
this.logger.warn(`Rejecting checkpoint attestation due to cap`, {
|
|
1160
|
+
slot: slot.toString(),
|
|
1161
|
+
archive: attestation.archive.toString(),
|
|
1162
|
+
source: peerId.toString(),
|
|
1163
|
+
attester: attestation.getSender()?.toString(),
|
|
1164
|
+
count,
|
|
889
1165
|
});
|
|
1166
|
+
return { result: TopicValidatorResult.Reject, severity: PeerErrorSeverity.HighToleranceError };
|
|
1167
|
+
}
|
|
890
1168
|
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
this.
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
1169
|
+
// Check if this is a duplicate attestation (signer attested to a different proposal at the same slot)
|
|
1170
|
+
// count is the number of attestations by this signer for this slot
|
|
1171
|
+
if (count === 2) {
|
|
1172
|
+
const attester = attestation.getSender();
|
|
1173
|
+
if (attester) {
|
|
1174
|
+
this.logger.warn(`Detected duplicate attestation (equivocation) at slot ${slot}`, {
|
|
1175
|
+
slot: slot.toString(),
|
|
1176
|
+
archive: attestation.archive.toString(),
|
|
1177
|
+
source: peerId.toString(),
|
|
1178
|
+
attester: attester.toString(),
|
|
901
1179
|
});
|
|
902
|
-
|
|
903
|
-
} else {
|
|
904
|
-
return { result: TopicValidatorResult.Accept, obj: block };
|
|
1180
|
+
this.duplicateAttestationCallback?.({ slot, attester });
|
|
905
1181
|
}
|
|
906
|
-
}
|
|
1182
|
+
}
|
|
907
1183
|
|
|
908
|
-
|
|
909
|
-
|
|
1184
|
+
// Attestation was added successfully - accept it so other nodes can also detect the equivocation
|
|
1185
|
+
return { result: TopicValidatorResult.Accept, obj: attestation };
|
|
1186
|
+
}
|
|
1187
|
+
|
|
1188
|
+
protected async processBlockFromPeer(payloadData: Buffer, msgId: string, source: PeerId): Promise<void> {
|
|
1189
|
+
const {
|
|
1190
|
+
result,
|
|
1191
|
+
obj: block,
|
|
1192
|
+
metadata: { isEquivocated } = {},
|
|
1193
|
+
} = await this.validateReceivedMessage<BlockProposal, { isEquivocated: boolean }>(
|
|
1194
|
+
() => this.validateAndStoreBlockProposal(source, BlockProposal.fromBuffer(payloadData)),
|
|
910
1195
|
msgId,
|
|
911
1196
|
source,
|
|
912
1197
|
TopicType.block_proposal,
|
|
913
1198
|
);
|
|
914
1199
|
|
|
915
|
-
|
|
1200
|
+
// If not accepted or equivocated, return
|
|
1201
|
+
if (result !== TopicValidatorResult.Accept || !block || isEquivocated) {
|
|
916
1202
|
return;
|
|
917
1203
|
}
|
|
918
1204
|
|
|
919
1205
|
await this.processValidBlockProposal(block, source);
|
|
920
1206
|
}
|
|
921
1207
|
|
|
922
|
-
|
|
1208
|
+
/** Validates a block proposal. Triggers a penalization to the peer that sent it if invalid. Adds to the mempool if valid. */
|
|
1209
|
+
@trackSpan('Libp2pService.validateAndStoreBlockProposal', (_peerId, block) => ({
|
|
1210
|
+
[Attributes.BLOCK_NUMBER]: block.blockNumber.toString(),
|
|
1211
|
+
[Attributes.SLOT_NUMBER]: block.slotNumber.toString(),
|
|
1212
|
+
}))
|
|
1213
|
+
protected async validateAndStoreBlockProposal(
|
|
1214
|
+
peerId: PeerId,
|
|
1215
|
+
block: BlockProposal,
|
|
1216
|
+
): Promise<ReceivedMessageValidationResult<BlockProposal, { isEquivocated: boolean }>> {
|
|
1217
|
+
const validationResult = await this.blockProposalValidator.validate(block);
|
|
1218
|
+
|
|
1219
|
+
if (validationResult.result === 'reject') {
|
|
1220
|
+
this.logger.warn(`Penalizing peer ${peerId} for block proposal validation failure`);
|
|
1221
|
+
return { result: TopicValidatorResult.Reject, severity: validationResult.severity };
|
|
1222
|
+
}
|
|
1223
|
+
|
|
1224
|
+
if (validationResult.result === 'ignore') {
|
|
1225
|
+
return { result: TopicValidatorResult.Ignore, obj: block };
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
// Try to add the proposal: this handles existence check, cap check, and adding in one call
|
|
1229
|
+
const { added, alreadyExists, count } = await this.mempools.attestationPool.tryAddBlockProposal(block);
|
|
1230
|
+
const isEquivocated = count !== undefined && count > 1;
|
|
1231
|
+
|
|
1232
|
+
// Duplicate proposal received, no need to re-broadcast
|
|
1233
|
+
if (alreadyExists) {
|
|
1234
|
+
this.logger.debug(`Ignoring duplicate block proposal received`, {
|
|
1235
|
+
...block.toBlockInfo(),
|
|
1236
|
+
indexWithinCheckpoint: block.indexWithinCheckpoint,
|
|
1237
|
+
proposer: block.getSender()?.toString(),
|
|
1238
|
+
source: peerId.toString(),
|
|
1239
|
+
});
|
|
1240
|
+
return { result: TopicValidatorResult.Ignore, obj: block, metadata: { isEquivocated } };
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1243
|
+
// Too many blocks received for this slot and index, penalize peer and do not re-broadcast
|
|
1244
|
+
if (!added) {
|
|
1245
|
+
this.logger.warn(`Penalizing peer for block proposal exceeding per-position cap`, {
|
|
1246
|
+
...block.toBlockInfo(),
|
|
1247
|
+
indexWithinCheckpoint: block.indexWithinCheckpoint,
|
|
1248
|
+
count,
|
|
1249
|
+
proposer: block.getSender()?.toString(),
|
|
1250
|
+
source: peerId.toString(),
|
|
1251
|
+
});
|
|
1252
|
+
return {
|
|
1253
|
+
result: TopicValidatorResult.Reject,
|
|
1254
|
+
metadata: { isEquivocated },
|
|
1255
|
+
severity: PeerErrorSeverity.HighToleranceError,
|
|
1256
|
+
};
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1259
|
+
// If this was a duplicate proposal, do not process it, but do invoke the duplicate callback,
|
|
1260
|
+
// and do re-broadcast it so other nodes in the network know to slash the proposer
|
|
1261
|
+
if (isEquivocated) {
|
|
1262
|
+
const proposer = block.getSender();
|
|
1263
|
+
this.logger.warn(`Detected duplicate block proposal (equivocation) at slot ${block.slotNumber}`, {
|
|
1264
|
+
...block.toBlockInfo(),
|
|
1265
|
+
source: peerId.toString(),
|
|
1266
|
+
proposer: proposer?.toString(),
|
|
1267
|
+
});
|
|
1268
|
+
// Invoke the duplicate callback on the first duplicate spotted only
|
|
1269
|
+
if (proposer && count === 2) {
|
|
1270
|
+
this.duplicateProposalCallback?.({ slot: block.slotNumber, proposer, type: 'block' });
|
|
1271
|
+
}
|
|
1272
|
+
return { result: TopicValidatorResult.Accept, obj: block, metadata: { isEquivocated } };
|
|
1273
|
+
}
|
|
1274
|
+
|
|
1275
|
+
// Otherwise, we're good to go!
|
|
1276
|
+
return { result: TopicValidatorResult.Accept, obj: block };
|
|
1277
|
+
}
|
|
1278
|
+
|
|
1279
|
+
// REFACTOR(palla): This method should be moved to the p2p_client or to a separate component,
|
|
1280
|
+
// should not be here as it does not deal with p2p networking.
|
|
923
1281
|
@trackSpan('Libp2pService.processValidBlockProposal', async block => ({
|
|
924
1282
|
[Attributes.SLOT_NUMBER]: block.slotNumber,
|
|
925
1283
|
[Attributes.BLOCK_ARCHIVE]: block.archive.toString(),
|
|
926
1284
|
[Attributes.P2P_ID]: await block.p2pMessageLoggingIdentifier().then(i => i.toString()),
|
|
927
1285
|
}))
|
|
928
|
-
|
|
1286
|
+
protected async processValidBlockProposal(block: BlockProposal, sender: PeerId) {
|
|
929
1287
|
const slot = block.slotNumber;
|
|
930
|
-
const previousSlot = SlotNumber(slot - 1);
|
|
931
1288
|
this.logger.verbose(`Received block proposal for slot ${slot} from external peer ${sender.toString()}.`, {
|
|
932
1289
|
p2pMessageIdentifier: await block.p2pMessageLoggingIdentifier(),
|
|
933
|
-
slot: block.slotNumber,
|
|
934
|
-
archive: block.archive.toString(),
|
|
935
1290
|
source: sender.toString(),
|
|
1291
|
+
...block.toBlockInfo(),
|
|
936
1292
|
});
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
1293
|
+
|
|
1294
|
+
// Mark the txs in this proposal as protected
|
|
1295
|
+
await this.mempools.txPool.protectTxs(block.txHashes, block.blockHeader);
|
|
1296
|
+
|
|
1297
|
+
// Call the block received callback to validate the proposal.
|
|
1298
|
+
// Note: Validators do NOT attest to individual blocks, only to checkpoint proposals.
|
|
1299
|
+
const isValid = await this.blockReceivedCallback(block, sender);
|
|
1300
|
+
if (!isValid) {
|
|
1301
|
+
this.logger.info(`Block proposal validation failed for block ${block.blockNumber}`, block.toBlockInfo());
|
|
940
1302
|
}
|
|
1303
|
+
}
|
|
941
1304
|
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
1305
|
+
/**
|
|
1306
|
+
* Handle a gossiped checkpoint proposal.
|
|
1307
|
+
* Validates and processes the checkpoint proposal, then triggers the callback for attestation.
|
|
1308
|
+
*/
|
|
1309
|
+
protected async handleGossipedCheckpointProposal(payloadData: Buffer, msgId: string, source: PeerId): Promise<void> {
|
|
1310
|
+
const {
|
|
1311
|
+
result,
|
|
1312
|
+
obj: checkpoint,
|
|
1313
|
+
metadata: { isEquivocated, processBlock } = {},
|
|
1314
|
+
} = await this.validateReceivedMessage<CheckpointProposal, { isEquivocated: boolean; processBlock: boolean }>(
|
|
1315
|
+
() => this.validateAndStoreCheckpointProposal(source, CheckpointProposal.fromBuffer(payloadData)),
|
|
1316
|
+
msgId,
|
|
1317
|
+
source,
|
|
1318
|
+
TopicType.checkpoint_proposal,
|
|
1319
|
+
);
|
|
1320
|
+
|
|
1321
|
+
// If the checkpoint contained a valid last block, we process it even if the checkpoint itself is to be rejected
|
|
1322
|
+
// TODO(palla/mbps): Is this ok? Should we be considering a block from a checkpoint that was equivocated?
|
|
1323
|
+
if (processBlock && checkpoint?.getBlockProposal()) {
|
|
1324
|
+
await this.processValidBlockProposal(checkpoint.getBlockProposal()!, source);
|
|
1325
|
+
}
|
|
1326
|
+
|
|
1327
|
+
if (result !== TopicValidatorResult.Accept || !checkpoint || isEquivocated) {
|
|
1328
|
+
return;
|
|
1329
|
+
}
|
|
1330
|
+
|
|
1331
|
+
await this.processValidCheckpointProposal(checkpoint.toCore(), source);
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1334
|
+
/**
|
|
1335
|
+
* Validates a checkpoint proposal. Penalizes peer if validation fails. Adds the checkpoint and
|
|
1336
|
+
* its last block (if present) to the mempool if valid. Triggers equivocation detection on both.
|
|
1337
|
+
*/
|
|
1338
|
+
@trackSpan('Libp2pService.validateAndStoreCheckpointProposal', (_peerId, checkpoint) => ({
|
|
1339
|
+
[Attributes.SLOT_NUMBER]: checkpoint.slotNumber.toString(),
|
|
1340
|
+
}))
|
|
1341
|
+
protected async validateAndStoreCheckpointProposal(
|
|
1342
|
+
peerId: PeerId,
|
|
1343
|
+
checkpoint: CheckpointProposal,
|
|
1344
|
+
): Promise<ReceivedMessageValidationResult<CheckpointProposal, { isEquivocated: boolean; processBlock: boolean }>> {
|
|
1345
|
+
const validationResult = await this.checkpointProposalValidator.validate(checkpoint);
|
|
1346
|
+
|
|
1347
|
+
if (validationResult.result === 'reject') {
|
|
1348
|
+
this.logger.warn(`Penalizing peer ${peerId} for checkpoint proposal validation failure`);
|
|
1349
|
+
return { result: TopicValidatorResult.Reject, severity: validationResult.severity };
|
|
1350
|
+
}
|
|
1351
|
+
|
|
1352
|
+
if (validationResult.result === 'ignore') {
|
|
1353
|
+
return { result: TopicValidatorResult.Ignore, obj: checkpoint };
|
|
1354
|
+
}
|
|
1355
|
+
|
|
1356
|
+
// Extract and try to add the block proposal first if present
|
|
1357
|
+
const blockProposal = checkpoint.getBlockProposal();
|
|
1358
|
+
let processBlock = false;
|
|
1359
|
+
if (blockProposal) {
|
|
1360
|
+
this.logger.debug(`Validating block proposal from propagated checkpoint`, {
|
|
1361
|
+
[Attributes.SLOT_NUMBER]: checkpoint.slotNumber.toString(),
|
|
1362
|
+
[Attributes.P2P_ID]: peerId.toString(),
|
|
1363
|
+
});
|
|
1364
|
+
const blockProposalResult = await this.validateAndStoreBlockProposal(peerId, blockProposal);
|
|
1365
|
+
const { obj, metadata: { isEquivocated } = {} } = blockProposalResult;
|
|
1366
|
+
if (blockProposalResult.result === TopicValidatorResult.Reject || !obj || isEquivocated) {
|
|
1367
|
+
this.logger.debug(`Rejecting checkpoint due to invalid last block proposal`, {
|
|
1368
|
+
[Attributes.SLOT_NUMBER]: checkpoint.slotNumber.toString(),
|
|
1369
|
+
[Attributes.P2P_ID]: peerId.toString(),
|
|
1370
|
+
isEquivocated,
|
|
1371
|
+
result: blockProposalResult.result,
|
|
952
1372
|
});
|
|
953
|
-
return
|
|
1373
|
+
return {
|
|
1374
|
+
result: TopicValidatorResult.Reject,
|
|
1375
|
+
severity:
|
|
1376
|
+
'severity' in blockProposalResult ? blockProposalResult.severity : PeerErrorSeverity.MidToleranceError,
|
|
1377
|
+
};
|
|
1378
|
+
} else if (blockProposalResult.result === TopicValidatorResult.Accept && obj && !isEquivocated) {
|
|
1379
|
+
processBlock = true;
|
|
954
1380
|
}
|
|
955
|
-
throw err;
|
|
956
1381
|
}
|
|
957
|
-
await this.mempools.txPool.markTxsAsNonEvictable(block.txHashes);
|
|
958
|
-
const attestations = await this.blockReceivedCallback(block, sender);
|
|
959
1382
|
|
|
960
|
-
//
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
1383
|
+
// Try to add the checkpoint proposal core: this handles existence check, cap check, and adding in one call
|
|
1384
|
+
const checkpointCore = checkpoint.toCore();
|
|
1385
|
+
const tryAddResult = await this.mempools.attestationPool.tryAddCheckpointProposal(checkpointCore);
|
|
1386
|
+
const { added, alreadyExists, count } = tryAddResult;
|
|
1387
|
+
const isEquivocated = count !== undefined && count > 1;
|
|
1388
|
+
|
|
1389
|
+
// Duplicate proposal received, do not re-broadcast
|
|
1390
|
+
if (alreadyExists) {
|
|
1391
|
+
this.logger.debug(`Ignoring duplicate checkpoint proposal received`, {
|
|
1392
|
+
...checkpoint.toCheckpointInfo(),
|
|
1393
|
+
source: peerId.toString(),
|
|
1394
|
+
});
|
|
1395
|
+
return {
|
|
1396
|
+
result: TopicValidatorResult.Ignore,
|
|
1397
|
+
obj: checkpoint,
|
|
1398
|
+
metadata: { isEquivocated, processBlock },
|
|
1399
|
+
};
|
|
1400
|
+
}
|
|
1401
|
+
|
|
1402
|
+
// Too many checkpoint proposals received for this slot, penalize peer and do not re-broadcast
|
|
1403
|
+
// Note: We still return the checkpoint obj so the lastBlock can be processed if valid
|
|
1404
|
+
if (!added) {
|
|
1405
|
+
this.logger.warn(`Penalizing peer for checkpoint proposal exceeding per-slot cap`, {
|
|
1406
|
+
...checkpoint.toCheckpointInfo(),
|
|
1407
|
+
count,
|
|
1408
|
+
source: peerId.toString(),
|
|
1409
|
+
});
|
|
1410
|
+
return {
|
|
1411
|
+
result: TopicValidatorResult.Reject,
|
|
1412
|
+
obj: checkpoint,
|
|
1413
|
+
metadata: { isEquivocated, processBlock },
|
|
1414
|
+
severity: PeerErrorSeverity.HighToleranceError,
|
|
1415
|
+
};
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1418
|
+
// If this was a duplicate proposal, do not process it, but do invoke the duplicate callback,
|
|
1419
|
+
// and do re-broadcast it so other nodes in the network know to slash the proposer
|
|
1420
|
+
if (isEquivocated) {
|
|
1421
|
+
const proposer = checkpoint.getSender();
|
|
1422
|
+
this.logger.warn(`Detected duplicate checkpoint proposal (equivocation) at slot ${checkpoint.slotNumber}`, {
|
|
1423
|
+
...checkpoint.toCheckpointInfo(),
|
|
1424
|
+
source: peerId.toString(),
|
|
1425
|
+
proposer: proposer?.toString(),
|
|
1426
|
+
});
|
|
1427
|
+
// Invoke the duplicate callback on the first duplicate spotted only
|
|
1428
|
+
if (proposer && count === 2) {
|
|
1429
|
+
this.duplicateProposalCallback?.({ slot: checkpoint.slotNumber, proposer, type: 'checkpoint' });
|
|
970
1430
|
}
|
|
1431
|
+
return {
|
|
1432
|
+
result: TopicValidatorResult.Accept,
|
|
1433
|
+
obj: checkpoint,
|
|
1434
|
+
metadata: { isEquivocated, processBlock },
|
|
1435
|
+
};
|
|
971
1436
|
}
|
|
1437
|
+
|
|
1438
|
+
// Otherwise, we're good to go!
|
|
1439
|
+
return { result: TopicValidatorResult.Accept, obj: checkpoint, metadata: { processBlock, isEquivocated } };
|
|
972
1440
|
}
|
|
973
1441
|
|
|
974
1442
|
/**
|
|
975
|
-
*
|
|
976
|
-
*
|
|
1443
|
+
* Process a validated checkpoint proposal.
|
|
1444
|
+
* Note: The proposal was already added to the pool by tryAddCheckpointProposal in handleGossipedCheckpointProposal.
|
|
977
1445
|
*/
|
|
978
|
-
@trackSpan('Libp2pService.
|
|
979
|
-
[Attributes.SLOT_NUMBER]:
|
|
980
|
-
[Attributes.BLOCK_ARCHIVE]:
|
|
981
|
-
[Attributes.P2P_ID]: await
|
|
1446
|
+
@trackSpan('Libp2pService.processValidCheckpointProposal', async checkpoint => ({
|
|
1447
|
+
[Attributes.SLOT_NUMBER]: checkpoint.slotNumber,
|
|
1448
|
+
[Attributes.BLOCK_ARCHIVE]: checkpoint.archive.toString(),
|
|
1449
|
+
[Attributes.P2P_ID]: await checkpoint.p2pMessageLoggingIdentifier().then(i => i.toString()),
|
|
982
1450
|
}))
|
|
983
|
-
|
|
984
|
-
|
|
1451
|
+
protected async processValidCheckpointProposal(checkpoint: CheckpointProposalCore, sender: PeerId) {
|
|
1452
|
+
const slot = checkpoint.slotNumber;
|
|
1453
|
+
this.logger.verbose(`Received checkpoint proposal for slot ${slot} from external peer ${sender.toString()}.`, {
|
|
1454
|
+
p2pMessageIdentifier: await checkpoint.p2pMessageLoggingIdentifier(),
|
|
1455
|
+
slot: checkpoint.slotNumber,
|
|
1456
|
+
archive: checkpoint.archive.toString(),
|
|
1457
|
+
source: sender.toString(),
|
|
1458
|
+
});
|
|
1459
|
+
|
|
1460
|
+
await this.allNodesCheckpointReceivedCallback(checkpoint, sender);
|
|
1461
|
+
|
|
1462
|
+
// Call the checkpoint received callback with the core version (without lastBlock)
|
|
1463
|
+
// to validate and potentially generate attestations
|
|
1464
|
+
const attestations = await this.validatorCheckpointReceivedCallback(checkpoint, sender);
|
|
1465
|
+
if (attestations && attestations.length > 0) {
|
|
1466
|
+
// If the callback returned attestations, add them to the pool and propagate them
|
|
1467
|
+
await this.mempools.attestationPool.addOwnCheckpointAttestations(attestations);
|
|
1468
|
+
for (const attestation of attestations) {
|
|
1469
|
+
await this.propagate(attestation);
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
985
1472
|
}
|
|
986
1473
|
|
|
987
1474
|
/**
|
|
@@ -1004,9 +1491,9 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1004
1491
|
* @returns True if the requested block transactions are valid, false otherwise.
|
|
1005
1492
|
*/
|
|
1006
1493
|
@trackSpan('Libp2pService.validateRequestedBlockTxs', request => ({
|
|
1007
|
-
[Attributes.
|
|
1494
|
+
[Attributes.BLOCK_ARCHIVE]: request.archiveRoot.toString(),
|
|
1008
1495
|
}))
|
|
1009
|
-
|
|
1496
|
+
protected async validateRequestedBlockTxs(
|
|
1010
1497
|
request: BlockTxsRequest,
|
|
1011
1498
|
response: BlockTxsResponse,
|
|
1012
1499
|
peerId: PeerId,
|
|
@@ -1014,10 +1501,10 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1014
1501
|
const requestedTxValidator = this.createRequestedTxValidator();
|
|
1015
1502
|
|
|
1016
1503
|
try {
|
|
1017
|
-
if (!response.
|
|
1504
|
+
if (!response.archiveRoot.equals(request.archiveRoot)) {
|
|
1018
1505
|
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
1019
1506
|
throw new ValidationError(
|
|
1020
|
-
`Received block txs for unexpected
|
|
1507
|
+
`Received block txs for unexpected archive root: expected ${request.archiveRoot.toString()}, got ${response.archiveRoot.toString()}`,
|
|
1021
1508
|
);
|
|
1022
1509
|
}
|
|
1023
1510
|
|
|
@@ -1047,7 +1534,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1047
1534
|
}
|
|
1048
1535
|
|
|
1049
1536
|
// Given proposal (should have locally), ensure returned txs are valid subset and match request indices
|
|
1050
|
-
const proposal = await this.mempools.attestationPool
|
|
1537
|
+
const proposal = await this.mempools.attestationPool.getBlockProposal(request.archiveRoot.toString());
|
|
1051
1538
|
if (proposal) {
|
|
1052
1539
|
// Build intersected indices
|
|
1053
1540
|
const intersectIdx = request.txIndices.getTrueIndices().filter(i => response.txIndices.isSet(i));
|
|
@@ -1067,7 +1554,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1067
1554
|
} else {
|
|
1068
1555
|
// No local proposal, cannot check the membership/order of the returned txs
|
|
1069
1556
|
this.logger.warn(
|
|
1070
|
-
`Block proposal not found for
|
|
1557
|
+
`Block proposal not found for archive root ${request.archiveRoot.toString()}; cannot validate membership/order of returned txs`,
|
|
1071
1558
|
);
|
|
1072
1559
|
return false;
|
|
1073
1560
|
}
|
|
@@ -1106,7 +1593,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1106
1593
|
const requested = new Set(requestedTxHash.map(h => h.toString()));
|
|
1107
1594
|
const requestedTxValidator = this.createRequestedTxValidator();
|
|
1108
1595
|
|
|
1109
|
-
//TODO: (mralj) - this is somewhat naive implementation, if single tx is
|
|
1596
|
+
//TODO: (mralj) - this is somewhat naive implementation, if single tx is invalid we consider the whole response invalid.
|
|
1110
1597
|
// I think we should still extract the valid txs and return them, so that we can still use the response.
|
|
1111
1598
|
try {
|
|
1112
1599
|
await Promise.all(responseTx.map(tx => this.validateRequestedTx(tx, peerId, requestedTxValidator, requested)));
|
|
@@ -1122,74 +1609,13 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1122
1609
|
}
|
|
1123
1610
|
}
|
|
1124
1611
|
|
|
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,
|
|
1612
|
+
protected async validateRequestedTx(
|
|
1613
|
+
tx: Tx,
|
|
1142
1614
|
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}`>) {
|
|
1615
|
+
txValidator: TxValidator,
|
|
1616
|
+
requested?: Set<`0x${string}`>,
|
|
1617
|
+
) {
|
|
1186
1618
|
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
1619
|
if (requested && !requested.has(tx.getTxHash().toString())) {
|
|
1194
1620
|
penalize(PeerErrorSeverity.MidToleranceError);
|
|
1195
1621
|
throw new ValidationError(`Received tx with hash ${tx.getTxHash().toString()} that was not requested.`);
|
|
@@ -1202,101 +1628,89 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1202
1628
|
}
|
|
1203
1629
|
}
|
|
1204
1630
|
|
|
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;
|
|
1631
|
+
protected createRequestedTxValidator(): TxValidator {
|
|
1632
|
+
return createTxValidatorForReqResponseReceivedTxs(this.proofVerifier, {
|
|
1633
|
+
l1ChainId: this.config.l1ChainId,
|
|
1634
|
+
rollupVersion: this.config.rollupVersion,
|
|
1635
|
+
});
|
|
1234
1636
|
}
|
|
1235
1637
|
|
|
1236
|
-
private
|
|
1237
|
-
|
|
1238
|
-
return this.feesCache.gasFees;
|
|
1239
|
-
}
|
|
1240
|
-
|
|
1241
|
-
const header = await this.archiver.getBlockHeader(blockNumber);
|
|
1242
|
-
const gasFees = header?.globalVariables.gasFees ?? GasFees.empty();
|
|
1243
|
-
this.feesCache = { blockNumber, gasFees };
|
|
1244
|
-
return gasFees;
|
|
1638
|
+
private getGasFees(): Promise<GasFees> {
|
|
1639
|
+
return this.blockMinFeesProvider.getCurrentMinFees();
|
|
1245
1640
|
}
|
|
1246
1641
|
|
|
1247
|
-
|
|
1248
|
-
|
|
1642
|
+
/**
|
|
1643
|
+
* Get the BatchTxRequesterLibP2PService dependencies for creating BatchTxRequester instances
|
|
1644
|
+
*/
|
|
1645
|
+
public getBatchTxRequesterService(): BatchTxRequesterLibP2PService {
|
|
1646
|
+
return {
|
|
1647
|
+
reqResp: this.reqresp,
|
|
1648
|
+
connectionSampler: this.reqresp.getConnectionSampler(),
|
|
1649
|
+
txValidatorConfig: {
|
|
1650
|
+
l1ChainId: this.config.l1ChainId,
|
|
1651
|
+
rollupVersion: this.config.rollupVersion,
|
|
1652
|
+
proofVerifier: this.proofVerifier,
|
|
1653
|
+
},
|
|
1654
|
+
peerScoring: this.peerManager,
|
|
1655
|
+
};
|
|
1656
|
+
}
|
|
1249
1657
|
|
|
1250
|
-
|
|
1251
|
-
const
|
|
1252
|
-
|
|
1658
|
+
public async validateTxsReceivedInBlockProposal(txs: Tx[]): Promise<void> {
|
|
1659
|
+
const validator = createTxValidatorForBlockProposalReceivedTxs(
|
|
1660
|
+
this.proofVerifier,
|
|
1661
|
+
{ l1ChainId: this.config.l1ChainId, rollupVersion: this.config.rollupVersion },
|
|
1662
|
+
this.logger.getBindings(),
|
|
1663
|
+
);
|
|
1253
1664
|
|
|
1254
|
-
await Promise.all(
|
|
1665
|
+
const results = await Promise.all(
|
|
1255
1666
|
txs.map(async tx => {
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
if (!outcome.allPassed) {
|
|
1259
|
-
throw new Error('Invalid tx detected', { cause: { outcome } });
|
|
1260
|
-
}
|
|
1261
|
-
}
|
|
1667
|
+
const result = await validator.validateTx(tx);
|
|
1668
|
+
return result.result !== 'invalid';
|
|
1262
1669
|
}),
|
|
1263
1670
|
);
|
|
1671
|
+
if (results.some(value => value === false)) {
|
|
1672
|
+
throw new Error('Invalid tx detected');
|
|
1673
|
+
}
|
|
1264
1674
|
}
|
|
1265
1675
|
|
|
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,
|
|
1676
|
+
/** Creates the first stage (fast) validators for gossiped transactions. */
|
|
1677
|
+
protected async createFirstStageMessageValidators(
|
|
1678
|
+
currentBlockNumber: BlockNumber,
|
|
1278
1679
|
nextSlotTimestamp: UInt64,
|
|
1279
|
-
): Promise<Record<string,
|
|
1280
|
-
const gasFees = await this.getGasFees(
|
|
1281
|
-
const allowedInSetup =
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1680
|
+
): Promise<Record<string, TransactionValidator>> {
|
|
1681
|
+
const gasFees = await this.getGasFees();
|
|
1682
|
+
const allowedInSetup = [
|
|
1683
|
+
...(await getDefaultAllowedSetupFunctions()),
|
|
1684
|
+
...(this.config.txPublicSetupAllowListExtend ?? []),
|
|
1685
|
+
];
|
|
1686
|
+
const blockNumber = BlockNumber(currentBlockNumber + 1);
|
|
1687
|
+
const l1Constants = await this.archiver.getL1Constants();
|
|
1688
|
+
|
|
1689
|
+
return createFirstStageTxValidationsForGossipedTransactions(
|
|
1286
1690
|
nextSlotTimestamp,
|
|
1287
|
-
|
|
1691
|
+
blockNumber,
|
|
1288
1692
|
this.worldStateSynchronizer,
|
|
1289
1693
|
gasFees,
|
|
1290
1694
|
this.config.l1ChainId,
|
|
1291
1695
|
this.config.rollupVersion,
|
|
1292
1696
|
protocolContractsHash,
|
|
1293
1697
|
this.archiver,
|
|
1294
|
-
this.proofVerifier,
|
|
1295
1698
|
!this.config.disableTransactions,
|
|
1296
1699
|
allowedInSetup,
|
|
1700
|
+
this.logger.getBindings(),
|
|
1701
|
+
{
|
|
1702
|
+
rollupManaLimit: l1Constants.rollupManaLimit,
|
|
1703
|
+
maxBlockL2Gas: this.config.validateMaxL2BlockGas,
|
|
1704
|
+
maxBlockDAGas: this.config.validateMaxDABlockGas,
|
|
1705
|
+
},
|
|
1297
1706
|
);
|
|
1298
1707
|
}
|
|
1299
1708
|
|
|
1709
|
+
/** Creates the second stage (expensive proof verification) validators for gossiped transactions. */
|
|
1710
|
+
protected createSecondStageMessageValidators(): Record<string, TransactionValidator> {
|
|
1711
|
+
return createSecondStageTxValidationsForGossipedTransactions(this.proofVerifier, this.logger.getBindings());
|
|
1712
|
+
}
|
|
1713
|
+
|
|
1300
1714
|
/**
|
|
1301
1715
|
* Run validations on a tx.
|
|
1302
1716
|
* @param tx - The tx to validate.
|
|
@@ -1305,7 +1719,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1305
1719
|
*/
|
|
1306
1720
|
private async runValidations(
|
|
1307
1721
|
tx: Tx,
|
|
1308
|
-
messageValidators: Record<string,
|
|
1722
|
+
messageValidators: Record<string, TransactionValidator>,
|
|
1309
1723
|
): Promise<ValidationOutcome> {
|
|
1310
1724
|
const validationPromises = Object.entries(messageValidators).map(async ([name, { validator, severity }]) => {
|
|
1311
1725
|
const { result } = await validator.validateTx(tx);
|
|
@@ -1314,8 +1728,10 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1314
1728
|
|
|
1315
1729
|
// A promise that resolves when all validations have been run
|
|
1316
1730
|
const allValidations = await Promise.all(validationPromises);
|
|
1317
|
-
const
|
|
1318
|
-
if (
|
|
1731
|
+
const failures = allValidations.filter(x => !x.isValid);
|
|
1732
|
+
if (failures.length > 0) {
|
|
1733
|
+
// Pick the most severe failure (lowest tolerance = harshest penalty)
|
|
1734
|
+
const failed = maxBy(failures, f => PeerErrorSeverityByHarshness.indexOf(f.severity))!;
|
|
1319
1735
|
return {
|
|
1320
1736
|
allPassed: false,
|
|
1321
1737
|
failure: {
|
|
@@ -1342,20 +1758,23 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1342
1758
|
* @param peerId - The peer ID of the peer that sent the tx.
|
|
1343
1759
|
* @returns Severity
|
|
1344
1760
|
*/
|
|
1345
|
-
private async handleDoubleSpendFailure(tx: Tx, blockNumber:
|
|
1761
|
+
private async handleDoubleSpendFailure(tx: Tx, blockNumber: BlockNumber): Promise<PeerErrorSeverity> {
|
|
1346
1762
|
if (blockNumber <= this.config.doubleSpendSeverePeerPenaltyWindow) {
|
|
1347
1763
|
return PeerErrorSeverity.HighToleranceError;
|
|
1348
1764
|
}
|
|
1349
1765
|
|
|
1350
|
-
const snapshotValidator = new DoubleSpendTxValidator(
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1766
|
+
const snapshotValidator = new DoubleSpendTxValidator(
|
|
1767
|
+
{
|
|
1768
|
+
nullifiersExist: async (nullifiers: Buffer[]) => {
|
|
1769
|
+
const merkleTree = this.worldStateSynchronizer.getSnapshot(
|
|
1770
|
+
BlockNumber(blockNumber - this.config.doubleSpendSeverePeerPenaltyWindow),
|
|
1771
|
+
);
|
|
1772
|
+
const indices = await merkleTree.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, nullifiers);
|
|
1773
|
+
return indices.map(index => index !== undefined);
|
|
1774
|
+
},
|
|
1357
1775
|
},
|
|
1358
|
-
|
|
1776
|
+
this.logger.getBindings(),
|
|
1777
|
+
);
|
|
1359
1778
|
|
|
1360
1779
|
const validSnapshot = await snapshotValidator.validateTx(tx);
|
|
1361
1780
|
if (validSnapshot.result !== 'valid') {
|
|
@@ -1365,47 +1784,6 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1365
1784
|
return PeerErrorSeverity.HighToleranceError;
|
|
1366
1785
|
}
|
|
1367
1786
|
|
|
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
1787
|
public getPeerScore(peerId: PeerId): number {
|
|
1410
1788
|
return this.node.services.pubsub.score.score(peerId.toString());
|
|
1411
1789
|
}
|