@aztec/p2p 0.0.1-commit.4d79d1f2d → 0.0.1-commit.4d9804df
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 +130 -3
- package/dest/bootstrap/bootstrap.d.ts +1 -1
- package/dest/bootstrap/bootstrap.d.ts.map +1 -1
- package/dest/bootstrap/bootstrap.js +22 -6
- package/dest/client/factory.d.ts +9 -8
- package/dest/client/factory.d.ts.map +1 -1
- package/dest/client/factory.js +50 -34
- package/dest/client/interface.d.ts +59 -27
- package/dest/client/interface.d.ts.map +1 -1
- package/dest/client/p2p_client.d.ts +40 -34
- package/dest/client/p2p_client.d.ts.map +1 -1
- package/dest/client/p2p_client.js +162 -135
- package/dest/config.d.ts +164 -100
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +149 -49
- package/dest/errors/p2p-service.error.d.ts +9 -0
- package/dest/errors/p2p-service.error.d.ts.map +1 -0
- package/dest/errors/p2p-service.error.js +10 -0
- package/dest/errors/reqresp.error.d.ts +9 -16
- package/dest/errors/reqresp.error.d.ts.map +1 -1
- package/dest/errors/reqresp.error.js +10 -17
- 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 +1 -2
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +0 -1
- package/dest/mem_pools/attestation_pool/attestation_pool.d.ts +103 -59
- package/dest/mem_pools/attestation_pool/attestation_pool.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/attestation_pool.js +278 -196
- package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.d.ts +1 -1
- package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.js +224 -65
- 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 +7 -5
- package/dest/mem_pools/index.d.ts +1 -2
- package/dest/mem_pools/index.d.ts.map +1 -1
- package/dest/mem_pools/instrumentation.d.ts +12 -5
- package/dest/mem_pools/instrumentation.d.ts.map +1 -1
- package/dest/mem_pools/instrumentation.js +38 -17
- package/dest/mem_pools/tx_pool_v2/archive/tx_archive.d.ts +1 -5
- package/dest/mem_pools/tx_pool_v2/archive/tx_archive.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/archive/tx_archive.js +1 -7
- package/dest/mem_pools/tx_pool_v2/deleted_pool.d.ts +32 -15
- package/dest/mem_pools/tx_pool_v2/deleted_pool.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/deleted_pool.js +95 -24
- package/dest/mem_pools/tx_pool_v2/eviction/eviction_manager.d.ts +3 -3
- package/dest/mem_pools/tx_pool_v2/eviction/eviction_manager.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/eviction_manager.js +18 -9
- package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.d.ts +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.js +8 -4
- package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.d.ts +3 -3
- package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.js +12 -4
- package/dest/mem_pools/tx_pool_v2/eviction/index.d.ts +3 -2
- package/dest/mem_pools/tx_pool_v2/eviction/index.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/index.js +2 -1
- package/dest/mem_pools/tx_pool_v2/eviction/insufficient_fee_per_gas_eviction_rule.d.ts +16 -0
- package/dest/mem_pools/tx_pool_v2/eviction/insufficient_fee_per_gas_eviction_rule.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/eviction/insufficient_fee_per_gas_eviction_rule.js +62 -0
- package/dest/mem_pools/tx_pool_v2/eviction/interfaces.d.ts +54 -5
- package/dest/mem_pools/tx_pool_v2/eviction/interfaces.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/interfaces.js +8 -0
- package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_mining_rule.js +7 -5
- package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.js +9 -7
- package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.d.ts +2 -2
- package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.js +14 -6
- package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.d.ts +4 -4
- package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.js +16 -4
- package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.d.ts +3 -3
- package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.js +3 -3
- package/dest/mem_pools/tx_pool_v2/index.d.ts +2 -2
- package/dest/mem_pools/tx_pool_v2/index.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/index.js +1 -1
- 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 +60 -14
- package/dest/mem_pools/tx_pool_v2/interfaces.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/interfaces.js +6 -1
- package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts +59 -15
- package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/tx_metadata.js +116 -20
- package/dest/mem_pools/tx_pool_v2/tx_pool_indices.d.ts +26 -3
- package/dest/mem_pools/tx_pool_v2/tx_pool_indices.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/tx_pool_indices.js +79 -43
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts +20 -7
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2.js +34 -12
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts +29 -7
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.js +473 -211
- package/dest/msg_validators/attestation_validator/attestation_validator.d.ts +10 -3
- package/dest/msg_validators/attestation_validator/attestation_validator.d.ts.map +1 -1
- package/dest/msg_validators/attestation_validator/attestation_validator.js +38 -15
- package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts +7 -3
- package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts.map +1 -1
- package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.js +4 -5
- package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts +12 -5
- package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts.map +1 -1
- package/dest/msg_validators/proposal_validator/block_proposal_validator.js +11 -3
- package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts +12 -5
- package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts.map +1 -1
- package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.js +23 -3
- package/dest/msg_validators/proposal_validator/proposal_validator.d.ts +36 -9
- package/dest/msg_validators/proposal_validator/proposal_validator.d.ts.map +1 -1
- package/dest/msg_validators/proposal_validator/proposal_validator.js +130 -48
- package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts +2 -2
- package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/aggregate_tx_validator.js +11 -18
- 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 +25 -21
- 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.js +1 -1
- package/dest/msg_validators/tx_validator/cached_tx_validator.d.ts +15 -0
- package/dest/msg_validators/tx_validator/cached_tx_validator.d.ts.map +1 -0
- package/dest/msg_validators/tx_validator/cached_tx_validator.js +19 -0
- 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 +2 -1
- package/dest/msg_validators/tx_validator/data_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/data_validator.js +36 -2
- package/dest/msg_validators/tx_validator/factory.d.ts +133 -7
- package/dest/msg_validators/tx_validator/factory.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/factory.js +261 -61
- 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 +104 -3
- package/dest/msg_validators/tx_validator/gas_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/gas_validator.js +137 -53
- package/dest/msg_validators/tx_validator/index.d.ts +5 -1
- package/dest/msg_validators/tx_validator/index.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/index.js +4 -0
- package/dest/msg_validators/tx_validator/metadata_validator.d.ts +1 -1
- package/dest/msg_validators/tx_validator/metadata_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/metadata_validator.js +4 -4
- 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 +22 -2
- package/dest/msg_validators/tx_validator/phases_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/phases_validator.js +72 -24
- package/dest/msg_validators/tx_validator/timestamp_validator.d.ts +2 -2
- package/dest/msg_validators/tx_validator/timestamp_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/timestamp_validator.js +6 -6
- package/dest/msg_validators/tx_validator/tx_proof_validator.d.ts +2 -1
- 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 -0
- package/dest/msg_validators/tx_validator/tx_validation_cache.d.ts +48 -0
- package/dest/msg_validators/tx_validator/tx_validation_cache.d.ts.map +1 -0
- package/dest/msg_validators/tx_validator/tx_validation_cache.js +68 -0
- 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 +5 -5
- package/dest/services/discv5/discV5_service.d.ts +13 -2
- package/dest/services/discv5/discV5_service.d.ts.map +1 -1
- package/dest/services/discv5/discV5_service.js +119 -23
- package/dest/services/discv5/persisted_enr_store.d.ts +38 -0
- package/dest/services/discv5/persisted_enr_store.d.ts.map +1 -0
- package/dest/services/discv5/persisted_enr_store.js +145 -0
- package/dest/services/dummy_service.d.ts +18 -18
- package/dest/services/dummy_service.d.ts.map +1 -1
- package/dest/services/dummy_service.js +19 -20
- package/dest/services/encoding.d.ts +23 -6
- package/dest/services/encoding.d.ts.map +1 -1
- package/dest/services/encoding.js +41 -24
- package/dest/services/gossipsub/topic_score_params.d.ts +23 -17
- package/dest/services/gossipsub/topic_score_params.d.ts.map +1 -1
- package/dest/services/gossipsub/topic_score_params.js +36 -24
- package/dest/services/libp2p/instrumentation.d.ts +3 -1
- package/dest/services/libp2p/instrumentation.d.ts.map +1 -1
- package/dest/services/libp2p/instrumentation.js +14 -0
- package/dest/services/libp2p/libp2p_service.d.ts +57 -56
- package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
- package/dest/services/libp2p/libp2p_service.js +483 -373
- package/dest/services/peer-manager/metrics.d.ts +3 -1
- package/dest/services/peer-manager/metrics.d.ts.map +1 -1
- package/dest/services/peer-manager/metrics.js +6 -0
- package/dest/services/peer-manager/peer_manager.d.ts +20 -3
- package/dest/services/peer-manager/peer_manager.d.ts.map +1 -1
- package/dest/services/peer-manager/peer_manager.js +83 -26
- package/dest/services/peer-manager/peer_scoring.d.ts +34 -2
- package/dest/services/peer-manager/peer_scoring.d.ts.map +1 -1
- package/dest/services/peer-manager/peer_scoring.js +102 -13
- package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts +5 -8
- package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts.map +1 -1
- package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.js +95 -127
- package/dest/services/reqresp/batch-tx-requester/interface.d.ts +11 -11
- package/dest/services/reqresp/batch-tx-requester/interface.d.ts.map +1 -1
- package/dest/services/reqresp/batch-tx-requester/missing_txs.d.ts +11 -13
- package/dest/services/reqresp/batch-tx-requester/missing_txs.d.ts.map +1 -1
- package/dest/services/reqresp/batch-tx-requester/missing_txs.js +31 -46
- package/dest/services/reqresp/batch-tx-requester/peer_collection.d.ts +19 -11
- package/dest/services/reqresp/batch-tx-requester/peer_collection.d.ts.map +1 -1
- package/dest/services/reqresp/batch-tx-requester/peer_collection.js +52 -15
- package/dest/services/reqresp/batch-tx-requester/tx_validator.d.ts +5 -14
- package/dest/services/reqresp/batch-tx-requester/tx_validator.d.ts.map +1 -1
- package/dest/services/reqresp/batch-tx-requester/tx_validator.js +6 -20
- package/dest/services/reqresp/config.d.ts +15 -3
- package/dest/services/reqresp/config.d.ts.map +1 -1
- package/dest/services/reqresp/config.js +11 -0
- package/dest/services/reqresp/interface.d.ts +16 -18
- package/dest/services/reqresp/interface.d.ts.map +1 -1
- package/dest/services/reqresp/interface.js +10 -20
- package/dest/services/reqresp/metrics.d.ts +1 -1
- package/dest/services/reqresp/metrics.d.ts.map +1 -1
- package/dest/services/reqresp/metrics.js +0 -1
- package/dest/services/reqresp/protocols/block_txs/bitvector.d.ts +4 -3
- package/dest/services/reqresp/protocols/block_txs/bitvector.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/block_txs/bitvector.js +3 -2
- package/dest/services/reqresp/protocols/block_txs/block_txs_handler.d.ts +1 -1
- 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 +31 -28
- package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.d.ts +12 -7
- package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.js +42 -24
- package/dest/services/reqresp/protocols/index.d.ts +1 -2
- package/dest/services/reqresp/protocols/index.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/index.js +0 -1
- package/dest/services/reqresp/protocols/tx.d.ts +1 -1
- package/dest/services/reqresp/protocols/tx.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/tx.js +1 -3
- package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts +5 -4
- package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts.map +1 -1
- package/dest/services/reqresp/rate-limiter/rate_limiter.js +10 -8
- package/dest/services/reqresp/rate-limiter/rate_limits.d.ts +1 -1
- package/dest/services/reqresp/rate-limiter/rate_limits.d.ts.map +1 -1
- package/dest/services/reqresp/rate-limiter/rate_limits.js +3 -13
- package/dest/services/reqresp/reqresp.d.ts +7 -29
- package/dest/services/reqresp/reqresp.d.ts.map +1 -1
- package/dest/services/reqresp/reqresp.js +75 -216
- package/dest/services/service.d.ts +29 -14
- package/dest/services/service.d.ts.map +1 -1
- package/dest/services/tx_collection/config.d.ts +8 -17
- package/dest/services/tx_collection/config.d.ts.map +1 -1
- package/dest/services/tx_collection/config.js +17 -40
- package/dest/services/tx_collection/file_store_tx_collection.d.ts +25 -32
- package/dest/services/tx_collection/file_store_tx_collection.d.ts.map +1 -1
- package/dest/services/tx_collection/file_store_tx_collection.js +96 -87
- package/dest/services/tx_collection/file_store_tx_source.d.ts +17 -6
- package/dest/services/tx_collection/file_store_tx_source.d.ts.map +1 -1
- package/dest/services/tx_collection/file_store_tx_source.js +53 -10
- package/dest/services/tx_collection/index.d.ts +2 -3
- package/dest/services/tx_collection/index.d.ts.map +1 -1
- package/dest/services/tx_collection/index.js +0 -1
- package/dest/services/tx_collection/instrumentation.js +1 -2
- 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/tx_collection.d.ts +39 -55
- package/dest/services/tx_collection/tx_collection.d.ts.map +1 -1
- package/dest/services/tx_collection/tx_collection.js +280 -108
- package/dest/services/tx_collection/tx_collection_sink.d.ts +7 -6
- package/dest/services/tx_collection/tx_collection_sink.d.ts.map +1 -1
- package/dest/services/tx_collection/tx_collection_sink.js +15 -24
- package/dest/services/tx_collection/tx_source.d.ts +13 -7
- package/dest/services/tx_collection/tx_source.d.ts.map +1 -1
- package/dest/services/tx_collection/tx_source.js +29 -7
- package/dest/services/tx_file_store/tx_file_store.d.ts +3 -4
- package/dest/services/tx_file_store/tx_file_store.d.ts.map +1 -1
- package/dest/services/tx_file_store/tx_file_store.js +13 -20
- package/dest/services/tx_provider.d.ts +5 -3
- package/dest/services/tx_provider.d.ts.map +1 -1
- package/dest/services/tx_provider.js +7 -4
- package/dest/test-helpers/make-test-p2p-clients.d.ts +5 -6
- package/dest/test-helpers/make-test-p2p-clients.d.ts.map +1 -1
- package/dest/test-helpers/make-test-p2p-clients.js +5 -3
- package/dest/test-helpers/mock-pubsub.d.ts +26 -12
- package/dest/test-helpers/mock-pubsub.d.ts.map +1 -1
- package/dest/test-helpers/mock-pubsub.js +51 -45
- package/dest/test-helpers/reqresp-nodes.d.ts +5 -7
- package/dest/test-helpers/reqresp-nodes.d.ts.map +1 -1
- package/dest/test-helpers/reqresp-nodes.js +17 -19
- package/dest/test-helpers/test_tx_provider.d.ts +3 -1
- package/dest/test-helpers/test_tx_provider.d.ts.map +1 -1
- package/dest/test-helpers/test_tx_provider.js +3 -0
- package/dest/test-helpers/testbench-utils.d.ts +22 -16
- package/dest/test-helpers/testbench-utils.d.ts.map +1 -1
- package/dest/test-helpers/testbench-utils.js +56 -16
- package/dest/testbench/p2p_client_testbench_worker.d.ts +3 -5
- package/dest/testbench/p2p_client_testbench_worker.d.ts.map +1 -1
- package/dest/testbench/p2p_client_testbench_worker.js +111 -48
- package/dest/testbench/worker_client_manager.d.ts +12 -6
- package/dest/testbench/worker_client_manager.d.ts.map +1 -1
- package/dest/testbench/worker_client_manager.js +57 -11
- package/dest/util.d.ts +13 -8
- package/dest/util.d.ts.map +1 -1
- package/dest/util.js +35 -14
- package/dest/versioning.d.ts +3 -6
- package/dest/versioning.d.ts.map +1 -1
- package/dest/versioning.js +3 -24
- package/package.json +16 -16
- package/src/bootstrap/bootstrap.ts +17 -3
- package/src/client/factory.ts +95 -51
- package/src/client/interface.ts +59 -35
- package/src/client/p2p_client.ts +186 -196
- package/src/client/test/{tx_proposal_collector/README.md → p2p_client.batch_tx_requester.bench.README.md} +23 -53
- package/src/config.ts +259 -57
- package/src/errors/p2p-service.error.ts +11 -0
- package/src/errors/reqresp.error.ts +13 -19
- package/src/errors/tx-pool.error.ts +12 -0
- package/src/index.ts +0 -1
- package/src/mem_pools/attestation_pool/attestation_pool.ts +336 -242
- package/src/mem_pools/attestation_pool/attestation_pool_test_suite.ts +244 -69
- package/src/mem_pools/attestation_pool/mocks.ts +14 -8
- package/src/mem_pools/index.ts +0 -3
- package/src/mem_pools/instrumentation.ts +27 -17
- package/src/mem_pools/tx_pool_v2/README.md +52 -28
- package/src/mem_pools/tx_pool_v2/archive/tx_archive.ts +1 -9
- package/src/mem_pools/tx_pool_v2/deleted_pool.ts +114 -27
- package/src/mem_pools/tx_pool_v2/eviction/eviction_manager.ts +21 -8
- package/src/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.ts +8 -4
- package/src/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.ts +18 -4
- package/src/mem_pools/tx_pool_v2/eviction/index.ts +5 -0
- package/src/mem_pools/tx_pool_v2/eviction/insufficient_fee_per_gas_eviction_rule.ts +65 -0
- package/src/mem_pools/tx_pool_v2/eviction/interfaces.ts +59 -4
- package/src/mem_pools/tx_pool_v2/eviction/invalid_txs_after_mining_rule.ts +5 -5
- package/src/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.ts +8 -8
- package/src/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.ts +14 -9
- package/src/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.ts +33 -6
- package/src/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.ts +4 -3
- package/src/mem_pools/tx_pool_v2/index.ts +1 -1
- package/src/mem_pools/tx_pool_v2/instrumentation.ts +69 -0
- package/src/mem_pools/tx_pool_v2/interfaces.ts +61 -14
- package/src/mem_pools/tx_pool_v2/tx_metadata.ts +170 -28
- package/src/mem_pools/tx_pool_v2/tx_pool_indices.ts +91 -43
- package/src/mem_pools/tx_pool_v2/tx_pool_v2.ts +54 -14
- package/src/mem_pools/tx_pool_v2/tx_pool_v2_impl.ts +527 -207
- package/src/msg_validators/attestation_validator/README.md +49 -0
- package/src/msg_validators/attestation_validator/attestation_validator.ts +46 -14
- package/src/msg_validators/attestation_validator/fisherman_attestation_validator.ts +15 -7
- package/src/msg_validators/proposal_validator/README.md +123 -0
- package/src/msg_validators/proposal_validator/block_proposal_validator.ts +26 -4
- package/src/msg_validators/proposal_validator/checkpoint_proposal_validator.ts +43 -7
- package/src/msg_validators/proposal_validator/proposal_validator.ts +155 -49
- package/src/msg_validators/tx_validator/README.md +129 -0
- package/src/msg_validators/tx_validator/aggregate_tx_validator.ts +6 -15
- 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 +1 -1
- package/src/msg_validators/tx_validator/cached_tx_validator.ts +31 -0
- package/src/msg_validators/tx_validator/contract_instance_validator.ts +56 -0
- package/src/msg_validators/tx_validator/data_validator.ts +44 -1
- package/src/msg_validators/tx_validator/factory.ts +413 -80
- package/src/msg_validators/tx_validator/fee_payer_balance.ts +6 -2
- package/src/msg_validators/tx_validator/gas_validator.ts +195 -54
- package/src/msg_validators/tx_validator/index.ts +4 -0
- package/src/msg_validators/tx_validator/metadata_validator.ts +12 -4
- package/src/msg_validators/tx_validator/nullifier_cache.ts +30 -0
- package/src/msg_validators/tx_validator/phases_validator.ts +82 -27
- package/src/msg_validators/tx_validator/timestamp_validator.ts +7 -7
- package/src/msg_validators/tx_validator/tx_proof_validator.ts +2 -0
- package/src/msg_validators/tx_validator/tx_validation_cache.ts +101 -0
- package/src/services/data_store.ts +5 -13
- package/src/services/discv5/discV5_service.ts +126 -14
- package/src/services/discv5/persisted_enr_store.ts +158 -0
- package/src/services/dummy_service.ts +26 -45
- package/src/services/encoding.ts +40 -24
- package/src/services/gossipsub/README.md +59 -22
- package/src/services/gossipsub/topic_score_params.ts +58 -31
- package/src/services/libp2p/instrumentation.ts +14 -0
- package/src/services/libp2p/libp2p_service.ts +554 -428
- package/src/services/peer-manager/metrics.ts +7 -0
- package/src/services/peer-manager/peer_manager.ts +91 -25
- package/src/services/peer-manager/peer_scoring.ts +102 -8
- package/src/services/reqresp/README.md +194 -0
- package/src/services/reqresp/batch-tx-requester/README.md +46 -7
- package/src/services/reqresp/batch-tx-requester/batch_tx_requester.ts +92 -138
- package/src/services/reqresp/batch-tx-requester/interface.ts +14 -10
- package/src/services/reqresp/batch-tx-requester/missing_txs.ts +30 -71
- package/src/services/reqresp/batch-tx-requester/peer_collection.ts +68 -24
- package/src/services/reqresp/batch-tx-requester/tx_validator.ts +12 -25
- package/src/services/reqresp/config.ts +19 -2
- package/src/services/reqresp/interface.ts +21 -47
- package/src/services/reqresp/metrics.ts +0 -1
- package/src/services/reqresp/protocols/block_txs/bitvector.ts +3 -2
- package/src/services/reqresp/protocols/block_txs/block_txs_handler.ts +34 -30
- package/src/services/reqresp/protocols/block_txs/block_txs_reqresp.ts +47 -20
- package/src/services/reqresp/protocols/index.ts +0 -1
- package/src/services/reqresp/protocols/tx.ts +1 -3
- package/src/services/reqresp/rate-limiter/rate_limiter.ts +13 -9
- package/src/services/reqresp/rate-limiter/rate_limits.ts +3 -13
- package/src/services/reqresp/reqresp.ts +87 -260
- package/src/services/service.ts +42 -30
- package/src/services/tx_collection/config.ts +24 -59
- package/src/services/tx_collection/file_store_tx_collection.ts +108 -107
- package/src/services/tx_collection/file_store_tx_source.ts +69 -10
- package/src/services/tx_collection/index.ts +1 -6
- package/src/services/tx_collection/instrumentation.ts +1 -1
- package/src/services/tx_collection/request_tracker.ts +127 -0
- package/src/services/tx_collection/tx_collection.ts +342 -156
- package/src/services/tx_collection/tx_collection_sink.ts +17 -31
- package/src/services/tx_collection/tx_source.ts +29 -8
- package/src/services/tx_file_store/tx_file_store.ts +11 -21
- package/src/services/tx_provider.ts +7 -2
- package/src/test-helpers/make-test-p2p-clients.ts +4 -3
- package/src/test-helpers/mock-pubsub.ts +59 -66
- package/src/test-helpers/reqresp-nodes.ts +15 -28
- package/src/test-helpers/test_tx_provider.ts +5 -0
- package/src/test-helpers/testbench-utils.ts +74 -31
- package/src/testbench/p2p_client_testbench_worker.ts +120 -63
- package/src/testbench/worker_client_manager.ts +72 -25
- package/src/util.ts +40 -19
- package/src/versioning.ts +3 -33
- package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.d.ts +0 -2
- package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.d.ts.map +0 -1
- package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.js +0 -305
- package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker_protocol.d.ts +0 -73
- package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker_protocol.d.ts.map +0 -1
- package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker_protocol.js +0 -8
- package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts +0 -125
- package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.js +0 -596
- package/dest/mem_pools/tx_pool/eviction/eviction_manager.d.ts +0 -32
- package/dest/mem_pools/tx_pool/eviction/eviction_manager.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/eviction/eviction_manager.js +0 -112
- package/dest/mem_pools/tx_pool/eviction/eviction_strategy.d.ts +0 -157
- package/dest/mem_pools/tx_pool/eviction/eviction_strategy.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/eviction/eviction_strategy.js +0 -52
- package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.d.ts +0 -16
- package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.js +0 -122
- package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.d.ts +0 -17
- package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.js +0 -84
- package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.d.ts +0 -19
- package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.js +0 -78
- package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.d.ts +0 -26
- package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.js +0 -84
- package/dest/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.d.ts +0 -25
- package/dest/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.js +0 -57
- package/dest/mem_pools/tx_pool/index.d.ts +0 -3
- package/dest/mem_pools/tx_pool/index.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/index.js +0 -2
- package/dest/mem_pools/tx_pool/priority.d.ts +0 -12
- package/dest/mem_pools/tx_pool/priority.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/priority.js +0 -15
- package/dest/mem_pools/tx_pool/tx_pool.d.ts +0 -127
- package/dest/mem_pools/tx_pool/tx_pool.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/tx_pool.js +0 -3
- package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts +0 -7
- package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/tx_pool_test_suite.js +0 -400
- package/dest/msg_validators/clock_tolerance.d.ts +0 -21
- package/dest/msg_validators/clock_tolerance.d.ts.map +0 -1
- package/dest/msg_validators/clock_tolerance.js +0 -37
- 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 -212
- package/dest/services/reqresp/connection-sampler/batch_connection_sampler.d.ts +0 -64
- package/dest/services/reqresp/connection-sampler/batch_connection_sampler.d.ts.map +0 -1
- package/dest/services/reqresp/connection-sampler/batch_connection_sampler.js +0 -151
- package/dest/services/reqresp/protocols/block.d.ts +0 -9
- package/dest/services/reqresp/protocols/block.d.ts.map +0 -1
- package/dest/services/reqresp/protocols/block.js +0 -32
- package/dest/services/tx_collection/fast_tx_collection.d.ts +0 -54
- package/dest/services/tx_collection/fast_tx_collection.d.ts.map +0 -1
- package/dest/services/tx_collection/fast_tx_collection.js +0 -321
- package/dest/services/tx_collection/proposal_tx_collector.d.ts +0 -48
- package/dest/services/tx_collection/proposal_tx_collector.d.ts.map +0 -1
- package/dest/services/tx_collection/proposal_tx_collector.js +0 -49
- package/dest/services/tx_collection/slow_tx_collection.d.ts +0 -55
- package/dest/services/tx_collection/slow_tx_collection.d.ts.map +0 -1
- package/dest/services/tx_collection/slow_tx_collection.js +0 -206
- package/src/client/test/tx_proposal_collector/proposal_tx_collector_worker.ts +0 -336
- package/src/client/test/tx_proposal_collector/proposal_tx_collector_worker_protocol.ts +0 -43
- package/src/mem_pools/tx_pool/README.md +0 -270
- package/src/mem_pools/tx_pool/aztec_kv_tx_pool.ts +0 -746
- package/src/mem_pools/tx_pool/eviction/eviction_manager.ts +0 -132
- package/src/mem_pools/tx_pool/eviction/eviction_strategy.ts +0 -208
- package/src/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.ts +0 -162
- package/src/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.ts +0 -104
- package/src/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.ts +0 -93
- package/src/mem_pools/tx_pool/eviction/low_priority_eviction_rule.ts +0 -106
- package/src/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.ts +0 -75
- package/src/mem_pools/tx_pool/index.ts +0 -2
- package/src/mem_pools/tx_pool/priority.ts +0 -20
- package/src/mem_pools/tx_pool/tx_pool.ts +0 -141
- package/src/mem_pools/tx_pool/tx_pool_test_suite.ts +0 -319
- package/src/msg_validators/clock_tolerance.ts +0 -51
- package/src/msg_validators/proposal_validator/proposal_validator_test_suite.ts +0 -230
- package/src/services/reqresp/connection-sampler/batch_connection_sampler.ts +0 -161
- package/src/services/reqresp/protocols/block.ts +0 -37
- package/src/services/tx_collection/fast_tx_collection.ts +0 -366
- package/src/services/tx_collection/proposal_tx_collector.ts +0 -112
- package/src/services/tx_collection/slow_tx_collection.ts +0 -262
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import type { EpochCacheInterface } from '@aztec/epoch-cache';
|
|
2
2
|
import { BlockNumber, type SlotNumber } from '@aztec/foundation/branded-types';
|
|
3
|
-
import {
|
|
3
|
+
import { compactArray, maxBy, merge } from '@aztec/foundation/collection';
|
|
4
4
|
import { type Logger, createLibp2pComponentLogger, createLogger } from '@aztec/foundation/log';
|
|
5
5
|
import { RunningPromise } from '@aztec/foundation/running-promise';
|
|
6
6
|
import { Timer } from '@aztec/foundation/timer';
|
|
7
7
|
import type { AztecAsyncKVStore } from '@aztec/kv-store';
|
|
8
8
|
import { protocolContractsHash } from '@aztec/protocol-contracts';
|
|
9
|
-
import type { EthAddress,
|
|
9
|
+
import type { EthAddress, L2BlockSource } from '@aztec/stdlib/block';
|
|
10
|
+
import { DEFAULT_MAX_BLOCKS_PER_CHECKPOINT } from '@aztec/stdlib/config';
|
|
10
11
|
import type { ContractDataSource } from '@aztec/stdlib/contract';
|
|
11
|
-
import { GasFees } from '@aztec/stdlib/gas';
|
|
12
|
+
import { type BlockMinFeesProvider, GasFees, getNetworkTxGasLimits } from '@aztec/stdlib/gas';
|
|
12
13
|
import type { ClientProtocolCircuitVerifier, PeerInfo, WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
|
|
13
14
|
import {
|
|
14
15
|
BlockProposal,
|
|
@@ -16,17 +17,17 @@ import {
|
|
|
16
17
|
CheckpointProposal,
|
|
17
18
|
type CheckpointProposalCore,
|
|
18
19
|
type Gossipable,
|
|
19
|
-
P2PClientType,
|
|
20
20
|
P2PMessage,
|
|
21
|
-
type ValidationResult as P2PValidationResult,
|
|
22
21
|
PeerErrorSeverity,
|
|
22
|
+
PeerErrorSeverityByHarshness,
|
|
23
23
|
TopicType,
|
|
24
24
|
createTopicString,
|
|
25
|
-
|
|
25
|
+
getTopicsForConfig,
|
|
26
26
|
metricsTopicStrToLabels,
|
|
27
27
|
} from '@aztec/stdlib/p2p';
|
|
28
|
+
import { ConsensusTimetable, getDefaultCheckpointProposalSyncGrace } from '@aztec/stdlib/timetable';
|
|
28
29
|
import { MerkleTreeId } from '@aztec/stdlib/trees';
|
|
29
|
-
import { Tx, type
|
|
30
|
+
import { Tx, type TxValidationResult } from '@aztec/stdlib/tx';
|
|
30
31
|
import type { UInt64 } from '@aztec/stdlib/types';
|
|
31
32
|
import { compressComponentVersions } from '@aztec/stdlib/versioning';
|
|
32
33
|
import {
|
|
@@ -51,13 +52,15 @@ import { yamux } from '@chainsafe/libp2p-yamux';
|
|
|
51
52
|
import { bootstrap } from '@libp2p/bootstrap';
|
|
52
53
|
import { identify } from '@libp2p/identify';
|
|
53
54
|
import { type Message, type MultiaddrConnection, type PeerId, TopicValidatorResult } from '@libp2p/interface';
|
|
54
|
-
import type { ConnectionManager } from '@libp2p/interface-internal';
|
|
55
|
+
import type { AddressManager, ConnectionManager } from '@libp2p/interface-internal';
|
|
55
56
|
import { mplex } from '@libp2p/mplex';
|
|
56
57
|
import { tcp } from '@libp2p/tcp';
|
|
58
|
+
import { multiaddr } from '@multiformats/multiaddr';
|
|
57
59
|
import { ENR } from '@nethermindeth/enr';
|
|
58
60
|
import { createLibp2p } from 'libp2p';
|
|
59
61
|
|
|
60
62
|
import type { P2PConfig } from '../../config.js';
|
|
63
|
+
import { CheckpointProposalReceivedCallbackNotRegisteredError } from '../../errors/p2p-service.error.js';
|
|
61
64
|
import type { MemPools } from '../../mem_pools/interface.js';
|
|
62
65
|
import {
|
|
63
66
|
BlockProposalValidator,
|
|
@@ -69,42 +72,38 @@ import {
|
|
|
69
72
|
} from '../../msg_validators/index.js';
|
|
70
73
|
import { MessageSeenValidator } from '../../msg_validators/msg_seen_validator/msg_seen_validator.js';
|
|
71
74
|
import {
|
|
72
|
-
type
|
|
73
|
-
|
|
74
|
-
|
|
75
|
+
type TransactionValidator,
|
|
76
|
+
createFirstStageTxValidationsForGossipedTransactions,
|
|
77
|
+
createSecondStageTxValidationsForGossipedTransactions,
|
|
78
|
+
createTxValidatorForBlockProposalReceivedTxs,
|
|
75
79
|
} from '../../msg_validators/tx_validator/factory.js';
|
|
80
|
+
import { TxValidationCache } from '../../msg_validators/tx_validator/tx_validation_cache.js';
|
|
76
81
|
import { GossipSubEvent } from '../../types/index.js';
|
|
77
82
|
import { type PubSubLibp2p, convertToMultiaddr } from '../../util.js';
|
|
78
83
|
import { getVersions } from '../../versioning.js';
|
|
79
84
|
import { AztecDatastore } from '../data_store.js';
|
|
80
85
|
import { DiscV5Service } from '../discv5/discV5_service.js';
|
|
81
|
-
import { SnappyTransform,
|
|
86
|
+
import { SnappyTransform, getMsgIdFn, msgIdToStrFn } from '../encoding.js';
|
|
82
87
|
import { APP_SPECIFIC_WEIGHT, gossipScoreThresholds } from '../gossipsub/scoring.js';
|
|
83
88
|
import { createAllTopicScoreParams } from '../gossipsub/topic_score_params.js';
|
|
84
89
|
import type { PeerManagerInterface } from '../peer-manager/interface.js';
|
|
85
90
|
import { PeerManager } from '../peer-manager/peer_manager.js';
|
|
86
91
|
import { PeerScoring } from '../peer-manager/peer_scoring.js';
|
|
87
92
|
import type { BatchTxRequesterLibP2PService } from '../reqresp/batch-tx-requester/interface.js';
|
|
88
|
-
import type
|
|
93
|
+
import { type P2PReqRespConfig, YAMUX_MAX_MESSAGE_SIZE_BYTES } from '../reqresp/config.js';
|
|
89
94
|
import {
|
|
90
|
-
|
|
95
|
+
AuthRequest,
|
|
96
|
+
BlockTxsRequest,
|
|
97
|
+
BlockTxsResponse,
|
|
91
98
|
type ReqRespInterface,
|
|
92
99
|
type ReqRespResponse,
|
|
93
100
|
ReqRespSubProtocol,
|
|
94
101
|
type ReqRespSubProtocolHandler,
|
|
95
102
|
type ReqRespSubProtocolHandlers,
|
|
96
|
-
type ReqRespSubProtocolValidators,
|
|
97
|
-
type SubProtocolMap,
|
|
98
|
-
ValidationError,
|
|
99
|
-
} from '../reqresp/index.js';
|
|
100
|
-
import {
|
|
101
|
-
AuthRequest,
|
|
102
|
-
BlockTxsRequest,
|
|
103
|
-
BlockTxsResponse,
|
|
104
103
|
StatusMessage,
|
|
104
|
+
ValidationError,
|
|
105
105
|
pingHandler,
|
|
106
106
|
reqGoodbyeHandler,
|
|
107
|
-
reqRespBlockHandler,
|
|
108
107
|
reqRespBlockTxsHandler,
|
|
109
108
|
reqRespStatusHandler,
|
|
110
109
|
reqRespTxHandler,
|
|
@@ -112,13 +111,33 @@ import {
|
|
|
112
111
|
import { ReqResp } from '../reqresp/reqresp.js';
|
|
113
112
|
import type {
|
|
114
113
|
P2PBlockReceivedCallback,
|
|
114
|
+
P2PCheckpointAttestationCallback,
|
|
115
115
|
P2PCheckpointReceivedCallback,
|
|
116
116
|
P2PDuplicateAttestationCallback,
|
|
117
|
+
P2POversizedProposalCallback,
|
|
117
118
|
P2PService,
|
|
118
119
|
PeerDiscoveryService,
|
|
119
120
|
} from '../service.js';
|
|
120
121
|
import { P2PInstrumentation } from './instrumentation.js';
|
|
121
122
|
|
|
123
|
+
/**
|
|
124
|
+
* Builds the {@link ConsensusTimetable} shared by the gossip validators for proposal/attestation receive-window
|
|
125
|
+
* bounds. Derived purely from protocol slot-timing constants plus the block sub-slot duration and the consensus
|
|
126
|
+
* materialization grace, so every node agrees on these bounds without depending on proposer operational budgets.
|
|
127
|
+
*/
|
|
128
|
+
function buildConsensusTimetable(
|
|
129
|
+
config: P2PConfig,
|
|
130
|
+
l1Constants: ReturnType<EpochCacheInterface['getL1Constants']>,
|
|
131
|
+
): ConsensusTimetable {
|
|
132
|
+
const blockDuration = config.blockDurationMs / 1000;
|
|
133
|
+
return new ConsensusTimetable({
|
|
134
|
+
l1Constants,
|
|
135
|
+
blockDuration,
|
|
136
|
+
checkpointProposalSyncGrace:
|
|
137
|
+
config.checkpointProposalSyncGraceSeconds ?? getDefaultCheckpointProposalSyncGrace(blockDuration),
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
|
|
122
141
|
interface ValidationResult {
|
|
123
142
|
name: string;
|
|
124
143
|
isValid: TxValidationResult;
|
|
@@ -130,12 +149,12 @@ type ValidationOutcome = { allPassed: true } | { allPassed: false; failure: Vali
|
|
|
130
149
|
// REFACTOR: Unify with the type above
|
|
131
150
|
type ReceivedMessageValidationResult<T, M = undefined> =
|
|
132
151
|
| { obj: T; result: Exclude<TopicValidatorResult, TopicValidatorResult.Reject>; metadata?: M }
|
|
133
|
-
| { obj?: T; result: TopicValidatorResult.Reject; metadata?: M };
|
|
152
|
+
| { obj?: T; result: TopicValidatorResult.Reject; metadata?: M; severity: PeerErrorSeverity };
|
|
134
153
|
|
|
135
154
|
/**
|
|
136
155
|
* Lib P2P implementation of the P2PService interface.
|
|
137
156
|
*/
|
|
138
|
-
export class LibP2PService
|
|
157
|
+
export class LibP2PService extends WithTracer implements P2PService {
|
|
139
158
|
private discoveryRunningPromise?: RunningPromise;
|
|
140
159
|
private msgIdSeenValidators: Record<TopicType, MessageSeenValidator> = {} as Record<TopicType, MessageSeenValidator>;
|
|
141
160
|
|
|
@@ -147,8 +166,6 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
147
166
|
private protocolVersion = '';
|
|
148
167
|
private topicStrings: Record<TopicType, string> = {} as Record<TopicType, string>;
|
|
149
168
|
|
|
150
|
-
private feesCache: { blockNumber: BlockNumber; gasFees: GasFees } | undefined;
|
|
151
|
-
|
|
152
169
|
/** Callback invoked when a duplicate proposal is detected (triggers slashing). */
|
|
153
170
|
private duplicateProposalCallback?: (info: {
|
|
154
171
|
slot: SlotNumber;
|
|
@@ -156,9 +173,15 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
156
173
|
type: 'checkpoint' | 'block';
|
|
157
174
|
}) => void;
|
|
158
175
|
|
|
176
|
+
/** Callback invoked when an oversized block proposal is stored as slashing evidence (triggers slashing). */
|
|
177
|
+
private oversizedProposalCallback?: P2POversizedProposalCallback;
|
|
178
|
+
|
|
159
179
|
/** Callback invoked when a duplicate attestation is detected (triggers slashing). */
|
|
160
180
|
private duplicateAttestationCallback?: P2PDuplicateAttestationCallback;
|
|
161
181
|
|
|
182
|
+
/** Callback invoked when a valid checkpoint attestation is accepted into the pool. */
|
|
183
|
+
private checkpointAttestationCallback?: P2PCheckpointAttestationCallback;
|
|
184
|
+
|
|
162
185
|
/**
|
|
163
186
|
* Callback for when a block is received from a peer.
|
|
164
187
|
* @param block - The block received from the peer.
|
|
@@ -171,10 +194,19 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
171
194
|
* @param checkpoint - The checkpoint proposal received from the peer.
|
|
172
195
|
* @returns The attestations for the checkpoint, if any.
|
|
173
196
|
*/
|
|
174
|
-
private
|
|
197
|
+
private allNodesCheckpointReceivedCallback: P2PCheckpointReceivedCallback;
|
|
198
|
+
/**
|
|
199
|
+
* Callback for when a checkpoint proposal is received - specifically for validators - from a peer.
|
|
200
|
+
* @param checkpoint - The checkpoint proposal received from the peer.
|
|
201
|
+
* @returns The attestations for the checkpoint, if any.
|
|
202
|
+
*/
|
|
203
|
+
private validatorCheckpointReceivedCallback: P2PCheckpointReceivedCallback;
|
|
175
204
|
|
|
176
205
|
private gossipSubEventHandler: (e: CustomEvent<GossipsubMessage>) => void;
|
|
177
206
|
|
|
207
|
+
private ipChangedHandler?: (ip: string) => void;
|
|
208
|
+
private discoveredP2pIp?: string;
|
|
209
|
+
|
|
178
210
|
private instrumentation: P2PInstrumentation;
|
|
179
211
|
|
|
180
212
|
private telemetry: TelemetryClient;
|
|
@@ -182,7 +214,6 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
182
214
|
protected logger: Logger;
|
|
183
215
|
|
|
184
216
|
constructor(
|
|
185
|
-
private clientType: T,
|
|
186
217
|
private config: P2PConfig,
|
|
187
218
|
protected node: PubSubLibp2p,
|
|
188
219
|
private peerDiscoveryService: PeerDiscoveryService,
|
|
@@ -193,8 +224,10 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
193
224
|
private epochCache: EpochCacheInterface,
|
|
194
225
|
private proofVerifier: ClientProtocolCircuitVerifier,
|
|
195
226
|
private worldStateSynchronizer: WorldStateSynchronizer,
|
|
227
|
+
private blockMinFeesProvider: BlockMinFeesProvider,
|
|
196
228
|
telemetry: TelemetryClient,
|
|
197
229
|
logger: Logger = createLogger('p2p:libp2p_service'),
|
|
230
|
+
private txValidationCache?: TxValidationCache,
|
|
198
231
|
) {
|
|
199
232
|
super(telemetry, 'LibP2PService');
|
|
200
233
|
this.telemetry = telemetry;
|
|
@@ -224,36 +257,66 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
224
257
|
this.protocolVersion,
|
|
225
258
|
);
|
|
226
259
|
|
|
227
|
-
|
|
228
|
-
|
|
260
|
+
// Build the consensus timetable once from protocol slot-timing constants and inject it into every
|
|
261
|
+
// validator so they share one set of receive-window bounds, independent of proposer operational budgets.
|
|
262
|
+
const consensusTimetable = buildConsensusTimetable(config, epochCache.getL1Constants());
|
|
263
|
+
const proposalValidatorOpts = {
|
|
229
264
|
txsPermitted: !config.disableTransactions,
|
|
230
|
-
|
|
265
|
+
maxTxsPerBlock: config.validateMaxTxsPerBlock ?? config.validateMaxTxsPerCheckpoint,
|
|
266
|
+
maxBlocksPerCheckpoint: config.maxBlocksPerCheckpoint,
|
|
267
|
+
skipSlotValidation: config.skipProposalSlotValidation,
|
|
268
|
+
signatureContext: {
|
|
269
|
+
chainId: config.l1ChainId,
|
|
270
|
+
rollupAddress: config.rollupAddress,
|
|
271
|
+
},
|
|
272
|
+
clockDisparityMs: config.maxGossipClockDisparityMs,
|
|
273
|
+
};
|
|
274
|
+
this.blockProposalValidator = new BlockProposalValidator(epochCache, consensusTimetable, proposalValidatorOpts);
|
|
275
|
+
this.checkpointProposalValidator = new CheckpointProposalValidator(
|
|
276
|
+
epochCache,
|
|
277
|
+
consensusTimetable,
|
|
278
|
+
proposalValidatorOpts,
|
|
279
|
+
);
|
|
280
|
+
const attestationValidatorOpts = {
|
|
281
|
+
signatureContext: proposalValidatorOpts.signatureContext,
|
|
282
|
+
clockDisparityMs: config.maxGossipClockDisparityMs,
|
|
283
|
+
};
|
|
231
284
|
this.checkpointAttestationValidator = config.fishermanMode
|
|
232
|
-
? new FishermanAttestationValidator(
|
|
233
|
-
|
|
285
|
+
? new FishermanAttestationValidator(
|
|
286
|
+
epochCache,
|
|
287
|
+
consensusTimetable,
|
|
288
|
+
mempools.attestationPool,
|
|
289
|
+
telemetry,
|
|
290
|
+
attestationValidatorOpts,
|
|
291
|
+
)
|
|
292
|
+
: new CheckpointAttestationValidator(epochCache, consensusTimetable, attestationValidatorOpts);
|
|
234
293
|
|
|
235
294
|
this.gossipSubEventHandler = this.handleGossipSubEvent.bind(this);
|
|
236
295
|
|
|
237
296
|
this.blockReceivedCallback = async (block: BlockProposal): Promise<boolean> => {
|
|
238
|
-
this.logger.
|
|
239
|
-
`Handler not yet registered
|
|
297
|
+
this.logger.warn(
|
|
298
|
+
`Handler for block received not yet registered on P2P service. Received block ${block.blockNumber} for slot ${block.slotNumber} from peer.`,
|
|
240
299
|
{ p2pMessageIdentifier: await block.p2pMessageLoggingIdentifier() },
|
|
241
300
|
);
|
|
242
|
-
return
|
|
301
|
+
return true;
|
|
243
302
|
};
|
|
244
303
|
|
|
245
|
-
this.
|
|
246
|
-
|
|
304
|
+
this.allNodesCheckpointReceivedCallback = (
|
|
305
|
+
_checkpoint: CheckpointProposalCore,
|
|
306
|
+
): Promise<CheckpointAttestation[] | undefined> => {
|
|
307
|
+
throw new CheckpointProposalReceivedCallbackNotRegisteredError();
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
this.validatorCheckpointReceivedCallback = (
|
|
311
|
+
_checkpoint: CheckpointProposalCore,
|
|
247
312
|
): Promise<CheckpointAttestation[] | undefined> => {
|
|
248
|
-
this.logger.debug(
|
|
249
|
-
`Handler not yet registered: Checkpoint received callback not set. Received checkpoint for slot ${checkpoint.slotNumber} from peer.`,
|
|
250
|
-
);
|
|
251
313
|
return Promise.resolve(undefined);
|
|
252
314
|
};
|
|
253
315
|
}
|
|
254
316
|
|
|
255
|
-
public updateConfig(config: Partial<P2PReqRespConfig
|
|
317
|
+
public updateConfig(config: Partial<P2PReqRespConfig & Pick<P2PConfig, 'skipIncomingProposals'>>) {
|
|
256
318
|
this.reqresp.updateConfig(config);
|
|
319
|
+
this.config = merge(this.config, config);
|
|
257
320
|
}
|
|
258
321
|
|
|
259
322
|
/**
|
|
@@ -262,8 +325,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
262
325
|
* @param txPool - The transaction pool to be accessed by the service.
|
|
263
326
|
* @returns The new service.
|
|
264
327
|
*/
|
|
265
|
-
public static async new
|
|
266
|
-
clientType: T,
|
|
328
|
+
public static async new(
|
|
267
329
|
config: P2PConfig,
|
|
268
330
|
peerId: PeerId,
|
|
269
331
|
deps: {
|
|
@@ -273,9 +335,11 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
273
335
|
proofVerifier: ClientProtocolCircuitVerifier;
|
|
274
336
|
worldStateSynchronizer: WorldStateSynchronizer;
|
|
275
337
|
peerStore: AztecAsyncKVStore;
|
|
338
|
+
blockMinFeesProvider: BlockMinFeesProvider;
|
|
276
339
|
telemetry: TelemetryClient;
|
|
277
340
|
logger: Logger;
|
|
278
341
|
packageVersion: string;
|
|
342
|
+
txValidationCache?: TxValidationCache;
|
|
279
343
|
},
|
|
280
344
|
) {
|
|
281
345
|
const {
|
|
@@ -285,9 +349,11 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
285
349
|
mempools,
|
|
286
350
|
proofVerifier,
|
|
287
351
|
peerStore,
|
|
352
|
+
blockMinFeesProvider,
|
|
288
353
|
telemetry,
|
|
289
354
|
logger,
|
|
290
355
|
packageVersion,
|
|
356
|
+
txValidationCache,
|
|
291
357
|
} = deps;
|
|
292
358
|
const { p2pPort, maxPeerCount, listenAddress } = config;
|
|
293
359
|
const bindAddrTcp = convertToMultiaddr(listenAddress, p2pPort, 'tcp');
|
|
@@ -302,6 +368,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
302
368
|
packageVersion,
|
|
303
369
|
telemetry,
|
|
304
370
|
createLogger(`${logger.module}:discv5_service`, logger.getBindings()),
|
|
371
|
+
peerStore,
|
|
305
372
|
);
|
|
306
373
|
|
|
307
374
|
// Seed libp2p's bootstrap discovery with private and trusted peers
|
|
@@ -316,33 +383,49 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
316
383
|
const protocolVersion = compressComponentVersions(versions);
|
|
317
384
|
|
|
318
385
|
const preferredPeersEnrs: ENR[] = config.preferredPeers.map(enr => ENR.decodeTxt(enr));
|
|
319
|
-
const directPeers = (
|
|
386
|
+
const directPeers = compactArray(
|
|
320
387
|
await Promise.all(
|
|
321
388
|
preferredPeersEnrs.map(async enr => {
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
389
|
+
try {
|
|
390
|
+
const peerId = await enr.peerId();
|
|
391
|
+
const address = enr.getLocationMultiaddr('tcp');
|
|
392
|
+
if (address === undefined) {
|
|
393
|
+
throw new Error(`Direct peer ${peerId.toString()} has no TCP address, ENR: ${enr.encodeTxt()}`);
|
|
394
|
+
}
|
|
395
|
+
return {
|
|
396
|
+
id: peerId,
|
|
397
|
+
addrs: [address],
|
|
398
|
+
};
|
|
399
|
+
} catch (err) {
|
|
400
|
+
// A malformed configured ENR shouldn't abort node setup — skip it and log.
|
|
401
|
+
logger.warn(`Skipping preferred peer with invalid ENR`, { err });
|
|
402
|
+
return undefined;
|
|
326
403
|
}
|
|
327
|
-
return {
|
|
328
|
-
id: peerId,
|
|
329
|
-
addrs: [address],
|
|
330
|
-
};
|
|
331
404
|
}),
|
|
332
|
-
)
|
|
333
|
-
)
|
|
405
|
+
),
|
|
406
|
+
);
|
|
334
407
|
|
|
335
408
|
const announceTcpMultiaddr = config.p2pIp ? [convertToMultiaddr(config.p2pIp, p2pPort, 'tcp')] : [];
|
|
336
409
|
|
|
337
|
-
// Create dynamic topic score params based on network configuration
|
|
410
|
+
// Create dynamic topic score params based on network configuration. Scoring uses the network-wide
|
|
411
|
+
// max-blocks-per-checkpoint config value directly to size expected per-slot message rates; these are
|
|
412
|
+
// peer-rate thresholds, not consensus deadlines, so they need no proposer operational budgets.
|
|
338
413
|
const l1Constants = epochCache.getL1Constants();
|
|
339
414
|
const topicScoreParams = createAllTopicScoreParams(protocolVersion, {
|
|
340
415
|
slotDurationMs: l1Constants.slotDuration * 1000,
|
|
341
416
|
heartbeatIntervalMs: config.gossipsubInterval,
|
|
342
417
|
targetCommitteeSize: l1Constants.targetCommitteeSize,
|
|
343
|
-
|
|
418
|
+
maxBlocksPerCheckpoint: config.maxBlocksPerCheckpoint ?? DEFAULT_MAX_BLOCKS_PER_CHECKPOINT,
|
|
419
|
+
expectedBlockProposalsPerSlot: config.expectedBlockProposalsPerSlot,
|
|
344
420
|
});
|
|
345
421
|
|
|
422
|
+
// Restrict gossipsub to exactly the topics we subscribe to. Without this, an arbitrary-topic
|
|
423
|
+
// message is transformed, msg-id'd and inserted into the seenCache before the subscription check,
|
|
424
|
+
// so a crafted topic colliding on msg id can suppress a real message as a duplicate.
|
|
425
|
+
const allowedTopics = getTopicsForConfig(config.disableTransactions).map(topic =>
|
|
426
|
+
createTopicString(topic, protocolVersion),
|
|
427
|
+
);
|
|
428
|
+
|
|
346
429
|
const node = await createLibp2p({
|
|
347
430
|
start: false,
|
|
348
431
|
peerId,
|
|
@@ -374,7 +457,8 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
374
457
|
],
|
|
375
458
|
datastore,
|
|
376
459
|
peerDiscovery,
|
|
377
|
-
|
|
460
|
+
// Pin the yamux frame size: MAX_REQRESP_REQUEST_SIZE_BYTES relies on a reqresp request fitting in one frame.
|
|
461
|
+
streamMuxers: [yamux({ maxMessageSize: YAMUX_MAX_MESSAGE_SIZE_BYTES }), mplex()],
|
|
378
462
|
connectionEncryption: [noise()],
|
|
379
463
|
connectionManager: {
|
|
380
464
|
minConnections: 0, // Disable libp2p peer dialing, we do it manually
|
|
@@ -388,7 +472,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
388
472
|
},
|
|
389
473
|
connectionGater: {
|
|
390
474
|
denyInboundConnection: (maConn: MultiaddrConnection) => {
|
|
391
|
-
const allowed = peerManager.
|
|
475
|
+
const allowed = peerManager.isAddressAllowedToConnect(maConn.remoteAddr.nodeAddress().address);
|
|
392
476
|
if (allowed) {
|
|
393
477
|
return false;
|
|
394
478
|
}
|
|
@@ -399,7 +483,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
399
483
|
denyInboundEncryptedConnection: (peerId: PeerId, _maConn: MultiaddrConnection) => {
|
|
400
484
|
//NOTE: it is not necessary to check address here because this was already done by
|
|
401
485
|
// denyInboundConnection
|
|
402
|
-
const allowed = peerManager.
|
|
486
|
+
const allowed = peerManager.isPeerAllowedToConnect(peerId);
|
|
403
487
|
if (allowed) {
|
|
404
488
|
return false;
|
|
405
489
|
}
|
|
@@ -427,9 +511,13 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
427
511
|
mcacheLength: config.gossipsubMcacheLength,
|
|
428
512
|
mcacheGossip: config.gossipsubMcacheGossip,
|
|
429
513
|
seenTTL: config.gossipsubSeenTTL,
|
|
514
|
+
allowedTopics,
|
|
515
|
+
// No fastMsgIdFn: the fast-path dedup cache keys on a non-cryptographic 64-bit hash of the
|
|
516
|
+
// raw data only (no topic), so a collision — accidental or engineered via a weak seed — drops
|
|
517
|
+
// a different message with no fallback to the full id. Dedup instead rests solely on the
|
|
518
|
+
// cryptographic, topic-framed msgIdFn below.
|
|
430
519
|
msgIdFn: getMsgIdFn,
|
|
431
520
|
msgIdToStrFn: msgIdToStrFn,
|
|
432
|
-
fastMsgIdFn: fastMsgIdFn,
|
|
433
521
|
dataTransform: new SnappyTransform(),
|
|
434
522
|
metricsRegister: otelMetricsAdapter,
|
|
435
523
|
metricsTopicStrToLabel: metricsTopicStrToLabels(protocolVersion),
|
|
@@ -441,8 +529,9 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
441
529
|
topics: topicScoreParams,
|
|
442
530
|
}),
|
|
443
531
|
}) as (components: GossipSubComponents) => GossipSub,
|
|
444
|
-
components: (components: { connectionManager: ConnectionManager }) => ({
|
|
532
|
+
components: (components: { connectionManager: ConnectionManager; addressManager: AddressManager }) => ({
|
|
445
533
|
connectionManager: components.connectionManager,
|
|
534
|
+
addressManager: components.addressManager,
|
|
446
535
|
}),
|
|
447
536
|
},
|
|
448
537
|
logger: createLibp2pComponentLogger(logger.module, logger.getBindings()),
|
|
@@ -464,6 +553,9 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
464
553
|
epochCache,
|
|
465
554
|
);
|
|
466
555
|
|
|
556
|
+
// Gate req/resp data protocols for unauthenticated peers when p2pAllowOnlyValidators is enabled
|
|
557
|
+
reqresp.setShouldRejectPeer(peerId => peerManager.shouldDisableP2PGossip(peerId));
|
|
558
|
+
|
|
467
559
|
// Configure application-specific scoring for gossipsub.
|
|
468
560
|
// The weight scales app score to align with gossipsub thresholds:
|
|
469
561
|
// - Disconnect (-50) × 10 = -500 = gossipThreshold (stops receiving gossip)
|
|
@@ -474,7 +566,6 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
474
566
|
peerManager.shouldDisableP2PGossip(peerId) ? -Infinity : peerManager.getPeerScore(peerId);
|
|
475
567
|
|
|
476
568
|
return new LibP2PService(
|
|
477
|
-
clientType,
|
|
478
569
|
config,
|
|
479
570
|
node,
|
|
480
571
|
peerDiscoveryService,
|
|
@@ -485,8 +576,10 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
485
576
|
epochCache,
|
|
486
577
|
proofVerifier,
|
|
487
578
|
worldStateSynchronizer,
|
|
579
|
+
blockMinFeesProvider,
|
|
488
580
|
telemetry,
|
|
489
581
|
logger,
|
|
582
|
+
txValidationCache,
|
|
490
583
|
);
|
|
491
584
|
}
|
|
492
585
|
|
|
@@ -500,24 +593,21 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
500
593
|
throw new Error('P2P service already started');
|
|
501
594
|
}
|
|
502
595
|
|
|
503
|
-
// Get listen & announce addresses for logging
|
|
504
596
|
const { p2pIp, p2pPort } = this.config;
|
|
505
|
-
if (!p2pIp) {
|
|
506
|
-
throw new Error('Announce address not provided.');
|
|
597
|
+
if (!p2pIp && !this.config.queryForIp) {
|
|
598
|
+
throw new Error('Announce address not provided and queryForIp is not enabled.');
|
|
507
599
|
}
|
|
508
|
-
const announceTcpMultiaddr = convertToMultiaddr(p2pIp, p2pPort, 'tcp');
|
|
600
|
+
const announceTcpMultiaddr = p2pIp ? convertToMultiaddr(p2pIp, p2pPort, 'tcp') : undefined;
|
|
509
601
|
|
|
510
602
|
// Create request response protocol handlers
|
|
511
603
|
const txHandler = reqRespTxHandler(this.mempools);
|
|
512
604
|
const goodbyeHandler = reqGoodbyeHandler(this.peerManager);
|
|
513
|
-
const blockHandler = reqRespBlockHandler(this.archiver);
|
|
514
605
|
const statusHandler = reqRespStatusHandler(this.protocolVersion, this.worldStateSynchronizer, this.logger);
|
|
515
606
|
|
|
516
607
|
const requestResponseHandlers: Partial<ReqRespSubProtocolHandlers> = {
|
|
517
608
|
[ReqRespSubProtocol.PING]: pingHandler,
|
|
518
609
|
[ReqRespSubProtocol.STATUS]: statusHandler.bind(this),
|
|
519
610
|
[ReqRespSubProtocol.GOODBYE]: goodbyeHandler.bind(this),
|
|
520
|
-
[ReqRespSubProtocol.BLOCK]: blockHandler.bind(this),
|
|
521
611
|
};
|
|
522
612
|
|
|
523
613
|
if (!this.config.disableTransactions) {
|
|
@@ -533,22 +623,14 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
533
623
|
requestResponseHandlers[ReqRespSubProtocol.TX] = txHandler.bind(this);
|
|
534
624
|
}
|
|
535
625
|
|
|
536
|
-
// Define the sub protocol validators - This is done within this start() method to gain a callback to the existing validateTx function
|
|
537
|
-
const reqrespSubProtocolValidators = {
|
|
538
|
-
...DEFAULT_SUB_PROTOCOL_VALIDATORS,
|
|
539
|
-
[ReqRespSubProtocol.TX]: this.validateRequestedTxs.bind(this),
|
|
540
|
-
[ReqRespSubProtocol.BLOCK_TXS]: this.validateRequestedBlockTxs.bind(this),
|
|
541
|
-
[ReqRespSubProtocol.BLOCK]: this.validateRequestedBlock.bind(this),
|
|
542
|
-
};
|
|
543
|
-
|
|
544
626
|
await this.peerManager.initializePeers();
|
|
545
627
|
|
|
546
|
-
await this.reqresp.start(requestResponseHandlers
|
|
628
|
+
await this.reqresp.start(requestResponseHandlers);
|
|
547
629
|
|
|
548
630
|
await this.node.start();
|
|
549
631
|
|
|
550
632
|
// Subscribe to standard GossipSub topics by default
|
|
551
|
-
for (const topic of
|
|
633
|
+
for (const topic of getTopicsForConfig(this.config.disableTransactions)) {
|
|
552
634
|
this.subscribeToTopic(this.topicStrings[topic]);
|
|
553
635
|
}
|
|
554
636
|
|
|
@@ -559,6 +641,38 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
559
641
|
if (!this.config.p2pDiscoveryDisabled) {
|
|
560
642
|
await this.peerDiscoveryService.start();
|
|
561
643
|
}
|
|
644
|
+
|
|
645
|
+
// Bridge discv5 IP changes to libp2p's AddressManager so peers see the updated address
|
|
646
|
+
if (this.config.queryForIp) {
|
|
647
|
+
this.discoveredP2pIp = this.config.p2pIp;
|
|
648
|
+
this.logger.info('IP change tracking enabled, bridging discv5 IP updates to libp2p AddressManager');
|
|
649
|
+
this.ipChangedHandler = (ip: string) => {
|
|
650
|
+
const addressManager = this.node.services.components.addressManager;
|
|
651
|
+
const newAddr = multiaddr(convertToMultiaddr(ip, this.config.p2pPort, 'tcp'));
|
|
652
|
+
const previousIp = this.discoveredP2pIp;
|
|
653
|
+
|
|
654
|
+
if (previousIp) {
|
|
655
|
+
const oldAddr = multiaddr(convertToMultiaddr(previousIp, this.config.p2pPort, 'tcp'));
|
|
656
|
+
addressManager.removeObservedAddr(oldAddr);
|
|
657
|
+
this.logger.info('Libp2p announce address updated due to IP change', {
|
|
658
|
+
previousIp,
|
|
659
|
+
newIp: ip,
|
|
660
|
+
newMultiaddr: newAddr.toString(),
|
|
661
|
+
});
|
|
662
|
+
} else {
|
|
663
|
+
this.logger.info('Libp2p announce address set from initial discv5 IP discovery', {
|
|
664
|
+
ip,
|
|
665
|
+
multiaddr: newAddr.toString(),
|
|
666
|
+
});
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
addressManager.addObservedAddr(newAddr);
|
|
670
|
+
addressManager.confirmObservedAddr(newAddr);
|
|
671
|
+
this.discoveredP2pIp = ip;
|
|
672
|
+
};
|
|
673
|
+
this.peerDiscoveryService.on('ip:changed', this.ipChangedHandler);
|
|
674
|
+
}
|
|
675
|
+
|
|
562
676
|
this.discoveryRunningPromise = new RunningPromise(
|
|
563
677
|
async () => {
|
|
564
678
|
await this.peerManager.heartbeat();
|
|
@@ -584,6 +698,11 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
584
698
|
// Remove gossip sub listener
|
|
585
699
|
this.node.services.pubsub.removeEventListener(GossipSubEvent.MESSAGE, this.gossipSubEventHandler);
|
|
586
700
|
|
|
701
|
+
if (this.ipChangedHandler) {
|
|
702
|
+
this.peerDiscoveryService.removeListener('ip:changed', this.ipChangedHandler);
|
|
703
|
+
this.ipChangedHandler = undefined;
|
|
704
|
+
}
|
|
705
|
+
|
|
587
706
|
// Stop peer manager
|
|
588
707
|
this.logger.debug('Stopping peer manager...');
|
|
589
708
|
await this.peerManager.stop();
|
|
@@ -598,12 +717,8 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
598
717
|
this.logger.info('LibP2P service stopped');
|
|
599
718
|
}
|
|
600
719
|
|
|
601
|
-
addReqRespSubProtocol(
|
|
602
|
-
subProtocol
|
|
603
|
-
handler: ReqRespSubProtocolHandler,
|
|
604
|
-
validator?: ReqRespSubProtocolValidators[ReqRespSubProtocol],
|
|
605
|
-
): Promise<void> {
|
|
606
|
-
return this.reqresp.addSubProtocol(subProtocol, handler, validator);
|
|
720
|
+
addReqRespSubProtocol(subProtocol: ReqRespSubProtocol, handler: ReqRespSubProtocolHandler): Promise<void> {
|
|
721
|
+
return this.reqresp.addSubProtocol(subProtocol, handler);
|
|
607
722
|
}
|
|
608
723
|
|
|
609
724
|
public registerThisValidatorAddresses(address: EthAddress[]): void {
|
|
@@ -614,6 +729,10 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
614
729
|
return this.peerManager.getPeers(includePending);
|
|
615
730
|
}
|
|
616
731
|
|
|
732
|
+
public getGossipMeshPeerCount(topicType: TopicType): number {
|
|
733
|
+
return this.node.services.pubsub.getMeshPeers(this.topicStrings[topicType]).length;
|
|
734
|
+
}
|
|
735
|
+
|
|
617
736
|
private handleGossipSubEvent(e: CustomEvent<GossipsubMessage>) {
|
|
618
737
|
this.logger.trace(`Received PUBSUB message.`);
|
|
619
738
|
|
|
@@ -627,20 +746,6 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
627
746
|
setImmediate(() => void safeJob());
|
|
628
747
|
}
|
|
629
748
|
|
|
630
|
-
/**
|
|
631
|
-
* Send a batch of requests to peers, and return the responses
|
|
632
|
-
* @param protocol - The request response protocol to use
|
|
633
|
-
* @param requests - The requests to send to the peers
|
|
634
|
-
* @returns The responses to the requests
|
|
635
|
-
*/
|
|
636
|
-
sendBatchRequest<SubProtocol extends ReqRespSubProtocol>(
|
|
637
|
-
protocol: SubProtocol,
|
|
638
|
-
requests: InstanceType<SubProtocolMap[SubProtocol]['request']>[],
|
|
639
|
-
pinnedPeerId: PeerId | undefined,
|
|
640
|
-
): Promise<InstanceType<SubProtocolMap[SubProtocol]['response']>[]> {
|
|
641
|
-
return this.reqresp.sendBatchRequest(protocol, requests, pinnedPeerId);
|
|
642
|
-
}
|
|
643
|
-
|
|
644
749
|
public sendRequestToPeer(
|
|
645
750
|
peerId: PeerId,
|
|
646
751
|
subProtocol: ReqRespSubProtocol,
|
|
@@ -662,8 +767,12 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
662
767
|
this.blockReceivedCallback = callback;
|
|
663
768
|
}
|
|
664
769
|
|
|
665
|
-
public
|
|
666
|
-
this.
|
|
770
|
+
public registerValidatorCheckpointReceivedCallback(callback: P2PCheckpointReceivedCallback) {
|
|
771
|
+
this.validatorCheckpointReceivedCallback = callback;
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
public registerAllNodesCheckpointReceivedCallback(callback: P2PCheckpointReceivedCallback) {
|
|
775
|
+
this.allNodesCheckpointReceivedCallback = callback;
|
|
667
776
|
}
|
|
668
777
|
|
|
669
778
|
/**
|
|
@@ -676,6 +785,13 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
676
785
|
this.duplicateProposalCallback = callback;
|
|
677
786
|
}
|
|
678
787
|
|
|
788
|
+
/**
|
|
789
|
+
* Registers a callback to be invoked when an oversized block proposal is stored as slashing evidence.
|
|
790
|
+
*/
|
|
791
|
+
public registerOversizedProposalCallback(callback: P2POversizedProposalCallback): void {
|
|
792
|
+
this.oversizedProposalCallback = callback;
|
|
793
|
+
}
|
|
794
|
+
|
|
679
795
|
/**
|
|
680
796
|
* Registers a callback to be invoked when a duplicate attestation is detected.
|
|
681
797
|
* A validator signing attestations for different proposals at the same slot.
|
|
@@ -685,6 +801,10 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
685
801
|
this.duplicateAttestationCallback = callback;
|
|
686
802
|
}
|
|
687
803
|
|
|
804
|
+
public registerCheckpointAttestationCallback(callback: P2PCheckpointAttestationCallback): void {
|
|
805
|
+
this.checkpointAttestationCallback = callback;
|
|
806
|
+
}
|
|
807
|
+
|
|
688
808
|
/**
|
|
689
809
|
* Subscribes to a topic.
|
|
690
810
|
* @param topic - The topic to subscribe to.
|
|
@@ -749,6 +869,9 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
749
869
|
if (!validator || !validator.addMessage(msgId)) {
|
|
750
870
|
this.instrumentation.incMessagePrevalidationStatus(false, topicType);
|
|
751
871
|
this.node.services.pubsub.reportMessageValidationResult(msgId, source.toString(), TopicValidatorResult.Ignore);
|
|
872
|
+
if (topicType === TopicType.tx) {
|
|
873
|
+
this.logger.verbose(`Ignoring already-seen tx gossip message`, { msgId, source: source.toString() });
|
|
874
|
+
}
|
|
752
875
|
return { result: false, topicType };
|
|
753
876
|
}
|
|
754
877
|
|
|
@@ -810,12 +933,19 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
810
933
|
|
|
811
934
|
// Process the message, optionally within a linked span for trace propagation
|
|
812
935
|
const processMessage = async () => {
|
|
936
|
+
if (
|
|
937
|
+
this.config.skipIncomingProposals &&
|
|
938
|
+
(msg.topic === this.topicStrings[TopicType.block_proposal] ||
|
|
939
|
+
msg.topic === this.topicStrings[TopicType.checkpoint_proposal])
|
|
940
|
+
) {
|
|
941
|
+
this.logger.warn(`Ignoring incoming proposal (skipIncomingProposals is set)`, { topic: msg.topic });
|
|
942
|
+
this.node.services.pubsub.reportMessageValidationResult(msgId, source.toString(), TopicValidatorResult.Ignore);
|
|
943
|
+
return;
|
|
944
|
+
}
|
|
813
945
|
if (msg.topic === this.topicStrings[TopicType.tx]) {
|
|
814
946
|
await this.handleGossipedTx(p2pMessage.payload, msgId, source);
|
|
815
947
|
} else if (msg.topic === this.topicStrings[TopicType.checkpoint_attestation]) {
|
|
816
|
-
|
|
817
|
-
await this.processCheckpointAttestationFromPeer(p2pMessage.payload, msgId, source);
|
|
818
|
-
}
|
|
948
|
+
await this.processCheckpointAttestationFromPeer(p2pMessage.payload, msgId, source);
|
|
819
949
|
} else if (msg.topic === this.topicStrings[TopicType.block_proposal]) {
|
|
820
950
|
await this.processBlockFromPeer(p2pMessage.payload, msgId, source);
|
|
821
951
|
} else if (msg.topic === this.topicStrings[TopicType.checkpoint_proposal]) {
|
|
@@ -877,47 +1007,124 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
877
1007
|
source: PeerId,
|
|
878
1008
|
topicType: TopicType,
|
|
879
1009
|
): Promise<ReceivedMessageValidationResult<T, M>> {
|
|
880
|
-
|
|
1010
|
+
// Default to reject result with a penalty if validation function throws an error
|
|
1011
|
+
let resultAndObj: ReceivedMessageValidationResult<T, M> = {
|
|
1012
|
+
result: TopicValidatorResult.Reject,
|
|
1013
|
+
severity: PeerErrorSeverity.MidToleranceError,
|
|
1014
|
+
};
|
|
881
1015
|
const timer = new Timer();
|
|
882
1016
|
try {
|
|
883
1017
|
resultAndObj = await validationFunc();
|
|
884
1018
|
} catch (err) {
|
|
885
|
-
this.
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
1019
|
+
this.logger.error(`Error validating gossipsub message`, err, { msgId, source: source.toString(), topicType });
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
const validationTimeMs = timer.ms();
|
|
1023
|
+
const mcacheWindowMs = this.config.gossipsubMcacheLength * this.config.gossipsubInterval;
|
|
1024
|
+
if (validationTimeMs > mcacheWindowMs * 0.75) {
|
|
1025
|
+
this.instrumentation.incSlowValidation(topicType);
|
|
1026
|
+
this.logger.warn(
|
|
1027
|
+
`Gossip validation for ${topicType} took ${validationTimeMs}ms, approaching mcache eviction window of ${mcacheWindowMs}ms. ` +
|
|
1028
|
+
`Message forwarding may be skipped if validation exceeds the window.`,
|
|
1029
|
+
{ msgId, source: source.toString(), topicType, validationTimeMs, mcacheWindowMs },
|
|
1030
|
+
);
|
|
891
1031
|
}
|
|
892
1032
|
|
|
893
1033
|
if (resultAndObj.result === TopicValidatorResult.Accept) {
|
|
1034
|
+
this.logger.debug(`Message ${topicType} accepted by validator`, { msgId, source: source.toString(), topicType });
|
|
894
1035
|
this.instrumentation.recordMessageValidation(topicType, timer);
|
|
1036
|
+
} else if (resultAndObj.result === TopicValidatorResult.Reject) {
|
|
1037
|
+
this.logger.warn(`Message ${topicType} rejected by validator with severity ${resultAndObj.severity}`, {
|
|
1038
|
+
msgId,
|
|
1039
|
+
source: source.toString(),
|
|
1040
|
+
topicType,
|
|
1041
|
+
severity: resultAndObj.severity,
|
|
1042
|
+
});
|
|
1043
|
+
this.peerManager.penalizePeer(source, resultAndObj.severity);
|
|
1044
|
+
} else {
|
|
1045
|
+
this.logger.trace(`Message ${topicType} ignored by validator`, { msgId, source: source.toString(), topicType });
|
|
895
1046
|
}
|
|
896
1047
|
|
|
897
1048
|
this.node.services.pubsub.reportMessageValidationResult(msgId, source.toString(), resultAndObj.result);
|
|
898
1049
|
return resultAndObj;
|
|
899
1050
|
}
|
|
900
1051
|
|
|
1052
|
+
private tryDeserialize<T>(deserializeFunc: () => T, msgId: string, source: PeerId): T | undefined {
|
|
1053
|
+
try {
|
|
1054
|
+
return deserializeFunc();
|
|
1055
|
+
} catch (err) {
|
|
1056
|
+
this.logger.warn(`Failed to deserialize gossipsub message from buffer`, {
|
|
1057
|
+
err,
|
|
1058
|
+
msgId,
|
|
1059
|
+
source: source.toString(),
|
|
1060
|
+
});
|
|
1061
|
+
return undefined;
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
|
|
901
1065
|
protected async handleGossipedTx(payloadData: Buffer, msgId: string, source: PeerId) {
|
|
902
1066
|
const validationFunc: () => Promise<ReceivedMessageValidationResult<Tx>> = async () => {
|
|
903
|
-
const tx = Tx.fromBuffer(payloadData);
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
1067
|
+
const tx = this.tryDeserialize(() => Tx.fromBuffer(payloadData), msgId, source);
|
|
1068
|
+
if (!tx) {
|
|
1069
|
+
return { result: TopicValidatorResult.Reject, severity: PeerErrorSeverity.LowToleranceError };
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
const currentBlockNumber = await this.archiver.getBlockNumber();
|
|
1073
|
+
const { ts: nextSlotTimestamp } = this.epochCache.getEpochAndSlotInNextL1Slot();
|
|
1074
|
+
|
|
1075
|
+
// Stage 1: fast validators (metadata, data, timestamps, double-spend, gas, phases, block header)
|
|
1076
|
+
const firstStageValidators = await this.createFirstStageMessageValidators(currentBlockNumber, nextSlotTimestamp);
|
|
1077
|
+
const firstStageOutcome = await this.runValidations(tx, firstStageValidators);
|
|
1078
|
+
if (!firstStageOutcome.allPassed) {
|
|
1079
|
+
const { name } = firstStageOutcome.failure;
|
|
1080
|
+
let { severity } = firstStageOutcome.failure;
|
|
1081
|
+
|
|
1082
|
+
// Double spend validator has a special case handler. We perform more detailed examination
|
|
1083
|
+
// as to how recently the nullifier was entered into the tree and if the transaction should
|
|
1084
|
+
// have 'known' the nullifier existed. This determines the severity of the penalty applied to the peer.
|
|
1085
|
+
if (name === 'doubleSpendValidator') {
|
|
1086
|
+
const txBlockNumber = BlockNumber(currentBlockNumber + 1);
|
|
1087
|
+
severity = await this.handleDoubleSpendFailure(tx, txBlockNumber);
|
|
1088
|
+
}
|
|
1089
|
+
|
|
1090
|
+
this.logger.verbose(`Rejecting gossiped tx ${tx.getTxHash().toString()}: stage 1 validation failed`, {
|
|
1091
|
+
validator: name,
|
|
1092
|
+
severity,
|
|
1093
|
+
source: source.toString(),
|
|
1094
|
+
});
|
|
1095
|
+
return { result: TopicValidatorResult.Reject, severity };
|
|
1096
|
+
}
|
|
1097
|
+
|
|
1098
|
+
// Pool pre-check: see if the pool would accept this tx before doing expensive proof verification
|
|
1099
|
+
const canAdd = await this.mempools.txPool.canAddPendingTx(tx);
|
|
1100
|
+
if (canAdd === 'ignored') {
|
|
1101
|
+
this.logger.verbose(`Ignoring gossiped tx ${tx.getTxHash().toString()}: pool pre-check returned ignored`, {
|
|
1102
|
+
source: source.toString(),
|
|
1103
|
+
});
|
|
1104
|
+
return { result: TopicValidatorResult.Ignore, obj: tx };
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1107
|
+
// Stage 2: expensive proof verification
|
|
1108
|
+
const secondStageValidators = this.createSecondStageMessageValidators();
|
|
1109
|
+
const secondStageOutcome = await this.runValidations(tx, secondStageValidators);
|
|
1110
|
+
if (!secondStageOutcome.allPassed) {
|
|
1111
|
+
const { severity, name } = secondStageOutcome.failure;
|
|
1112
|
+
this.logger.verbose(`Rejecting gossiped tx ${tx.getTxHash().toString()}: stage 2 validation failed`, {
|
|
1113
|
+
validator: name,
|
|
1114
|
+
severity,
|
|
1115
|
+
source: source.toString(),
|
|
908
1116
|
});
|
|
909
|
-
return { result: TopicValidatorResult.Reject };
|
|
1117
|
+
return { result: TopicValidatorResult.Reject, severity };
|
|
910
1118
|
}
|
|
911
1119
|
|
|
912
|
-
//
|
|
1120
|
+
// Pool add: persist the tx
|
|
913
1121
|
const txHash = tx.getTxHash();
|
|
914
1122
|
const addResult = await this.mempools.txPool.addPendingTxs([tx], { source: 'gossip' });
|
|
915
1123
|
|
|
916
1124
|
const wasAccepted = addResult.accepted.some(h => h.equals(txHash));
|
|
917
1125
|
const wasIgnored = addResult.ignored.some(h => h.equals(txHash));
|
|
918
1126
|
|
|
919
|
-
this.logger.
|
|
920
|
-
isValid,
|
|
1127
|
+
this.logger.verbose(`Validate propagated tx ${txHash.toString()}`, {
|
|
921
1128
|
wasAccepted,
|
|
922
1129
|
wasIgnored,
|
|
923
1130
|
[Attributes.P2P_ID]: source.toString(),
|
|
@@ -928,7 +1135,11 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
928
1135
|
} else if (wasIgnored) {
|
|
929
1136
|
return { result: TopicValidatorResult.Ignore, obj: tx };
|
|
930
1137
|
} else {
|
|
931
|
-
|
|
1138
|
+
this.logger.warn(`Gossiped tx ${txHash.toString()} unexpectedly rejected by pool`, {
|
|
1139
|
+
source: source.toString(),
|
|
1140
|
+
txHash: txHash.toString(),
|
|
1141
|
+
});
|
|
1142
|
+
return { result: TopicValidatorResult.Reject, severity: PeerErrorSeverity.HighToleranceError };
|
|
932
1143
|
}
|
|
933
1144
|
};
|
|
934
1145
|
|
|
@@ -958,7 +1169,16 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
958
1169
|
source: PeerId,
|
|
959
1170
|
): Promise<void> {
|
|
960
1171
|
const { result, obj: attestation } = await this.validateReceivedMessage<CheckpointAttestation>(
|
|
961
|
-
() =>
|
|
1172
|
+
() => {
|
|
1173
|
+
const attestation = this.tryDeserialize(() => CheckpointAttestation.fromBuffer(payloadData), msgId, source);
|
|
1174
|
+
if (!attestation) {
|
|
1175
|
+
return Promise.resolve({
|
|
1176
|
+
result: TopicValidatorResult.Reject,
|
|
1177
|
+
severity: PeerErrorSeverity.LowToleranceError,
|
|
1178
|
+
});
|
|
1179
|
+
}
|
|
1180
|
+
return this.validateAndStoreCheckpointAttestation(source, attestation);
|
|
1181
|
+
},
|
|
962
1182
|
msgId,
|
|
963
1183
|
source,
|
|
964
1184
|
TopicType.checkpoint_attestation,
|
|
@@ -991,8 +1211,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
991
1211
|
|
|
992
1212
|
if (validationResult.result === 'reject') {
|
|
993
1213
|
this.logger.warn(`Penalizing peer ${peerId} for checkpoint attestation validation failure`);
|
|
994
|
-
|
|
995
|
-
return { result: TopicValidatorResult.Reject };
|
|
1214
|
+
return { result: TopicValidatorResult.Reject, severity: validationResult.severity };
|
|
996
1215
|
}
|
|
997
1216
|
|
|
998
1217
|
if (validationResult.result === 'ignore') {
|
|
@@ -1018,16 +1237,16 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1018
1237
|
return { result: TopicValidatorResult.Ignore, obj: attestation };
|
|
1019
1238
|
}
|
|
1020
1239
|
|
|
1021
|
-
// Could not add (cap reached for signer),
|
|
1240
|
+
// Could not add (cap reached for signer), penalize and do not re-broadcast
|
|
1022
1241
|
if (!added) {
|
|
1023
|
-
this.logger.warn(`
|
|
1242
|
+
this.logger.warn(`Rejecting checkpoint attestation due to cap`, {
|
|
1024
1243
|
slot: slot.toString(),
|
|
1025
1244
|
archive: attestation.archive.toString(),
|
|
1026
1245
|
source: peerId.toString(),
|
|
1027
1246
|
attester: attestation.getSender()?.toString(),
|
|
1028
1247
|
count,
|
|
1029
1248
|
});
|
|
1030
|
-
return { result: TopicValidatorResult.
|
|
1249
|
+
return { result: TopicValidatorResult.Reject, severity: PeerErrorSeverity.HighToleranceError };
|
|
1031
1250
|
}
|
|
1032
1251
|
|
|
1033
1252
|
// Check if this is a duplicate attestation (signer attested to a different proposal at the same slot)
|
|
@@ -1046,6 +1265,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1046
1265
|
}
|
|
1047
1266
|
|
|
1048
1267
|
// Attestation was added successfully - accept it so other nodes can also detect the equivocation
|
|
1268
|
+
this.checkpointAttestationCallback?.(attestation);
|
|
1049
1269
|
return { result: TopicValidatorResult.Accept, obj: attestation };
|
|
1050
1270
|
}
|
|
1051
1271
|
|
|
@@ -1053,16 +1273,17 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1053
1273
|
const {
|
|
1054
1274
|
result,
|
|
1055
1275
|
obj: block,
|
|
1056
|
-
metadata: { isEquivocated } = {},
|
|
1057
|
-
} = await this.validateReceivedMessage<BlockProposal, { isEquivocated: boolean }>(
|
|
1276
|
+
metadata: { isEquivocated, isOversized } = {},
|
|
1277
|
+
} = await this.validateReceivedMessage<BlockProposal, { isEquivocated: boolean; isOversized: boolean }>(
|
|
1058
1278
|
() => this.validateAndStoreBlockProposal(source, BlockProposal.fromBuffer(payloadData)),
|
|
1059
1279
|
msgId,
|
|
1060
1280
|
source,
|
|
1061
1281
|
TopicType.block_proposal,
|
|
1062
1282
|
);
|
|
1063
1283
|
|
|
1064
|
-
// If not accepted or
|
|
1065
|
-
|
|
1284
|
+
// If not accepted, equivocated, or oversized, return. Oversized proposals are re-broadcast as
|
|
1285
|
+
// slashing evidence but never attested or processed.
|
|
1286
|
+
if (result !== TopicValidatorResult.Accept || !block || isEquivocated || isOversized) {
|
|
1066
1287
|
return;
|
|
1067
1288
|
}
|
|
1068
1289
|
|
|
@@ -1077,13 +1298,12 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1077
1298
|
protected async validateAndStoreBlockProposal(
|
|
1078
1299
|
peerId: PeerId,
|
|
1079
1300
|
block: BlockProposal,
|
|
1080
|
-
): Promise<ReceivedMessageValidationResult<BlockProposal, { isEquivocated: boolean }>> {
|
|
1301
|
+
): Promise<ReceivedMessageValidationResult<BlockProposal, { isEquivocated: boolean; isOversized: boolean }>> {
|
|
1081
1302
|
const validationResult = await this.blockProposalValidator.validate(block);
|
|
1082
1303
|
|
|
1083
1304
|
if (validationResult.result === 'reject') {
|
|
1084
1305
|
this.logger.warn(`Penalizing peer ${peerId} for block proposal validation failure`);
|
|
1085
|
-
|
|
1086
|
-
return { result: TopicValidatorResult.Reject };
|
|
1306
|
+
return { result: TopicValidatorResult.Reject, severity: validationResult.severity };
|
|
1087
1307
|
}
|
|
1088
1308
|
|
|
1089
1309
|
if (validationResult.result === 'ignore') {
|
|
@@ -1093,6 +1313,12 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1093
1313
|
// Try to add the proposal: this handles existence check, cap check, and adding in one call
|
|
1094
1314
|
const { added, alreadyExists, count } = await this.mempools.attestationPool.tryAddBlockProposal(block);
|
|
1095
1315
|
const isEquivocated = count !== undefined && count > 1;
|
|
1316
|
+
// An oversized proposal (index at or beyond the consensus per-checkpoint limit) is structurally valid
|
|
1317
|
+
// proposer misbehavior: it is stored and re-broadcast as slashing evidence but never processed or
|
|
1318
|
+
// attested to. No-ops when maxBlocksPerCheckpoint is unset (local/test).
|
|
1319
|
+
const isOversized =
|
|
1320
|
+
this.config.maxBlocksPerCheckpoint !== undefined &&
|
|
1321
|
+
block.indexWithinCheckpoint >= this.config.maxBlocksPerCheckpoint;
|
|
1096
1322
|
|
|
1097
1323
|
// Duplicate proposal received, no need to re-broadcast
|
|
1098
1324
|
if (alreadyExists) {
|
|
@@ -1102,12 +1328,11 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1102
1328
|
proposer: block.getSender()?.toString(),
|
|
1103
1329
|
source: peerId.toString(),
|
|
1104
1330
|
});
|
|
1105
|
-
return { result: TopicValidatorResult.Ignore, obj: block, metadata: { isEquivocated } };
|
|
1331
|
+
return { result: TopicValidatorResult.Ignore, obj: block, metadata: { isEquivocated, isOversized } };
|
|
1106
1332
|
}
|
|
1107
1333
|
|
|
1108
1334
|
// Too many blocks received for this slot and index, penalize peer and do not re-broadcast
|
|
1109
1335
|
if (!added) {
|
|
1110
|
-
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.HighToleranceError);
|
|
1111
1336
|
this.logger.warn(`Penalizing peer for block proposal exceeding per-position cap`, {
|
|
1112
1337
|
...block.toBlockInfo(),
|
|
1113
1338
|
indexWithinCheckpoint: block.indexWithinCheckpoint,
|
|
@@ -1115,7 +1340,27 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1115
1340
|
proposer: block.getSender()?.toString(),
|
|
1116
1341
|
source: peerId.toString(),
|
|
1117
1342
|
});
|
|
1118
|
-
return {
|
|
1343
|
+
return {
|
|
1344
|
+
result: TopicValidatorResult.Reject,
|
|
1345
|
+
metadata: { isEquivocated, isOversized },
|
|
1346
|
+
severity: PeerErrorSeverity.HighToleranceError,
|
|
1347
|
+
};
|
|
1348
|
+
}
|
|
1349
|
+
|
|
1350
|
+
// The proposal was stored: if oversized, invoke the oversized callback so the proposer can be
|
|
1351
|
+
// slashed. Fired alongside (not instead of) equivocation detection below.
|
|
1352
|
+
if (isOversized) {
|
|
1353
|
+
const proposer = block.getSender();
|
|
1354
|
+
if (proposer) {
|
|
1355
|
+
this.logger.warn(`Detected oversized block proposal at slot ${block.slotNumber}`, {
|
|
1356
|
+
...block.toBlockInfo(),
|
|
1357
|
+
indexWithinCheckpoint: block.indexWithinCheckpoint,
|
|
1358
|
+
maxBlocksPerCheckpoint: this.config.maxBlocksPerCheckpoint,
|
|
1359
|
+
source: peerId.toString(),
|
|
1360
|
+
proposer: proposer.toString(),
|
|
1361
|
+
});
|
|
1362
|
+
this.oversizedProposalCallback?.({ slot: block.slotNumber, proposer });
|
|
1363
|
+
}
|
|
1119
1364
|
}
|
|
1120
1365
|
|
|
1121
1366
|
// If this was a duplicate proposal, do not process it, but do invoke the duplicate callback,
|
|
@@ -1131,11 +1376,11 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1131
1376
|
if (proposer && count === 2) {
|
|
1132
1377
|
this.duplicateProposalCallback?.({ slot: block.slotNumber, proposer, type: 'block' });
|
|
1133
1378
|
}
|
|
1134
|
-
return { result: TopicValidatorResult.Accept, obj: block, metadata: { isEquivocated } };
|
|
1379
|
+
return { result: TopicValidatorResult.Accept, obj: block, metadata: { isEquivocated, isOversized } };
|
|
1135
1380
|
}
|
|
1136
1381
|
|
|
1137
1382
|
// Otherwise, we're good to go!
|
|
1138
|
-
return { result: TopicValidatorResult.Accept, obj: block };
|
|
1383
|
+
return { result: TopicValidatorResult.Accept, obj: block, metadata: { isEquivocated: false, isOversized } };
|
|
1139
1384
|
}
|
|
1140
1385
|
|
|
1141
1386
|
// REFACTOR(palla): This method should be moved to the p2p_client or to a separate component,
|
|
@@ -1160,7 +1405,10 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1160
1405
|
// Note: Validators do NOT attest to individual blocks, only to checkpoint proposals.
|
|
1161
1406
|
const isValid = await this.blockReceivedCallback(block, sender);
|
|
1162
1407
|
if (!isValid) {
|
|
1163
|
-
this.logger.
|
|
1408
|
+
this.logger.info(`Block proposal validation failed for block ${block.blockNumber}`, block.toBlockInfo());
|
|
1409
|
+
// Release the protections this proposal created so its txs return to pending. Only entries still
|
|
1410
|
+
// keyed to this slot are cleared, so a tx referenced by a live proposal at another slot stays protected.
|
|
1411
|
+
await this.mempools.txPool.unprotectTxs(block.txHashes, slot);
|
|
1164
1412
|
}
|
|
1165
1413
|
}
|
|
1166
1414
|
|
|
@@ -1172,25 +1420,45 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1172
1420
|
const {
|
|
1173
1421
|
result,
|
|
1174
1422
|
obj: checkpoint,
|
|
1175
|
-
metadata: { isEquivocated, processBlock } = {},
|
|
1176
|
-
} = await this.validateReceivedMessage<
|
|
1423
|
+
metadata: { isEquivocated, processBlock, isOversized } = {},
|
|
1424
|
+
} = await this.validateReceivedMessage<
|
|
1425
|
+
CheckpointProposal,
|
|
1426
|
+
{ isEquivocated: boolean; processBlock: boolean; isOversized: boolean }
|
|
1427
|
+
>(
|
|
1177
1428
|
() => this.validateAndStoreCheckpointProposal(source, CheckpointProposal.fromBuffer(payloadData)),
|
|
1178
1429
|
msgId,
|
|
1179
1430
|
source,
|
|
1180
1431
|
TopicType.checkpoint_proposal,
|
|
1181
1432
|
);
|
|
1182
1433
|
|
|
1434
|
+
// An oversized checkpoint is re-broadcast as slashing evidence but never attested or processed.
|
|
1435
|
+
// Process checkpoint proposal if valid and neither equivocated nor oversized.
|
|
1436
|
+
const processCheckpointFn = () =>
|
|
1437
|
+
result === TopicValidatorResult.Accept && checkpoint && !isEquivocated && !isOversized
|
|
1438
|
+
? this.processValidCheckpointProposal(checkpoint.toCore(), source)
|
|
1439
|
+
: Promise.resolve();
|
|
1440
|
+
|
|
1183
1441
|
// If the checkpoint contained a valid last block, we process it even if the checkpoint itself is to be rejected
|
|
1184
1442
|
// TODO(palla/mbps): Is this ok? Should we be considering a block from a checkpoint that was equivocated?
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1443
|
+
const processBlockFn = () =>
|
|
1444
|
+
processBlock && checkpoint && checkpoint.getBlockProposal()
|
|
1445
|
+
? this.processValidBlockProposal(checkpoint.getBlockProposal()!, source)
|
|
1446
|
+
: Promise.resolve();
|
|
1447
|
+
|
|
1448
|
+
// A node that skips checkpoint validation attests without re-executing the embedded last block, so run
|
|
1449
|
+
// the checkpoint callback first: this creates and broadcasts the attestation before the block is
|
|
1450
|
+
// processed. Otherwise the block's re-execution — which can stall until the re-execution deadline
|
|
1451
|
+
// waiting for a parent that may never arrive — would delay the attestation past the slot's attestation
|
|
1452
|
+
// window, after which peers reject it as stale.
|
|
1453
|
+
if (this.config.skipCheckpointProposalValidation) {
|
|
1454
|
+
await processCheckpointFn();
|
|
1455
|
+
await processBlockFn();
|
|
1190
1456
|
return;
|
|
1191
1457
|
}
|
|
1192
1458
|
|
|
1193
|
-
|
|
1459
|
+
// Process the block first, since it's required for the checkpoint proposal validation.
|
|
1460
|
+
await processBlockFn();
|
|
1461
|
+
await processCheckpointFn();
|
|
1194
1462
|
}
|
|
1195
1463
|
|
|
1196
1464
|
/**
|
|
@@ -1203,13 +1471,17 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1203
1471
|
protected async validateAndStoreCheckpointProposal(
|
|
1204
1472
|
peerId: PeerId,
|
|
1205
1473
|
checkpoint: CheckpointProposal,
|
|
1206
|
-
): Promise<
|
|
1474
|
+
): Promise<
|
|
1475
|
+
ReceivedMessageValidationResult<
|
|
1476
|
+
CheckpointProposal,
|
|
1477
|
+
{ isEquivocated: boolean; processBlock: boolean; isOversized: boolean }
|
|
1478
|
+
>
|
|
1479
|
+
> {
|
|
1207
1480
|
const validationResult = await this.checkpointProposalValidator.validate(checkpoint);
|
|
1208
1481
|
|
|
1209
1482
|
if (validationResult.result === 'reject') {
|
|
1210
1483
|
this.logger.warn(`Penalizing peer ${peerId} for checkpoint proposal validation failure`);
|
|
1211
|
-
|
|
1212
|
-
return { result: TopicValidatorResult.Reject };
|
|
1484
|
+
return { result: TopicValidatorResult.Reject, severity: validationResult.severity };
|
|
1213
1485
|
}
|
|
1214
1486
|
|
|
1215
1487
|
if (validationResult.result === 'ignore') {
|
|
@@ -1219,25 +1491,30 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1219
1491
|
// Extract and try to add the block proposal first if present
|
|
1220
1492
|
const blockProposal = checkpoint.getBlockProposal();
|
|
1221
1493
|
let processBlock = false;
|
|
1494
|
+
let isOversized = false;
|
|
1222
1495
|
if (blockProposal) {
|
|
1223
1496
|
this.logger.debug(`Validating block proposal from propagated checkpoint`, {
|
|
1224
1497
|
[Attributes.SLOT_NUMBER]: checkpoint.slotNumber.toString(),
|
|
1225
1498
|
[Attributes.P2P_ID]: peerId.toString(),
|
|
1226
1499
|
});
|
|
1227
|
-
const
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
if (result === TopicValidatorResult.Reject || !obj || isEquivocated) {
|
|
1500
|
+
const blockProposalResult = await this.validateAndStoreBlockProposal(peerId, blockProposal);
|
|
1501
|
+
const { obj, metadata: { isEquivocated, isOversized: blockIsOversized } = {} } = blockProposalResult;
|
|
1502
|
+
isOversized = blockIsOversized ?? false;
|
|
1503
|
+
|
|
1504
|
+
if (blockProposalResult.result === TopicValidatorResult.Reject || !obj || isEquivocated) {
|
|
1233
1505
|
this.logger.debug(`Rejecting checkpoint due to invalid last block proposal`, {
|
|
1234
1506
|
[Attributes.SLOT_NUMBER]: checkpoint.slotNumber.toString(),
|
|
1235
1507
|
[Attributes.P2P_ID]: peerId.toString(),
|
|
1236
1508
|
isEquivocated,
|
|
1237
|
-
result,
|
|
1509
|
+
result: blockProposalResult.result,
|
|
1238
1510
|
});
|
|
1239
|
-
return {
|
|
1240
|
-
|
|
1511
|
+
return {
|
|
1512
|
+
result: TopicValidatorResult.Reject,
|
|
1513
|
+
severity:
|
|
1514
|
+
'severity' in blockProposalResult ? blockProposalResult.severity : PeerErrorSeverity.MidToleranceError,
|
|
1515
|
+
};
|
|
1516
|
+
} else if (blockProposalResult.result === TopicValidatorResult.Accept && obj && !isEquivocated && !isOversized) {
|
|
1517
|
+
// An oversized terminal block is re-broadcast as slashing evidence but never processed.
|
|
1241
1518
|
processBlock = true;
|
|
1242
1519
|
}
|
|
1243
1520
|
}
|
|
@@ -1257,20 +1534,24 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1257
1534
|
return {
|
|
1258
1535
|
result: TopicValidatorResult.Ignore,
|
|
1259
1536
|
obj: checkpoint,
|
|
1260
|
-
metadata: { isEquivocated, processBlock },
|
|
1537
|
+
metadata: { isEquivocated, processBlock, isOversized },
|
|
1261
1538
|
};
|
|
1262
1539
|
}
|
|
1263
1540
|
|
|
1264
|
-
// Too many checkpoint proposals received for this slot, penalize peer and do not re-broadcast
|
|
1541
|
+
// Too many checkpoint proposals received for this slot, penalize peer and do not re-broadcast.
|
|
1265
1542
|
// Note: We still return the checkpoint obj so the lastBlock can be processed if valid
|
|
1266
1543
|
if (!added) {
|
|
1267
|
-
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.HighToleranceError);
|
|
1268
1544
|
this.logger.warn(`Penalizing peer for checkpoint proposal exceeding per-slot cap`, {
|
|
1269
1545
|
...checkpoint.toCheckpointInfo(),
|
|
1270
1546
|
count,
|
|
1271
1547
|
source: peerId.toString(),
|
|
1272
1548
|
});
|
|
1273
|
-
return {
|
|
1549
|
+
return {
|
|
1550
|
+
result: TopicValidatorResult.Reject,
|
|
1551
|
+
obj: checkpoint,
|
|
1552
|
+
metadata: { isEquivocated, processBlock, isOversized },
|
|
1553
|
+
severity: PeerErrorSeverity.HighToleranceError,
|
|
1554
|
+
};
|
|
1274
1555
|
}
|
|
1275
1556
|
|
|
1276
1557
|
// If this was a duplicate proposal, do not process it, but do invoke the duplicate callback,
|
|
@@ -1289,12 +1570,16 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1289
1570
|
return {
|
|
1290
1571
|
result: TopicValidatorResult.Accept,
|
|
1291
1572
|
obj: checkpoint,
|
|
1292
|
-
metadata: { isEquivocated, processBlock },
|
|
1573
|
+
metadata: { isEquivocated, processBlock, isOversized },
|
|
1293
1574
|
};
|
|
1294
1575
|
}
|
|
1295
1576
|
|
|
1296
1577
|
// Otherwise, we're good to go!
|
|
1297
|
-
return {
|
|
1578
|
+
return {
|
|
1579
|
+
result: TopicValidatorResult.Accept,
|
|
1580
|
+
obj: checkpoint,
|
|
1581
|
+
metadata: { processBlock, isEquivocated, isOversized },
|
|
1582
|
+
};
|
|
1298
1583
|
}
|
|
1299
1584
|
|
|
1300
1585
|
/**
|
|
@@ -1315,9 +1600,11 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1315
1600
|
source: sender.toString(),
|
|
1316
1601
|
});
|
|
1317
1602
|
|
|
1603
|
+
await this.allNodesCheckpointReceivedCallback(checkpoint, sender);
|
|
1604
|
+
|
|
1318
1605
|
// Call the checkpoint received callback with the core version (without lastBlock)
|
|
1319
1606
|
// to validate and potentially generate attestations
|
|
1320
|
-
const attestations = await this.
|
|
1607
|
+
const attestations = await this.validatorCheckpointReceivedCallback(checkpoint, sender);
|
|
1321
1608
|
if (attestations && attestations.length > 0) {
|
|
1322
1609
|
// If the callback returned attestations, add them to the pool and propagate them
|
|
1323
1610
|
await this.mempools.attestationPool.addOwnCheckpointAttestations(attestations);
|
|
@@ -1340,82 +1627,87 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1340
1627
|
}
|
|
1341
1628
|
|
|
1342
1629
|
/**
|
|
1343
|
-
* Validate the requested block transactions
|
|
1630
|
+
* Validate the requested block transactions request-response consistency.
|
|
1631
|
+
* It does NOT validate the transactions themselves.
|
|
1344
1632
|
* @param request - The block transactions request.
|
|
1345
1633
|
* @param response - The block transactions response.
|
|
1346
1634
|
* @param peerId - The ID of the peer that made the request.
|
|
1347
|
-
* @returns True if the
|
|
1635
|
+
* @returns True if the request-response is consistent, false otherwise.
|
|
1348
1636
|
*/
|
|
1349
|
-
@trackSpan('Libp2pService.
|
|
1637
|
+
@trackSpan('Libp2pService.validateRequestedBlockTxsConsistency', request => ({
|
|
1350
1638
|
[Attributes.BLOCK_ARCHIVE]: request.archiveRoot.toString(),
|
|
1351
1639
|
}))
|
|
1352
|
-
protected async
|
|
1640
|
+
protected async validateRequestedBlockTxsConsistency(
|
|
1353
1641
|
request: BlockTxsRequest,
|
|
1354
1642
|
response: BlockTxsResponse,
|
|
1355
1643
|
peerId: PeerId,
|
|
1356
1644
|
): Promise<boolean> {
|
|
1357
|
-
const requestedTxValidator = this.createRequestedTxValidator();
|
|
1358
|
-
|
|
1359
1645
|
try {
|
|
1360
|
-
|
|
1646
|
+
// Check for duplicates txs (or hashes) in the response.
|
|
1647
|
+
const returnedHashes = response.txs.map(tx => tx.getTxHash().toString());
|
|
1648
|
+
const uniqueReturned = new Set(returnedHashes.map(h => h.toString()));
|
|
1649
|
+
if (uniqueReturned.size !== returnedHashes.length) {
|
|
1361
1650
|
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
1362
|
-
throw new ValidationError(
|
|
1363
|
-
|
|
1651
|
+
throw new ValidationError(`Received duplicate txs in block txs response`);
|
|
1652
|
+
}
|
|
1653
|
+
|
|
1654
|
+
// We get the block tx hashes from the proposal or the archiver.
|
|
1655
|
+
const proposal = await this.mempools.attestationPool.getBlockProposalByArchive(request.archiveRoot.toString());
|
|
1656
|
+
const blockTxHashes =
|
|
1657
|
+
proposal?.txHashes ??
|
|
1658
|
+
(await this.archiver.getBlock({ archive: request.archiveRoot }))?.body.txEffects.map(e => e.txHash);
|
|
1659
|
+
|
|
1660
|
+
// If we don't have the block, we can't verify membership/order of the returned txs.
|
|
1661
|
+
if (!blockTxHashes) {
|
|
1662
|
+
// This shouldn't happen, since we asked for the block (proposal).
|
|
1663
|
+
// Neither a local proposal nor an archived block: we cannot verify membership/order of the
|
|
1664
|
+
// returned txs. This is a local-state gap, not a peer fault, so we do not penalize.
|
|
1665
|
+
this.logger.warn(
|
|
1666
|
+
`Block ${request.archiveRoot.toString()} not found in attestation pool or archiver; cannot validate membership/order of returned txs`,
|
|
1364
1667
|
);
|
|
1668
|
+
// NOTE: We mark the response as invalid, given the limitations of a true/false return value.
|
|
1669
|
+
return false;
|
|
1365
1670
|
}
|
|
1366
1671
|
|
|
1367
|
-
|
|
1368
|
-
|
|
1672
|
+
// Verify that the returned tx hashes are a subset of (tx hashes by index) U (explicitly requested tx hashes).
|
|
1673
|
+
const uniqueRequestedHashes = new Set([
|
|
1674
|
+
// tx hashes requested by index.
|
|
1675
|
+
...request.txIndices.getTrueIndices().map(i => blockTxHashes[i].toString()),
|
|
1676
|
+
// explicitly requested tx hashes.
|
|
1677
|
+
...request.txHashes.map(h => h.toString()),
|
|
1678
|
+
]);
|
|
1679
|
+
if (!returnedHashes.every(h => uniqueRequestedHashes.has(h))) {
|
|
1680
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
|
|
1369
1681
|
throw new ValidationError(
|
|
1370
|
-
|
|
1682
|
+
'Returned txs should be a subset of (tx hashes by index) U (explicitly requested tx hashes)',
|
|
1371
1683
|
);
|
|
1372
1684
|
}
|
|
1373
1685
|
|
|
1374
|
-
//
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
const returnedHashes = await Promise.all(response.txs.map(tx => tx.getTxHash().toString()));
|
|
1380
|
-
const uniqueReturned = new Set(returnedHashes.map(h => h.toString()));
|
|
1381
|
-
if (uniqueReturned.size !== returnedHashes.length) {
|
|
1382
|
-
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
1383
|
-
throw new ValidationError(`Received duplicate txs in block txs response`);
|
|
1686
|
+
// Tx indices information is optional, but if present, we need to verify a few things.
|
|
1687
|
+
if (!response.peerHasBlock()) {
|
|
1688
|
+
this.logger.debug(`Peer ${peerId.toString()} signalled missing block`);
|
|
1689
|
+
return true;
|
|
1384
1690
|
}
|
|
1385
|
-
|
|
1691
|
+
|
|
1692
|
+
// If the response has a non-empty bitvector, it needs to be consistent with the number of txs in the block.
|
|
1693
|
+
if (response.txIndices.getLength() !== blockTxHashes.length) {
|
|
1386
1694
|
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
1387
1695
|
throw new ValidationError(
|
|
1388
|
-
`Received
|
|
1696
|
+
`Received block txs with mismatched bitvector length: expected ${blockTxHashes.length}, got ${response.txIndices.getLength()}`,
|
|
1389
1697
|
);
|
|
1390
1698
|
}
|
|
1391
1699
|
|
|
1392
|
-
//
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
);
|
|
1402
|
-
const allowedIndexSet = new Set(intersectIdx);
|
|
1403
|
-
const indices = returnedHashes.map(h => hashToIndexInProposal.get(h));
|
|
1404
|
-
const allAllowed = indices.every(idx => idx !== undefined && allowedIndexSet.has(idx));
|
|
1405
|
-
const strictlyIncreasing = indices.every((idx, i) => (i === 0 ? idx !== undefined : idx! > indices[i - 1]!));
|
|
1406
|
-
if (!allAllowed || !strictlyIncreasing) {
|
|
1407
|
-
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
|
|
1408
|
-
throw new ValidationError('Returned txs do not match expected subset/order for requested indices');
|
|
1409
|
-
}
|
|
1410
|
-
} else {
|
|
1411
|
-
// No local proposal, cannot check the membership/order of the returned txs
|
|
1412
|
-
this.logger.warn(
|
|
1413
|
-
`Block proposal not found for archive root ${request.archiveRoot.toString()}; cannot validate membership/order of returned txs`,
|
|
1414
|
-
);
|
|
1415
|
-
return false;
|
|
1700
|
+
// For every index we requested that the peer claims to have (per its bitvector), the
|
|
1701
|
+
// corresponding tx must be present in the response. A peer advertising availability but
|
|
1702
|
+
// withholding the tx is inconsistent.
|
|
1703
|
+
const returnedHashSet = new Set(returnedHashes);
|
|
1704
|
+
const expectedIndices = request.txIndices.getTrueIndices().filter(i => response.txIndices.isSet(i));
|
|
1705
|
+
const missingExpected = expectedIndices.some(i => !returnedHashSet.has(blockTxHashes[i].toString()));
|
|
1706
|
+
if (missingExpected) {
|
|
1707
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
|
|
1708
|
+
throw new ValidationError('Peer advertised requested txs via indices but did not return them');
|
|
1416
1709
|
}
|
|
1417
1710
|
|
|
1418
|
-
await Promise.all(response.txs.map(tx => this.validateRequestedTx(tx, peerId, requestedTxValidator)));
|
|
1419
1711
|
return true;
|
|
1420
1712
|
} catch (e: any) {
|
|
1421
1713
|
if (e instanceof ValidationError) {
|
|
@@ -1428,156 +1720,8 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1428
1720
|
}
|
|
1429
1721
|
}
|
|
1430
1722
|
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
*
|
|
1434
|
-
* The core component of this validator is that each tx hash MUST match the requested tx hash,
|
|
1435
|
-
* In order to perform this check, the tx proof must be verified.
|
|
1436
|
-
*
|
|
1437
|
-
* Note: This function is called from within `ReqResp.sendRequest` as part of the
|
|
1438
|
-
* ReqRespSubProtocol.TX subprotocol validation.
|
|
1439
|
-
*
|
|
1440
|
-
* @param requestedTxHash - The collection of the txs that was requested.
|
|
1441
|
-
* @param responseTx - The collection of txs that was received as a response to the request.
|
|
1442
|
-
* @param peerId - The peer ID of the peer that sent the tx.
|
|
1443
|
-
* @returns True if the whole collection of txs is valid, false otherwise.
|
|
1444
|
-
*/
|
|
1445
|
-
@trackSpan('Libp2pService.validateRequestedTx', (requestedTxHash, _responseTx) => ({
|
|
1446
|
-
[Attributes.TX_HASH]: requestedTxHash.toString(),
|
|
1447
|
-
}))
|
|
1448
|
-
private async validateRequestedTxs(requestedTxHash: TxHash[], responseTx: Tx[], peerId: PeerId): Promise<boolean> {
|
|
1449
|
-
const requested = new Set(requestedTxHash.map(h => h.toString()));
|
|
1450
|
-
const requestedTxValidator = this.createRequestedTxValidator();
|
|
1451
|
-
|
|
1452
|
-
//TODO: (mralj) - this is somewhat naive implementation, if single tx is invalid we consider the whole response invalid.
|
|
1453
|
-
// I think we should still extract the valid txs and return them, so that we can still use the response.
|
|
1454
|
-
try {
|
|
1455
|
-
await Promise.all(responseTx.map(tx => this.validateRequestedTx(tx, peerId, requestedTxValidator, requested)));
|
|
1456
|
-
return true;
|
|
1457
|
-
} catch (e: any) {
|
|
1458
|
-
if (e instanceof ValidationError) {
|
|
1459
|
-
this.logger.warn(`Failed to validate requested txs from peer ${peerId.toString()}, reason ${e.message}`);
|
|
1460
|
-
} else {
|
|
1461
|
-
this.logger.error(`Error during validation of requested txs`, e);
|
|
1462
|
-
}
|
|
1463
|
-
|
|
1464
|
-
return false;
|
|
1465
|
-
}
|
|
1466
|
-
}
|
|
1467
|
-
|
|
1468
|
-
/**
|
|
1469
|
-
* Validates a BLOCK response.
|
|
1470
|
-
*
|
|
1471
|
-
* If a local copy exists, enforces hash equality. If missing, rejects (no penalty) since the hash cannot be verified.
|
|
1472
|
-
* Penalizes on block number mismatch or hash mismatch.
|
|
1473
|
-
*
|
|
1474
|
-
* @param requestedBlockNumber - The requested block number.
|
|
1475
|
-
* @param responseBlock - The block returned by the peer.
|
|
1476
|
-
* @param peerId - The peer that returned the block.
|
|
1477
|
-
* @returns True if the response is valid, false otherwise.
|
|
1478
|
-
*/
|
|
1479
|
-
@trackSpan('Libp2pService.validateRequestedBlock', (requestedBlockNumber, _responseBlock) => ({
|
|
1480
|
-
[Attributes.BLOCK_NUMBER]: requestedBlockNumber.toString(),
|
|
1481
|
-
}))
|
|
1482
|
-
protected async validateRequestedBlock(
|
|
1483
|
-
requestedBlockNumber: Fr,
|
|
1484
|
-
responseBlock: L2Block,
|
|
1485
|
-
peerId: PeerId,
|
|
1486
|
-
): Promise<boolean> {
|
|
1487
|
-
try {
|
|
1488
|
-
const reqNum = Number(requestedBlockNumber.toString());
|
|
1489
|
-
if (responseBlock.number !== reqNum) {
|
|
1490
|
-
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
|
|
1491
|
-
return false;
|
|
1492
|
-
}
|
|
1493
|
-
|
|
1494
|
-
const local = await this.archiver.getBlock(BlockNumber(reqNum));
|
|
1495
|
-
if (!local) {
|
|
1496
|
-
// We are missing the local block; we cannot verify the hash yet. Reject without penalizing.
|
|
1497
|
-
// TODO: Consider extending this validator to accept an expected hash or
|
|
1498
|
-
// performing quorum-based checks when using P2P syncing prior to L1 sync.
|
|
1499
|
-
this.logger.warn(`Local block ${reqNum} not found; rejecting BLOCK response without hash verification`);
|
|
1500
|
-
return false;
|
|
1501
|
-
}
|
|
1502
|
-
const [localHash, respHash] = await Promise.all([local.hash(), responseBlock.hash()]);
|
|
1503
|
-
if (!localHash.equals(respHash)) {
|
|
1504
|
-
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
1505
|
-
return false;
|
|
1506
|
-
}
|
|
1507
|
-
|
|
1508
|
-
return true;
|
|
1509
|
-
} catch (e) {
|
|
1510
|
-
this.logger.warn(`Error validating requested block`, e);
|
|
1511
|
-
return false;
|
|
1512
|
-
}
|
|
1513
|
-
}
|
|
1514
|
-
|
|
1515
|
-
protected async validateRequestedTx(
|
|
1516
|
-
tx: Tx,
|
|
1517
|
-
peerId: PeerId,
|
|
1518
|
-
txValidator: TxValidator,
|
|
1519
|
-
requested?: Set<`0x${string}`>,
|
|
1520
|
-
) {
|
|
1521
|
-
const penalize = (severity: PeerErrorSeverity) => this.peerManager.penalizePeer(peerId, severity);
|
|
1522
|
-
if (requested && !requested.has(tx.getTxHash().toString())) {
|
|
1523
|
-
penalize(PeerErrorSeverity.MidToleranceError);
|
|
1524
|
-
throw new ValidationError(`Received tx with hash ${tx.getTxHash().toString()} that was not requested.`);
|
|
1525
|
-
}
|
|
1526
|
-
|
|
1527
|
-
const { result } = await txValidator.validateTx(tx);
|
|
1528
|
-
if (result === 'invalid') {
|
|
1529
|
-
penalize(PeerErrorSeverity.LowToleranceError);
|
|
1530
|
-
throw new ValidationError(`Received tx with hash ${tx.getTxHash().toString()} that is invalid.`);
|
|
1531
|
-
}
|
|
1532
|
-
}
|
|
1533
|
-
|
|
1534
|
-
protected createRequestedTxValidator(): TxValidator {
|
|
1535
|
-
return createTxReqRespValidator(this.proofVerifier, {
|
|
1536
|
-
l1ChainId: this.config.l1ChainId,
|
|
1537
|
-
rollupVersion: this.config.rollupVersion,
|
|
1538
|
-
});
|
|
1539
|
-
}
|
|
1540
|
-
|
|
1541
|
-
@trackSpan('Libp2pService.validatePropagatedTx', tx => ({
|
|
1542
|
-
[Attributes.TX_HASH]: tx.getTxHash().toString(),
|
|
1543
|
-
}))
|
|
1544
|
-
protected async validatePropagatedTx(tx: Tx, peerId: PeerId): Promise<boolean> {
|
|
1545
|
-
const currentBlockNumber = await this.archiver.getBlockNumber();
|
|
1546
|
-
|
|
1547
|
-
// We accept transactions if they are not expired by the next slot (checked based on the IncludeByTimestamp field)
|
|
1548
|
-
const { ts: nextSlotTimestamp } = this.epochCache.getEpochAndSlotInNextL1Slot();
|
|
1549
|
-
const messageValidators = await this.createMessageValidators(currentBlockNumber, nextSlotTimestamp);
|
|
1550
|
-
|
|
1551
|
-
for (const validator of messageValidators) {
|
|
1552
|
-
const outcome = await this.runValidations(tx, validator);
|
|
1553
|
-
|
|
1554
|
-
if (outcome.allPassed) {
|
|
1555
|
-
continue;
|
|
1556
|
-
}
|
|
1557
|
-
const { name } = outcome.failure;
|
|
1558
|
-
let { severity } = outcome.failure;
|
|
1559
|
-
|
|
1560
|
-
// Double spend validator has a special case handler
|
|
1561
|
-
if (name === 'doubleSpendValidator') {
|
|
1562
|
-
const txBlockNumber = BlockNumber(currentBlockNumber + 1); // tx is expected to be in the next block
|
|
1563
|
-
severity = await this.handleDoubleSpendFailure(tx, txBlockNumber);
|
|
1564
|
-
}
|
|
1565
|
-
|
|
1566
|
-
this.peerManager.penalizePeer(peerId, severity);
|
|
1567
|
-
return false;
|
|
1568
|
-
}
|
|
1569
|
-
return true;
|
|
1570
|
-
}
|
|
1571
|
-
|
|
1572
|
-
private async getGasFees(blockNumber: BlockNumber): Promise<GasFees> {
|
|
1573
|
-
if (blockNumber === this.feesCache?.blockNumber) {
|
|
1574
|
-
return this.feesCache.gasFees;
|
|
1575
|
-
}
|
|
1576
|
-
|
|
1577
|
-
const header = await this.archiver.getBlockHeader(blockNumber);
|
|
1578
|
-
const gasFees = header?.globalVariables.gasFees ?? GasFees.empty();
|
|
1579
|
-
this.feesCache = { blockNumber, gasFees };
|
|
1580
|
-
return gasFees;
|
|
1723
|
+
private getGasFees(): Promise<GasFees> {
|
|
1724
|
+
return this.blockMinFeesProvider.getCurrentMinFees();
|
|
1581
1725
|
}
|
|
1582
1726
|
|
|
1583
1727
|
/**
|
|
@@ -1591,65 +1735,70 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1591
1735
|
l1ChainId: this.config.l1ChainId,
|
|
1592
1736
|
rollupVersion: this.config.rollupVersion,
|
|
1593
1737
|
proofVerifier: this.proofVerifier,
|
|
1738
|
+
txValidationCache: this.txValidationCache,
|
|
1594
1739
|
},
|
|
1595
1740
|
peerScoring: this.peerManager,
|
|
1741
|
+
validateRequestedBlockTxsConsistency: this.validateRequestedBlockTxsConsistency.bind(this),
|
|
1596
1742
|
};
|
|
1597
1743
|
}
|
|
1598
1744
|
|
|
1599
|
-
public async
|
|
1600
|
-
const
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1745
|
+
public async validateTxsReceivedInBlockProposal(txs: Tx[]): Promise<void> {
|
|
1746
|
+
const validator = createTxValidatorForBlockProposalReceivedTxs(
|
|
1747
|
+
this.proofVerifier,
|
|
1748
|
+
{ l1ChainId: this.config.l1ChainId, rollupVersion: this.config.rollupVersion },
|
|
1749
|
+
this.logger.getBindings(),
|
|
1750
|
+
this.txValidationCache,
|
|
1751
|
+
);
|
|
1605
1752
|
|
|
1606
|
-
await Promise.all(
|
|
1753
|
+
const results = await Promise.all(
|
|
1607
1754
|
txs.map(async tx => {
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
if (!outcome.allPassed) {
|
|
1611
|
-
throw new Error('Invalid tx detected', { cause: { outcome } });
|
|
1612
|
-
}
|
|
1613
|
-
}
|
|
1755
|
+
const result = await validator.validateTx(tx);
|
|
1756
|
+
return result.result !== 'invalid';
|
|
1614
1757
|
}),
|
|
1615
1758
|
);
|
|
1759
|
+
if (results.some(value => value === false)) {
|
|
1760
|
+
throw new Error('Invalid tx detected');
|
|
1761
|
+
}
|
|
1616
1762
|
}
|
|
1617
1763
|
|
|
1618
|
-
/**
|
|
1619
|
-
|
|
1620
|
-
*
|
|
1621
|
-
* Each validator is a pair of a validator and a severity.
|
|
1622
|
-
* If a validator fails, the peer is penalized with the severity of the validator.
|
|
1623
|
-
*
|
|
1624
|
-
* @param currentBlockNumber - The current synced block number.
|
|
1625
|
-
* @param nextSlotTimestamp - The timestamp of the next slot (used to validate txs are not expired).
|
|
1626
|
-
* @returns The message validators.
|
|
1627
|
-
*/
|
|
1628
|
-
private async createMessageValidators(
|
|
1764
|
+
/** Creates the first stage (fast) validators for gossiped transactions. */
|
|
1765
|
+
protected async createFirstStageMessageValidators(
|
|
1629
1766
|
currentBlockNumber: BlockNumber,
|
|
1630
1767
|
nextSlotTimestamp: UInt64,
|
|
1631
|
-
): Promise<Record<string,
|
|
1632
|
-
const gasFees = await this.getGasFees(
|
|
1633
|
-
const allowedInSetup =
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1768
|
+
): Promise<Record<string, TransactionValidator>> {
|
|
1769
|
+
const gasFees = await this.getGasFees();
|
|
1770
|
+
const allowedInSetup = [
|
|
1771
|
+
...(await getDefaultAllowedSetupFunctions()),
|
|
1772
|
+
...(this.config.txPublicSetupAllowListExtend ?? []),
|
|
1773
|
+
];
|
|
1774
|
+
const blockNumber = BlockNumber(currentBlockNumber + 1);
|
|
1775
|
+
const l1Constants = await this.archiver.getL1Constants();
|
|
1776
|
+
const networkTxGasLimits = getNetworkTxGasLimits(this.config, l1Constants);
|
|
1777
|
+
|
|
1778
|
+
return createFirstStageTxValidationsForGossipedTransactions(
|
|
1638
1779
|
nextSlotTimestamp,
|
|
1639
|
-
|
|
1780
|
+
blockNumber,
|
|
1640
1781
|
this.worldStateSynchronizer,
|
|
1641
1782
|
gasFees,
|
|
1642
1783
|
this.config.l1ChainId,
|
|
1643
1784
|
this.config.rollupVersion,
|
|
1644
1785
|
protocolContractsHash,
|
|
1645
1786
|
this.archiver,
|
|
1646
|
-
this.proofVerifier,
|
|
1647
1787
|
!this.config.disableTransactions,
|
|
1648
1788
|
allowedInSetup,
|
|
1649
1789
|
this.logger.getBindings(),
|
|
1790
|
+
{
|
|
1791
|
+
maxTxL2Gas: networkTxGasLimits.l2Gas,
|
|
1792
|
+
maxTxDAGas: networkTxGasLimits.daGas,
|
|
1793
|
+
},
|
|
1650
1794
|
);
|
|
1651
1795
|
}
|
|
1652
1796
|
|
|
1797
|
+
/** Creates the second stage (expensive proof verification) validators for gossiped transactions. */
|
|
1798
|
+
protected createSecondStageMessageValidators(): Record<string, TransactionValidator> {
|
|
1799
|
+
return createSecondStageTxValidationsForGossipedTransactions(this.proofVerifier, this.logger.getBindings());
|
|
1800
|
+
}
|
|
1801
|
+
|
|
1653
1802
|
/**
|
|
1654
1803
|
* Run validations on a tx.
|
|
1655
1804
|
* @param tx - The tx to validate.
|
|
@@ -1658,7 +1807,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1658
1807
|
*/
|
|
1659
1808
|
private async runValidations(
|
|
1660
1809
|
tx: Tx,
|
|
1661
|
-
messageValidators: Record<string,
|
|
1810
|
+
messageValidators: Record<string, TransactionValidator>,
|
|
1662
1811
|
): Promise<ValidationOutcome> {
|
|
1663
1812
|
const validationPromises = Object.entries(messageValidators).map(async ([name, { validator, severity }]) => {
|
|
1664
1813
|
const { result } = await validator.validateTx(tx);
|
|
@@ -1667,8 +1816,10 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1667
1816
|
|
|
1668
1817
|
// A promise that resolves when all validations have been run
|
|
1669
1818
|
const allValidations = await Promise.all(validationPromises);
|
|
1670
|
-
const
|
|
1671
|
-
if (
|
|
1819
|
+
const failures = allValidations.filter(x => !x.isValid);
|
|
1820
|
+
if (failures.length > 0) {
|
|
1821
|
+
// Pick the most severe failure (lowest tolerance = harshest penalty)
|
|
1822
|
+
const failed = maxBy(failures, f => PeerErrorSeverityByHarshness.indexOf(f.severity))!;
|
|
1672
1823
|
return {
|
|
1673
1824
|
allPassed: false,
|
|
1674
1825
|
failure: {
|
|
@@ -1721,31 +1872,6 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1721
1872
|
return PeerErrorSeverity.HighToleranceError;
|
|
1722
1873
|
}
|
|
1723
1874
|
|
|
1724
|
-
/**
|
|
1725
|
-
* Validate a checkpoint attestation.
|
|
1726
|
-
*
|
|
1727
|
-
* @param attestation - The checkpoint attestation to validate.
|
|
1728
|
-
* @returns True if the checkpoint attestation is valid, false otherwise.
|
|
1729
|
-
*/
|
|
1730
|
-
@trackSpan('Libp2pService.validateCheckpointAttestation', async (_, attestation) => ({
|
|
1731
|
-
[Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber,
|
|
1732
|
-
[Attributes.BLOCK_ARCHIVE]: attestation.archive.toString(),
|
|
1733
|
-
[Attributes.P2P_ID]: await attestation.p2pMessageLoggingIdentifier().then(i => i.toString()),
|
|
1734
|
-
}))
|
|
1735
|
-
public async validateCheckpointAttestation(
|
|
1736
|
-
peerId: PeerId,
|
|
1737
|
-
attestation: CheckpointAttestation,
|
|
1738
|
-
): Promise<P2PValidationResult> {
|
|
1739
|
-
const result = await this.checkpointAttestationValidator.validate(attestation);
|
|
1740
|
-
|
|
1741
|
-
if (result.result === 'reject') {
|
|
1742
|
-
this.logger.warn(`Penalizing peer ${peerId} for checkpoint attestation validation failure`);
|
|
1743
|
-
this.peerManager.penalizePeer(peerId, result.severity);
|
|
1744
|
-
}
|
|
1745
|
-
|
|
1746
|
-
return result;
|
|
1747
|
-
}
|
|
1748
|
-
|
|
1749
1875
|
public getPeerScore(peerId: PeerId): number {
|
|
1750
1876
|
return this.node.services.pubsub.score.score(peerId.toString());
|
|
1751
1877
|
}
|