@aztec/p2p 0.0.1-commit.c2eed6949 → 0.0.1-commit.c52d6e7
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 +7 -6
- 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 +4 -3
- package/dest/client/factory.d.ts.map +1 -1
- package/dest/client/factory.js +36 -26
- package/dest/client/interface.d.ts +52 -12
- package/dest/client/interface.d.ts.map +1 -1
- package/dest/client/p2p_client.d.ts +34 -19
- package/dest/client/p2p_client.d.ts.map +1 -1
- package/dest/client/p2p_client.js +105 -46
- package/dest/config.d.ts +143 -107
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +72 -26
- 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/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 +98 -56
- package/dest/mem_pools/attestation_pool/attestation_pool.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/attestation_pool.js +269 -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 +218 -59
- package/dest/mem_pools/attestation_pool/mocks.d.ts +1 -1
- package/dest/mem_pools/attestation_pool/mocks.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/mocks.js +6 -4
- 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 +9 -4
- package/dest/mem_pools/instrumentation.d.ts.map +1 -1
- package/dest/mem_pools/instrumentation.js +28 -9
- 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 +3 -3
- package/dest/mem_pools/tx_pool_v2/deleted_pool.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/deleted_pool.js +6 -6
- 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 +3 -3
- package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.d.ts +1 -1
- 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 +3 -1
- package/dest/mem_pools/tx_pool_v2/eviction/index.d.ts +2 -1
- package/dest/mem_pools/tx_pool_v2/eviction/index.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/index.js +1 -0
- package/dest/mem_pools/tx_pool_v2/eviction/insufficient_fee_per_gas_eviction_rule.d.ts +16 -0
- package/dest/mem_pools/tx_pool_v2/eviction/insufficient_fee_per_gas_eviction_rule.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/eviction/insufficient_fee_per_gas_eviction_rule.js +64 -0
- package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_mining_rule.d.ts +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_mining_rule.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_mining_rule.js +3 -4
- package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.d.ts +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.js +6 -7
- package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.d.ts +1 -1
- 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 +6 -5
- package/dest/mem_pools/tx_pool_v2/interfaces.d.ts +33 -5
- package/dest/mem_pools/tx_pool_v2/interfaces.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/interfaces.js +2 -1
- package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts +5 -2
- package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/tx_metadata.js +13 -6
- package/dest/mem_pools/tx_pool_v2/tx_pool_indices.d.ts +15 -1
- 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 +31 -0
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts +9 -3
- 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 +19 -8
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts +17 -4
- 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 +208 -118
- 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 -16
- 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 +8 -3
- package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts.map +1 -1
- package/dest/msg_validators/proposal_validator/block_proposal_validator.js +2 -2
- package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts +8 -3
- package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts.map +1 -1
- package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.js +8 -2
- package/dest/msg_validators/proposal_validator/proposal_validator.d.ts +25 -3
- package/dest/msg_validators/proposal_validator/proposal_validator.d.ts.map +1 -1
- package/dest/msg_validators/proposal_validator/proposal_validator.js +85 -15
- package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts +1 -1
- package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/aggregate_tx_validator.js +8 -15
- package/dest/msg_validators/tx_validator/allowed_public_setup.js +3 -3
- 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/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 +1 -0
- package/dest/msg_validators/tx_validator/factory.d.ts +14 -15
- package/dest/msg_validators/tx_validator/factory.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/factory.js +29 -16
- package/dest/msg_validators/tx_validator/gas_validator.d.ts +47 -10
- package/dest/msg_validators/tx_validator/gas_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/gas_validator.js +65 -48
- package/dest/msg_validators/tx_validator/index.d.ts +3 -1
- package/dest/msg_validators/tx_validator/index.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/index.js +2 -0
- package/dest/msg_validators/tx_validator/phases_validator.js +2 -2
- package/dest/msg_validators/tx_validator/timestamp_validator.js +1 -1
- 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 -25
- 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 +15 -15
- package/dest/services/dummy_service.d.ts.map +1 -1
- package/dest/services/dummy_service.js +15 -16
- package/dest/services/encoding.d.ts +19 -6
- package/dest/services/encoding.d.ts.map +1 -1
- package/dest/services/encoding.js +25 -15
- package/dest/services/gossipsub/topic_score_params.d.ts +6 -12
- package/dest/services/gossipsub/topic_score_params.d.ts.map +1 -1
- package/dest/services/gossipsub/topic_score_params.js +4 -14
- 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 +41 -40
- package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
- package/dest/services/libp2p/libp2p_service.js +323 -275
- 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 +77 -23
- 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 +1 -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 +35 -44
- package/dest/services/reqresp/batch-tx-requester/interface.d.ts +8 -5
- package/dest/services/reqresp/batch-tx-requester/interface.d.ts.map +1 -1
- 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 +59 -209
- package/dest/services/service.d.ts +27 -16
- package/dest/services/service.d.ts.map +1 -1
- package/dest/services/tx_collection/config.d.ts +2 -23
- package/dest/services/tx_collection/config.d.ts.map +1 -1
- package/dest/services/tx_collection/config.js +2 -55
- package/dest/services/tx_collection/file_store_tx_collection.d.ts +12 -28
- package/dest/services/tx_collection/file_store_tx_collection.d.ts.map +1 -1
- package/dest/services/tx_collection/file_store_tx_collection.js +43 -83
- package/dest/services/tx_collection/file_store_tx_source.d.ts +5 -4
- package/dest/services/tx_collection/file_store_tx_source.d.ts.map +1 -1
- package/dest/services/tx_collection/file_store_tx_source.js +39 -29
- 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.d.ts +1 -1
- package/dest/services/tx_collection/instrumentation.d.ts.map +1 -1
- package/dest/services/tx_collection/instrumentation.js +0 -2
- package/dest/services/tx_collection/tx_collection.d.ts +35 -51
- package/dest/services/tx_collection/tx_collection.d.ts.map +1 -1
- package/dest/services/tx_collection/tx_collection.js +275 -119
- package/dest/services/tx_collection/tx_collection_sink.d.ts +1 -1
- package/dest/services/tx_collection/tx_collection_sink.js +2 -2
- package/dest/services/tx_collection/tx_source.d.ts +6 -5
- package/dest/services/tx_collection/tx_source.d.ts.map +1 -1
- package/dest/services/tx_collection/tx_source.js +13 -8
- package/dest/services/tx_file_store/tx_file_store.d.ts +1 -3
- package/dest/services/tx_file_store/tx_file_store.d.ts.map +1 -1
- package/dest/services/tx_file_store/tx_file_store.js +4 -14
- package/dest/services/tx_provider.d.ts +3 -1
- package/dest/services/tx_provider.d.ts.map +1 -1
- package/dest/services/tx_provider.js +3 -0
- package/dest/test-helpers/make-test-p2p-clients.d.ts +1 -1
- package/dest/test-helpers/make-test-p2p-clients.d.ts.map +1 -1
- package/dest/test-helpers/make-test-p2p-clients.js +5 -2
- package/dest/test-helpers/mock-pubsub.d.ts +21 -12
- package/dest/test-helpers/mock-pubsub.d.ts.map +1 -1
- package/dest/test-helpers/mock-pubsub.js +39 -47
- package/dest/test-helpers/reqresp-nodes.d.ts +4 -5
- package/dest/test-helpers/reqresp-nodes.d.ts.map +1 -1
- package/dest/test-helpers/reqresp-nodes.js +16 -18
- 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 +15 -14
- package/dest/test-helpers/testbench-utils.d.ts.map +1 -1
- package/dest/test-helpers/testbench-utils.js +30 -14
- 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 +101 -39
- package/dest/testbench/worker_client_manager.d.ts +10 -6
- package/dest/testbench/worker_client_manager.d.ts.map +1 -1
- package/dest/testbench/worker_client_manager.js +51 -9
- package/dest/util.d.ts +8 -8
- package/dest/util.d.ts.map +1 -1
- package/dest/util.js +38 -10
- package/dest/versioning.d.ts +3 -6
- package/dest/versioning.d.ts.map +1 -1
- package/dest/versioning.js +3 -24
- package/package.json +15 -16
- package/src/bootstrap/bootstrap.ts +17 -3
- package/src/client/factory.ts +54 -25
- package/src/client/interface.ts +48 -18
- package/src/client/p2p_client.ts +125 -79
- package/src/client/test/{tx_proposal_collector/README.md → p2p_client.batch_tx_requester.bench.README.md} +23 -53
- package/src/config.ts +146 -34
- package/src/errors/p2p-service.error.ts +11 -0
- package/src/errors/reqresp.error.ts +13 -19
- package/src/index.ts +0 -1
- package/src/mem_pools/attestation_pool/attestation_pool.ts +324 -239
- package/src/mem_pools/attestation_pool/attestation_pool_test_suite.ts +238 -63
- package/src/mem_pools/attestation_pool/mocks.ts +13 -8
- package/src/mem_pools/index.ts +0 -3
- package/src/mem_pools/instrumentation.ts +18 -12
- package/src/mem_pools/tx_pool_v2/archive/tx_archive.ts +1 -9
- package/src/mem_pools/tx_pool_v2/deleted_pool.ts +7 -7
- package/src/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.ts +2 -4
- package/src/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.ts +3 -2
- package/src/mem_pools/tx_pool_v2/eviction/index.ts +1 -0
- package/src/mem_pools/tx_pool_v2/eviction/insufficient_fee_per_gas_eviction_rule.ts +67 -0
- package/src/mem_pools/tx_pool_v2/eviction/invalid_txs_after_mining_rule.ts +1 -3
- package/src/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.ts +5 -7
- package/src/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.ts +5 -6
- package/src/mem_pools/tx_pool_v2/interfaces.ts +31 -4
- package/src/mem_pools/tx_pool_v2/tx_metadata.ts +20 -8
- package/src/mem_pools/tx_pool_v2/tx_pool_indices.ts +35 -0
- package/src/mem_pools/tx_pool_v2/tx_pool_v2.ts +22 -8
- package/src/mem_pools/tx_pool_v2/tx_pool_v2_impl.ts +233 -123
- package/src/msg_validators/attestation_validator/attestation_validator.ts +46 -15
- package/src/msg_validators/attestation_validator/fisherman_attestation_validator.ts +15 -7
- package/src/msg_validators/proposal_validator/README.md +1 -1
- package/src/msg_validators/proposal_validator/block_proposal_validator.ts +15 -3
- package/src/msg_validators/proposal_validator/checkpoint_proposal_validator.ts +26 -3
- package/src/msg_validators/proposal_validator/proposal_validator.ts +94 -12
- package/src/msg_validators/tx_validator/README.md +13 -3
- package/src/msg_validators/tx_validator/aggregate_tx_validator.ts +3 -12
- package/src/msg_validators/tx_validator/allowed_public_setup.ts +3 -3
- 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/data_validator.ts +2 -0
- package/src/msg_validators/tx_validator/factory.ts +37 -20
- package/src/msg_validators/tx_validator/gas_validator.ts +99 -54
- package/src/msg_validators/tx_validator/index.ts +2 -0
- package/src/msg_validators/tx_validator/phases_validator.ts +2 -2
- package/src/msg_validators/tx_validator/timestamp_validator.ts +1 -1
- 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 -16
- package/src/services/discv5/persisted_enr_store.ts +158 -0
- package/src/services/dummy_service.ts +20 -39
- package/src/services/encoding.ts +28 -20
- package/src/services/gossipsub/README.md +33 -11
- package/src/services/gossipsub/topic_score_params.ts +9 -18
- package/src/services/libp2p/instrumentation.ts +14 -0
- package/src/services/libp2p/libp2p_service.ts +371 -301
- package/src/services/peer-manager/peer_manager.ts +84 -22
- package/src/services/peer-manager/peer_scoring.ts +102 -8
- package/src/services/reqresp/README.md +2 -37
- package/src/services/reqresp/batch-tx-requester/batch_tx_requester.ts +39 -52
- package/src/services/reqresp/batch-tx-requester/interface.ts +11 -4
- 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 +69 -252
- package/src/services/service.ts +32 -32
- package/src/services/tx_collection/config.ts +3 -80
- package/src/services/tx_collection/file_store_tx_collection.ts +54 -103
- package/src/services/tx_collection/file_store_tx_source.ts +43 -31
- package/src/services/tx_collection/index.ts +1 -6
- package/src/services/tx_collection/instrumentation.ts +1 -7
- package/src/services/tx_collection/tx_collection.ts +330 -173
- package/src/services/tx_collection/tx_collection_sink.ts +2 -2
- package/src/services/tx_collection/tx_source.ts +10 -8
- package/src/services/tx_file_store/tx_file_store.ts +5 -17
- package/src/services/tx_provider.ts +5 -0
- package/src/test-helpers/make-test-p2p-clients.ts +3 -0
- package/src/test-helpers/mock-pubsub.ts +41 -64
- package/src/test-helpers/reqresp-nodes.ts +12 -22
- package/src/test-helpers/test_tx_provider.ts +5 -0
- package/src/test-helpers/testbench-utils.ts +36 -26
- package/src/testbench/p2p_client_testbench_worker.ts +108 -53
- package/src/testbench/worker_client_manager.ts +59 -20
- package/src/util.ts +33 -14
- 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 -304
- 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 -123
- 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 -402
- 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 -38
- 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 -51
- package/dest/services/tx_collection/fast_tx_collection.d.ts.map +0 -1
- package/dest/services/tx_collection/fast_tx_collection.js +0 -311
- 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 -50
- package/dest/services/tx_collection/slow_tx_collection.d.ts +0 -57
- package/dest/services/tx_collection/slow_tx_collection.d.ts.map +0 -1
- package/dest/services/tx_collection/slow_tx_collection.js +0 -211
- package/src/client/test/tx_proposal_collector/proposal_tx_collector_worker.ts +0 -343
- 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 -163
- 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 -321
- package/src/msg_validators/clock_tolerance.ts +0 -52
- 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 -361
- package/src/services/tx_collection/proposal_tx_collector.ts +0 -108
- package/src/services/tx_collection/slow_tx_collection.ts +0 -266
|
@@ -370,17 +370,20 @@ function applyDecs2203RFactory() {
|
|
|
370
370
|
function _apply_decs_2203_r(targetClass, memberDecs, classDecs, parentClass) {
|
|
371
371
|
return (_apply_decs_2203_r = applyDecs2203RFactory())(targetClass, memberDecs, classDecs, parentClass);
|
|
372
372
|
}
|
|
373
|
-
var _dec, _dec1, _dec2, _dec3, _dec4, _dec5,
|
|
373
|
+
var _dec, _dec1, _dec2, _dec3, _dec4, _dec5, _initProto;
|
|
374
374
|
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
375
|
-
import { maxBy } from '@aztec/foundation/collection';
|
|
375
|
+
import { compactArray, maxBy, merge } from '@aztec/foundation/collection';
|
|
376
376
|
import { createLibp2pComponentLogger, createLogger } from '@aztec/foundation/log';
|
|
377
377
|
import { RunningPromise } from '@aztec/foundation/running-promise';
|
|
378
378
|
import { Timer } from '@aztec/foundation/timer';
|
|
379
379
|
import { protocolContractsHash } from '@aztec/protocol-contracts';
|
|
380
|
-
import {
|
|
380
|
+
import { DEFAULT_MAX_BLOCKS_PER_CHECKPOINT } from '@aztec/stdlib/config';
|
|
381
|
+
import { getNetworkTxGasLimits } from '@aztec/stdlib/gas';
|
|
381
382
|
import { BlockProposal, CheckpointAttestation, CheckpointProposal, P2PMessage, PeerErrorSeverity, PeerErrorSeverityByHarshness, TopicType, createTopicString, getTopicsForConfig, metricsTopicStrToLabels } from '@aztec/stdlib/p2p';
|
|
383
|
+
import { ConsensusTimetable, getDefaultCheckpointProposalSyncGrace } from '@aztec/stdlib/timetable';
|
|
382
384
|
import { MerkleTreeId } from '@aztec/stdlib/trees';
|
|
383
385
|
import { Tx } from '@aztec/stdlib/tx';
|
|
386
|
+
import { InvalidBlockProposalTxsError } from '@aztec/stdlib/validators';
|
|
384
387
|
import { compressComponentVersions } from '@aztec/stdlib/versioning';
|
|
385
388
|
import { Attributes, OtelMetricsAdapter, SpanStatusCode, WithTracer, trackSpan } from '@aztec/telemetry-client';
|
|
386
389
|
import { gossipsub } from '@chainsafe/libp2p-gossipsub';
|
|
@@ -396,22 +399,36 @@ import { tcp } from '@libp2p/tcp';
|
|
|
396
399
|
import { multiaddr } from '@multiformats/multiaddr';
|
|
397
400
|
import { ENR } from '@nethermindeth/enr';
|
|
398
401
|
import { createLibp2p } from 'libp2p';
|
|
402
|
+
import { CheckpointProposalReceivedCallbackNotRegisteredError } from '../../errors/p2p-service.error.js';
|
|
399
403
|
import { BlockProposalValidator, CheckpointAttestationValidator, CheckpointProposalValidator, DoubleSpendTxValidator, FishermanAttestationValidator, getDefaultAllowedSetupFunctions } from '../../msg_validators/index.js';
|
|
400
404
|
import { MessageSeenValidator } from '../../msg_validators/msg_seen_validator/msg_seen_validator.js';
|
|
401
|
-
import { createFirstStageTxValidationsForGossipedTransactions, createSecondStageTxValidationsForGossipedTransactions, createTxValidatorForBlockProposalReceivedTxs
|
|
405
|
+
import { createFirstStageTxValidationsForGossipedTransactions, createSecondStageTxValidationsForGossipedTransactions, createTxValidatorForBlockProposalReceivedTxs } from '../../msg_validators/tx_validator/factory.js';
|
|
402
406
|
import { GossipSubEvent } from '../../types/index.js';
|
|
403
407
|
import { convertToMultiaddr } from '../../util.js';
|
|
404
408
|
import { getVersions } from '../../versioning.js';
|
|
405
409
|
import { AztecDatastore } from '../data_store.js';
|
|
406
410
|
import { DiscV5Service } from '../discv5/discV5_service.js';
|
|
407
|
-
import { SnappyTransform,
|
|
411
|
+
import { SnappyTransform, getMsgIdFn, msgIdToStrFn } from '../encoding.js';
|
|
408
412
|
import { APP_SPECIFIC_WEIGHT, gossipScoreThresholds } from '../gossipsub/scoring.js';
|
|
409
413
|
import { createAllTopicScoreParams } from '../gossipsub/topic_score_params.js';
|
|
410
414
|
import { PeerManager } from '../peer-manager/peer_manager.js';
|
|
411
415
|
import { PeerScoring } from '../peer-manager/peer_scoring.js';
|
|
412
|
-
import {
|
|
416
|
+
import { YAMUX_MAX_MESSAGE_SIZE_BYTES } from '../reqresp/config.js';
|
|
417
|
+
import { ReqRespSubProtocol, ValidationError, pingHandler, reqGoodbyeHandler, reqRespBlockTxsHandler, reqRespStatusHandler, reqRespTxHandler } from '../reqresp/index.js';
|
|
413
418
|
import { ReqResp } from '../reqresp/reqresp.js';
|
|
414
419
|
import { P2PInstrumentation } from './instrumentation.js';
|
|
420
|
+
/**
|
|
421
|
+
* Builds the {@link ConsensusTimetable} shared by the gossip validators for proposal/attestation receive-window
|
|
422
|
+
* bounds. Derived purely from protocol slot-timing constants plus the block sub-slot duration and the consensus
|
|
423
|
+
* materialization grace, so every node agrees on these bounds without depending on proposer operational budgets.
|
|
424
|
+
*/ function buildConsensusTimetable(config, l1Constants) {
|
|
425
|
+
const blockDuration = config.blockDurationMs / 1000;
|
|
426
|
+
return new ConsensusTimetable({
|
|
427
|
+
l1Constants,
|
|
428
|
+
blockDuration,
|
|
429
|
+
checkpointProposalSyncGrace: config.checkpointProposalSyncGraceSeconds ?? getDefaultCheckpointProposalSyncGrace(blockDuration)
|
|
430
|
+
});
|
|
431
|
+
}
|
|
415
432
|
_dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId, attestation)=>({
|
|
416
433
|
[Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber.toString()
|
|
417
434
|
})), _dec1 = trackSpan('Libp2pService.validateAndStoreBlockProposal', (_peerId, block)=>({
|
|
@@ -427,12 +444,8 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
427
444
|
[Attributes.SLOT_NUMBER]: checkpoint.slotNumber,
|
|
428
445
|
[Attributes.BLOCK_ARCHIVE]: checkpoint.archive.toString(),
|
|
429
446
|
[Attributes.P2P_ID]: await checkpoint.p2pMessageLoggingIdentifier().then((i)=>i.toString())
|
|
430
|
-
})), _dec5 = trackSpan('Libp2pService.
|
|
447
|
+
})), _dec5 = trackSpan('Libp2pService.validateRequestedBlockTxsConsistency', (request)=>({
|
|
431
448
|
[Attributes.BLOCK_ARCHIVE]: request.archiveRoot.toString()
|
|
432
|
-
})), _dec6 = trackSpan('Libp2pService.validateRequestedTx', (requestedTxHash, _responseTx)=>({
|
|
433
|
-
[Attributes.TX_HASH]: requestedTxHash.toString()
|
|
434
|
-
})), _dec7 = trackSpan('Libp2pService.validateRequestedBlock', (requestedBlockNumber, _responseBlock)=>({
|
|
435
|
-
[Attributes.BLOCK_NUMBER]: requestedBlockNumber.toString()
|
|
436
449
|
}));
|
|
437
450
|
/**
|
|
438
451
|
* Lib P2P implementation of the P2PService interface.
|
|
@@ -447,6 +460,8 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
447
460
|
epochCache;
|
|
448
461
|
proofVerifier;
|
|
449
462
|
worldStateSynchronizer;
|
|
463
|
+
blockMinFeesProvider;
|
|
464
|
+
txValidationCache;
|
|
450
465
|
static{
|
|
451
466
|
({ e: [_initProto] } = _apply_decs_2203_r(this, [
|
|
452
467
|
[
|
|
@@ -477,17 +492,7 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
477
492
|
[
|
|
478
493
|
_dec5,
|
|
479
494
|
2,
|
|
480
|
-
"
|
|
481
|
-
],
|
|
482
|
-
[
|
|
483
|
-
_dec6,
|
|
484
|
-
2,
|
|
485
|
-
"validateRequestedTxs"
|
|
486
|
-
],
|
|
487
|
-
[
|
|
488
|
-
_dec7,
|
|
489
|
-
2,
|
|
490
|
-
"validateRequestedBlock"
|
|
495
|
+
"validateRequestedBlockTxsConsistency"
|
|
491
496
|
]
|
|
492
497
|
], []));
|
|
493
498
|
}
|
|
@@ -499,9 +504,10 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
499
504
|
checkpointAttestationValidator;
|
|
500
505
|
protocolVersion;
|
|
501
506
|
topicStrings;
|
|
502
|
-
feesCache;
|
|
503
507
|
/** Callback invoked when a duplicate proposal is detected (triggers slashing). */ duplicateProposalCallback;
|
|
508
|
+
/** Callback invoked when an oversized block proposal is stored as slashing evidence (triggers slashing). */ oversizedProposalCallback;
|
|
504
509
|
/** Callback invoked when a duplicate attestation is detected (triggers slashing). */ duplicateAttestationCallback;
|
|
510
|
+
/** Callback invoked when a valid checkpoint attestation is accepted into the pool. */ checkpointAttestationCallback;
|
|
505
511
|
/**
|
|
506
512
|
* Callback for when a block is received from a peer.
|
|
507
513
|
* @param block - The block received from the peer.
|
|
@@ -511,15 +517,20 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
511
517
|
* Callback for when a checkpoint proposal is received from a peer.
|
|
512
518
|
* @param checkpoint - The checkpoint proposal received from the peer.
|
|
513
519
|
* @returns The attestations for the checkpoint, if any.
|
|
514
|
-
*/
|
|
520
|
+
*/ allNodesCheckpointReceivedCallback;
|
|
521
|
+
/**
|
|
522
|
+
* Callback for when a checkpoint proposal is received - specifically for validators - from a peer.
|
|
523
|
+
* @param checkpoint - The checkpoint proposal received from the peer.
|
|
524
|
+
* @returns The attestations for the checkpoint, if any.
|
|
525
|
+
*/ validatorCheckpointReceivedCallback;
|
|
515
526
|
gossipSubEventHandler;
|
|
516
527
|
ipChangedHandler;
|
|
517
|
-
|
|
528
|
+
discoveredP2pIp;
|
|
518
529
|
instrumentation;
|
|
519
530
|
telemetry;
|
|
520
531
|
logger;
|
|
521
|
-
constructor(config, node, peerDiscoveryService, reqresp, peerManager, mempools, archiver, epochCache, proofVerifier, worldStateSynchronizer, telemetry, logger = createLogger('p2p:libp2p_service')){
|
|
522
|
-
super(telemetry, 'LibP2PService'), this.config = config, this.node = node, this.peerDiscoveryService = peerDiscoveryService, this.reqresp = reqresp, this.peerManager = peerManager, this.mempools = mempools, this.archiver = archiver, this.epochCache = epochCache, this.proofVerifier = proofVerifier, this.worldStateSynchronizer = worldStateSynchronizer, this.msgIdSeenValidators = (_initProto(this), {}), this.protocolVersion = '', this.topicStrings = {};
|
|
532
|
+
constructor(config, node, peerDiscoveryService, reqresp, peerManager, mempools, archiver, epochCache, proofVerifier, worldStateSynchronizer, blockMinFeesProvider, telemetry, logger = createLogger('p2p:libp2p_service'), txValidationCache){
|
|
533
|
+
super(telemetry, 'LibP2PService'), this.config = config, this.node = node, this.peerDiscoveryService = peerDiscoveryService, this.reqresp = reqresp, this.peerManager = peerManager, this.mempools = mempools, this.archiver = archiver, this.epochCache = epochCache, this.proofVerifier = proofVerifier, this.worldStateSynchronizer = worldStateSynchronizer, this.blockMinFeesProvider = blockMinFeesProvider, this.txValidationCache = txValidationCache, this.msgIdSeenValidators = (_initProto(this), {}), this.protocolVersion = '', this.topicStrings = {};
|
|
523
534
|
this.telemetry = telemetry;
|
|
524
535
|
// Create child logger with fisherman prefix if in fisherman mode
|
|
525
536
|
this.logger = config.fishermanMode ? logger.createChild('[FISHERMAN]') : logger;
|
|
@@ -535,13 +546,27 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
535
546
|
this.topicStrings[TopicType.block_proposal] = createTopicString(TopicType.block_proposal, this.protocolVersion);
|
|
536
547
|
this.topicStrings[TopicType.checkpoint_proposal] = createTopicString(TopicType.checkpoint_proposal, this.protocolVersion);
|
|
537
548
|
this.topicStrings[TopicType.checkpoint_attestation] = createTopicString(TopicType.checkpoint_attestation, this.protocolVersion);
|
|
549
|
+
// Build the consensus timetable once from protocol slot-timing constants and inject it into every
|
|
550
|
+
// validator so they share one set of receive-window bounds, independent of proposer operational budgets.
|
|
551
|
+
const consensusTimetable = buildConsensusTimetable(config, epochCache.getL1Constants());
|
|
538
552
|
const proposalValidatorOpts = {
|
|
539
553
|
txsPermitted: !config.disableTransactions,
|
|
540
|
-
maxTxsPerBlock: config.validateMaxTxsPerBlock ?? config.validateMaxTxsPerCheckpoint
|
|
554
|
+
maxTxsPerBlock: config.validateMaxTxsPerBlock ?? config.validateMaxTxsPerCheckpoint,
|
|
555
|
+
maxBlocksPerCheckpoint: config.maxBlocksPerCheckpoint,
|
|
556
|
+
skipSlotValidation: config.skipProposalSlotValidation,
|
|
557
|
+
signatureContext: {
|
|
558
|
+
chainId: config.l1ChainId,
|
|
559
|
+
rollupAddress: config.rollupAddress
|
|
560
|
+
},
|
|
561
|
+
clockDisparityMs: config.maxGossipClockDisparityMs
|
|
541
562
|
};
|
|
542
|
-
this.blockProposalValidator = new BlockProposalValidator(epochCache, proposalValidatorOpts);
|
|
543
|
-
this.checkpointProposalValidator = new CheckpointProposalValidator(epochCache, proposalValidatorOpts);
|
|
544
|
-
|
|
563
|
+
this.blockProposalValidator = new BlockProposalValidator(epochCache, consensusTimetable, proposalValidatorOpts);
|
|
564
|
+
this.checkpointProposalValidator = new CheckpointProposalValidator(epochCache, consensusTimetable, proposalValidatorOpts);
|
|
565
|
+
const attestationValidatorOpts = {
|
|
566
|
+
signatureContext: proposalValidatorOpts.signatureContext,
|
|
567
|
+
clockDisparityMs: config.maxGossipClockDisparityMs
|
|
568
|
+
};
|
|
569
|
+
this.checkpointAttestationValidator = config.fishermanMode ? new FishermanAttestationValidator(epochCache, consensusTimetable, mempools.attestationPool, telemetry, attestationValidatorOpts) : new CheckpointAttestationValidator(epochCache, consensusTimetable, attestationValidatorOpts);
|
|
545
570
|
this.gossipSubEventHandler = this.handleGossipSubEvent.bind(this);
|
|
546
571
|
this.blockReceivedCallback = async (block)=>{
|
|
547
572
|
this.logger.warn(`Handler for block received not yet registered on P2P service. Received block ${block.blockNumber} for slot ${block.slotNumber} from peer.`, {
|
|
@@ -549,13 +574,16 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
549
574
|
});
|
|
550
575
|
return true;
|
|
551
576
|
};
|
|
552
|
-
this.
|
|
553
|
-
|
|
577
|
+
this.allNodesCheckpointReceivedCallback = (_checkpoint)=>{
|
|
578
|
+
throw new CheckpointProposalReceivedCallbackNotRegisteredError();
|
|
579
|
+
};
|
|
580
|
+
this.validatorCheckpointReceivedCallback = (_checkpoint)=>{
|
|
554
581
|
return Promise.resolve(undefined);
|
|
555
582
|
};
|
|
556
583
|
}
|
|
557
584
|
updateConfig(config) {
|
|
558
585
|
this.reqresp.updateConfig(config);
|
|
586
|
+
this.config = merge(this.config, config);
|
|
559
587
|
}
|
|
560
588
|
/**
|
|
561
589
|
* Creates an instance of the LibP2P service.
|
|
@@ -563,12 +591,12 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
563
591
|
* @param txPool - The transaction pool to be accessed by the service.
|
|
564
592
|
* @returns The new service.
|
|
565
593
|
*/ static async new(config, peerId, deps) {
|
|
566
|
-
const { worldStateSynchronizer, epochCache, l2BlockSource, mempools, proofVerifier, peerStore, telemetry, logger, packageVersion } = deps;
|
|
594
|
+
const { worldStateSynchronizer, epochCache, l2BlockSource, mempools, proofVerifier, peerStore, blockMinFeesProvider, telemetry, logger, packageVersion, txValidationCache } = deps;
|
|
567
595
|
const { p2pPort, maxPeerCount, listenAddress } = config;
|
|
568
596
|
const bindAddrTcp = convertToMultiaddr(listenAddress, p2pPort, 'tcp');
|
|
569
597
|
const datastore = new AztecDatastore(peerStore);
|
|
570
598
|
const otelMetricsAdapter = new OtelMetricsAdapter(telemetry, logger.getBindings());
|
|
571
|
-
const peerDiscoveryService = new DiscV5Service(peerId, config, packageVersion, telemetry, createLogger(`${logger.module}:discv5_service`, logger.getBindings()));
|
|
599
|
+
const peerDiscoveryService = new DiscV5Service(peerId, config, packageVersion, telemetry, createLogger(`${logger.module}:discv5_service`, logger.getBindings()), peerStore);
|
|
572
600
|
// Seed libp2p's bootstrap discovery with private and trusted peers
|
|
573
601
|
const bootstrapNodes = [
|
|
574
602
|
...config.privatePeers,
|
|
@@ -583,31 +611,45 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
583
611
|
const versions = getVersions(config);
|
|
584
612
|
const protocolVersion = compressComponentVersions(versions);
|
|
585
613
|
const preferredPeersEnrs = config.preferredPeers.map((enr)=>ENR.decodeTxt(enr));
|
|
586
|
-
const directPeers = (await Promise.all(preferredPeersEnrs.map(async (enr)=>{
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
614
|
+
const directPeers = compactArray(await Promise.all(preferredPeersEnrs.map(async (enr)=>{
|
|
615
|
+
try {
|
|
616
|
+
const peerId = await enr.peerId();
|
|
617
|
+
const address = enr.getLocationMultiaddr('tcp');
|
|
618
|
+
if (address === undefined) {
|
|
619
|
+
throw new Error(`Direct peer ${peerId.toString()} has no TCP address, ENR: ${enr.encodeTxt()}`);
|
|
620
|
+
}
|
|
621
|
+
return {
|
|
622
|
+
id: peerId,
|
|
623
|
+
addrs: [
|
|
624
|
+
address
|
|
625
|
+
]
|
|
626
|
+
};
|
|
627
|
+
} catch (err) {
|
|
628
|
+
// A malformed configured ENR shouldn't abort node setup — skip it and log.
|
|
629
|
+
logger.warn(`Skipping preferred peer with invalid ENR`, {
|
|
630
|
+
err
|
|
631
|
+
});
|
|
632
|
+
return undefined;
|
|
591
633
|
}
|
|
592
|
-
|
|
593
|
-
id: peerId,
|
|
594
|
-
addrs: [
|
|
595
|
-
address
|
|
596
|
-
]
|
|
597
|
-
};
|
|
598
|
-
}))).filter((peer)=>peer !== undefined);
|
|
634
|
+
})));
|
|
599
635
|
const announceTcpMultiaddr = config.p2pIp ? [
|
|
600
636
|
convertToMultiaddr(config.p2pIp, p2pPort, 'tcp')
|
|
601
637
|
] : [];
|
|
602
|
-
// Create dynamic topic score params based on network configuration
|
|
638
|
+
// Create dynamic topic score params based on network configuration. Scoring uses the network-wide
|
|
639
|
+
// max-blocks-per-checkpoint config value directly to size expected per-slot message rates; these are
|
|
640
|
+
// peer-rate thresholds, not consensus deadlines, so they need no proposer operational budgets.
|
|
603
641
|
const l1Constants = epochCache.getL1Constants();
|
|
604
642
|
const topicScoreParams = createAllTopicScoreParams(protocolVersion, {
|
|
605
643
|
slotDurationMs: l1Constants.slotDuration * 1000,
|
|
606
644
|
heartbeatIntervalMs: config.gossipsubInterval,
|
|
607
645
|
targetCommitteeSize: l1Constants.targetCommitteeSize,
|
|
608
|
-
|
|
646
|
+
maxBlocksPerCheckpoint: config.maxBlocksPerCheckpoint ?? DEFAULT_MAX_BLOCKS_PER_CHECKPOINT,
|
|
609
647
|
expectedBlockProposalsPerSlot: config.expectedBlockProposalsPerSlot
|
|
610
648
|
});
|
|
649
|
+
// Restrict gossipsub to exactly the topics we subscribe to. Without this, an arbitrary-topic
|
|
650
|
+
// message is transformed, msg-id'd and inserted into the seenCache before the subscription check,
|
|
651
|
+
// so a crafted topic colliding on msg id can suppress a real message as a duplicate.
|
|
652
|
+
const allowedTopics = getTopicsForConfig(config.disableTransactions).map((topic)=>createTopicString(topic, protocolVersion));
|
|
611
653
|
const node = await createLibp2p({
|
|
612
654
|
start: false,
|
|
613
655
|
peerId,
|
|
@@ -641,8 +683,11 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
641
683
|
],
|
|
642
684
|
datastore,
|
|
643
685
|
peerDiscovery,
|
|
686
|
+
// Pin the yamux frame size: MAX_REQRESP_REQUEST_SIZE_BYTES relies on a reqresp request fitting in one frame.
|
|
644
687
|
streamMuxers: [
|
|
645
|
-
yamux(
|
|
688
|
+
yamux({
|
|
689
|
+
maxMessageSize: YAMUX_MAX_MESSAGE_SIZE_BYTES
|
|
690
|
+
}),
|
|
646
691
|
mplex()
|
|
647
692
|
],
|
|
648
693
|
connectionEncryption: [
|
|
@@ -660,7 +705,7 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
660
705
|
},
|
|
661
706
|
connectionGater: {
|
|
662
707
|
denyInboundConnection: (maConn)=>{
|
|
663
|
-
const allowed = peerManager.
|
|
708
|
+
const allowed = peerManager.isAddressAllowedToConnect(maConn.remoteAddr.nodeAddress().address);
|
|
664
709
|
if (allowed) {
|
|
665
710
|
return false;
|
|
666
711
|
}
|
|
@@ -670,7 +715,7 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
670
715
|
denyInboundEncryptedConnection: (peerId, _maConn)=>{
|
|
671
716
|
//NOTE: it is not necessary to check address here because this was already done by
|
|
672
717
|
// denyInboundConnection
|
|
673
|
-
const allowed = peerManager.
|
|
718
|
+
const allowed = peerManager.isPeerAllowedToConnect(peerId);
|
|
674
719
|
if (allowed) {
|
|
675
720
|
return false;
|
|
676
721
|
}
|
|
@@ -697,9 +742,13 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
697
742
|
mcacheLength: config.gossipsubMcacheLength,
|
|
698
743
|
mcacheGossip: config.gossipsubMcacheGossip,
|
|
699
744
|
seenTTL: config.gossipsubSeenTTL,
|
|
745
|
+
allowedTopics,
|
|
746
|
+
// No fastMsgIdFn: the fast-path dedup cache keys on a non-cryptographic 64-bit hash of the
|
|
747
|
+
// raw data only (no topic), so a collision — accidental or engineered via a weak seed — drops
|
|
748
|
+
// a different message with no fallback to the full id. Dedup instead rests solely on the
|
|
749
|
+
// cryptographic, topic-framed msgIdFn below.
|
|
700
750
|
msgIdFn: getMsgIdFn,
|
|
701
751
|
msgIdToStrFn: msgIdToStrFn,
|
|
702
|
-
fastMsgIdFn: fastMsgIdFn,
|
|
703
752
|
dataTransform: new SnappyTransform(),
|
|
704
753
|
metricsRegister: otelMetricsAdapter,
|
|
705
754
|
metricsTopicStrToLabel: metricsTopicStrToLabels(protocolVersion),
|
|
@@ -721,6 +770,8 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
721
770
|
const peerScoring = new PeerScoring(config, telemetry);
|
|
722
771
|
const reqresp = new ReqResp(config, node, peerScoring, createLogger(`${logger.module}:reqresp`));
|
|
723
772
|
const peerManager = new PeerManager(node, peerDiscoveryService, config, telemetry, createLogger(`${logger.module}:peer_manager`), peerScoring, reqresp, worldStateSynchronizer, protocolVersion, epochCache);
|
|
773
|
+
// Gate req/resp data protocols for unauthenticated peers when p2pAllowOnlyValidators is enabled
|
|
774
|
+
reqresp.setShouldRejectPeer((peerId)=>peerManager.shouldDisableP2PGossip(peerId));
|
|
724
775
|
// Configure application-specific scoring for gossipsub.
|
|
725
776
|
// The weight scales app score to align with gossipsub thresholds:
|
|
726
777
|
// - Disconnect (-50) × 10 = -500 = gossipThreshold (stops receiving gossip)
|
|
@@ -728,7 +779,7 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
728
779
|
// Note: positive topic scores can offset penalties, so alignment is best-effort.
|
|
729
780
|
node.services.pubsub.score.params.appSpecificWeight = APP_SPECIFIC_WEIGHT;
|
|
730
781
|
node.services.pubsub.score.params.appSpecificScore = (peerId)=>peerManager.shouldDisableP2PGossip(peerId) ? -Infinity : peerManager.getPeerScore(peerId);
|
|
731
|
-
return new LibP2PService(config, node, peerDiscoveryService, reqresp, peerManager, mempools, l2BlockSource, epochCache, proofVerifier, worldStateSynchronizer, telemetry, logger);
|
|
782
|
+
return new LibP2PService(config, node, peerDiscoveryService, reqresp, peerManager, mempools, l2BlockSource, epochCache, proofVerifier, worldStateSynchronizer, blockMinFeesProvider, telemetry, logger, txValidationCache);
|
|
732
783
|
}
|
|
733
784
|
/**
|
|
734
785
|
* Starts the LibP2P service.
|
|
@@ -738,22 +789,19 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
738
789
|
if (this.node.status === 'started') {
|
|
739
790
|
throw new Error('P2P service already started');
|
|
740
791
|
}
|
|
741
|
-
// Get listen & announce addresses for logging
|
|
742
792
|
const { p2pIp, p2pPort } = this.config;
|
|
743
793
|
if (!p2pIp && !this.config.queryForIp) {
|
|
744
|
-
throw new Error('Announce address not provided.');
|
|
794
|
+
throw new Error('Announce address not provided and queryForIp is not enabled.');
|
|
745
795
|
}
|
|
746
796
|
const announceTcpMultiaddr = p2pIp ? convertToMultiaddr(p2pIp, p2pPort, 'tcp') : undefined;
|
|
747
797
|
// Create request response protocol handlers
|
|
748
798
|
const txHandler = reqRespTxHandler(this.mempools);
|
|
749
799
|
const goodbyeHandler = reqGoodbyeHandler(this.peerManager);
|
|
750
|
-
const blockHandler = reqRespBlockHandler(this.archiver);
|
|
751
800
|
const statusHandler = reqRespStatusHandler(this.protocolVersion, this.worldStateSynchronizer, this.logger);
|
|
752
801
|
const requestResponseHandlers = {
|
|
753
802
|
[ReqRespSubProtocol.PING]: pingHandler,
|
|
754
803
|
[ReqRespSubProtocol.STATUS]: statusHandler.bind(this),
|
|
755
|
-
[ReqRespSubProtocol.GOODBYE]: goodbyeHandler.bind(this)
|
|
756
|
-
[ReqRespSubProtocol.BLOCK]: blockHandler.bind(this)
|
|
804
|
+
[ReqRespSubProtocol.GOODBYE]: goodbyeHandler.bind(this)
|
|
757
805
|
};
|
|
758
806
|
if (!this.config.disableTransactions) {
|
|
759
807
|
const blockTxsHandler = reqRespBlockTxsHandler(this.mempools.attestationPool, this.archiver, this.mempools.txPool);
|
|
@@ -762,15 +810,8 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
762
810
|
if (!this.config.disableTransactions) {
|
|
763
811
|
requestResponseHandlers[ReqRespSubProtocol.TX] = txHandler.bind(this);
|
|
764
812
|
}
|
|
765
|
-
// Define the sub protocol validators - This is done within this start() method to gain a callback to the existing validateTx function
|
|
766
|
-
const reqrespSubProtocolValidators = {
|
|
767
|
-
...DEFAULT_SUB_PROTOCOL_VALIDATORS,
|
|
768
|
-
[ReqRespSubProtocol.TX]: this.validateRequestedTxs.bind(this),
|
|
769
|
-
[ReqRespSubProtocol.BLOCK_TXS]: this.validateRequestedBlockTxs.bind(this),
|
|
770
|
-
[ReqRespSubProtocol.BLOCK]: this.validateRequestedBlock.bind(this)
|
|
771
|
-
};
|
|
772
813
|
await this.peerManager.initializePeers();
|
|
773
|
-
await this.reqresp.start(requestResponseHandlers
|
|
814
|
+
await this.reqresp.start(requestResponseHandlers);
|
|
774
815
|
await this.node.start();
|
|
775
816
|
// Subscribe to standard GossipSub topics by default
|
|
776
817
|
for (const topic of getTopicsForConfig(this.config.disableTransactions)){
|
|
@@ -782,26 +823,31 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
782
823
|
if (!this.config.p2pDiscoveryDisabled) {
|
|
783
824
|
await this.peerDiscoveryService.start();
|
|
784
825
|
}
|
|
785
|
-
//
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
if (this.config.queryForIp && !p2pIp) {
|
|
826
|
+
// Bridge discv5 IP changes to libp2p's AddressManager so peers see the updated address
|
|
827
|
+
if (this.config.queryForIp) {
|
|
828
|
+
this.discoveredP2pIp = this.config.p2pIp;
|
|
829
|
+
this.logger.info('IP change tracking enabled, bridging discv5 IP updates to libp2p AddressManager');
|
|
790
830
|
this.ipChangedHandler = (ip)=>{
|
|
791
831
|
const addressManager = this.node.services.components.addressManager;
|
|
792
832
|
const newAddr = multiaddr(convertToMultiaddr(ip, this.config.p2pPort, 'tcp'));
|
|
793
|
-
|
|
794
|
-
if (
|
|
795
|
-
const oldAddr = multiaddr(convertToMultiaddr(
|
|
833
|
+
const previousIp = this.discoveredP2pIp;
|
|
834
|
+
if (previousIp) {
|
|
835
|
+
const oldAddr = multiaddr(convertToMultiaddr(previousIp, this.config.p2pPort, 'tcp'));
|
|
796
836
|
addressManager.removeObservedAddr(oldAddr);
|
|
837
|
+
this.logger.info('Libp2p announce address updated due to IP change', {
|
|
838
|
+
previousIp,
|
|
839
|
+
newIp: ip,
|
|
840
|
+
newMultiaddr: newAddr.toString()
|
|
841
|
+
});
|
|
842
|
+
} else {
|
|
843
|
+
this.logger.info('Libp2p announce address set from initial discv5 IP discovery', {
|
|
844
|
+
ip,
|
|
845
|
+
multiaddr: newAddr.toString()
|
|
846
|
+
});
|
|
797
847
|
}
|
|
798
848
|
addressManager.addObservedAddr(newAddr);
|
|
799
849
|
addressManager.confirmObservedAddr(newAddr);
|
|
800
|
-
// Store discovered IP
|
|
801
850
|
this.discoveredP2pIp = ip;
|
|
802
|
-
this.logger.info('Public IP discovered via discv5', {
|
|
803
|
-
ip
|
|
804
|
-
});
|
|
805
851
|
};
|
|
806
852
|
this.peerDiscoveryService.on('ip:changed', this.ipChangedHandler);
|
|
807
853
|
}
|
|
@@ -812,7 +858,7 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
812
858
|
this.logger.info(`Started P2P service`, {
|
|
813
859
|
listen: this.config.listenAddress,
|
|
814
860
|
port: this.config.p2pPort,
|
|
815
|
-
announce: announceTcpMultiaddr
|
|
861
|
+
announce: announceTcpMultiaddr,
|
|
816
862
|
peerId: this.node.peerId.toString()
|
|
817
863
|
});
|
|
818
864
|
}
|
|
@@ -822,9 +868,8 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
822
868
|
*/ async stop() {
|
|
823
869
|
// Remove gossip sub listener
|
|
824
870
|
this.node.services.pubsub.removeEventListener(GossipSubEvent.MESSAGE, this.gossipSubEventHandler);
|
|
825
|
-
// Remove ip:changed listener if registered
|
|
826
871
|
if (this.ipChangedHandler) {
|
|
827
|
-
this.peerDiscoveryService.
|
|
872
|
+
this.peerDiscoveryService.removeListener('ip:changed', this.ipChangedHandler);
|
|
828
873
|
this.ipChangedHandler = undefined;
|
|
829
874
|
}
|
|
830
875
|
// Stop peer manager
|
|
@@ -840,8 +885,8 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
840
885
|
await this.stopLibP2P();
|
|
841
886
|
this.logger.info('LibP2P service stopped');
|
|
842
887
|
}
|
|
843
|
-
addReqRespSubProtocol(subProtocol, handler
|
|
844
|
-
return this.reqresp.addSubProtocol(subProtocol, handler
|
|
888
|
+
addReqRespSubProtocol(subProtocol, handler) {
|
|
889
|
+
return this.reqresp.addSubProtocol(subProtocol, handler);
|
|
845
890
|
}
|
|
846
891
|
registerThisValidatorAddresses(address) {
|
|
847
892
|
this.peerManager.registerThisValidatorAddresses(address);
|
|
@@ -863,14 +908,6 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
863
908
|
};
|
|
864
909
|
setImmediate(()=>void safeJob());
|
|
865
910
|
}
|
|
866
|
-
/**
|
|
867
|
-
* Send a batch of requests to peers, and return the responses
|
|
868
|
-
* @param protocol - The request response protocol to use
|
|
869
|
-
* @param requests - The requests to send to the peers
|
|
870
|
-
* @returns The responses to the requests
|
|
871
|
-
*/ sendBatchRequest(protocol, requests, pinnedPeerId) {
|
|
872
|
-
return this.reqresp.sendBatchRequest(protocol, requests, pinnedPeerId);
|
|
873
|
-
}
|
|
874
911
|
sendRequestToPeer(peerId, subProtocol, payload, dialTimeout) {
|
|
875
912
|
return this.reqresp.sendRequestToPeer(peerId, subProtocol, payload, dialTimeout);
|
|
876
913
|
}
|
|
@@ -883,8 +920,11 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
883
920
|
registerBlockReceivedCallback(callback) {
|
|
884
921
|
this.blockReceivedCallback = callback;
|
|
885
922
|
}
|
|
886
|
-
|
|
887
|
-
this.
|
|
923
|
+
registerValidatorCheckpointReceivedCallback(callback) {
|
|
924
|
+
this.validatorCheckpointReceivedCallback = callback;
|
|
925
|
+
}
|
|
926
|
+
registerAllNodesCheckpointReceivedCallback(callback) {
|
|
927
|
+
this.allNodesCheckpointReceivedCallback = callback;
|
|
888
928
|
}
|
|
889
929
|
/**
|
|
890
930
|
* Registers a callback to be invoked when a duplicate proposal is detected.
|
|
@@ -893,12 +933,20 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
893
933
|
this.duplicateProposalCallback = callback;
|
|
894
934
|
}
|
|
895
935
|
/**
|
|
936
|
+
* Registers a callback to be invoked when an oversized block proposal is stored as slashing evidence.
|
|
937
|
+
*/ registerOversizedProposalCallback(callback) {
|
|
938
|
+
this.oversizedProposalCallback = callback;
|
|
939
|
+
}
|
|
940
|
+
/**
|
|
896
941
|
* Registers a callback to be invoked when a duplicate attestation is detected.
|
|
897
942
|
* A validator signing attestations for different proposals at the same slot.
|
|
898
943
|
* This callback is triggered on the first duplicate (when count goes from 1 to 2).
|
|
899
944
|
*/ registerDuplicateAttestationCallback(callback) {
|
|
900
945
|
this.duplicateAttestationCallback = callback;
|
|
901
946
|
}
|
|
947
|
+
registerCheckpointAttestationCallback(callback) {
|
|
948
|
+
this.checkpointAttestationCallback = callback;
|
|
949
|
+
}
|
|
902
950
|
/**
|
|
903
951
|
* Subscribes to a topic.
|
|
904
952
|
* @param topic - The topic to subscribe to.
|
|
@@ -1013,6 +1061,13 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1013
1061
|
}
|
|
1014
1062
|
// Process the message, optionally within a linked span for trace propagation
|
|
1015
1063
|
const processMessage = async ()=>{
|
|
1064
|
+
if (this.config.skipIncomingProposals && (msg.topic === this.topicStrings[TopicType.block_proposal] || msg.topic === this.topicStrings[TopicType.checkpoint_proposal])) {
|
|
1065
|
+
this.logger.warn(`Ignoring incoming proposal (skipIncomingProposals is set)`, {
|
|
1066
|
+
topic: msg.topic
|
|
1067
|
+
});
|
|
1068
|
+
this.node.services.pubsub.reportMessageValidationResult(msgId, source.toString(), TopicValidatorResult.Ignore);
|
|
1069
|
+
return;
|
|
1070
|
+
}
|
|
1016
1071
|
if (msg.topic === this.topicStrings[TopicType.tx]) {
|
|
1017
1072
|
await this.handleGossipedTx(p2pMessage.payload, msgId, source);
|
|
1018
1073
|
} else if (msg.topic === this.topicStrings[TopicType.checkpoint_attestation]) {
|
|
@@ -1076,6 +1131,18 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1076
1131
|
topicType
|
|
1077
1132
|
});
|
|
1078
1133
|
}
|
|
1134
|
+
const validationTimeMs = timer.ms();
|
|
1135
|
+
const mcacheWindowMs = this.config.gossipsubMcacheLength * this.config.gossipsubInterval;
|
|
1136
|
+
if (validationTimeMs > mcacheWindowMs * 0.75) {
|
|
1137
|
+
this.instrumentation.incSlowValidation(topicType);
|
|
1138
|
+
this.logger.warn(`Gossip validation for ${topicType} took ${validationTimeMs}ms, approaching mcache eviction window of ${mcacheWindowMs}ms. ` + `Message forwarding may be skipped if validation exceeds the window.`, {
|
|
1139
|
+
msgId,
|
|
1140
|
+
source: source.toString(),
|
|
1141
|
+
topicType,
|
|
1142
|
+
validationTimeMs,
|
|
1143
|
+
mcacheWindowMs
|
|
1144
|
+
});
|
|
1145
|
+
}
|
|
1079
1146
|
if (resultAndObj.result === TopicValidatorResult.Accept) {
|
|
1080
1147
|
this.logger.debug(`Message ${topicType} accepted by validator`, {
|
|
1081
1148
|
msgId,
|
|
@@ -1310,15 +1377,17 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1310
1377
|
}
|
|
1311
1378
|
}
|
|
1312
1379
|
// Attestation was added successfully - accept it so other nodes can also detect the equivocation
|
|
1380
|
+
this.checkpointAttestationCallback?.(attestation);
|
|
1313
1381
|
return {
|
|
1314
1382
|
result: TopicValidatorResult.Accept,
|
|
1315
1383
|
obj: attestation
|
|
1316
1384
|
};
|
|
1317
1385
|
}
|
|
1318
1386
|
async processBlockFromPeer(payloadData, msgId, source) {
|
|
1319
|
-
const { result, obj: block, metadata: { isEquivocated } = {} } = await this.validateReceivedMessage(()=>this.validateAndStoreBlockProposal(source, BlockProposal.fromBuffer(payloadData)), msgId, source, TopicType.block_proposal);
|
|
1320
|
-
// If not accepted or
|
|
1321
|
-
|
|
1387
|
+
const { result, obj: block, metadata: { isEquivocated, isOversized } = {} } = await this.validateReceivedMessage(()=>this.validateAndStoreBlockProposal(source, BlockProposal.fromBuffer(payloadData)), msgId, source, TopicType.block_proposal);
|
|
1388
|
+
// If not accepted, equivocated, or oversized, return. Oversized proposals are re-broadcast as
|
|
1389
|
+
// slashing evidence but never attested or processed.
|
|
1390
|
+
if (result !== TopicValidatorResult.Accept || !block || isEquivocated || isOversized) {
|
|
1322
1391
|
return;
|
|
1323
1392
|
}
|
|
1324
1393
|
await this.processValidBlockProposal(block, source);
|
|
@@ -1341,6 +1410,10 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1341
1410
|
// Try to add the proposal: this handles existence check, cap check, and adding in one call
|
|
1342
1411
|
const { added, alreadyExists, count } = await this.mempools.attestationPool.tryAddBlockProposal(block);
|
|
1343
1412
|
const isEquivocated = count !== undefined && count > 1;
|
|
1413
|
+
// An oversized proposal (index at or beyond the consensus per-checkpoint limit) is structurally valid
|
|
1414
|
+
// proposer misbehavior: it is stored and re-broadcast as slashing evidence but never processed or
|
|
1415
|
+
// attested to. No-ops when maxBlocksPerCheckpoint is unset (local/test).
|
|
1416
|
+
const isOversized = this.config.maxBlocksPerCheckpoint !== undefined && block.indexWithinCheckpoint >= this.config.maxBlocksPerCheckpoint;
|
|
1344
1417
|
// Duplicate proposal received, no need to re-broadcast
|
|
1345
1418
|
if (alreadyExists) {
|
|
1346
1419
|
this.logger.debug(`Ignoring duplicate block proposal received`, {
|
|
@@ -1353,7 +1426,8 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1353
1426
|
result: TopicValidatorResult.Ignore,
|
|
1354
1427
|
obj: block,
|
|
1355
1428
|
metadata: {
|
|
1356
|
-
isEquivocated
|
|
1429
|
+
isEquivocated,
|
|
1430
|
+
isOversized
|
|
1357
1431
|
}
|
|
1358
1432
|
};
|
|
1359
1433
|
}
|
|
@@ -1369,11 +1443,30 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1369
1443
|
return {
|
|
1370
1444
|
result: TopicValidatorResult.Reject,
|
|
1371
1445
|
metadata: {
|
|
1372
|
-
isEquivocated
|
|
1446
|
+
isEquivocated,
|
|
1447
|
+
isOversized
|
|
1373
1448
|
},
|
|
1374
1449
|
severity: PeerErrorSeverity.HighToleranceError
|
|
1375
1450
|
};
|
|
1376
1451
|
}
|
|
1452
|
+
// The proposal was stored: if oversized, invoke the oversized callback so the proposer can be
|
|
1453
|
+
// slashed. Fired alongside (not instead of) equivocation detection below.
|
|
1454
|
+
if (isOversized) {
|
|
1455
|
+
const proposer = block.getSender();
|
|
1456
|
+
if (proposer) {
|
|
1457
|
+
this.logger.warn(`Detected oversized block proposal at slot ${block.slotNumber}`, {
|
|
1458
|
+
...block.toBlockInfo(),
|
|
1459
|
+
indexWithinCheckpoint: block.indexWithinCheckpoint,
|
|
1460
|
+
maxBlocksPerCheckpoint: this.config.maxBlocksPerCheckpoint,
|
|
1461
|
+
source: peerId.toString(),
|
|
1462
|
+
proposer: proposer.toString()
|
|
1463
|
+
});
|
|
1464
|
+
this.oversizedProposalCallback?.({
|
|
1465
|
+
slot: block.slotNumber,
|
|
1466
|
+
proposer
|
|
1467
|
+
});
|
|
1468
|
+
}
|
|
1469
|
+
}
|
|
1377
1470
|
// If this was a duplicate proposal, do not process it, but do invoke the duplicate callback,
|
|
1378
1471
|
// and do re-broadcast it so other nodes in the network know to slash the proposer
|
|
1379
1472
|
if (isEquivocated) {
|
|
@@ -1395,14 +1488,19 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1395
1488
|
result: TopicValidatorResult.Accept,
|
|
1396
1489
|
obj: block,
|
|
1397
1490
|
metadata: {
|
|
1398
|
-
isEquivocated
|
|
1491
|
+
isEquivocated,
|
|
1492
|
+
isOversized
|
|
1399
1493
|
}
|
|
1400
1494
|
};
|
|
1401
1495
|
}
|
|
1402
1496
|
// Otherwise, we're good to go!
|
|
1403
1497
|
return {
|
|
1404
1498
|
result: TopicValidatorResult.Accept,
|
|
1405
|
-
obj: block
|
|
1499
|
+
obj: block,
|
|
1500
|
+
metadata: {
|
|
1501
|
+
isEquivocated: false,
|
|
1502
|
+
isOversized
|
|
1503
|
+
}
|
|
1406
1504
|
};
|
|
1407
1505
|
}
|
|
1408
1506
|
// REFACTOR(palla): This method should be moved to the p2p_client or to a separate component,
|
|
@@ -1416,27 +1514,53 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1416
1514
|
});
|
|
1417
1515
|
// Mark the txs in this proposal as protected
|
|
1418
1516
|
await this.mempools.txPool.protectTxs(block.txHashes, block.blockHeader);
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1517
|
+
if (!await this.tryBlockReceivedCallback(block, sender)) {
|
|
1518
|
+
// Release the protections this proposal created so its txs return to pending. Only entries still
|
|
1519
|
+
// keyed to this slot are cleared, so a tx referenced by a live proposal at another slot stays protected.
|
|
1520
|
+
await this.mempools.txPool.unprotectTxs(block.txHashes, slot);
|
|
1521
|
+
}
|
|
1522
|
+
}
|
|
1523
|
+
/**
|
|
1524
|
+
* Runs the block received callback to validate a proposal, and returns whether it was accepted.
|
|
1525
|
+
* A callback that throws is reported as a rejection: the proposal is no more usable than one explicitly
|
|
1526
|
+
* rejected, and letting the error escape would leave the proposal's tx protections in place.
|
|
1527
|
+
* Note: Validators do NOT attest to individual blocks, only to checkpoint proposals.
|
|
1528
|
+
*/ async tryBlockReceivedCallback(block, sender) {
|
|
1529
|
+
try {
|
|
1530
|
+
const isValid = await this.blockReceivedCallback(block, sender);
|
|
1531
|
+
if (!isValid) {
|
|
1532
|
+
this.logger.info(`Block proposal validation failed for block ${block.blockNumber}`, block.toBlockInfo());
|
|
1533
|
+
}
|
|
1534
|
+
return isValid;
|
|
1535
|
+
} catch (err) {
|
|
1536
|
+
this.logger.error(`Error validating block proposal for block ${block.blockNumber}`, err, block.toBlockInfo());
|
|
1537
|
+
return false;
|
|
1424
1538
|
}
|
|
1425
1539
|
}
|
|
1426
1540
|
/**
|
|
1427
1541
|
* Handle a gossiped checkpoint proposal.
|
|
1428
1542
|
* Validates and processes the checkpoint proposal, then triggers the callback for attestation.
|
|
1429
1543
|
*/ async handleGossipedCheckpointProposal(payloadData, msgId, source) {
|
|
1430
|
-
const { result, obj: checkpoint, metadata: { isEquivocated, processBlock } = {} } = await this.validateReceivedMessage(()=>this.validateAndStoreCheckpointProposal(source, CheckpointProposal.fromBuffer(payloadData)), msgId, source, TopicType.checkpoint_proposal);
|
|
1544
|
+
const { result, obj: checkpoint, metadata: { isEquivocated, processBlock, isOversized } = {} } = await this.validateReceivedMessage(()=>this.validateAndStoreCheckpointProposal(source, CheckpointProposal.fromBuffer(payloadData)), msgId, source, TopicType.checkpoint_proposal);
|
|
1545
|
+
// An oversized checkpoint is re-broadcast as slashing evidence but never attested or processed.
|
|
1546
|
+
// Process checkpoint proposal if valid and neither equivocated nor oversized.
|
|
1547
|
+
const processCheckpointFn = ()=>result === TopicValidatorResult.Accept && checkpoint && !isEquivocated && !isOversized ? this.processValidCheckpointProposal(checkpoint.toCore(), source) : Promise.resolve();
|
|
1431
1548
|
// If the checkpoint contained a valid last block, we process it even if the checkpoint itself is to be rejected
|
|
1432
1549
|
// TODO(palla/mbps): Is this ok? Should we be considering a block from a checkpoint that was equivocated?
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1550
|
+
const processBlockFn = ()=>processBlock && checkpoint && checkpoint.getBlockProposal() ? this.processValidBlockProposal(checkpoint.getBlockProposal(), source) : Promise.resolve();
|
|
1551
|
+
// A node that skips checkpoint validation attests without re-executing the embedded last block, so run
|
|
1552
|
+
// the checkpoint callback first: this creates and broadcasts the attestation before the block is
|
|
1553
|
+
// processed. Otherwise the block's re-execution — which can stall until the re-execution deadline
|
|
1554
|
+
// waiting for a parent that may never arrive — would delay the attestation past the slot's attestation
|
|
1555
|
+
// window, after which peers reject it as stale.
|
|
1556
|
+
if (this.config.skipCheckpointProposalValidation) {
|
|
1557
|
+
await processCheckpointFn();
|
|
1558
|
+
await processBlockFn();
|
|
1437
1559
|
return;
|
|
1438
1560
|
}
|
|
1439
|
-
|
|
1561
|
+
// Process the block first, since it's required for the checkpoint proposal validation.
|
|
1562
|
+
await processBlockFn();
|
|
1563
|
+
await processCheckpointFn();
|
|
1440
1564
|
}
|
|
1441
1565
|
/**
|
|
1442
1566
|
* Validates a checkpoint proposal. Penalizes peer if validation fails. Adds the checkpoint and
|
|
@@ -1459,13 +1583,15 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1459
1583
|
// Extract and try to add the block proposal first if present
|
|
1460
1584
|
const blockProposal = checkpoint.getBlockProposal();
|
|
1461
1585
|
let processBlock = false;
|
|
1586
|
+
let isOversized = false;
|
|
1462
1587
|
if (blockProposal) {
|
|
1463
1588
|
this.logger.debug(`Validating block proposal from propagated checkpoint`, {
|
|
1464
1589
|
[Attributes.SLOT_NUMBER]: checkpoint.slotNumber.toString(),
|
|
1465
1590
|
[Attributes.P2P_ID]: peerId.toString()
|
|
1466
1591
|
});
|
|
1467
1592
|
const blockProposalResult = await this.validateAndStoreBlockProposal(peerId, blockProposal);
|
|
1468
|
-
const { obj, metadata: { isEquivocated } = {} } = blockProposalResult;
|
|
1593
|
+
const { obj, metadata: { isEquivocated, isOversized: blockIsOversized } = {} } = blockProposalResult;
|
|
1594
|
+
isOversized = blockIsOversized ?? false;
|
|
1469
1595
|
if (blockProposalResult.result === TopicValidatorResult.Reject || !obj || isEquivocated) {
|
|
1470
1596
|
this.logger.debug(`Rejecting checkpoint due to invalid last block proposal`, {
|
|
1471
1597
|
[Attributes.SLOT_NUMBER]: checkpoint.slotNumber.toString(),
|
|
@@ -1477,7 +1603,8 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1477
1603
|
result: TopicValidatorResult.Reject,
|
|
1478
1604
|
severity: 'severity' in blockProposalResult ? blockProposalResult.severity : PeerErrorSeverity.MidToleranceError
|
|
1479
1605
|
};
|
|
1480
|
-
} else if (blockProposalResult.result === TopicValidatorResult.Accept && obj && !isEquivocated) {
|
|
1606
|
+
} else if (blockProposalResult.result === TopicValidatorResult.Accept && obj && !isEquivocated && !isOversized) {
|
|
1607
|
+
// An oversized terminal block is re-broadcast as slashing evidence but never processed.
|
|
1481
1608
|
processBlock = true;
|
|
1482
1609
|
}
|
|
1483
1610
|
}
|
|
@@ -1497,11 +1624,12 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1497
1624
|
obj: checkpoint,
|
|
1498
1625
|
metadata: {
|
|
1499
1626
|
isEquivocated,
|
|
1500
|
-
processBlock
|
|
1627
|
+
processBlock,
|
|
1628
|
+
isOversized
|
|
1501
1629
|
}
|
|
1502
1630
|
};
|
|
1503
1631
|
}
|
|
1504
|
-
// Too many checkpoint proposals received for this slot, penalize peer and do not re-broadcast
|
|
1632
|
+
// Too many checkpoint proposals received for this slot, penalize peer and do not re-broadcast.
|
|
1505
1633
|
// Note: We still return the checkpoint obj so the lastBlock can be processed if valid
|
|
1506
1634
|
if (!added) {
|
|
1507
1635
|
this.logger.warn(`Penalizing peer for checkpoint proposal exceeding per-slot cap`, {
|
|
@@ -1514,7 +1642,8 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1514
1642
|
obj: checkpoint,
|
|
1515
1643
|
metadata: {
|
|
1516
1644
|
isEquivocated,
|
|
1517
|
-
processBlock
|
|
1645
|
+
processBlock,
|
|
1646
|
+
isOversized
|
|
1518
1647
|
},
|
|
1519
1648
|
severity: PeerErrorSeverity.HighToleranceError
|
|
1520
1649
|
};
|
|
@@ -1541,7 +1670,8 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1541
1670
|
obj: checkpoint,
|
|
1542
1671
|
metadata: {
|
|
1543
1672
|
isEquivocated,
|
|
1544
|
-
processBlock
|
|
1673
|
+
processBlock,
|
|
1674
|
+
isOversized
|
|
1545
1675
|
}
|
|
1546
1676
|
};
|
|
1547
1677
|
}
|
|
@@ -1551,7 +1681,8 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1551
1681
|
obj: checkpoint,
|
|
1552
1682
|
metadata: {
|
|
1553
1683
|
processBlock,
|
|
1554
|
-
isEquivocated
|
|
1684
|
+
isEquivocated,
|
|
1685
|
+
isOversized
|
|
1555
1686
|
}
|
|
1556
1687
|
};
|
|
1557
1688
|
}
|
|
@@ -1566,9 +1697,10 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1566
1697
|
archive: checkpoint.archive.toString(),
|
|
1567
1698
|
source: sender.toString()
|
|
1568
1699
|
});
|
|
1700
|
+
await this.allNodesCheckpointReceivedCallback(checkpoint, sender);
|
|
1569
1701
|
// Call the checkpoint received callback with the core version (without lastBlock)
|
|
1570
1702
|
// to validate and potentially generate attestations
|
|
1571
|
-
const attestations = await this.
|
|
1703
|
+
const attestations = await this.validatorCheckpointReceivedCallback(checkpoint, sender);
|
|
1572
1704
|
if (attestations && attestations.length > 0) {
|
|
1573
1705
|
// If the callback returned attestations, add them to the pool and propagate them
|
|
1574
1706
|
await this.mempools.attestationPool.addOwnCheckpointAttestations(attestations);
|
|
@@ -1592,62 +1724,66 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1592
1724
|
});
|
|
1593
1725
|
}
|
|
1594
1726
|
/**
|
|
1595
|
-
* Validate the requested block transactions
|
|
1727
|
+
* Validate the requested block transactions request-response consistency.
|
|
1728
|
+
* It does NOT validate the transactions themselves.
|
|
1596
1729
|
* @param request - The block transactions request.
|
|
1597
1730
|
* @param response - The block transactions response.
|
|
1598
1731
|
* @param peerId - The ID of the peer that made the request.
|
|
1599
|
-
* @returns True if the
|
|
1600
|
-
*/ async
|
|
1601
|
-
const requestedTxValidator = this.createRequestedTxValidator();
|
|
1732
|
+
* @returns True if the request-response is consistent, false otherwise.
|
|
1733
|
+
*/ async validateRequestedBlockTxsConsistency(request, response, peerId) {
|
|
1602
1734
|
try {
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
throw new ValidationError(`Received block txs for unexpected archive root: expected ${request.archiveRoot.toString()}, got ${response.archiveRoot.toString()}`);
|
|
1606
|
-
}
|
|
1607
|
-
if (response.txIndices.getLength() !== request.txIndices.getLength()) {
|
|
1608
|
-
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
1609
|
-
throw new ValidationError(`Received block txs with mismatched bitvector length: expected ${request.txIndices.getLength()}, got ${response.txIndices.getLength()}`);
|
|
1610
|
-
}
|
|
1611
|
-
// Check no duplicates and not exceeding returnable count
|
|
1612
|
-
const requestedIndices = new Set(request.txIndices.getTrueIndices());
|
|
1613
|
-
const availableIndices = new Set(response.txIndices.getTrueIndices());
|
|
1614
|
-
const maxReturnable = [
|
|
1615
|
-
...requestedIndices
|
|
1616
|
-
].filter((i)=>availableIndices.has(i)).length;
|
|
1617
|
-
const returnedHashes = await Promise.all(response.txs.map((tx)=>tx.getTxHash().toString()));
|
|
1735
|
+
// Check for duplicates txs (or hashes) in the response.
|
|
1736
|
+
const returnedHashes = response.txs.map((tx)=>tx.getTxHash().toString());
|
|
1618
1737
|
const uniqueReturned = new Set(returnedHashes.map((h)=>h.toString()));
|
|
1619
1738
|
if (uniqueReturned.size !== returnedHashes.length) {
|
|
1620
1739
|
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
1621
1740
|
throw new ValidationError(`Received duplicate txs in block txs response`);
|
|
1622
1741
|
}
|
|
1623
|
-
|
|
1742
|
+
// We get the block tx hashes from the proposal or the archiver.
|
|
1743
|
+
const proposal = await this.mempools.attestationPool.getBlockProposalByArchive(request.archiveRoot.toString());
|
|
1744
|
+
const blockTxHashes = proposal?.txHashes ?? (await this.archiver.getBlock({
|
|
1745
|
+
archive: request.archiveRoot
|
|
1746
|
+
}))?.body.txEffects.map((e)=>e.txHash);
|
|
1747
|
+
// If we don't have the block, we can't verify membership/order of the returned txs.
|
|
1748
|
+
if (!blockTxHashes) {
|
|
1749
|
+
// This shouldn't happen, since we asked for the block (proposal).
|
|
1750
|
+
// Neither a local proposal nor an archived block: we cannot verify membership/order of the
|
|
1751
|
+
// returned txs. This is a local-state gap, not a peer fault, so we do not penalize.
|
|
1752
|
+
this.logger.warn(`Block ${request.archiveRoot.toString()} not found in attestation pool or archiver; cannot validate membership/order of returned txs`);
|
|
1753
|
+
// NOTE: We mark the response as invalid, given the limitations of a true/false return value.
|
|
1754
|
+
return false;
|
|
1755
|
+
}
|
|
1756
|
+
// Verify that the returned tx hashes are a subset of (tx hashes by index) U (explicitly requested tx hashes).
|
|
1757
|
+
const uniqueRequestedHashes = new Set([
|
|
1758
|
+
// tx hashes requested by index.
|
|
1759
|
+
...request.txIndices.getTrueIndices().map((i)=>blockTxHashes[i].toString()),
|
|
1760
|
+
// explicitly requested tx hashes.
|
|
1761
|
+
...request.txHashes.map((h)=>h.toString())
|
|
1762
|
+
]);
|
|
1763
|
+
if (!returnedHashes.every((h)=>uniqueRequestedHashes.has(h))) {
|
|
1764
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
|
|
1765
|
+
throw new ValidationError('Returned txs should be a subset of (tx hashes by index) U (explicitly requested tx hashes)');
|
|
1766
|
+
}
|
|
1767
|
+
// Tx indices information is optional, but if present, we need to verify a few things.
|
|
1768
|
+
if (!response.peerHasBlock()) {
|
|
1769
|
+
this.logger.debug(`Peer ${peerId.toString()} signalled missing block`);
|
|
1770
|
+
return true;
|
|
1771
|
+
}
|
|
1772
|
+
// If the response has a non-empty bitvector, it needs to be consistent with the number of txs in the block.
|
|
1773
|
+
if (response.txIndices.getLength() !== blockTxHashes.length) {
|
|
1624
1774
|
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
1625
|
-
throw new ValidationError(`Received
|
|
1775
|
+
throw new ValidationError(`Received block txs with mismatched bitvector length: expected ${blockTxHashes.length}, got ${response.txIndices.getLength()}`);
|
|
1626
1776
|
}
|
|
1627
|
-
//
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
]));
|
|
1637
|
-
const allowedIndexSet = new Set(intersectIdx);
|
|
1638
|
-
const indices = returnedHashes.map((h)=>hashToIndexInProposal.get(h));
|
|
1639
|
-
const allAllowed = indices.every((idx)=>idx !== undefined && allowedIndexSet.has(idx));
|
|
1640
|
-
const strictlyIncreasing = indices.every((idx, i)=>i === 0 ? idx !== undefined : idx > indices[i - 1]);
|
|
1641
|
-
if (!allAllowed || !strictlyIncreasing) {
|
|
1642
|
-
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
|
|
1643
|
-
throw new ValidationError('Returned txs do not match expected subset/order for requested indices');
|
|
1644
|
-
}
|
|
1645
|
-
} else {
|
|
1646
|
-
// No local proposal, cannot check the membership/order of the returned txs
|
|
1647
|
-
this.logger.warn(`Block proposal not found for archive root ${request.archiveRoot.toString()}; cannot validate membership/order of returned txs`);
|
|
1648
|
-
return false;
|
|
1777
|
+
// For every index we requested that the peer claims to have (per its bitvector), the
|
|
1778
|
+
// corresponding tx must be present in the response. A peer advertising availability but
|
|
1779
|
+
// withholding the tx is inconsistent.
|
|
1780
|
+
const returnedHashSet = new Set(returnedHashes);
|
|
1781
|
+
const expectedIndices = request.txIndices.getTrueIndices().filter((i)=>response.txIndices.isSet(i));
|
|
1782
|
+
const missingExpected = expectedIndices.some((i)=>!returnedHashSet.has(blockTxHashes[i].toString()));
|
|
1783
|
+
if (missingExpected) {
|
|
1784
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
|
|
1785
|
+
throw new ValidationError('Peer advertised requested txs via indices but did not return them');
|
|
1649
1786
|
}
|
|
1650
|
-
await Promise.all(response.txs.map((tx)=>this.validateRequestedTx(tx, peerId, requestedTxValidator)));
|
|
1651
1787
|
return true;
|
|
1652
1788
|
} catch (e) {
|
|
1653
1789
|
if (e instanceof ValidationError) {
|
|
@@ -1658,104 +1794,8 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1658
1794
|
return false;
|
|
1659
1795
|
}
|
|
1660
1796
|
}
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
*
|
|
1664
|
-
* The core component of this validator is that each tx hash MUST match the requested tx hash,
|
|
1665
|
-
* In order to perform this check, the tx proof must be verified.
|
|
1666
|
-
*
|
|
1667
|
-
* Note: This function is called from within `ReqResp.sendRequest` as part of the
|
|
1668
|
-
* ReqRespSubProtocol.TX subprotocol validation.
|
|
1669
|
-
*
|
|
1670
|
-
* @param requestedTxHash - The collection of the txs that was requested.
|
|
1671
|
-
* @param responseTx - The collection of txs that was received as a response to the request.
|
|
1672
|
-
* @param peerId - The peer ID of the peer that sent the tx.
|
|
1673
|
-
* @returns True if the whole collection of txs is valid, false otherwise.
|
|
1674
|
-
*/ async validateRequestedTxs(requestedTxHash, responseTx, peerId) {
|
|
1675
|
-
const requested = new Set(requestedTxHash.map((h)=>h.toString()));
|
|
1676
|
-
const requestedTxValidator = this.createRequestedTxValidator();
|
|
1677
|
-
//TODO: (mralj) - this is somewhat naive implementation, if single tx is invalid we consider the whole response invalid.
|
|
1678
|
-
// I think we should still extract the valid txs and return them, so that we can still use the response.
|
|
1679
|
-
try {
|
|
1680
|
-
await Promise.all(responseTx.map((tx)=>this.validateRequestedTx(tx, peerId, requestedTxValidator, requested)));
|
|
1681
|
-
return true;
|
|
1682
|
-
} catch (e) {
|
|
1683
|
-
if (e instanceof ValidationError) {
|
|
1684
|
-
this.logger.warn(`Failed to validate requested txs from peer ${peerId.toString()}, reason ${e.message}`);
|
|
1685
|
-
} else {
|
|
1686
|
-
this.logger.error(`Error during validation of requested txs`, e);
|
|
1687
|
-
}
|
|
1688
|
-
return false;
|
|
1689
|
-
}
|
|
1690
|
-
}
|
|
1691
|
-
/**
|
|
1692
|
-
* Validates a BLOCK response.
|
|
1693
|
-
*
|
|
1694
|
-
* If a local copy exists, enforces hash equality. If missing, rejects (no penalty) since the hash cannot be verified.
|
|
1695
|
-
* Penalizes on block number mismatch or hash mismatch.
|
|
1696
|
-
*
|
|
1697
|
-
* @param requestedBlockNumber - The requested block number.
|
|
1698
|
-
* @param responseBlock - The block returned by the peer.
|
|
1699
|
-
* @param peerId - The peer that returned the block.
|
|
1700
|
-
* @returns True if the response is valid, false otherwise.
|
|
1701
|
-
*/ async validateRequestedBlock(requestedBlockNumber, responseBlock, peerId) {
|
|
1702
|
-
try {
|
|
1703
|
-
const reqNum = Number(requestedBlockNumber.toString());
|
|
1704
|
-
if (responseBlock.number !== reqNum) {
|
|
1705
|
-
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
|
|
1706
|
-
return false;
|
|
1707
|
-
}
|
|
1708
|
-
const local = await this.archiver.getBlock(BlockNumber(reqNum));
|
|
1709
|
-
if (!local) {
|
|
1710
|
-
// We are missing the local block; we cannot verify the hash yet. Reject without penalizing.
|
|
1711
|
-
// TODO: Consider extending this validator to accept an expected hash or
|
|
1712
|
-
// performing quorum-based checks when using P2P syncing prior to L1 sync.
|
|
1713
|
-
this.logger.warn(`Local block ${reqNum} not found; rejecting BLOCK response without hash verification`);
|
|
1714
|
-
return false;
|
|
1715
|
-
}
|
|
1716
|
-
const [localHash, respHash] = await Promise.all([
|
|
1717
|
-
local.hash(),
|
|
1718
|
-
responseBlock.hash()
|
|
1719
|
-
]);
|
|
1720
|
-
if (!localHash.equals(respHash)) {
|
|
1721
|
-
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
1722
|
-
return false;
|
|
1723
|
-
}
|
|
1724
|
-
return true;
|
|
1725
|
-
} catch (e) {
|
|
1726
|
-
this.logger.warn(`Error validating requested block`, e);
|
|
1727
|
-
return false;
|
|
1728
|
-
}
|
|
1729
|
-
}
|
|
1730
|
-
async validateRequestedTx(tx, peerId, txValidator, requested) {
|
|
1731
|
-
const penalize = (severity)=>this.peerManager.penalizePeer(peerId, severity);
|
|
1732
|
-
if (requested && !requested.has(tx.getTxHash().toString())) {
|
|
1733
|
-
penalize(PeerErrorSeverity.MidToleranceError);
|
|
1734
|
-
throw new ValidationError(`Received tx with hash ${tx.getTxHash().toString()} that was not requested.`);
|
|
1735
|
-
}
|
|
1736
|
-
const { result } = await txValidator.validateTx(tx);
|
|
1737
|
-
if (result === 'invalid') {
|
|
1738
|
-
penalize(PeerErrorSeverity.LowToleranceError);
|
|
1739
|
-
throw new ValidationError(`Received tx with hash ${tx.getTxHash().toString()} that is invalid.`);
|
|
1740
|
-
}
|
|
1741
|
-
}
|
|
1742
|
-
createRequestedTxValidator() {
|
|
1743
|
-
return createTxValidatorForReqResponseReceivedTxs(this.proofVerifier, {
|
|
1744
|
-
l1ChainId: this.config.l1ChainId,
|
|
1745
|
-
rollupVersion: this.config.rollupVersion
|
|
1746
|
-
});
|
|
1747
|
-
}
|
|
1748
|
-
async getGasFees(blockNumber) {
|
|
1749
|
-
if (blockNumber === this.feesCache?.blockNumber) {
|
|
1750
|
-
return this.feesCache.gasFees;
|
|
1751
|
-
}
|
|
1752
|
-
const header = await this.archiver.getBlockHeader(blockNumber);
|
|
1753
|
-
const gasFees = header?.globalVariables.gasFees ?? GasFees.empty();
|
|
1754
|
-
this.feesCache = {
|
|
1755
|
-
blockNumber,
|
|
1756
|
-
gasFees
|
|
1757
|
-
};
|
|
1758
|
-
return gasFees;
|
|
1797
|
+
getGasFees() {
|
|
1798
|
+
return this.blockMinFeesProvider.getCurrentMinFees();
|
|
1759
1799
|
}
|
|
1760
1800
|
/**
|
|
1761
1801
|
* Get the BatchTxRequesterLibP2PService dependencies for creating BatchTxRequester instances
|
|
@@ -1766,36 +1806,44 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1766
1806
|
txValidatorConfig: {
|
|
1767
1807
|
l1ChainId: this.config.l1ChainId,
|
|
1768
1808
|
rollupVersion: this.config.rollupVersion,
|
|
1769
|
-
proofVerifier: this.proofVerifier
|
|
1809
|
+
proofVerifier: this.proofVerifier,
|
|
1810
|
+
txValidationCache: this.txValidationCache
|
|
1770
1811
|
},
|
|
1771
|
-
peerScoring: this.peerManager
|
|
1812
|
+
peerScoring: this.peerManager,
|
|
1813
|
+
validateRequestedBlockTxsConsistency: this.validateRequestedBlockTxsConsistency.bind(this)
|
|
1772
1814
|
};
|
|
1773
1815
|
}
|
|
1774
1816
|
async validateTxsReceivedInBlockProposal(txs) {
|
|
1775
1817
|
const validator = createTxValidatorForBlockProposalReceivedTxs(this.proofVerifier, {
|
|
1776
1818
|
l1ChainId: this.config.l1ChainId,
|
|
1777
1819
|
rollupVersion: this.config.rollupVersion
|
|
1778
|
-
}, this.logger.getBindings());
|
|
1779
|
-
const results = await Promise.all(txs.map(async (tx)=>{
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1820
|
+
}, this.logger.getBindings(), this.txValidationCache);
|
|
1821
|
+
const results = await Promise.all(txs.map(async (tx)=>({
|
|
1822
|
+
txHash: tx.getTxHash(),
|
|
1823
|
+
result: await validator.validateTx(tx)
|
|
1824
|
+
})));
|
|
1825
|
+
const invalidTxs = results.flatMap(({ txHash, result })=>result.result === 'invalid' ? [
|
|
1826
|
+
{
|
|
1827
|
+
txHash,
|
|
1828
|
+
reasons: result.reason
|
|
1829
|
+
}
|
|
1830
|
+
] : []);
|
|
1831
|
+
if (invalidTxs.length > 0) {
|
|
1832
|
+
throw new InvalidBlockProposalTxsError(invalidTxs);
|
|
1785
1833
|
}
|
|
1786
1834
|
}
|
|
1787
1835
|
/** Creates the first stage (fast) validators for gossiped transactions. */ async createFirstStageMessageValidators(currentBlockNumber, nextSlotTimestamp) {
|
|
1788
|
-
const gasFees = await this.getGasFees(
|
|
1836
|
+
const gasFees = await this.getGasFees();
|
|
1789
1837
|
const allowedInSetup = [
|
|
1790
1838
|
...await getDefaultAllowedSetupFunctions(),
|
|
1791
1839
|
...this.config.txPublicSetupAllowListExtend ?? []
|
|
1792
1840
|
];
|
|
1793
1841
|
const blockNumber = BlockNumber(currentBlockNumber + 1);
|
|
1794
1842
|
const l1Constants = await this.archiver.getL1Constants();
|
|
1843
|
+
const networkTxGasLimits = getNetworkTxGasLimits(this.config, l1Constants);
|
|
1795
1844
|
return createFirstStageTxValidationsForGossipedTransactions(nextSlotTimestamp, blockNumber, this.worldStateSynchronizer, gasFees, this.config.l1ChainId, this.config.rollupVersion, protocolContractsHash, this.archiver, !this.config.disableTransactions, allowedInSetup, this.logger.getBindings(), {
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
maxBlockDAGas: this.config.validateMaxDABlockGas
|
|
1845
|
+
maxTxL2Gas: networkTxGasLimits.l2Gas,
|
|
1846
|
+
maxTxDAGas: networkTxGasLimits.daGas
|
|
1799
1847
|
});
|
|
1800
1848
|
}
|
|
1801
1849
|
/** Creates the second stage (expensive proof verification) validators for gossiped transactions. */ createSecondStageMessageValidators() {
|