@aztec/p2p 0.0.1-commit.3469e52 → 0.0.1-commit.35158ae7e
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +129 -3
- package/dest/bootstrap/bootstrap.d.ts +4 -3
- package/dest/bootstrap/bootstrap.d.ts.map +1 -1
- package/dest/bootstrap/bootstrap.js +4 -4
- package/dest/client/factory.d.ts +11 -11
- package/dest/client/factory.d.ts.map +1 -1
- package/dest/client/factory.js +59 -19
- package/dest/client/interface.d.ts +46 -33
- package/dest/client/interface.d.ts.map +1 -1
- package/dest/client/p2p_client.d.ts +41 -51
- package/dest/client/p2p_client.d.ts.map +1 -1
- package/dest/client/p2p_client.js +168 -224
- package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.d.ts +2 -0
- package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.d.ts.map +1 -0
- package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.js +304 -0
- package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker_protocol.d.ts +73 -0
- package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker_protocol.d.ts.map +1 -0
- package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker_protocol.js +8 -0
- package/dest/config.d.ts +65 -16
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +107 -39
- package/dest/errors/tx-pool.error.d.ts +8 -0
- package/dest/errors/tx-pool.error.d.ts.map +1 -0
- package/dest/errors/tx-pool.error.js +9 -0
- package/dest/index.d.ts +2 -1
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +1 -0
- package/dest/mem_pools/attestation_pool/attestation_pool.d.ts +104 -88
- package/dest/mem_pools/attestation_pool/attestation_pool.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/attestation_pool.js +445 -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 +353 -87
- 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 +2 -2
- package/dest/mem_pools/attestation_pool/mocks.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/mocks.js +2 -2
- package/dest/mem_pools/index.d.ts +3 -2
- package/dest/mem_pools/index.d.ts.map +1 -1
- package/dest/mem_pools/index.js +1 -1
- package/dest/mem_pools/instrumentation.d.ts +4 -2
- package/dest/mem_pools/instrumentation.d.ts.map +1 -1
- package/dest/mem_pools/instrumentation.js +18 -16
- package/dest/mem_pools/interface.d.ts +5 -5
- package/dest/mem_pools/interface.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts +3 -3
- package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/eviction/eviction_manager.d.ts +3 -2
- package/dest/mem_pools/tx_pool/eviction/eviction_manager.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/eviction/eviction_strategy.d.ts +3 -2
- package/dest/mem_pools/tx_pool/eviction/eviction_strategy.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.d.ts +3 -3
- package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.js +9 -1
- package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.js +3 -3
- package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.d.ts +3 -3
- package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.js +2 -0
- package/dest/mem_pools/tx_pool/priority.d.ts +2 -2
- package/dest/mem_pools/tx_pool/priority.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/priority.js +4 -4
- package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts +1 -1
- package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/tx_pool_test_suite.js +3 -1
- package/dest/mem_pools/tx_pool_v2/archive/index.d.ts +2 -0
- package/dest/mem_pools/tx_pool_v2/archive/index.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/archive/index.js +1 -0
- package/dest/mem_pools/tx_pool_v2/archive/tx_archive.d.ts +43 -0
- package/dest/mem_pools/tx_pool_v2/archive/tx_archive.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/archive/tx_archive.js +103 -0
- package/dest/mem_pools/tx_pool_v2/deleted_pool.d.ts +104 -0
- package/dest/mem_pools/tx_pool_v2/deleted_pool.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/deleted_pool.js +251 -0
- package/dest/mem_pools/tx_pool_v2/eviction/eviction_manager.d.ts +47 -0
- package/dest/mem_pools/tx_pool_v2/eviction/eviction_manager.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/eviction/eviction_manager.js +128 -0
- package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.d.ts +17 -0
- package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.js +94 -0
- package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.d.ts +19 -0
- package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.js +97 -0
- package/dest/mem_pools/tx_pool_v2/eviction/index.d.ts +10 -0
- package/dest/mem_pools/tx_pool_v2/eviction/index.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/eviction/index.js +11 -0
- package/dest/mem_pools/tx_pool_v2/eviction/interfaces.d.ts +180 -0
- package/dest/mem_pools/tx_pool_v2/eviction/interfaces.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/eviction/interfaces.js +25 -0
- package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_mining_rule.d.ts +15 -0
- package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_mining_rule.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_mining_rule.js +65 -0
- package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.d.ts +17 -0
- package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.js +93 -0
- package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.d.ts +16 -0
- package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.js +78 -0
- package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.d.ts +20 -0
- package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.js +75 -0
- package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.d.ts +15 -0
- package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.js +19 -0
- package/dest/mem_pools/tx_pool_v2/index.d.ts +6 -0
- package/dest/mem_pools/tx_pool_v2/index.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/index.js +5 -0
- package/dest/mem_pools/tx_pool_v2/instrumentation.d.ts +15 -0
- package/dest/mem_pools/tx_pool_v2/instrumentation.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/instrumentation.js +43 -0
- package/dest/mem_pools/tx_pool_v2/interfaces.d.ts +215 -0
- package/dest/mem_pools/tx_pool_v2/interfaces.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/interfaces.js +10 -0
- package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts +134 -0
- package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/tx_metadata.js +216 -0
- package/dest/mem_pools/tx_pool_v2/tx_pool_bench_metrics.d.ts +26 -0
- package/dest/mem_pools/tx_pool_v2/tx_pool_bench_metrics.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/tx_pool_bench_metrics.js +70 -0
- package/dest/mem_pools/tx_pool_v2/tx_pool_indices.d.ts +108 -0
- package/dest/mem_pools/tx_pool_v2/tx_pool_indices.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/tx_pool_indices.js +337 -0
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts +62 -0
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2.js +167 -0
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts +78 -0
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.js +923 -0
- package/dest/msg_validators/attestation_validator/attestation_validator.d.ts +3 -3
- package/dest/msg_validators/attestation_validator/attestation_validator.d.ts.map +1 -1
- package/dest/msg_validators/attestation_validator/attestation_validator.js +43 -11
- package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts +5 -5
- package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts.map +1 -1
- package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.js +18 -6
- package/dest/msg_validators/clock_tolerance.d.ts +21 -0
- package/dest/msg_validators/clock_tolerance.d.ts.map +1 -0
- package/dest/msg_validators/clock_tolerance.js +38 -0
- package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts +6 -4
- package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts.map +1 -1
- package/dest/msg_validators/proposal_validator/block_proposal_validator.js +10 -2
- package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts +6 -4
- package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts.map +1 -1
- package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.js +16 -2
- package/dest/msg_validators/proposal_validator/proposal_validator.d.ts +13 -8
- package/dest/msg_validators/proposal_validator/proposal_validator.d.ts.map +1 -1
- package/dest/msg_validators/proposal_validator/proposal_validator.js +84 -41
- 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/archive_cache.js +1 -1
- package/dest/msg_validators/tx_validator/block_header_validator.d.ts +20 -6
- package/dest/msg_validators/tx_validator/block_header_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/block_header_validator.js +4 -3
- package/dest/msg_validators/tx_validator/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 +137 -5
- 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 +1 -1
- package/dest/msg_validators/tx_validator/fee_payer_balance.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/fee_payer_balance.js +6 -2
- package/dest/msg_validators/tx_validator/gas_validator.d.ts +68 -3
- package/dest/msg_validators/tx_validator/gas_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/gas_validator.js +106 -38
- package/dest/msg_validators/tx_validator/index.d.ts +3 -1
- package/dest/msg_validators/tx_validator/index.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/index.js +2 -0
- package/dest/msg_validators/tx_validator/metadata_validator.d.ts +3 -2
- 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 +3 -1
- package/dest/msg_validators/tx_validator/size_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/size_validator.js +4 -1
- package/dest/msg_validators/tx_validator/timestamp_validator.d.ts +22 -5
- package/dest/msg_validators/tx_validator/timestamp_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/timestamp_validator.js +8 -8
- package/dest/msg_validators/tx_validator/tx_permitted_validator.d.ts +3 -2
- package/dest/msg_validators/tx_validator/tx_permitted_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/tx_permitted_validator.js +2 -2
- package/dest/msg_validators/tx_validator/tx_proof_validator.d.ts +3 -2
- package/dest/msg_validators/tx_validator/tx_proof_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/tx_proof_validator.js +2 -2
- package/dest/services/data_store.d.ts +1 -1
- package/dest/services/data_store.d.ts.map +1 -1
- package/dest/services/data_store.js +10 -6
- package/dest/services/discv5/discV5_service.d.ts +1 -1
- package/dest/services/discv5/discV5_service.d.ts.map +1 -1
- package/dest/services/discv5/discV5_service.js +5 -3
- package/dest/services/dummy_service.d.ts +24 -4
- package/dest/services/dummy_service.d.ts.map +1 -1
- package/dest/services/dummy_service.js +46 -1
- package/dest/services/encoding.d.ts +7 -3
- package/dest/services/encoding.d.ts.map +1 -1
- package/dest/services/encoding.js +18 -11
- package/dest/services/gossipsub/index.d.ts +3 -0
- package/dest/services/gossipsub/index.d.ts.map +1 -0
- package/dest/services/gossipsub/index.js +2 -0
- package/dest/services/gossipsub/scoring.d.ts +21 -3
- package/dest/services/gossipsub/scoring.d.ts.map +1 -1
- package/dest/services/gossipsub/scoring.js +24 -7
- package/dest/services/gossipsub/topic_score_params.d.ts +173 -0
- package/dest/services/gossipsub/topic_score_params.d.ts.map +1 -0
- package/dest/services/gossipsub/topic_score_params.js +346 -0
- package/dest/services/index.d.ts +2 -1
- package/dest/services/index.d.ts.map +1 -1
- package/dest/services/index.js +1 -0
- package/dest/services/libp2p/instrumentation.d.ts +1 -1
- package/dest/services/libp2p/instrumentation.d.ts.map +1 -1
- package/dest/services/libp2p/instrumentation.js +14 -3
- package/dest/services/libp2p/libp2p_service.d.ts +102 -46
- package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
- package/dest/services/libp2p/libp2p_service.js +585 -399
- package/dest/services/peer-manager/metrics.d.ts +4 -2
- package/dest/services/peer-manager/metrics.d.ts.map +1 -1
- package/dest/services/peer-manager/metrics.js +26 -5
- package/dest/services/peer-manager/peer_manager.d.ts +1 -1
- package/dest/services/peer-manager/peer_manager.d.ts.map +1 -1
- package/dest/services/peer-manager/peer_manager.js +6 -3
- package/dest/services/peer-manager/peer_scoring.d.ts +1 -1
- package/dest/services/peer-manager/peer_scoring.d.ts.map +1 -1
- package/dest/services/peer-manager/peer_scoring.js +33 -4
- 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/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/interface.d.ts +14 -3
- package/dest/services/reqresp/interface.d.ts.map +1 -1
- package/dest/services/reqresp/interface.js +17 -3
- package/dest/services/reqresp/metrics.d.ts +6 -5
- package/dest/services/reqresp/metrics.d.ts.map +1 -1
- package/dest/services/reqresp/metrics.js +17 -5
- 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 +5 -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 +29 -6
- 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 +59 -13
- package/dest/services/reqresp/protocols/tx.d.ts +7 -1
- package/dest/services/reqresp/protocols/tx.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/tx.js +20 -0
- package/dest/services/reqresp/reqresp.d.ts +6 -1
- package/dest/services/reqresp/reqresp.d.ts.map +1 -1
- package/dest/services/reqresp/reqresp.js +86 -34
- package/dest/services/service.d.ts +48 -3
- 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 +55 -1
- package/dest/services/tx_collection/fast_tx_collection.d.ts +7 -7
- 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 +37 -0
- package/dest/services/tx_collection/file_store_tx_source.d.ts.map +1 -0
- package/dest/services/tx_collection/file_store_tx_source.js +90 -0
- package/dest/services/tx_collection/index.d.ts +3 -1
- package/dest/services/tx_collection/index.d.ts.map +1 -1
- package/dest/services/tx_collection/index.js +2 -0
- package/dest/services/tx_collection/instrumentation.d.ts +1 -1
- package/dest/services/tx_collection/instrumentation.d.ts.map +1 -1
- package/dest/services/tx_collection/instrumentation.js +10 -2
- 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 -5
- 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 +29 -19
- 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 +8 -3
- package/dest/services/tx_collection/tx_source.d.ts.map +1 -1
- package/dest/services/tx_collection/tx_source.js +19 -2
- package/dest/services/tx_file_store/config.d.ts +16 -0
- package/dest/services/tx_file_store/config.d.ts.map +1 -0
- package/dest/services/tx_file_store/config.js +22 -0
- package/dest/services/tx_file_store/index.d.ts +4 -0
- package/dest/services/tx_file_store/index.d.ts.map +1 -0
- package/dest/services/tx_file_store/index.js +3 -0
- package/dest/services/tx_file_store/instrumentation.d.ts +15 -0
- package/dest/services/tx_file_store/instrumentation.d.ts.map +1 -0
- package/dest/services/tx_file_store/instrumentation.js +29 -0
- package/dest/services/tx_file_store/tx_file_store.d.ts +48 -0
- package/dest/services/tx_file_store/tx_file_store.d.ts.map +1 -0
- package/dest/services/tx_file_store/tx_file_store.js +152 -0
- package/dest/services/tx_provider.d.ts +6 -6
- package/dest/services/tx_provider.d.ts.map +1 -1
- package/dest/services/tx_provider.js +9 -8
- package/dest/services/tx_provider_instrumentation.d.ts +1 -1
- package/dest/services/tx_provider_instrumentation.d.ts.map +1 -1
- package/dest/services/tx_provider_instrumentation.js +5 -5
- package/dest/test-helpers/index.d.ts +3 -1
- package/dest/test-helpers/index.d.ts.map +1 -1
- package/dest/test-helpers/index.js +2 -0
- package/dest/test-helpers/make-test-p2p-clients.d.ts +7 -8
- package/dest/test-helpers/make-test-p2p-clients.d.ts.map +1 -1
- package/dest/test-helpers/make-test-p2p-clients.js +1 -2
- package/dest/test-helpers/mock-pubsub.d.ts +35 -4
- package/dest/test-helpers/mock-pubsub.d.ts.map +1 -1
- package/dest/test-helpers/mock-pubsub.js +114 -5
- package/dest/test-helpers/reqresp-nodes.d.ts +2 -3
- package/dest/test-helpers/reqresp-nodes.d.ts.map +1 -1
- package/dest/test-helpers/reqresp-nodes.js +4 -3
- package/dest/test-helpers/test_tx_provider.d.ts +40 -0
- package/dest/test-helpers/test_tx_provider.d.ts.map +1 -0
- package/dest/test-helpers/test_tx_provider.js +41 -0
- package/dest/test-helpers/testbench-utils.d.ts +163 -0
- package/dest/test-helpers/testbench-utils.d.ts.map +1 -0
- package/dest/test-helpers/testbench-utils.js +385 -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 +221 -138
- package/dest/testbench/worker_client_manager.d.ts +53 -6
- package/dest/testbench/worker_client_manager.d.ts.map +1 -1
- package/dest/testbench/worker_client_manager.js +231 -45
- package/dest/util.d.ts +10 -5
- package/dest/util.d.ts.map +1 -1
- package/dest/util.js +2 -9
- package/package.json +14 -14
- package/src/bootstrap/bootstrap.ts +7 -4
- package/src/client/factory.ts +109 -38
- package/src/client/interface.ts +56 -34
- package/src/client/p2p_client.ts +206 -273
- package/src/client/test/tx_proposal_collector/README.md +227 -0
- package/src/client/test/tx_proposal_collector/proposal_tx_collector_worker.ts +343 -0
- package/src/client/test/tx_proposal_collector/proposal_tx_collector_worker_protocol.ts +43 -0
- package/src/config.ts +170 -44
- package/src/errors/tx-pool.error.ts +12 -0
- package/src/index.ts +1 -0
- package/src/mem_pools/attestation_pool/attestation_pool.ts +497 -91
- package/src/mem_pools/attestation_pool/attestation_pool_test_suite.ts +442 -102
- package/src/mem_pools/attestation_pool/index.ts +9 -2
- package/src/mem_pools/attestation_pool/mocks.ts +2 -1
- package/src/mem_pools/index.ts +4 -1
- package/src/mem_pools/instrumentation.ts +19 -14
- package/src/mem_pools/interface.ts +4 -4
- package/src/mem_pools/tx_pool/README.md +1 -1
- package/src/mem_pools/tx_pool/aztec_kv_tx_pool.ts +2 -2
- package/src/mem_pools/tx_pool/eviction/eviction_manager.ts +2 -1
- package/src/mem_pools/tx_pool/eviction/eviction_strategy.ts +2 -1
- package/src/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.ts +11 -7
- package/src/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.ts +3 -3
- package/src/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.ts +4 -2
- package/src/mem_pools/tx_pool/priority.ts +4 -4
- package/src/mem_pools/tx_pool/tx_pool_test_suite.ts +3 -1
- package/src/mem_pools/tx_pool_v2/README.md +283 -0
- package/src/mem_pools/tx_pool_v2/archive/index.ts +1 -0
- package/src/mem_pools/tx_pool_v2/archive/tx_archive.ts +120 -0
- package/src/mem_pools/tx_pool_v2/deleted_pool.ts +321 -0
- package/src/mem_pools/tx_pool_v2/eviction/eviction_manager.ts +160 -0
- package/src/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.ts +122 -0
- package/src/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.ts +125 -0
- package/src/mem_pools/tx_pool_v2/eviction/index.ts +27 -0
- package/src/mem_pools/tx_pool_v2/eviction/interfaces.ts +219 -0
- package/src/mem_pools/tx_pool_v2/eviction/invalid_txs_after_mining_rule.ts +74 -0
- package/src/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.ts +101 -0
- package/src/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.ts +91 -0
- package/src/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.ts +99 -0
- package/src/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.ts +32 -0
- package/src/mem_pools/tx_pool_v2/index.ts +12 -0
- package/src/mem_pools/tx_pool_v2/instrumentation.ts +69 -0
- package/src/mem_pools/tx_pool_v2/interfaces.ts +247 -0
- package/src/mem_pools/tx_pool_v2/tx_metadata.ts +337 -0
- package/src/mem_pools/tx_pool_v2/tx_pool_bench_metrics.ts +77 -0
- package/src/mem_pools/tx_pool_v2/tx_pool_indices.ts +430 -0
- package/src/mem_pools/tx_pool_v2/tx_pool_v2.ts +238 -0
- package/src/mem_pools/tx_pool_v2/tx_pool_v2_impl.ts +1105 -0
- package/src/msg_validators/attestation_validator/README.md +49 -0
- package/src/msg_validators/attestation_validator/attestation_validator.ts +28 -15
- package/src/msg_validators/attestation_validator/fisherman_attestation_validator.ts +16 -10
- package/src/msg_validators/clock_tolerance.ts +52 -0
- package/src/msg_validators/proposal_validator/README.md +123 -0
- package/src/msg_validators/proposal_validator/block_proposal_validator.ts +14 -4
- package/src/msg_validators/proposal_validator/checkpoint_proposal_validator.ts +20 -7
- package/src/msg_validators/proposal_validator/proposal_validator.ts +82 -51
- package/src/msg_validators/tx_validator/README.md +119 -0
- package/src/msg_validators/tx_validator/aggregate_tx_validator.ts +5 -5
- package/src/msg_validators/tx_validator/allowed_public_setup.ts +22 -27
- package/src/msg_validators/tx_validator/allowed_setup_helpers.ts +31 -0
- package/src/msg_validators/tx_validator/archive_cache.ts +3 -3
- 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 +48 -3
- package/src/msg_validators/tx_validator/double_spend_validator.ts +15 -9
- package/src/msg_validators/tx_validator/factory.ts +413 -56
- package/src/msg_validators/tx_validator/fee_payer_balance.ts +6 -2
- package/src/msg_validators/tx_validator/gas_validator.ts +132 -30
- package/src/msg_validators/tx_validator/index.ts +2 -0
- package/src/msg_validators/tx_validator/metadata_validator.ts +18 -7
- 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 +6 -2
- package/src/msg_validators/tx_validator/timestamp_validator.ts +29 -21
- package/src/msg_validators/tx_validator/tx_permitted_validator.ts +8 -3
- package/src/msg_validators/tx_validator/tx_proof_validator.ts +8 -3
- package/src/services/data_store.ts +10 -7
- package/src/services/discv5/discV5_service.ts +5 -3
- package/src/services/dummy_service.ts +59 -2
- package/src/services/encoding.ts +18 -10
- package/src/services/gossipsub/README.md +641 -0
- package/src/services/gossipsub/index.ts +2 -0
- package/src/services/gossipsub/scoring.ts +29 -5
- package/src/services/gossipsub/topic_score_params.ts +487 -0
- package/src/services/index.ts +1 -0
- package/src/services/libp2p/instrumentation.ts +15 -2
- package/src/services/libp2p/libp2p_service.ts +630 -437
- package/src/services/peer-manager/metrics.ts +28 -4
- package/src/services/peer-manager/peer_manager.ts +7 -3
- package/src/services/peer-manager/peer_scoring.ts +29 -1
- 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/connection-sampler/batch_connection_sampler.ts +65 -4
- package/src/services/reqresp/connection-sampler/connection_sampler.ts +16 -0
- package/src/services/reqresp/interface.ts +31 -3
- package/src/services/reqresp/metrics.ts +34 -9
- package/src/services/reqresp/protocols/block_txs/bitvector.ts +7 -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 +74 -9
- package/src/services/reqresp/protocols/tx.ts +22 -0
- package/src/services/reqresp/reqresp.ts +99 -32
- package/src/services/service.ts +62 -2
- package/src/services/tx_collection/config.ts +83 -1
- package/src/services/tx_collection/fast_tx_collection.ts +111 -91
- package/src/services/tx_collection/file_store_tx_collection.ts +202 -0
- package/src/services/tx_collection/file_store_tx_source.ts +117 -0
- package/src/services/tx_collection/index.ts +6 -0
- package/src/services/tx_collection/instrumentation.ts +17 -2
- 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 +68 -35
- package/src/services/tx_collection/tx_collection.ts +122 -27
- package/src/services/tx_collection/tx_collection_sink.ts +30 -34
- package/src/services/tx_collection/tx_source.ts +22 -3
- package/src/services/tx_file_store/config.ts +37 -0
- package/src/services/tx_file_store/index.ts +3 -0
- package/src/services/tx_file_store/instrumentation.ts +36 -0
- package/src/services/tx_file_store/tx_file_store.ts +175 -0
- package/src/services/tx_provider.ts +12 -11
- package/src/services/tx_provider_instrumentation.ts +11 -5
- package/src/test-helpers/index.ts +2 -0
- package/src/test-helpers/make-test-p2p-clients.ts +4 -6
- package/src/test-helpers/mock-pubsub.ts +155 -9
- package/src/test-helpers/reqresp-nodes.ts +5 -7
- package/src/test-helpers/test_tx_provider.ts +64 -0
- package/src/test-helpers/testbench-utils.ts +456 -0
- package/src/testbench/p2p_client_testbench_worker.ts +333 -132
- package/src/testbench/worker_client_manager.ts +312 -47
- package/src/util.ts +16 -14
- package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts +0 -40
- 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 -218
- package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts +0 -31
- 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 -180
- package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.d.ts +0 -23
- package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.d.ts.map +0 -1
- package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.js +0 -157
- package/src/mem_pools/attestation_pool/kv_attestation_pool.ts +0 -320
- package/src/mem_pools/attestation_pool/memory_attestation_pool.ts +0 -264
- package/src/msg_validators/proposal_validator/proposal_validator_test_suite.ts +0 -191
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
import type { EpochCacheInterface } from '@aztec/epoch-cache';
|
|
2
|
-
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
3
|
-
import {
|
|
2
|
+
import { BlockNumber, type SlotNumber } from '@aztec/foundation/branded-types';
|
|
3
|
+
import { maxBy } from '@aztec/foundation/collection';
|
|
4
4
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
5
5
|
import { type Logger, createLibp2pComponentLogger, createLogger } from '@aztec/foundation/log';
|
|
6
6
|
import { RunningPromise } from '@aztec/foundation/running-promise';
|
|
7
7
|
import { Timer } from '@aztec/foundation/timer';
|
|
8
8
|
import type { AztecAsyncKVStore } from '@aztec/kv-store';
|
|
9
|
-
import { getVKTreeRoot } from '@aztec/noir-protocol-circuits-types/vk-tree';
|
|
10
9
|
import { protocolContractsHash } from '@aztec/protocol-contracts';
|
|
11
|
-
import type { EthAddress,
|
|
10
|
+
import type { EthAddress, L2Block, L2BlockSource } from '@aztec/stdlib/block';
|
|
12
11
|
import type { ContractDataSource } from '@aztec/stdlib/contract';
|
|
13
12
|
import { GasFees } from '@aztec/stdlib/gas';
|
|
14
13
|
import type { ClientProtocolCircuitVerifier, PeerInfo, WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
|
|
@@ -18,12 +17,12 @@ import {
|
|
|
18
17
|
CheckpointProposal,
|
|
19
18
|
type CheckpointProposalCore,
|
|
20
19
|
type Gossipable,
|
|
21
|
-
P2PClientType,
|
|
22
20
|
P2PMessage,
|
|
23
21
|
PeerErrorSeverity,
|
|
22
|
+
PeerErrorSeverityByHarshness,
|
|
24
23
|
TopicType,
|
|
25
24
|
createTopicString,
|
|
26
|
-
|
|
25
|
+
getTopicsForConfig,
|
|
27
26
|
metricsTopicStrToLabels,
|
|
28
27
|
} from '@aztec/stdlib/p2p';
|
|
29
28
|
import { MerkleTreeId } from '@aztec/stdlib/trees';
|
|
@@ -45,76 +44,77 @@ import {
|
|
|
45
44
|
type GossipsubMessage,
|
|
46
45
|
gossipsub,
|
|
47
46
|
} from '@chainsafe/libp2p-gossipsub';
|
|
48
|
-
import { createPeerScoreParams
|
|
47
|
+
import { createPeerScoreParams } from '@chainsafe/libp2p-gossipsub/score';
|
|
49
48
|
import { SignaturePolicy } from '@chainsafe/libp2p-gossipsub/types';
|
|
50
49
|
import { noise } from '@chainsafe/libp2p-noise';
|
|
51
50
|
import { yamux } from '@chainsafe/libp2p-yamux';
|
|
52
51
|
import { bootstrap } from '@libp2p/bootstrap';
|
|
53
52
|
import { identify } from '@libp2p/identify';
|
|
54
53
|
import { type Message, type MultiaddrConnection, type PeerId, TopicValidatorResult } from '@libp2p/interface';
|
|
55
|
-
import type { ConnectionManager } from '@libp2p/interface-internal';
|
|
54
|
+
import type { AddressManager, ConnectionManager } from '@libp2p/interface-internal';
|
|
56
55
|
import { mplex } from '@libp2p/mplex';
|
|
57
56
|
import { tcp } from '@libp2p/tcp';
|
|
57
|
+
import { multiaddr } from '@multiformats/multiaddr';
|
|
58
58
|
import { ENR } from '@nethermindeth/enr';
|
|
59
59
|
import { createLibp2p } from 'libp2p';
|
|
60
60
|
|
|
61
61
|
import type { P2PConfig } from '../../config.js';
|
|
62
|
-
import { ProposalSlotCapExceededError } from '../../errors/attestation-pool.error.js';
|
|
63
62
|
import type { MemPools } from '../../mem_pools/interface.js';
|
|
64
63
|
import {
|
|
65
64
|
BlockProposalValidator,
|
|
66
65
|
CheckpointAttestationValidator,
|
|
67
66
|
CheckpointProposalValidator,
|
|
67
|
+
DoubleSpendTxValidator,
|
|
68
68
|
FishermanAttestationValidator,
|
|
69
|
-
|
|
69
|
+
getDefaultAllowedSetupFunctions,
|
|
70
70
|
} from '../../msg_validators/index.js';
|
|
71
71
|
import { MessageSeenValidator } from '../../msg_validators/msg_seen_validator/msg_seen_validator.js';
|
|
72
|
-
import { getDefaultAllowedSetupFunctions } from '../../msg_validators/tx_validator/allowed_public_setup.js';
|
|
73
|
-
import { type MessageValidator, createTxMessageValidators } from '../../msg_validators/tx_validator/factory.js';
|
|
74
72
|
import {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
} from '../../msg_validators/tx_validator/
|
|
73
|
+
type TransactionValidator,
|
|
74
|
+
createFirstStageTxValidationsForGossipedTransactions,
|
|
75
|
+
createSecondStageTxValidationsForGossipedTransactions,
|
|
76
|
+
createTxValidatorForBlockProposalReceivedTxs,
|
|
77
|
+
createTxValidatorForReqResponseReceivedTxs,
|
|
78
|
+
} from '../../msg_validators/tx_validator/factory.js';
|
|
81
79
|
import { GossipSubEvent } from '../../types/index.js';
|
|
82
80
|
import { type PubSubLibp2p, convertToMultiaddr } from '../../util.js';
|
|
83
81
|
import { getVersions } from '../../versioning.js';
|
|
84
82
|
import { AztecDatastore } from '../data_store.js';
|
|
85
83
|
import { DiscV5Service } from '../discv5/discV5_service.js';
|
|
86
84
|
import { SnappyTransform, fastMsgIdFn, getMsgIdFn, msgIdToStrFn } from '../encoding.js';
|
|
87
|
-
import { gossipScoreThresholds } from '../gossipsub/scoring.js';
|
|
85
|
+
import { APP_SPECIFIC_WEIGHT, gossipScoreThresholds } from '../gossipsub/scoring.js';
|
|
86
|
+
import { createAllTopicScoreParams } from '../gossipsub/topic_score_params.js';
|
|
88
87
|
import type { PeerManagerInterface } from '../peer-manager/interface.js';
|
|
89
88
|
import { PeerManager } from '../peer-manager/peer_manager.js';
|
|
90
89
|
import { PeerScoring } from '../peer-manager/peer_scoring.js';
|
|
90
|
+
import type { BatchTxRequesterLibP2PService } from '../reqresp/batch-tx-requester/interface.js';
|
|
91
91
|
import type { P2PReqRespConfig } from '../reqresp/config.js';
|
|
92
92
|
import {
|
|
93
|
+
AuthRequest,
|
|
94
|
+
BlockTxsRequest,
|
|
95
|
+
BlockTxsResponse,
|
|
93
96
|
DEFAULT_SUB_PROTOCOL_VALIDATORS,
|
|
94
97
|
type ReqRespInterface,
|
|
98
|
+
type ReqRespResponse,
|
|
95
99
|
ReqRespSubProtocol,
|
|
96
100
|
type ReqRespSubProtocolHandler,
|
|
97
101
|
type ReqRespSubProtocolHandlers,
|
|
98
102
|
type ReqRespSubProtocolValidators,
|
|
103
|
+
StatusMessage,
|
|
99
104
|
type SubProtocolMap,
|
|
100
105
|
ValidationError,
|
|
101
|
-
} from '../reqresp/interface.js';
|
|
102
|
-
import { reqRespBlockTxsHandler } from '../reqresp/protocols/block_txs/block_txs_handler.js';
|
|
103
|
-
import { reqGoodbyeHandler } from '../reqresp/protocols/goodbye.js';
|
|
104
|
-
import {
|
|
105
|
-
AuthRequest,
|
|
106
|
-
BlockTxsRequest,
|
|
107
|
-
BlockTxsResponse,
|
|
108
|
-
StatusMessage,
|
|
109
106
|
pingHandler,
|
|
107
|
+
reqGoodbyeHandler,
|
|
110
108
|
reqRespBlockHandler,
|
|
109
|
+
reqRespBlockTxsHandler,
|
|
111
110
|
reqRespStatusHandler,
|
|
112
111
|
reqRespTxHandler,
|
|
113
|
-
} from '../reqresp/
|
|
112
|
+
} from '../reqresp/index.js';
|
|
114
113
|
import { ReqResp } from '../reqresp/reqresp.js';
|
|
115
114
|
import type {
|
|
116
115
|
P2PBlockReceivedCallback,
|
|
117
116
|
P2PCheckpointReceivedCallback,
|
|
117
|
+
P2PDuplicateAttestationCallback,
|
|
118
118
|
P2PService,
|
|
119
119
|
PeerDiscoveryService,
|
|
120
120
|
} from '../service.js';
|
|
@@ -129,14 +129,14 @@ interface ValidationResult {
|
|
|
129
129
|
type ValidationOutcome = { allPassed: true } | { allPassed: false; failure: ValidationResult };
|
|
130
130
|
|
|
131
131
|
// REFACTOR: Unify with the type above
|
|
132
|
-
type ReceivedMessageValidationResult<T> =
|
|
133
|
-
| { obj: T; result: Exclude<TopicValidatorResult, TopicValidatorResult.Reject
|
|
134
|
-
| { obj?:
|
|
132
|
+
type ReceivedMessageValidationResult<T, M = undefined> =
|
|
133
|
+
| { obj: T; result: Exclude<TopicValidatorResult, TopicValidatorResult.Reject>; metadata?: M }
|
|
134
|
+
| { obj?: T; result: TopicValidatorResult.Reject; metadata?: M; severity: PeerErrorSeverity };
|
|
135
135
|
|
|
136
136
|
/**
|
|
137
137
|
* Lib P2P implementation of the P2PService interface.
|
|
138
138
|
*/
|
|
139
|
-
export class LibP2PService
|
|
139
|
+
export class LibP2PService extends WithTracer implements P2PService {
|
|
140
140
|
private discoveryRunningPromise?: RunningPromise;
|
|
141
141
|
private msgIdSeenValidators: Record<TopicType, MessageSeenValidator> = {} as Record<TopicType, MessageSeenValidator>;
|
|
142
142
|
|
|
@@ -150,6 +150,16 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
150
150
|
|
|
151
151
|
private feesCache: { blockNumber: BlockNumber; gasFees: GasFees } | undefined;
|
|
152
152
|
|
|
153
|
+
/** Callback invoked when a duplicate proposal is detected (triggers slashing). */
|
|
154
|
+
private duplicateProposalCallback?: (info: {
|
|
155
|
+
slot: SlotNumber;
|
|
156
|
+
proposer: EthAddress;
|
|
157
|
+
type: 'checkpoint' | 'block';
|
|
158
|
+
}) => void;
|
|
159
|
+
|
|
160
|
+
/** Callback invoked when a duplicate attestation is detected (triggers slashing). */
|
|
161
|
+
private duplicateAttestationCallback?: P2PDuplicateAttestationCallback;
|
|
162
|
+
|
|
153
163
|
/**
|
|
154
164
|
* Callback for when a block is received from a peer.
|
|
155
165
|
* @param block - The block received from the peer.
|
|
@@ -165,6 +175,10 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
165
175
|
private checkpointReceivedCallback: P2PCheckpointReceivedCallback;
|
|
166
176
|
|
|
167
177
|
private gossipSubEventHandler: (e: CustomEvent<GossipsubMessage>) => void;
|
|
178
|
+
private ipChangedHandler?: (ip: string) => void;
|
|
179
|
+
|
|
180
|
+
/** Discovered public IP address (set when queryForIp is enabled and no static IP was configured). */
|
|
181
|
+
private discoveredP2pIp?: string;
|
|
168
182
|
|
|
169
183
|
private instrumentation: P2PInstrumentation;
|
|
170
184
|
|
|
@@ -173,14 +187,13 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
173
187
|
protected logger: Logger;
|
|
174
188
|
|
|
175
189
|
constructor(
|
|
176
|
-
private clientType: T,
|
|
177
190
|
private config: P2PConfig,
|
|
178
191
|
protected node: PubSubLibp2p,
|
|
179
192
|
private peerDiscoveryService: PeerDiscoveryService,
|
|
180
193
|
private reqresp: ReqRespInterface,
|
|
181
|
-
|
|
194
|
+
protected peerManager: PeerManagerInterface,
|
|
182
195
|
protected mempools: MemPools,
|
|
183
|
-
|
|
196
|
+
protected archiver: L2BlockSource & ContractDataSource,
|
|
184
197
|
private epochCache: EpochCacheInterface,
|
|
185
198
|
private proofVerifier: ClientProtocolCircuitVerifier,
|
|
186
199
|
private worldStateSynchronizer: WorldStateSynchronizer,
|
|
@@ -215,10 +228,12 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
215
228
|
this.protocolVersion,
|
|
216
229
|
);
|
|
217
230
|
|
|
218
|
-
|
|
219
|
-
this.checkpointProposalValidator = new CheckpointProposalValidator(epochCache, {
|
|
231
|
+
const proposalValidatorOpts = {
|
|
220
232
|
txsPermitted: !config.disableTransactions,
|
|
221
|
-
|
|
233
|
+
maxTxsPerBlock: config.validateMaxTxsPerBlock ?? config.validateMaxTxsPerCheckpoint,
|
|
234
|
+
};
|
|
235
|
+
this.blockProposalValidator = new BlockProposalValidator(epochCache, proposalValidatorOpts);
|
|
236
|
+
this.checkpointProposalValidator = new CheckpointProposalValidator(epochCache, proposalValidatorOpts);
|
|
222
237
|
this.checkpointAttestationValidator = config.fishermanMode
|
|
223
238
|
? new FishermanAttestationValidator(epochCache, mempools.attestationPool, telemetry)
|
|
224
239
|
: new CheckpointAttestationValidator(epochCache);
|
|
@@ -226,11 +241,11 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
226
241
|
this.gossipSubEventHandler = this.handleGossipSubEvent.bind(this);
|
|
227
242
|
|
|
228
243
|
this.blockReceivedCallback = async (block: BlockProposal): Promise<boolean> => {
|
|
229
|
-
this.logger.
|
|
230
|
-
`Handler not yet registered
|
|
244
|
+
this.logger.warn(
|
|
245
|
+
`Handler for block received not yet registered on P2P service. Received block ${block.blockNumber} for slot ${block.slotNumber} from peer.`,
|
|
231
246
|
{ p2pMessageIdentifier: await block.p2pMessageLoggingIdentifier() },
|
|
232
247
|
);
|
|
233
|
-
return
|
|
248
|
+
return true;
|
|
234
249
|
};
|
|
235
250
|
|
|
236
251
|
this.checkpointReceivedCallback = (
|
|
@@ -253,8 +268,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
253
268
|
* @param txPool - The transaction pool to be accessed by the service.
|
|
254
269
|
* @returns The new service.
|
|
255
270
|
*/
|
|
256
|
-
public static async new
|
|
257
|
-
clientType: T,
|
|
271
|
+
public static async new(
|
|
258
272
|
config: P2PConfig,
|
|
259
273
|
peerId: PeerId,
|
|
260
274
|
deps: {
|
|
@@ -285,14 +299,14 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
285
299
|
|
|
286
300
|
const datastore = new AztecDatastore(peerStore);
|
|
287
301
|
|
|
288
|
-
const otelMetricsAdapter = new OtelMetricsAdapter(telemetry);
|
|
302
|
+
const otelMetricsAdapter = new OtelMetricsAdapter(telemetry, logger.getBindings());
|
|
289
303
|
|
|
290
304
|
const peerDiscoveryService = new DiscV5Service(
|
|
291
305
|
peerId,
|
|
292
306
|
config,
|
|
293
307
|
packageVersion,
|
|
294
308
|
telemetry,
|
|
295
|
-
createLogger(`${logger.module}:discv5_service
|
|
309
|
+
createLogger(`${logger.module}:discv5_service`, logger.getBindings()),
|
|
296
310
|
);
|
|
297
311
|
|
|
298
312
|
// Seed libp2p's bootstrap discovery with private and trusted peers
|
|
@@ -306,11 +320,6 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
306
320
|
const versions = getVersions(config);
|
|
307
321
|
const protocolVersion = compressComponentVersions(versions);
|
|
308
322
|
|
|
309
|
-
const txTopic = createTopicString(TopicType.tx, protocolVersion);
|
|
310
|
-
const blockProposalTopic = createTopicString(TopicType.block_proposal, protocolVersion);
|
|
311
|
-
const checkpointProposalTopic = createTopicString(TopicType.checkpoint_proposal, protocolVersion);
|
|
312
|
-
const checkpointAttestationTopic = createTopicString(TopicType.checkpoint_attestation, protocolVersion);
|
|
313
|
-
|
|
314
323
|
const preferredPeersEnrs: ENR[] = config.preferredPeers.map(enr => ENR.decodeTxt(enr));
|
|
315
324
|
const directPeers = (
|
|
316
325
|
await Promise.all(
|
|
@@ -330,6 +339,16 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
330
339
|
|
|
331
340
|
const announceTcpMultiaddr = config.p2pIp ? [convertToMultiaddr(config.p2pIp, p2pPort, 'tcp')] : [];
|
|
332
341
|
|
|
342
|
+
// Create dynamic topic score params based on network configuration
|
|
343
|
+
const l1Constants = epochCache.getL1Constants();
|
|
344
|
+
const topicScoreParams = createAllTopicScoreParams(protocolVersion, {
|
|
345
|
+
slotDurationMs: l1Constants.slotDuration * 1000,
|
|
346
|
+
heartbeatIntervalMs: config.gossipsubInterval,
|
|
347
|
+
targetCommitteeSize: l1Constants.targetCommitteeSize,
|
|
348
|
+
blockDurationMs: config.blockDurationMs,
|
|
349
|
+
expectedBlockProposalsPerSlot: config.expectedBlockProposalsPerSlot,
|
|
350
|
+
});
|
|
351
|
+
|
|
333
352
|
const node = await createLibp2p({
|
|
334
353
|
start: false,
|
|
335
354
|
peerId,
|
|
@@ -425,35 +444,15 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
425
444
|
scoreParams: createPeerScoreParams({
|
|
426
445
|
// IPColocation factor can be disabled for local testing - default to -5
|
|
427
446
|
IPColocationFactorWeight: config.debugDisableColocationPenalty ? 0 : -5.0,
|
|
428
|
-
topics:
|
|
429
|
-
[txTopic]: createTopicScoreParams({
|
|
430
|
-
topicWeight: 1,
|
|
431
|
-
invalidMessageDeliveriesWeight: -20,
|
|
432
|
-
invalidMessageDeliveriesDecay: 0.5,
|
|
433
|
-
}),
|
|
434
|
-
[blockProposalTopic]: createTopicScoreParams({
|
|
435
|
-
topicWeight: 1,
|
|
436
|
-
invalidMessageDeliveriesWeight: -20,
|
|
437
|
-
invalidMessageDeliveriesDecay: 0.5,
|
|
438
|
-
}),
|
|
439
|
-
[checkpointProposalTopic]: createTopicScoreParams({
|
|
440
|
-
topicWeight: 1,
|
|
441
|
-
invalidMessageDeliveriesWeight: -20,
|
|
442
|
-
invalidMessageDeliveriesDecay: 0.5,
|
|
443
|
-
}),
|
|
444
|
-
[checkpointAttestationTopic]: createTopicScoreParams({
|
|
445
|
-
topicWeight: 1,
|
|
446
|
-
invalidMessageDeliveriesWeight: -20,
|
|
447
|
-
invalidMessageDeliveriesDecay: 0.5,
|
|
448
|
-
}),
|
|
449
|
-
},
|
|
447
|
+
topics: topicScoreParams,
|
|
450
448
|
}),
|
|
451
449
|
}) as (components: GossipSubComponents) => GossipSub,
|
|
452
|
-
components: (components: { connectionManager: ConnectionManager }) => ({
|
|
450
|
+
components: (components: { connectionManager: ConnectionManager; addressManager: AddressManager }) => ({
|
|
453
451
|
connectionManager: components.connectionManager,
|
|
452
|
+
addressManager: components.addressManager,
|
|
454
453
|
}),
|
|
455
454
|
},
|
|
456
|
-
logger: createLibp2pComponentLogger(logger.module),
|
|
455
|
+
logger: createLibp2pComponentLogger(logger.module, logger.getBindings()),
|
|
457
456
|
});
|
|
458
457
|
|
|
459
458
|
const peerScoring = new PeerScoring(config, telemetry);
|
|
@@ -472,13 +471,16 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
472
471
|
epochCache,
|
|
473
472
|
);
|
|
474
473
|
|
|
475
|
-
//
|
|
476
|
-
|
|
474
|
+
// Configure application-specific scoring for gossipsub.
|
|
475
|
+
// The weight scales app score to align with gossipsub thresholds:
|
|
476
|
+
// - Disconnect (-50) × 10 = -500 = gossipThreshold (stops receiving gossip)
|
|
477
|
+
// - Ban (-100) × 10 = -1000 = publishThreshold (cannot publish)
|
|
478
|
+
// Note: positive topic scores can offset penalties, so alignment is best-effort.
|
|
479
|
+
node.services.pubsub.score.params.appSpecificWeight = APP_SPECIFIC_WEIGHT;
|
|
477
480
|
node.services.pubsub.score.params.appSpecificScore = (peerId: string) =>
|
|
478
481
|
peerManager.shouldDisableP2PGossip(peerId) ? -Infinity : peerManager.getPeerScore(peerId);
|
|
479
482
|
|
|
480
483
|
return new LibP2PService(
|
|
481
|
-
clientType,
|
|
482
484
|
config,
|
|
483
485
|
node,
|
|
484
486
|
peerDiscoveryService,
|
|
@@ -506,10 +508,10 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
506
508
|
|
|
507
509
|
// Get listen & announce addresses for logging
|
|
508
510
|
const { p2pIp, p2pPort } = this.config;
|
|
509
|
-
if (!p2pIp) {
|
|
511
|
+
if (!p2pIp && !this.config.queryForIp) {
|
|
510
512
|
throw new Error('Announce address not provided.');
|
|
511
513
|
}
|
|
512
|
-
const announceTcpMultiaddr = convertToMultiaddr(p2pIp, p2pPort, 'tcp');
|
|
514
|
+
const announceTcpMultiaddr = p2pIp ? convertToMultiaddr(p2pIp, p2pPort, 'tcp') : undefined;
|
|
513
515
|
|
|
514
516
|
// Create request response protocol handlers
|
|
515
517
|
const txHandler = reqRespTxHandler(this.mempools);
|
|
@@ -525,7 +527,11 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
525
527
|
};
|
|
526
528
|
|
|
527
529
|
if (!this.config.disableTransactions) {
|
|
528
|
-
const blockTxsHandler = reqRespBlockTxsHandler(
|
|
530
|
+
const blockTxsHandler = reqRespBlockTxsHandler(
|
|
531
|
+
this.mempools.attestationPool,
|
|
532
|
+
this.archiver,
|
|
533
|
+
this.mempools.txPool,
|
|
534
|
+
);
|
|
529
535
|
requestResponseHandlers[ReqRespSubProtocol.BLOCK_TXS] = blockTxsHandler.bind(this);
|
|
530
536
|
}
|
|
531
537
|
|
|
@@ -548,7 +554,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
548
554
|
await this.node.start();
|
|
549
555
|
|
|
550
556
|
// Subscribe to standard GossipSub topics by default
|
|
551
|
-
for (const topic of
|
|
557
|
+
for (const topic of getTopicsForConfig(this.config.disableTransactions)) {
|
|
552
558
|
this.subscribeToTopic(this.topicStrings[topic]);
|
|
553
559
|
}
|
|
554
560
|
|
|
@@ -559,6 +565,31 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
559
565
|
if (!this.config.p2pDiscoveryDisabled) {
|
|
560
566
|
await this.peerDiscoveryService.start();
|
|
561
567
|
}
|
|
568
|
+
|
|
569
|
+
// When queryForIp is enabled and no static IP was configured, bridge discv5 IP discovery to libp2p.
|
|
570
|
+
// Discv5 discovers our public IP via peer WHOAREYOU exchanges (enrUpdate=true) and emits 'ip:changed'.
|
|
571
|
+
// We confirm the discovered address in the libp2p AddressManager so it appears in getMultiaddrs()
|
|
572
|
+
// and is pushed to all connected peers via the identify protocol.
|
|
573
|
+
if (this.config.queryForIp && !p2pIp) {
|
|
574
|
+
this.ipChangedHandler = (ip: string) => {
|
|
575
|
+
const addressManager = this.node.services.components.addressManager;
|
|
576
|
+
const newAddr = multiaddr(convertToMultiaddr(ip, this.config.p2pPort, 'tcp'));
|
|
577
|
+
|
|
578
|
+
// Remove old discovered IP if one exists
|
|
579
|
+
if (this.discoveredP2pIp) {
|
|
580
|
+
const oldAddr = multiaddr(convertToMultiaddr(this.discoveredP2pIp, this.config.p2pPort, 'tcp'));
|
|
581
|
+
addressManager.removeObservedAddr(oldAddr);
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
addressManager.addObservedAddr(newAddr);
|
|
585
|
+
addressManager.confirmObservedAddr(newAddr);
|
|
586
|
+
// Store discovered IP
|
|
587
|
+
this.discoveredP2pIp = ip;
|
|
588
|
+
this.logger.info('Public IP discovered via discv5', { ip });
|
|
589
|
+
};
|
|
590
|
+
this.peerDiscoveryService.on('ip:changed', this.ipChangedHandler);
|
|
591
|
+
}
|
|
592
|
+
|
|
562
593
|
this.discoveryRunningPromise = new RunningPromise(
|
|
563
594
|
async () => {
|
|
564
595
|
await this.peerManager.heartbeat();
|
|
@@ -571,7 +602,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
571
602
|
this.logger.info(`Started P2P service`, {
|
|
572
603
|
listen: this.config.listenAddress,
|
|
573
604
|
port: this.config.p2pPort,
|
|
574
|
-
announce: announceTcpMultiaddr,
|
|
605
|
+
announce: announceTcpMultiaddr ?? 'pending (queryForIp=true)',
|
|
575
606
|
peerId: this.node.peerId.toString(),
|
|
576
607
|
});
|
|
577
608
|
}
|
|
@@ -584,6 +615,12 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
584
615
|
// Remove gossip sub listener
|
|
585
616
|
this.node.services.pubsub.removeEventListener(GossipSubEvent.MESSAGE, this.gossipSubEventHandler);
|
|
586
617
|
|
|
618
|
+
// Remove ip:changed listener if registered
|
|
619
|
+
if (this.ipChangedHandler) {
|
|
620
|
+
this.peerDiscoveryService.off('ip:changed', this.ipChangedHandler);
|
|
621
|
+
this.ipChangedHandler = undefined;
|
|
622
|
+
}
|
|
623
|
+
|
|
587
624
|
// Stop peer manager
|
|
588
625
|
this.logger.debug('Stopping peer manager...');
|
|
589
626
|
await this.peerManager.stop();
|
|
@@ -614,6 +651,10 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
614
651
|
return this.peerManager.getPeers(includePending);
|
|
615
652
|
}
|
|
616
653
|
|
|
654
|
+
public getGossipMeshPeerCount(topicType: TopicType): number {
|
|
655
|
+
return this.node.services.pubsub.getMeshPeers(this.topicStrings[topicType]).length;
|
|
656
|
+
}
|
|
657
|
+
|
|
617
658
|
private handleGossipSubEvent(e: CustomEvent<GossipsubMessage>) {
|
|
618
659
|
this.logger.trace(`Received PUBSUB message.`);
|
|
619
660
|
|
|
@@ -641,6 +682,15 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
641
682
|
return this.reqresp.sendBatchRequest(protocol, requests, pinnedPeerId);
|
|
642
683
|
}
|
|
643
684
|
|
|
685
|
+
public sendRequestToPeer(
|
|
686
|
+
peerId: PeerId,
|
|
687
|
+
subProtocol: ReqRespSubProtocol,
|
|
688
|
+
payload: Buffer,
|
|
689
|
+
dialTimeout?: number,
|
|
690
|
+
): Promise<ReqRespResponse> {
|
|
691
|
+
return this.reqresp.sendRequestToPeer(peerId, subProtocol, payload, dialTimeout);
|
|
692
|
+
}
|
|
693
|
+
|
|
644
694
|
/**
|
|
645
695
|
* Get the ENR of the node
|
|
646
696
|
* @returns The ENR of the node
|
|
@@ -657,6 +707,25 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
657
707
|
this.checkpointReceivedCallback = callback;
|
|
658
708
|
}
|
|
659
709
|
|
|
710
|
+
/**
|
|
711
|
+
* Registers a callback to be invoked when a duplicate proposal is detected.
|
|
712
|
+
* This callback is triggered on the first duplicate (when count goes from 1 to 2).
|
|
713
|
+
*/
|
|
714
|
+
public registerDuplicateProposalCallback(
|
|
715
|
+
callback: (info: { slot: SlotNumber; proposer: EthAddress; type: 'checkpoint' | 'block' }) => void,
|
|
716
|
+
): void {
|
|
717
|
+
this.duplicateProposalCallback = callback;
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
/**
|
|
721
|
+
* Registers a callback to be invoked when a duplicate attestation is detected.
|
|
722
|
+
* A validator signing attestations for different proposals at the same slot.
|
|
723
|
+
* This callback is triggered on the first duplicate (when count goes from 1 to 2).
|
|
724
|
+
*/
|
|
725
|
+
public registerDuplicateAttestationCallback(callback: P2PDuplicateAttestationCallback): void {
|
|
726
|
+
this.duplicateAttestationCallback = callback;
|
|
727
|
+
}
|
|
728
|
+
|
|
660
729
|
/**
|
|
661
730
|
* Subscribes to a topic.
|
|
662
731
|
* @param topic - The topic to subscribe to.
|
|
@@ -721,6 +790,9 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
721
790
|
if (!validator || !validator.addMessage(msgId)) {
|
|
722
791
|
this.instrumentation.incMessagePrevalidationStatus(false, topicType);
|
|
723
792
|
this.node.services.pubsub.reportMessageValidationResult(msgId, source.toString(), TopicValidatorResult.Ignore);
|
|
793
|
+
if (topicType === TopicType.tx) {
|
|
794
|
+
this.logger.verbose(`Ignoring already-seen tx gossip message`, { msgId, source: source.toString() });
|
|
795
|
+
}
|
|
724
796
|
return { result: false, topicType };
|
|
725
797
|
}
|
|
726
798
|
|
|
@@ -785,9 +857,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
785
857
|
if (msg.topic === this.topicStrings[TopicType.tx]) {
|
|
786
858
|
await this.handleGossipedTx(p2pMessage.payload, msgId, source);
|
|
787
859
|
} else if (msg.topic === this.topicStrings[TopicType.checkpoint_attestation]) {
|
|
788
|
-
|
|
789
|
-
await this.processCheckpointAttestationFromPeer(p2pMessage.payload, msgId, source);
|
|
790
|
-
}
|
|
860
|
+
await this.processCheckpointAttestationFromPeer(p2pMessage.payload, msgId, source);
|
|
791
861
|
} else if (msg.topic === this.topicStrings[TopicType.block_proposal]) {
|
|
792
862
|
await this.processBlockFromPeer(p2pMessage.payload, msgId, source);
|
|
793
863
|
} else if (msg.topic === this.topicStrings[TopicType.checkpoint_proposal]) {
|
|
@@ -843,51 +913,134 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
843
913
|
return;
|
|
844
914
|
}
|
|
845
915
|
|
|
846
|
-
protected async validateReceivedMessage<T>(
|
|
847
|
-
validationFunc: () => Promise<ReceivedMessageValidationResult<T>>,
|
|
916
|
+
protected async validateReceivedMessage<T, M = undefined>(
|
|
917
|
+
validationFunc: () => Promise<ReceivedMessageValidationResult<T, M>>,
|
|
848
918
|
msgId: string,
|
|
849
919
|
source: PeerId,
|
|
850
920
|
topicType: TopicType,
|
|
851
|
-
): Promise<ReceivedMessageValidationResult<T>> {
|
|
852
|
-
|
|
921
|
+
): Promise<ReceivedMessageValidationResult<T, M>> {
|
|
922
|
+
// Default to reject result with a penalty if validation function throws an error
|
|
923
|
+
let resultAndObj: ReceivedMessageValidationResult<T, M> = {
|
|
924
|
+
result: TopicValidatorResult.Reject,
|
|
925
|
+
severity: PeerErrorSeverity.MidToleranceError,
|
|
926
|
+
};
|
|
853
927
|
const timer = new Timer();
|
|
854
928
|
try {
|
|
855
929
|
resultAndObj = await validationFunc();
|
|
856
930
|
} catch (err) {
|
|
857
|
-
this.
|
|
858
|
-
this.logger.error(`Error deserializing and validating gossipsub message`, err, {
|
|
859
|
-
msgId,
|
|
860
|
-
source: source.toString(),
|
|
861
|
-
topicType,
|
|
862
|
-
});
|
|
931
|
+
this.logger.error(`Error validating gossipsub message`, err, { msgId, source: source.toString(), topicType });
|
|
863
932
|
}
|
|
864
933
|
|
|
865
934
|
if (resultAndObj.result === TopicValidatorResult.Accept) {
|
|
935
|
+
this.logger.debug(`Message ${topicType} accepted by validator`, { msgId, source: source.toString(), topicType });
|
|
866
936
|
this.instrumentation.recordMessageValidation(topicType, timer);
|
|
937
|
+
} else if (resultAndObj.result === TopicValidatorResult.Reject) {
|
|
938
|
+
this.logger.warn(`Message ${topicType} rejected by validator with severity ${resultAndObj.severity}`, {
|
|
939
|
+
msgId,
|
|
940
|
+
source: source.toString(),
|
|
941
|
+
topicType,
|
|
942
|
+
severity: resultAndObj.severity,
|
|
943
|
+
});
|
|
944
|
+
this.peerManager.penalizePeer(source, resultAndObj.severity);
|
|
945
|
+
} else {
|
|
946
|
+
this.logger.trace(`Message ${topicType} ignored by validator`, { msgId, source: source.toString(), topicType });
|
|
867
947
|
}
|
|
868
948
|
|
|
869
949
|
this.node.services.pubsub.reportMessageValidationResult(msgId, source.toString(), resultAndObj.result);
|
|
870
950
|
return resultAndObj;
|
|
871
951
|
}
|
|
872
952
|
|
|
953
|
+
private tryDeserialize<T>(deserializeFunc: () => T, msgId: string, source: PeerId): T | undefined {
|
|
954
|
+
try {
|
|
955
|
+
return deserializeFunc();
|
|
956
|
+
} catch (err) {
|
|
957
|
+
this.logger.warn(`Failed to deserialize gossipsub message from buffer`, {
|
|
958
|
+
err,
|
|
959
|
+
msgId,
|
|
960
|
+
source: source.toString(),
|
|
961
|
+
});
|
|
962
|
+
return undefined;
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
|
|
873
966
|
protected async handleGossipedTx(payloadData: Buffer, msgId: string, source: PeerId) {
|
|
874
967
|
const validationFunc: () => Promise<ReceivedMessageValidationResult<Tx>> = async () => {
|
|
875
|
-
const tx = Tx.fromBuffer(payloadData);
|
|
876
|
-
|
|
877
|
-
|
|
968
|
+
const tx = this.tryDeserialize(() => Tx.fromBuffer(payloadData), msgId, source);
|
|
969
|
+
if (!tx) {
|
|
970
|
+
return { result: TopicValidatorResult.Reject, severity: PeerErrorSeverity.LowToleranceError };
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
const currentBlockNumber = await this.archiver.getBlockNumber();
|
|
974
|
+
const { ts: nextSlotTimestamp } = this.epochCache.getEpochAndSlotInNextL1Slot();
|
|
975
|
+
|
|
976
|
+
// Stage 1: fast validators (metadata, data, timestamps, double-spend, gas, phases, block header)
|
|
977
|
+
const firstStageValidators = await this.createFirstStageMessageValidators(currentBlockNumber, nextSlotTimestamp);
|
|
978
|
+
const firstStageOutcome = await this.runValidations(tx, firstStageValidators);
|
|
979
|
+
if (!firstStageOutcome.allPassed) {
|
|
980
|
+
const { name } = firstStageOutcome.failure;
|
|
981
|
+
let { severity } = firstStageOutcome.failure;
|
|
982
|
+
|
|
983
|
+
// Double spend validator has a special case handler. We perform more detailed examination
|
|
984
|
+
// as to how recently the nullifier was entered into the tree and if the transaction should
|
|
985
|
+
// have 'known' the nullifier existed. This determines the severity of the penalty applied to the peer.
|
|
986
|
+
if (name === 'doubleSpendValidator') {
|
|
987
|
+
const txBlockNumber = BlockNumber(currentBlockNumber + 1);
|
|
988
|
+
severity = await this.handleDoubleSpendFailure(tx, txBlockNumber);
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
this.logger.verbose(`Rejecting gossiped tx ${tx.getTxHash().toString()}: stage 1 validation failed`, {
|
|
992
|
+
validator: name,
|
|
993
|
+
severity,
|
|
994
|
+
source: source.toString(),
|
|
995
|
+
});
|
|
996
|
+
return { result: TopicValidatorResult.Reject, severity };
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
// Pool pre-check: see if the pool would accept this tx before doing expensive proof verification
|
|
1000
|
+
const canAdd = await this.mempools.txPool.canAddPendingTx(tx);
|
|
1001
|
+
if (canAdd === 'ignored') {
|
|
1002
|
+
this.logger.verbose(`Ignoring gossiped tx ${tx.getTxHash().toString()}: pool pre-check returned ignored`, {
|
|
1003
|
+
source: source.toString(),
|
|
1004
|
+
});
|
|
1005
|
+
return { result: TopicValidatorResult.Ignore, obj: tx };
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
// Stage 2: expensive proof verification
|
|
1009
|
+
const secondStageValidators = this.createSecondStageMessageValidators();
|
|
1010
|
+
const secondStageOutcome = await this.runValidations(tx, secondStageValidators);
|
|
1011
|
+
if (!secondStageOutcome.allPassed) {
|
|
1012
|
+
const { severity, name } = secondStageOutcome.failure;
|
|
1013
|
+
this.logger.verbose(`Rejecting gossiped tx ${tx.getTxHash().toString()}: stage 2 validation failed`, {
|
|
1014
|
+
validator: name,
|
|
1015
|
+
severity,
|
|
1016
|
+
source: source.toString(),
|
|
1017
|
+
});
|
|
1018
|
+
return { result: TopicValidatorResult.Reject, severity };
|
|
1019
|
+
}
|
|
878
1020
|
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
1021
|
+
// Pool add: persist the tx
|
|
1022
|
+
const txHash = tx.getTxHash();
|
|
1023
|
+
const addResult = await this.mempools.txPool.addPendingTxs([tx], { source: 'gossip' });
|
|
1024
|
+
|
|
1025
|
+
const wasAccepted = addResult.accepted.some(h => h.equals(txHash));
|
|
1026
|
+
const wasIgnored = addResult.ignored.some(h => h.equals(txHash));
|
|
1027
|
+
|
|
1028
|
+
this.logger.verbose(`Validate propagated tx ${txHash.toString()}`, {
|
|
1029
|
+
wasAccepted,
|
|
1030
|
+
wasIgnored,
|
|
882
1031
|
[Attributes.P2P_ID]: source.toString(),
|
|
883
1032
|
});
|
|
884
1033
|
|
|
885
|
-
if (
|
|
886
|
-
return { result: TopicValidatorResult.
|
|
887
|
-
} else if (
|
|
1034
|
+
if (wasAccepted) {
|
|
1035
|
+
return { result: TopicValidatorResult.Accept, obj: tx };
|
|
1036
|
+
} else if (wasIgnored) {
|
|
888
1037
|
return { result: TopicValidatorResult.Ignore, obj: tx };
|
|
889
1038
|
} else {
|
|
890
|
-
|
|
1039
|
+
this.logger.warn(`Gossiped tx ${txHash.toString()} unexpectedly rejected by pool`, {
|
|
1040
|
+
source: source.toString(),
|
|
1041
|
+
txHash: txHash.toString(),
|
|
1042
|
+
});
|
|
1043
|
+
return { result: TopicValidatorResult.Reject, severity: PeerErrorSeverity.HighToleranceError };
|
|
891
1044
|
}
|
|
892
1045
|
};
|
|
893
1046
|
|
|
@@ -896,6 +1049,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
896
1049
|
return;
|
|
897
1050
|
}
|
|
898
1051
|
|
|
1052
|
+
// Tx was accepted into pool and will be propagated - just log and record metrics
|
|
899
1053
|
const txHash = tx.getTxHash();
|
|
900
1054
|
const txHashString = txHash.toString();
|
|
901
1055
|
this.logger.verbose(`Received tx ${txHashString} from external peer ${source.toString()} via gossip`, {
|
|
@@ -903,13 +1057,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
903
1057
|
txHash: txHashString,
|
|
904
1058
|
});
|
|
905
1059
|
|
|
906
|
-
if (this.config.dropTransactions && randomInt(1000) < this.config.dropTransactionsProbability * 1000) {
|
|
907
|
-
this.logger.warn(`Intentionally dropping tx ${txHashString} (probability rule)`);
|
|
908
|
-
return;
|
|
909
|
-
}
|
|
910
|
-
|
|
911
1060
|
this.instrumentation.incrementTxReceived(1);
|
|
912
|
-
await this.mempools.txPool.addTxs([tx]);
|
|
913
1061
|
}
|
|
914
1062
|
|
|
915
1063
|
/**
|
|
@@ -921,46 +1069,17 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
921
1069
|
msgId: string,
|
|
922
1070
|
source: PeerId,
|
|
923
1071
|
): Promise<void> {
|
|
924
|
-
const validationFunc: () => Promise<ReceivedMessageValidationResult<CheckpointAttestation>> = async () => {
|
|
925
|
-
const attestation = CheckpointAttestation.fromBuffer(payloadData);
|
|
926
|
-
const pool = this.mempools.attestationPool;
|
|
927
|
-
const isValid = await this.validateCheckpointAttestation(source, attestation);
|
|
928
|
-
const exists = isValid && (await pool.hasCheckpointAttestation(attestation));
|
|
929
|
-
|
|
930
|
-
let canAdd = true;
|
|
931
|
-
if (isValid && !exists) {
|
|
932
|
-
const slot = attestation.payload.header.slotNumber;
|
|
933
|
-
const { committee } = await this.epochCache.getCommittee(slot);
|
|
934
|
-
const committeeSize = committee?.length ?? 0;
|
|
935
|
-
canAdd = await pool.canAddCheckpointAttestation(attestation, committeeSize);
|
|
936
|
-
}
|
|
937
|
-
|
|
938
|
-
this.logger.trace(`Validate propagated checkpoint attestation`, {
|
|
939
|
-
isValid,
|
|
940
|
-
exists,
|
|
941
|
-
canAdd,
|
|
942
|
-
[Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber.toString(),
|
|
943
|
-
[Attributes.P2P_ID]: source.toString(),
|
|
944
|
-
});
|
|
945
|
-
|
|
946
|
-
if (!isValid) {
|
|
947
|
-
return { result: TopicValidatorResult.Reject };
|
|
948
|
-
} else if (exists) {
|
|
949
|
-
return { result: TopicValidatorResult.Ignore, obj: attestation };
|
|
950
|
-
} else if (!canAdd) {
|
|
951
|
-
this.logger.warn(`Dropping checkpoint attestation due to per-(slot, proposalId) attestation cap`, {
|
|
952
|
-
slot: attestation.payload.header.slotNumber.toString(),
|
|
953
|
-
archive: attestation.archive.toString(),
|
|
954
|
-
source: source.toString(),
|
|
955
|
-
});
|
|
956
|
-
return { result: TopicValidatorResult.Ignore, obj: attestation };
|
|
957
|
-
} else {
|
|
958
|
-
return { result: TopicValidatorResult.Accept, obj: attestation };
|
|
959
|
-
}
|
|
960
|
-
};
|
|
961
|
-
|
|
962
1072
|
const { result, obj: attestation } = await this.validateReceivedMessage<CheckpointAttestation>(
|
|
963
|
-
|
|
1073
|
+
() => {
|
|
1074
|
+
const attestation = this.tryDeserialize(() => CheckpointAttestation.fromBuffer(payloadData), msgId, source);
|
|
1075
|
+
if (!attestation) {
|
|
1076
|
+
return Promise.resolve({
|
|
1077
|
+
result: TopicValidatorResult.Reject,
|
|
1078
|
+
severity: PeerErrorSeverity.LowToleranceError,
|
|
1079
|
+
});
|
|
1080
|
+
}
|
|
1081
|
+
return this.validateAndStoreCheckpointAttestation(source, attestation);
|
|
1082
|
+
},
|
|
964
1083
|
msgId,
|
|
965
1084
|
source,
|
|
966
1085
|
TopicType.checkpoint_attestation,
|
|
@@ -970,8 +1089,8 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
970
1089
|
return;
|
|
971
1090
|
}
|
|
972
1091
|
|
|
973
|
-
this.logger.
|
|
974
|
-
`Received checkpoint attestation for slot ${attestation.slotNumber} from external peer ${source.toString()}`,
|
|
1092
|
+
this.logger.verbose(
|
|
1093
|
+
`Received valid checkpoint attestation for slot ${attestation.slotNumber} from external peer ${source.toString()}`,
|
|
975
1094
|
{
|
|
976
1095
|
p2pMessageIdentifier: await attestation.p2pMessageLoggingIdentifier(),
|
|
977
1096
|
slot: attestation.slotNumber,
|
|
@@ -979,59 +1098,168 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
979
1098
|
source: source.toString(),
|
|
980
1099
|
},
|
|
981
1100
|
);
|
|
982
|
-
|
|
983
|
-
await this.mempools.attestationPool.addCheckpointAttestations([attestation]);
|
|
984
1101
|
}
|
|
985
1102
|
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
1103
|
+
/** Validates a checkpoint attestation and adds it to the pool. Penalizes the peer if validation fails. */
|
|
1104
|
+
@trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId, attestation) => ({
|
|
1105
|
+
[Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber.toString(),
|
|
1106
|
+
}))
|
|
1107
|
+
protected async validateAndStoreCheckpointAttestation(
|
|
1108
|
+
peerId: PeerId,
|
|
1109
|
+
attestation: CheckpointAttestation,
|
|
1110
|
+
): Promise<ReceivedMessageValidationResult<CheckpointAttestation>> {
|
|
1111
|
+
const validationResult = await this.checkpointAttestationValidator.validate(attestation);
|
|
991
1112
|
|
|
992
|
-
|
|
993
|
-
|
|
1113
|
+
if (validationResult.result === 'reject') {
|
|
1114
|
+
this.logger.warn(`Penalizing peer ${peerId} for checkpoint attestation validation failure`);
|
|
1115
|
+
return { result: TopicValidatorResult.Reject, severity: validationResult.severity };
|
|
1116
|
+
}
|
|
994
1117
|
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1118
|
+
if (validationResult.result === 'ignore') {
|
|
1119
|
+
return { result: TopicValidatorResult.Ignore, obj: attestation };
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
// Try to add the attestation: this handles existence check, cap check, and adding in one call
|
|
1123
|
+
// count is the number of attestations by this signer for this slot (for duplicate detection)
|
|
1124
|
+
const slot = attestation.payload.header.slotNumber;
|
|
1125
|
+
const { added, alreadyExists, count } =
|
|
1126
|
+
await this.mempools.attestationPool.tryAddCheckpointAttestation(attestation);
|
|
1127
|
+
|
|
1128
|
+
this.logger.trace(`Validate propagated checkpoint attestation`, {
|
|
1129
|
+
added,
|
|
1130
|
+
alreadyExists,
|
|
1131
|
+
count,
|
|
1132
|
+
[Attributes.SLOT_NUMBER]: slot.toString(),
|
|
1133
|
+
[Attributes.P2P_ID]: peerId.toString(),
|
|
1134
|
+
});
|
|
1135
|
+
|
|
1136
|
+
// Exact same attestation received, no need to re-broadcast
|
|
1137
|
+
if (alreadyExists) {
|
|
1138
|
+
return { result: TopicValidatorResult.Ignore, obj: attestation };
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1141
|
+
// Could not add (cap reached for signer), penalize and do not re-broadcast
|
|
1142
|
+
if (!added) {
|
|
1143
|
+
this.logger.warn(`Rejecting checkpoint attestation due to cap`, {
|
|
1144
|
+
slot: slot.toString(),
|
|
1145
|
+
archive: attestation.archive.toString(),
|
|
1146
|
+
source: peerId.toString(),
|
|
1147
|
+
attester: attestation.getSender()?.toString(),
|
|
1148
|
+
count,
|
|
1001
1149
|
});
|
|
1150
|
+
return { result: TopicValidatorResult.Reject, severity: PeerErrorSeverity.HighToleranceError };
|
|
1151
|
+
}
|
|
1002
1152
|
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
this.
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1153
|
+
// Check if this is a duplicate attestation (signer attested to a different proposal at the same slot)
|
|
1154
|
+
// count is the number of attestations by this signer for this slot
|
|
1155
|
+
if (count === 2) {
|
|
1156
|
+
const attester = attestation.getSender();
|
|
1157
|
+
if (attester) {
|
|
1158
|
+
this.logger.warn(`Detected duplicate attestation (equivocation) at slot ${slot}`, {
|
|
1159
|
+
slot: slot.toString(),
|
|
1160
|
+
archive: attestation.archive.toString(),
|
|
1161
|
+
source: peerId.toString(),
|
|
1162
|
+
attester: attester.toString(),
|
|
1013
1163
|
});
|
|
1014
|
-
|
|
1015
|
-
} else {
|
|
1016
|
-
return { result: TopicValidatorResult.Accept, obj: block };
|
|
1164
|
+
this.duplicateAttestationCallback?.({ slot, attester });
|
|
1017
1165
|
}
|
|
1018
|
-
}
|
|
1166
|
+
}
|
|
1167
|
+
|
|
1168
|
+
// Attestation was added successfully - accept it so other nodes can also detect the equivocation
|
|
1169
|
+
return { result: TopicValidatorResult.Accept, obj: attestation };
|
|
1170
|
+
}
|
|
1019
1171
|
|
|
1020
|
-
|
|
1021
|
-
|
|
1172
|
+
protected async processBlockFromPeer(payloadData: Buffer, msgId: string, source: PeerId): Promise<void> {
|
|
1173
|
+
const {
|
|
1174
|
+
result,
|
|
1175
|
+
obj: block,
|
|
1176
|
+
metadata: { isEquivocated } = {},
|
|
1177
|
+
} = await this.validateReceivedMessage<BlockProposal, { isEquivocated: boolean }>(
|
|
1178
|
+
() => this.validateAndStoreBlockProposal(source, BlockProposal.fromBuffer(payloadData)),
|
|
1022
1179
|
msgId,
|
|
1023
1180
|
source,
|
|
1024
1181
|
TopicType.block_proposal,
|
|
1025
1182
|
);
|
|
1026
1183
|
|
|
1027
|
-
|
|
1184
|
+
// If not accepted or equivocated, return
|
|
1185
|
+
if (result !== TopicValidatorResult.Accept || !block || isEquivocated) {
|
|
1028
1186
|
return;
|
|
1029
1187
|
}
|
|
1030
1188
|
|
|
1031
1189
|
await this.processValidBlockProposal(block, source);
|
|
1032
1190
|
}
|
|
1033
1191
|
|
|
1034
|
-
|
|
1192
|
+
/** Validates a block proposal. Triggers a penalization to the peer that sent it if invalid. Adds to the mempool if valid. */
|
|
1193
|
+
@trackSpan('Libp2pService.validateAndStoreBlockProposal', (_peerId, block) => ({
|
|
1194
|
+
[Attributes.BLOCK_NUMBER]: block.blockNumber.toString(),
|
|
1195
|
+
[Attributes.SLOT_NUMBER]: block.slotNumber.toString(),
|
|
1196
|
+
}))
|
|
1197
|
+
protected async validateAndStoreBlockProposal(
|
|
1198
|
+
peerId: PeerId,
|
|
1199
|
+
block: BlockProposal,
|
|
1200
|
+
): Promise<ReceivedMessageValidationResult<BlockProposal, { isEquivocated: boolean }>> {
|
|
1201
|
+
const validationResult = await this.blockProposalValidator.validate(block);
|
|
1202
|
+
|
|
1203
|
+
if (validationResult.result === 'reject') {
|
|
1204
|
+
this.logger.warn(`Penalizing peer ${peerId} for block proposal validation failure`);
|
|
1205
|
+
return { result: TopicValidatorResult.Reject, severity: validationResult.severity };
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
if (validationResult.result === 'ignore') {
|
|
1209
|
+
return { result: TopicValidatorResult.Ignore, obj: block };
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1212
|
+
// Try to add the proposal: this handles existence check, cap check, and adding in one call
|
|
1213
|
+
const { added, alreadyExists, count } = await this.mempools.attestationPool.tryAddBlockProposal(block);
|
|
1214
|
+
const isEquivocated = count !== undefined && count > 1;
|
|
1215
|
+
|
|
1216
|
+
// Duplicate proposal received, no need to re-broadcast
|
|
1217
|
+
if (alreadyExists) {
|
|
1218
|
+
this.logger.debug(`Ignoring duplicate block proposal received`, {
|
|
1219
|
+
...block.toBlockInfo(),
|
|
1220
|
+
indexWithinCheckpoint: block.indexWithinCheckpoint,
|
|
1221
|
+
proposer: block.getSender()?.toString(),
|
|
1222
|
+
source: peerId.toString(),
|
|
1223
|
+
});
|
|
1224
|
+
return { result: TopicValidatorResult.Ignore, obj: block, metadata: { isEquivocated } };
|
|
1225
|
+
}
|
|
1226
|
+
|
|
1227
|
+
// Too many blocks received for this slot and index, penalize peer and do not re-broadcast
|
|
1228
|
+
if (!added) {
|
|
1229
|
+
this.logger.warn(`Penalizing peer for block proposal exceeding per-position cap`, {
|
|
1230
|
+
...block.toBlockInfo(),
|
|
1231
|
+
indexWithinCheckpoint: block.indexWithinCheckpoint,
|
|
1232
|
+
count,
|
|
1233
|
+
proposer: block.getSender()?.toString(),
|
|
1234
|
+
source: peerId.toString(),
|
|
1235
|
+
});
|
|
1236
|
+
return {
|
|
1237
|
+
result: TopicValidatorResult.Reject,
|
|
1238
|
+
metadata: { isEquivocated },
|
|
1239
|
+
severity: PeerErrorSeverity.HighToleranceError,
|
|
1240
|
+
};
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1243
|
+
// If this was a duplicate proposal, do not process it, but do invoke the duplicate callback,
|
|
1244
|
+
// and do re-broadcast it so other nodes in the network know to slash the proposer
|
|
1245
|
+
if (isEquivocated) {
|
|
1246
|
+
const proposer = block.getSender();
|
|
1247
|
+
this.logger.warn(`Detected duplicate block proposal (equivocation) at slot ${block.slotNumber}`, {
|
|
1248
|
+
...block.toBlockInfo(),
|
|
1249
|
+
source: peerId.toString(),
|
|
1250
|
+
proposer: proposer?.toString(),
|
|
1251
|
+
});
|
|
1252
|
+
// Invoke the duplicate callback on the first duplicate spotted only
|
|
1253
|
+
if (proposer && count === 2) {
|
|
1254
|
+
this.duplicateProposalCallback?.({ slot: block.slotNumber, proposer, type: 'block' });
|
|
1255
|
+
}
|
|
1256
|
+
return { result: TopicValidatorResult.Accept, obj: block, metadata: { isEquivocated } };
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1259
|
+
// Otherwise, we're good to go!
|
|
1260
|
+
return { result: TopicValidatorResult.Accept, obj: block };
|
|
1261
|
+
}
|
|
1262
|
+
|
|
1035
1263
|
// REFACTOR(palla): This method should be moved to the p2p_client or to a separate component,
|
|
1036
1264
|
// should not be here as it does not deal with p2p networking.
|
|
1037
1265
|
@trackSpan('Libp2pService.processValidBlockProposal', async block => ({
|
|
@@ -1039,7 +1267,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1039
1267
|
[Attributes.BLOCK_ARCHIVE]: block.archive.toString(),
|
|
1040
1268
|
[Attributes.P2P_ID]: await block.p2pMessageLoggingIdentifier().then(i => i.toString()),
|
|
1041
1269
|
}))
|
|
1042
|
-
|
|
1270
|
+
protected async processValidBlockProposal(block: BlockProposal, sender: PeerId) {
|
|
1043
1271
|
const slot = block.slotNumber;
|
|
1044
1272
|
this.logger.verbose(`Received block proposal for slot ${slot} from external peer ${sender.toString()}.`, {
|
|
1045
1273
|
p2pMessageIdentifier: await block.p2pMessageLoggingIdentifier(),
|
|
@@ -1047,30 +1275,14 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1047
1275
|
...block.toBlockInfo(),
|
|
1048
1276
|
});
|
|
1049
1277
|
|
|
1050
|
-
//
|
|
1051
|
-
|
|
1052
|
-
await this.mempools.attestationPool.addBlockProposal(block);
|
|
1053
|
-
} catch (err: unknown) {
|
|
1054
|
-
// Drop proposals if we hit per-slot cap in the attestation pool; rethrow unknown errors
|
|
1055
|
-
if (err instanceof ProposalSlotCapExceededError) {
|
|
1056
|
-
this.logger.warn(`Dropping block proposal due to per-slot proposal cap`, {
|
|
1057
|
-
slot: String(slot),
|
|
1058
|
-
archive: block.archive.toString(),
|
|
1059
|
-
error: (err as Error).message,
|
|
1060
|
-
});
|
|
1061
|
-
return;
|
|
1062
|
-
}
|
|
1063
|
-
throw err;
|
|
1064
|
-
}
|
|
1065
|
-
|
|
1066
|
-
// Mark the txs in this proposal as non-evictable
|
|
1067
|
-
await this.mempools.txPool.markTxsAsNonEvictable(block.txHashes);
|
|
1278
|
+
// Mark the txs in this proposal as protected
|
|
1279
|
+
await this.mempools.txPool.protectTxs(block.txHashes, block.blockHeader);
|
|
1068
1280
|
|
|
1069
1281
|
// Call the block received callback to validate the proposal.
|
|
1070
1282
|
// Note: Validators do NOT attest to individual blocks, only to checkpoint proposals.
|
|
1071
1283
|
const isValid = await this.blockReceivedCallback(block, sender);
|
|
1072
1284
|
if (!isValid) {
|
|
1073
|
-
this.logger.
|
|
1285
|
+
this.logger.info(`Block proposal validation failed for block ${block.blockNumber}`, block.toBlockInfo());
|
|
1074
1286
|
}
|
|
1075
1287
|
}
|
|
1076
1288
|
|
|
@@ -1078,66 +1290,149 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1078
1290
|
* Handle a gossiped checkpoint proposal.
|
|
1079
1291
|
* Validates and processes the checkpoint proposal, then triggers the callback for attestation.
|
|
1080
1292
|
*/
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
const exists = isValid && (await pool.hasCheckpointProposal(checkpoint));
|
|
1089
|
-
const canAdd = isValid && (await pool.canAddCheckpointProposal(checkpoint));
|
|
1090
|
-
|
|
1091
|
-
this.logger.trace(`Validate propagated checkpoint proposal`, {
|
|
1092
|
-
isValid,
|
|
1093
|
-
exists,
|
|
1094
|
-
canAdd,
|
|
1095
|
-
[Attributes.SLOT_NUMBER]: checkpoint.slotNumber.toString(),
|
|
1096
|
-
[Attributes.P2P_ID]: source.toString(),
|
|
1097
|
-
});
|
|
1098
|
-
|
|
1099
|
-
if (!isValid) {
|
|
1100
|
-
return { result: TopicValidatorResult.Reject };
|
|
1101
|
-
} else if (exists) {
|
|
1102
|
-
return { result: TopicValidatorResult.Ignore, obj: checkpoint };
|
|
1103
|
-
} else if (!canAdd) {
|
|
1104
|
-
this.peerManager.penalizePeer(source, PeerErrorSeverity.MidToleranceError);
|
|
1105
|
-
this.logger.warn(`Penalizing peer for checkpoint proposal exceeding per-slot cap`, {
|
|
1106
|
-
slot: checkpoint.slotNumber.toString(),
|
|
1107
|
-
archive: checkpoint.archive.toString(),
|
|
1108
|
-
source: source.toString(),
|
|
1109
|
-
});
|
|
1110
|
-
return { result: TopicValidatorResult.Reject };
|
|
1111
|
-
} else {
|
|
1112
|
-
return { result: TopicValidatorResult.Accept, obj: checkpoint };
|
|
1113
|
-
}
|
|
1114
|
-
};
|
|
1115
|
-
|
|
1116
|
-
const { result, obj: checkpoint } = await this.validateReceivedMessage<CheckpointProposal>(
|
|
1117
|
-
validationFunc,
|
|
1293
|
+
protected async handleGossipedCheckpointProposal(payloadData: Buffer, msgId: string, source: PeerId): Promise<void> {
|
|
1294
|
+
const {
|
|
1295
|
+
result,
|
|
1296
|
+
obj: checkpoint,
|
|
1297
|
+
metadata: { isEquivocated, processBlock } = {},
|
|
1298
|
+
} = await this.validateReceivedMessage<CheckpointProposal, { isEquivocated: boolean; processBlock: boolean }>(
|
|
1299
|
+
() => this.validateAndStoreCheckpointProposal(source, CheckpointProposal.fromBuffer(payloadData)),
|
|
1118
1300
|
msgId,
|
|
1119
1301
|
source,
|
|
1120
1302
|
TopicType.checkpoint_proposal,
|
|
1121
1303
|
);
|
|
1122
1304
|
|
|
1123
|
-
|
|
1305
|
+
// If the checkpoint contained a valid last block, we process it even if the checkpoint itself is to be rejected
|
|
1306
|
+
// TODO(palla/mbps): Is this ok? Should we be considering a block from a checkpoint that was equivocated?
|
|
1307
|
+
if (processBlock && checkpoint?.getBlockProposal()) {
|
|
1308
|
+
await this.processValidBlockProposal(checkpoint.getBlockProposal()!, source);
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1311
|
+
if (result !== TopicValidatorResult.Accept || !checkpoint || isEquivocated) {
|
|
1124
1312
|
return;
|
|
1125
1313
|
}
|
|
1126
1314
|
|
|
1127
|
-
await this.processValidCheckpointProposal(checkpoint, source);
|
|
1315
|
+
await this.processValidCheckpointProposal(checkpoint.toCore(), source);
|
|
1316
|
+
}
|
|
1317
|
+
|
|
1318
|
+
/**
|
|
1319
|
+
* Validates a checkpoint proposal. Penalizes peer if validation fails. Adds the checkpoint and
|
|
1320
|
+
* its last block (if present) to the mempool if valid. Triggers equivocation detection on both.
|
|
1321
|
+
*/
|
|
1322
|
+
@trackSpan('Libp2pService.validateAndStoreCheckpointProposal', (_peerId, checkpoint) => ({
|
|
1323
|
+
[Attributes.SLOT_NUMBER]: checkpoint.slotNumber.toString(),
|
|
1324
|
+
}))
|
|
1325
|
+
protected async validateAndStoreCheckpointProposal(
|
|
1326
|
+
peerId: PeerId,
|
|
1327
|
+
checkpoint: CheckpointProposal,
|
|
1328
|
+
): Promise<ReceivedMessageValidationResult<CheckpointProposal, { isEquivocated: boolean; processBlock: boolean }>> {
|
|
1329
|
+
const validationResult = await this.checkpointProposalValidator.validate(checkpoint);
|
|
1330
|
+
|
|
1331
|
+
if (validationResult.result === 'reject') {
|
|
1332
|
+
this.logger.warn(`Penalizing peer ${peerId} for checkpoint proposal validation failure`);
|
|
1333
|
+
return { result: TopicValidatorResult.Reject, severity: validationResult.severity };
|
|
1334
|
+
}
|
|
1335
|
+
|
|
1336
|
+
if (validationResult.result === 'ignore') {
|
|
1337
|
+
return { result: TopicValidatorResult.Ignore, obj: checkpoint };
|
|
1338
|
+
}
|
|
1339
|
+
|
|
1340
|
+
// Extract and try to add the block proposal first if present
|
|
1341
|
+
const blockProposal = checkpoint.getBlockProposal();
|
|
1342
|
+
let processBlock = false;
|
|
1343
|
+
if (blockProposal) {
|
|
1344
|
+
this.logger.debug(`Validating block proposal from propagated checkpoint`, {
|
|
1345
|
+
[Attributes.SLOT_NUMBER]: checkpoint.slotNumber.toString(),
|
|
1346
|
+
[Attributes.P2P_ID]: peerId.toString(),
|
|
1347
|
+
});
|
|
1348
|
+
const blockProposalResult = await this.validateAndStoreBlockProposal(peerId, blockProposal);
|
|
1349
|
+
const { obj, metadata: { isEquivocated } = {} } = blockProposalResult;
|
|
1350
|
+
if (blockProposalResult.result === TopicValidatorResult.Reject || !obj || isEquivocated) {
|
|
1351
|
+
this.logger.debug(`Rejecting checkpoint due to invalid last block proposal`, {
|
|
1352
|
+
[Attributes.SLOT_NUMBER]: checkpoint.slotNumber.toString(),
|
|
1353
|
+
[Attributes.P2P_ID]: peerId.toString(),
|
|
1354
|
+
isEquivocated,
|
|
1355
|
+
result: blockProposalResult.result,
|
|
1356
|
+
});
|
|
1357
|
+
return {
|
|
1358
|
+
result: TopicValidatorResult.Reject,
|
|
1359
|
+
severity:
|
|
1360
|
+
'severity' in blockProposalResult ? blockProposalResult.severity : PeerErrorSeverity.MidToleranceError,
|
|
1361
|
+
};
|
|
1362
|
+
} else if (blockProposalResult.result === TopicValidatorResult.Accept && obj && !isEquivocated) {
|
|
1363
|
+
processBlock = true;
|
|
1364
|
+
}
|
|
1365
|
+
}
|
|
1366
|
+
|
|
1367
|
+
// Try to add the checkpoint proposal core: this handles existence check, cap check, and adding in one call
|
|
1368
|
+
const checkpointCore = checkpoint.toCore();
|
|
1369
|
+
const tryAddResult = await this.mempools.attestationPool.tryAddCheckpointProposal(checkpointCore);
|
|
1370
|
+
const { added, alreadyExists, count } = tryAddResult;
|
|
1371
|
+
const isEquivocated = count !== undefined && count > 1;
|
|
1372
|
+
|
|
1373
|
+
// Duplicate proposal received, do not re-broadcast
|
|
1374
|
+
if (alreadyExists) {
|
|
1375
|
+
this.logger.debug(`Ignoring duplicate checkpoint proposal received`, {
|
|
1376
|
+
...checkpoint.toCheckpointInfo(),
|
|
1377
|
+
source: peerId.toString(),
|
|
1378
|
+
});
|
|
1379
|
+
return {
|
|
1380
|
+
result: TopicValidatorResult.Ignore,
|
|
1381
|
+
obj: checkpoint,
|
|
1382
|
+
metadata: { isEquivocated, processBlock },
|
|
1383
|
+
};
|
|
1384
|
+
}
|
|
1385
|
+
|
|
1386
|
+
// Too many checkpoint proposals received for this slot, penalize peer and do not re-broadcast
|
|
1387
|
+
// Note: We still return the checkpoint obj so the lastBlock can be processed if valid
|
|
1388
|
+
if (!added) {
|
|
1389
|
+
this.logger.warn(`Penalizing peer for checkpoint proposal exceeding per-slot cap`, {
|
|
1390
|
+
...checkpoint.toCheckpointInfo(),
|
|
1391
|
+
count,
|
|
1392
|
+
source: peerId.toString(),
|
|
1393
|
+
});
|
|
1394
|
+
return {
|
|
1395
|
+
result: TopicValidatorResult.Reject,
|
|
1396
|
+
obj: checkpoint,
|
|
1397
|
+
metadata: { isEquivocated, processBlock },
|
|
1398
|
+
severity: PeerErrorSeverity.HighToleranceError,
|
|
1399
|
+
};
|
|
1400
|
+
}
|
|
1401
|
+
|
|
1402
|
+
// If this was a duplicate proposal, do not process it, but do invoke the duplicate callback,
|
|
1403
|
+
// and do re-broadcast it so other nodes in the network know to slash the proposer
|
|
1404
|
+
if (isEquivocated) {
|
|
1405
|
+
const proposer = checkpoint.getSender();
|
|
1406
|
+
this.logger.warn(`Detected duplicate checkpoint proposal (equivocation) at slot ${checkpoint.slotNumber}`, {
|
|
1407
|
+
...checkpoint.toCheckpointInfo(),
|
|
1408
|
+
source: peerId.toString(),
|
|
1409
|
+
proposer: proposer?.toString(),
|
|
1410
|
+
});
|
|
1411
|
+
// Invoke the duplicate callback on the first duplicate spotted only
|
|
1412
|
+
if (proposer && count === 2) {
|
|
1413
|
+
this.duplicateProposalCallback?.({ slot: checkpoint.slotNumber, proposer, type: 'checkpoint' });
|
|
1414
|
+
}
|
|
1415
|
+
return {
|
|
1416
|
+
result: TopicValidatorResult.Accept,
|
|
1417
|
+
obj: checkpoint,
|
|
1418
|
+
metadata: { isEquivocated, processBlock },
|
|
1419
|
+
};
|
|
1420
|
+
}
|
|
1421
|
+
|
|
1422
|
+
// Otherwise, we're good to go!
|
|
1423
|
+
return { result: TopicValidatorResult.Accept, obj: checkpoint, metadata: { processBlock, isEquivocated } };
|
|
1128
1424
|
}
|
|
1129
1425
|
|
|
1130
1426
|
/**
|
|
1131
1427
|
* Process a validated checkpoint proposal.
|
|
1132
|
-
*
|
|
1133
|
-
* The block callback is invoked before the checkpoint callback.
|
|
1428
|
+
* Note: The proposal was already added to the pool by tryAddCheckpointProposal in handleGossipedCheckpointProposal.
|
|
1134
1429
|
*/
|
|
1135
1430
|
@trackSpan('Libp2pService.processValidCheckpointProposal', async checkpoint => ({
|
|
1136
1431
|
[Attributes.SLOT_NUMBER]: checkpoint.slotNumber,
|
|
1137
1432
|
[Attributes.BLOCK_ARCHIVE]: checkpoint.archive.toString(),
|
|
1138
1433
|
[Attributes.P2P_ID]: await checkpoint.p2pMessageLoggingIdentifier().then(i => i.toString()),
|
|
1139
1434
|
}))
|
|
1140
|
-
|
|
1435
|
+
protected async processValidCheckpointProposal(checkpoint: CheckpointProposalCore, sender: PeerId) {
|
|
1141
1436
|
const slot = checkpoint.slotNumber;
|
|
1142
1437
|
this.logger.verbose(`Received checkpoint proposal for slot ${slot} from external peer ${sender.toString()}.`, {
|
|
1143
1438
|
p2pMessageIdentifier: await checkpoint.p2pMessageLoggingIdentifier(),
|
|
@@ -1146,37 +1441,12 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1146
1441
|
source: sender.toString(),
|
|
1147
1442
|
});
|
|
1148
1443
|
|
|
1149
|
-
// Extract block proposal before adding to pool (pool stores them separately)
|
|
1150
|
-
const blockProposal = checkpoint.getBlockProposal();
|
|
1151
|
-
|
|
1152
|
-
// Add proposal to the pool (this extracts and stores block proposal separately)
|
|
1153
|
-
await this.mempools.attestationPool.addCheckpointProposal(checkpoint);
|
|
1154
|
-
|
|
1155
|
-
// Mark txs as non-evictable if present (from the last block)
|
|
1156
|
-
if (checkpoint.txHashes.length > 0) {
|
|
1157
|
-
await this.mempools.txPool.markTxsAsNonEvictable(checkpoint.txHashes);
|
|
1158
|
-
}
|
|
1159
|
-
|
|
1160
|
-
// If there was a last block proposal, invoke the block callback first for validation.
|
|
1161
|
-
// Note: The block proposal is already stored in the pool by addCheckpointProposal.
|
|
1162
|
-
if (blockProposal) {
|
|
1163
|
-
const isValid = await this.blockReceivedCallback(blockProposal, sender);
|
|
1164
|
-
if (!isValid) {
|
|
1165
|
-
this.logger.warn(`Block proposal from checkpoint failed validation`, {
|
|
1166
|
-
slot: slot.toString(),
|
|
1167
|
-
archive: checkpoint.archive.toString(),
|
|
1168
|
-
blockNumber: blockProposal.blockNumber.toString(),
|
|
1169
|
-
});
|
|
1170
|
-
return;
|
|
1171
|
-
}
|
|
1172
|
-
}
|
|
1173
|
-
|
|
1174
1444
|
// Call the checkpoint received callback with the core version (without lastBlock)
|
|
1175
1445
|
// to validate and potentially generate attestations
|
|
1176
|
-
const attestations = await this.checkpointReceivedCallback(checkpoint
|
|
1446
|
+
const attestations = await this.checkpointReceivedCallback(checkpoint, sender);
|
|
1177
1447
|
if (attestations && attestations.length > 0) {
|
|
1178
1448
|
// If the callback returned attestations, add them to the pool and propagate them
|
|
1179
|
-
await this.mempools.attestationPool.
|
|
1449
|
+
await this.mempools.attestationPool.addOwnCheckpointAttestations(attestations);
|
|
1180
1450
|
for (const attestation of attestations) {
|
|
1181
1451
|
await this.propagate(attestation);
|
|
1182
1452
|
}
|
|
@@ -1203,9 +1473,9 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1203
1473
|
* @returns True if the requested block transactions are valid, false otherwise.
|
|
1204
1474
|
*/
|
|
1205
1475
|
@trackSpan('Libp2pService.validateRequestedBlockTxs', request => ({
|
|
1206
|
-
[Attributes.
|
|
1476
|
+
[Attributes.BLOCK_ARCHIVE]: request.archiveRoot.toString(),
|
|
1207
1477
|
}))
|
|
1208
|
-
|
|
1478
|
+
protected async validateRequestedBlockTxs(
|
|
1209
1479
|
request: BlockTxsRequest,
|
|
1210
1480
|
response: BlockTxsResponse,
|
|
1211
1481
|
peerId: PeerId,
|
|
@@ -1213,10 +1483,10 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1213
1483
|
const requestedTxValidator = this.createRequestedTxValidator();
|
|
1214
1484
|
|
|
1215
1485
|
try {
|
|
1216
|
-
if (!response.
|
|
1486
|
+
if (!response.archiveRoot.equals(request.archiveRoot)) {
|
|
1217
1487
|
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
1218
1488
|
throw new ValidationError(
|
|
1219
|
-
`Received block txs for unexpected
|
|
1489
|
+
`Received block txs for unexpected archive root: expected ${request.archiveRoot.toString()}, got ${response.archiveRoot.toString()}`,
|
|
1220
1490
|
);
|
|
1221
1491
|
}
|
|
1222
1492
|
|
|
@@ -1246,7 +1516,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1246
1516
|
}
|
|
1247
1517
|
|
|
1248
1518
|
// Given proposal (should have locally), ensure returned txs are valid subset and match request indices
|
|
1249
|
-
const proposal = await this.mempools.attestationPool.getBlockProposal(request.
|
|
1519
|
+
const proposal = await this.mempools.attestationPool.getBlockProposal(request.archiveRoot.toString());
|
|
1250
1520
|
if (proposal) {
|
|
1251
1521
|
// Build intersected indices
|
|
1252
1522
|
const intersectIdx = request.txIndices.getTrueIndices().filter(i => response.txIndices.isSet(i));
|
|
@@ -1266,7 +1536,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1266
1536
|
} else {
|
|
1267
1537
|
// No local proposal, cannot check the membership/order of the returned txs
|
|
1268
1538
|
this.logger.warn(
|
|
1269
|
-
`Block proposal not found for
|
|
1539
|
+
`Block proposal not found for archive root ${request.archiveRoot.toString()}; cannot validate membership/order of returned txs`,
|
|
1270
1540
|
);
|
|
1271
1541
|
return false;
|
|
1272
1542
|
}
|
|
@@ -1305,7 +1575,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1305
1575
|
const requested = new Set(requestedTxHash.map(h => h.toString()));
|
|
1306
1576
|
const requestedTxValidator = this.createRequestedTxValidator();
|
|
1307
1577
|
|
|
1308
|
-
//TODO: (mralj) - this is somewhat naive implementation, if single tx is
|
|
1578
|
+
//TODO: (mralj) - this is somewhat naive implementation, if single tx is invalid we consider the whole response invalid.
|
|
1309
1579
|
// I think we should still extract the valid txs and return them, so that we can still use the response.
|
|
1310
1580
|
try {
|
|
1311
1581
|
await Promise.all(responseTx.map(tx => this.validateRequestedTx(tx, peerId, requestedTxValidator, requested)));
|
|
@@ -1335,9 +1605,9 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1335
1605
|
@trackSpan('Libp2pService.validateRequestedBlock', (requestedBlockNumber, _responseBlock) => ({
|
|
1336
1606
|
[Attributes.BLOCK_NUMBER]: requestedBlockNumber.toString(),
|
|
1337
1607
|
}))
|
|
1338
|
-
|
|
1608
|
+
protected async validateRequestedBlock(
|
|
1339
1609
|
requestedBlockNumber: Fr,
|
|
1340
|
-
responseBlock:
|
|
1610
|
+
responseBlock: L2Block,
|
|
1341
1611
|
peerId: PeerId,
|
|
1342
1612
|
): Promise<boolean> {
|
|
1343
1613
|
try {
|
|
@@ -1368,28 +1638,13 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1368
1638
|
}
|
|
1369
1639
|
}
|
|
1370
1640
|
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
rollupVersion: new Fr(this.config.rollupVersion),
|
|
1378
|
-
protocolContractsHash,
|
|
1379
|
-
vkTreeRoot: getVKTreeRoot(),
|
|
1380
|
-
}),
|
|
1381
|
-
new TxProofValidator(this.proofVerifier),
|
|
1382
|
-
);
|
|
1383
|
-
}
|
|
1384
|
-
|
|
1385
|
-
private async validateRequestedTx(tx: Tx, peerId: PeerId, txValidator: TxValidator, requested?: Set<`0x${string}`>) {
|
|
1641
|
+
protected async validateRequestedTx(
|
|
1642
|
+
tx: Tx,
|
|
1643
|
+
peerId: PeerId,
|
|
1644
|
+
txValidator: TxValidator,
|
|
1645
|
+
requested?: Set<`0x${string}`>,
|
|
1646
|
+
) {
|
|
1386
1647
|
const penalize = (severity: PeerErrorSeverity) => this.peerManager.penalizePeer(peerId, severity);
|
|
1387
|
-
|
|
1388
|
-
if (!(await tx.validateTxHash())) {
|
|
1389
|
-
penalize(PeerErrorSeverity.MidToleranceError);
|
|
1390
|
-
throw new ValidationError(`Received tx with invalid hash ${tx.getTxHash().toString()}.`);
|
|
1391
|
-
}
|
|
1392
|
-
|
|
1393
1648
|
if (requested && !requested.has(tx.getTxHash().toString())) {
|
|
1394
1649
|
penalize(PeerErrorSeverity.MidToleranceError);
|
|
1395
1650
|
throw new ValidationError(`Received tx with hash ${tx.getTxHash().toString()} that was not requested.`);
|
|
@@ -1402,35 +1657,11 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1402
1657
|
}
|
|
1403
1658
|
}
|
|
1404
1659
|
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
// We accept transactions if they are not expired by the next slot (checked based on the IncludeByTimestamp field)
|
|
1412
|
-
const { ts: nextSlotTimestamp } = this.epochCache.getEpochAndSlotInNextL1Slot();
|
|
1413
|
-
const messageValidators = await this.createMessageValidators(currentBlockNumber, nextSlotTimestamp);
|
|
1414
|
-
|
|
1415
|
-
for (const validator of messageValidators) {
|
|
1416
|
-
const outcome = await this.runValidations(tx, validator);
|
|
1417
|
-
|
|
1418
|
-
if (outcome.allPassed) {
|
|
1419
|
-
continue;
|
|
1420
|
-
}
|
|
1421
|
-
const { name } = outcome.failure;
|
|
1422
|
-
let { severity } = outcome.failure;
|
|
1423
|
-
|
|
1424
|
-
// Double spend validator has a special case handler
|
|
1425
|
-
if (name === 'doubleSpendValidator') {
|
|
1426
|
-
const txBlockNumber = BlockNumber(currentBlockNumber + 1); // tx is expected to be in the next block
|
|
1427
|
-
severity = await this.handleDoubleSpendFailure(tx, txBlockNumber);
|
|
1428
|
-
}
|
|
1429
|
-
|
|
1430
|
-
this.peerManager.penalizePeer(peerId, severity);
|
|
1431
|
-
return false;
|
|
1432
|
-
}
|
|
1433
|
-
return true;
|
|
1660
|
+
protected createRequestedTxValidator(): TxValidator {
|
|
1661
|
+
return createTxValidatorForReqResponseReceivedTxs(this.proofVerifier, {
|
|
1662
|
+
l1ChainId: this.config.l1ChainId,
|
|
1663
|
+
rollupVersion: this.config.rollupVersion,
|
|
1664
|
+
});
|
|
1434
1665
|
}
|
|
1435
1666
|
|
|
1436
1667
|
private async getGasFees(blockNumber: BlockNumber): Promise<GasFees> {
|
|
@@ -1444,59 +1675,78 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1444
1675
|
return gasFees;
|
|
1445
1676
|
}
|
|
1446
1677
|
|
|
1447
|
-
|
|
1448
|
-
|
|
1678
|
+
/**
|
|
1679
|
+
* Get the BatchTxRequesterLibP2PService dependencies for creating BatchTxRequester instances
|
|
1680
|
+
*/
|
|
1681
|
+
public getBatchTxRequesterService(): BatchTxRequesterLibP2PService {
|
|
1682
|
+
return {
|
|
1683
|
+
reqResp: this.reqresp,
|
|
1684
|
+
connectionSampler: this.reqresp.getConnectionSampler(),
|
|
1685
|
+
txValidatorConfig: {
|
|
1686
|
+
l1ChainId: this.config.l1ChainId,
|
|
1687
|
+
rollupVersion: this.config.rollupVersion,
|
|
1688
|
+
proofVerifier: this.proofVerifier,
|
|
1689
|
+
},
|
|
1690
|
+
peerScoring: this.peerManager,
|
|
1691
|
+
};
|
|
1692
|
+
}
|
|
1449
1693
|
|
|
1450
|
-
|
|
1451
|
-
const
|
|
1452
|
-
|
|
1694
|
+
public async validateTxsReceivedInBlockProposal(txs: Tx[]): Promise<void> {
|
|
1695
|
+
const validator = createTxValidatorForBlockProposalReceivedTxs(
|
|
1696
|
+
this.proofVerifier,
|
|
1697
|
+
{ l1ChainId: this.config.l1ChainId, rollupVersion: this.config.rollupVersion },
|
|
1698
|
+
this.logger.getBindings(),
|
|
1699
|
+
);
|
|
1453
1700
|
|
|
1454
|
-
await Promise.all(
|
|
1701
|
+
const results = await Promise.all(
|
|
1455
1702
|
txs.map(async tx => {
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
if (!outcome.allPassed) {
|
|
1459
|
-
throw new Error('Invalid tx detected', { cause: { outcome } });
|
|
1460
|
-
}
|
|
1461
|
-
}
|
|
1703
|
+
const result = await validator.validateTx(tx);
|
|
1704
|
+
return result.result !== 'invalid';
|
|
1462
1705
|
}),
|
|
1463
1706
|
);
|
|
1707
|
+
if (results.some(value => value === false)) {
|
|
1708
|
+
throw new Error('Invalid tx detected');
|
|
1709
|
+
}
|
|
1464
1710
|
}
|
|
1465
1711
|
|
|
1466
|
-
/**
|
|
1467
|
-
|
|
1468
|
-
*
|
|
1469
|
-
* Each validator is a pair of a validator and a severity.
|
|
1470
|
-
* If a validator fails, the peer is penalized with the severity of the validator.
|
|
1471
|
-
*
|
|
1472
|
-
* @param currentBlockNumber - The current synced block number.
|
|
1473
|
-
* @param nextSlotTimestamp - The timestamp of the next slot (used to validate txs are not expired).
|
|
1474
|
-
* @returns The message validators.
|
|
1475
|
-
*/
|
|
1476
|
-
private async createMessageValidators(
|
|
1712
|
+
/** Creates the first stage (fast) validators for gossiped transactions. */
|
|
1713
|
+
protected async createFirstStageMessageValidators(
|
|
1477
1714
|
currentBlockNumber: BlockNumber,
|
|
1478
1715
|
nextSlotTimestamp: UInt64,
|
|
1479
|
-
): Promise<Record<string,
|
|
1716
|
+
): Promise<Record<string, TransactionValidator>> {
|
|
1480
1717
|
const gasFees = await this.getGasFees(currentBlockNumber);
|
|
1481
|
-
const allowedInSetup =
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1718
|
+
const allowedInSetup = [
|
|
1719
|
+
...(await getDefaultAllowedSetupFunctions()),
|
|
1720
|
+
...(this.config.txPublicSetupAllowListExtend ?? []),
|
|
1721
|
+
];
|
|
1722
|
+
const blockNumber = BlockNumber(currentBlockNumber + 1);
|
|
1723
|
+
const l1Constants = await this.archiver.getL1Constants();
|
|
1724
|
+
|
|
1725
|
+
return createFirstStageTxValidationsForGossipedTransactions(
|
|
1486
1726
|
nextSlotTimestamp,
|
|
1487
|
-
|
|
1727
|
+
blockNumber,
|
|
1488
1728
|
this.worldStateSynchronizer,
|
|
1489
1729
|
gasFees,
|
|
1490
1730
|
this.config.l1ChainId,
|
|
1491
1731
|
this.config.rollupVersion,
|
|
1492
1732
|
protocolContractsHash,
|
|
1493
1733
|
this.archiver,
|
|
1494
|
-
this.proofVerifier,
|
|
1495
1734
|
!this.config.disableTransactions,
|
|
1496
1735
|
allowedInSetup,
|
|
1736
|
+
this.logger.getBindings(),
|
|
1737
|
+
{
|
|
1738
|
+
rollupManaLimit: l1Constants.rollupManaLimit,
|
|
1739
|
+
maxBlockL2Gas: this.config.validateMaxL2BlockGas,
|
|
1740
|
+
maxBlockDAGas: this.config.validateMaxDABlockGas,
|
|
1741
|
+
},
|
|
1497
1742
|
);
|
|
1498
1743
|
}
|
|
1499
1744
|
|
|
1745
|
+
/** Creates the second stage (expensive proof verification) validators for gossiped transactions. */
|
|
1746
|
+
protected createSecondStageMessageValidators(): Record<string, TransactionValidator> {
|
|
1747
|
+
return createSecondStageTxValidationsForGossipedTransactions(this.proofVerifier, this.logger.getBindings());
|
|
1748
|
+
}
|
|
1749
|
+
|
|
1500
1750
|
/**
|
|
1501
1751
|
* Run validations on a tx.
|
|
1502
1752
|
* @param tx - The tx to validate.
|
|
@@ -1505,7 +1755,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1505
1755
|
*/
|
|
1506
1756
|
private async runValidations(
|
|
1507
1757
|
tx: Tx,
|
|
1508
|
-
messageValidators: Record<string,
|
|
1758
|
+
messageValidators: Record<string, TransactionValidator>,
|
|
1509
1759
|
): Promise<ValidationOutcome> {
|
|
1510
1760
|
const validationPromises = Object.entries(messageValidators).map(async ([name, { validator, severity }]) => {
|
|
1511
1761
|
const { result } = await validator.validateTx(tx);
|
|
@@ -1514,8 +1764,10 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1514
1764
|
|
|
1515
1765
|
// A promise that resolves when all validations have been run
|
|
1516
1766
|
const allValidations = await Promise.all(validationPromises);
|
|
1517
|
-
const
|
|
1518
|
-
if (
|
|
1767
|
+
const failures = allValidations.filter(x => !x.isValid);
|
|
1768
|
+
if (failures.length > 0) {
|
|
1769
|
+
// Pick the most severe failure (lowest tolerance = harshest penalty)
|
|
1770
|
+
const failed = maxBy(failures, f => PeerErrorSeverityByHarshness.indexOf(f.severity))!;
|
|
1519
1771
|
return {
|
|
1520
1772
|
allPassed: false,
|
|
1521
1773
|
failure: {
|
|
@@ -1547,15 +1799,18 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1547
1799
|
return PeerErrorSeverity.HighToleranceError;
|
|
1548
1800
|
}
|
|
1549
1801
|
|
|
1550
|
-
const snapshotValidator = new DoubleSpendTxValidator(
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1802
|
+
const snapshotValidator = new DoubleSpendTxValidator(
|
|
1803
|
+
{
|
|
1804
|
+
nullifiersExist: async (nullifiers: Buffer[]) => {
|
|
1805
|
+
const merkleTree = this.worldStateSynchronizer.getSnapshot(
|
|
1806
|
+
BlockNumber(blockNumber - this.config.doubleSpendSeverePeerPenaltyWindow),
|
|
1807
|
+
);
|
|
1808
|
+
const indices = await merkleTree.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, nullifiers);
|
|
1809
|
+
return indices.map(index => index !== undefined);
|
|
1810
|
+
},
|
|
1557
1811
|
},
|
|
1558
|
-
|
|
1812
|
+
this.logger.getBindings(),
|
|
1813
|
+
);
|
|
1559
1814
|
|
|
1560
1815
|
const validSnapshot = await snapshotValidator.validateTx(tx);
|
|
1561
1816
|
if (validSnapshot.result !== 'valid') {
|
|
@@ -1565,68 +1820,6 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1565
1820
|
return PeerErrorSeverity.HighToleranceError;
|
|
1566
1821
|
}
|
|
1567
1822
|
|
|
1568
|
-
/**
|
|
1569
|
-
* Validate a checkpoint attestation.
|
|
1570
|
-
*
|
|
1571
|
-
* @param attestation - The checkpoint attestation to validate.
|
|
1572
|
-
* @returns True if the checkpoint attestation is valid, false otherwise.
|
|
1573
|
-
*/
|
|
1574
|
-
@trackSpan('Libp2pService.validateCheckpointAttestation', async (_, attestation) => ({
|
|
1575
|
-
[Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber,
|
|
1576
|
-
[Attributes.BLOCK_ARCHIVE]: attestation.archive.toString(),
|
|
1577
|
-
[Attributes.P2P_ID]: await attestation.p2pMessageLoggingIdentifier().then(i => i.toString()),
|
|
1578
|
-
}))
|
|
1579
|
-
public async validateCheckpointAttestation(peerId: PeerId, attestation: CheckpointAttestation): Promise<boolean> {
|
|
1580
|
-
const severity = await this.checkpointAttestationValidator.validate(attestation);
|
|
1581
|
-
if (severity) {
|
|
1582
|
-
this.logger.debug(`Penalizing peer ${peerId} for checkpoint attestation validation failure`);
|
|
1583
|
-
this.peerManager.penalizePeer(peerId, severity);
|
|
1584
|
-
return false;
|
|
1585
|
-
}
|
|
1586
|
-
|
|
1587
|
-
return true;
|
|
1588
|
-
}
|
|
1589
|
-
|
|
1590
|
-
/**
|
|
1591
|
-
* Validate a block proposal.
|
|
1592
|
-
*
|
|
1593
|
-
* @param block - The block proposal to validate.
|
|
1594
|
-
* @returns True if the block proposal is valid, false otherwise.
|
|
1595
|
-
*/
|
|
1596
|
-
@trackSpan('Libp2pService.validateBlockProposal', (_peerId, block) => ({
|
|
1597
|
-
[Attributes.SLOT_NUMBER]: block.slotNumber.toString(),
|
|
1598
|
-
}))
|
|
1599
|
-
public async validateBlockProposal(peerId: PeerId, block: BlockProposal): Promise<boolean> {
|
|
1600
|
-
const severity = await this.blockProposalValidator.validate(block);
|
|
1601
|
-
if (severity) {
|
|
1602
|
-
this.logger.debug(`Penalizing peer ${peerId} for block proposal validation failure`);
|
|
1603
|
-
this.peerManager.penalizePeer(peerId, severity);
|
|
1604
|
-
return false;
|
|
1605
|
-
}
|
|
1606
|
-
|
|
1607
|
-
return true;
|
|
1608
|
-
}
|
|
1609
|
-
|
|
1610
|
-
/**
|
|
1611
|
-
* Validate a checkpoint proposal.
|
|
1612
|
-
*
|
|
1613
|
-
* @param checkpoint - The checkpoint proposal to validate.
|
|
1614
|
-
* @returns True if the checkpoint proposal is valid, false otherwise.
|
|
1615
|
-
*/
|
|
1616
|
-
@trackSpan('Libp2pService.validateCheckpointProposal', (_peerId, checkpoint) => ({
|
|
1617
|
-
[Attributes.SLOT_NUMBER]: checkpoint.slotNumber.toString(),
|
|
1618
|
-
}))
|
|
1619
|
-
public async validateCheckpointProposal(peerId: PeerId, checkpoint: CheckpointProposal): Promise<boolean> {
|
|
1620
|
-
const severity = await this.checkpointProposalValidator.validate(checkpoint);
|
|
1621
|
-
if (severity) {
|
|
1622
|
-
this.logger.debug(`Penalizing peer ${peerId} for checkpoint proposal validation failure`);
|
|
1623
|
-
this.peerManager.penalizePeer(peerId, severity);
|
|
1624
|
-
return false;
|
|
1625
|
-
}
|
|
1626
|
-
|
|
1627
|
-
return true;
|
|
1628
|
-
}
|
|
1629
|
-
|
|
1630
1823
|
public getPeerScore(peerId: PeerId): number {
|
|
1631
1824
|
return this.node.services.pubsub.score.score(peerId.toString());
|
|
1632
1825
|
}
|