@aztec/p2p 0.0.1-commit.9ef841308 → 0.0.1-commit.a4600f49
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 +33 -24
- package/dest/client/interface.d.ts +48 -11
- 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/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/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.js +1 -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 +62 -0
- package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.js +2 -2
- 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 +8 -5
- 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/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 +40 -40
- package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
- package/dest/services/libp2p/libp2p_service.js +292 -264
- package/dest/services/peer-manager/peer_manager.d.ts +15 -2
- package/dest/services/peer-manager/peer_manager.d.ts.map +1 -1
- package/dest/services/peer-manager/peer_manager.js +59 -17
- package/dest/services/peer-manager/peer_scoring.d.ts +30 -1
- package/dest/services/peer-manager/peer_scoring.d.ts.map +1 -1
- package/dest/services/peer-manager/peer_scoring.js +74 -3
- 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_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 +23 -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/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 +1 -1
- package/dest/services/tx_collection/tx_source.d.ts.map +1 -1
- package/dest/services/tx_collection/tx_source.js +4 -1
- 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 +28 -13
- 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 +60 -27
- 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 -8
- 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 +16 -16
- package/src/bootstrap/bootstrap.ts +17 -3
- package/src/client/factory.ts +49 -25
- package/src/client/interface.ts +44 -17
- 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/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/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 +1 -1
- 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 +65 -0
- package/src/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.ts +3 -3
- package/src/mem_pools/tx_pool_v2/interfaces.ts +31 -4
- package/src/mem_pools/tx_pool_v2/tx_metadata.ts +13 -7
- 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/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/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 +342 -290
- package/src/services/peer-manager/peer_manager.ts +63 -16
- package/src/services/peer-manager/peer_scoring.ts +81 -3
- 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_limits.ts +3 -13
- package/src/services/reqresp/reqresp.ts +69 -252
- package/src/services/service.ts +28 -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/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 +2 -1
- 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 +35 -26
- package/src/testbench/p2p_client_testbench_worker.ts +68 -44
- package/src/testbench/worker_client_manager.ts +59 -19
- 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 -315
- 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/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 -355
- package/src/client/test/tx_proposal_collector/proposal_tx_collector_worker_protocol.ts +0 -43
- 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
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import type { EpochCacheInterface } from '@aztec/epoch-cache';
|
|
2
2
|
import { BlockNumber, type SlotNumber } from '@aztec/foundation/branded-types';
|
|
3
|
-
import { maxBy } from '@aztec/foundation/collection';
|
|
4
|
-
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
3
|
+
import { compactArray, maxBy, merge } from '@aztec/foundation/collection';
|
|
5
4
|
import { type Logger, createLibp2pComponentLogger, createLogger } from '@aztec/foundation/log';
|
|
6
5
|
import { RunningPromise } from '@aztec/foundation/running-promise';
|
|
7
6
|
import { Timer } from '@aztec/foundation/timer';
|
|
8
7
|
import type { AztecAsyncKVStore } from '@aztec/kv-store';
|
|
9
8
|
import { protocolContractsHash } from '@aztec/protocol-contracts';
|
|
10
|
-
import type { EthAddress,
|
|
9
|
+
import type { EthAddress, L2BlockSource } from '@aztec/stdlib/block';
|
|
10
|
+
import { DEFAULT_MAX_BLOCKS_PER_CHECKPOINT } from '@aztec/stdlib/config';
|
|
11
11
|
import type { ContractDataSource } from '@aztec/stdlib/contract';
|
|
12
|
-
import { GasFees } from '@aztec/stdlib/gas';
|
|
12
|
+
import { type BlockMinFeesProvider, GasFees, getNetworkTxGasLimits } from '@aztec/stdlib/gas';
|
|
13
13
|
import type { ClientProtocolCircuitVerifier, PeerInfo, WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
|
|
14
14
|
import {
|
|
15
15
|
BlockProposal,
|
|
@@ -25,8 +25,9 @@ import {
|
|
|
25
25
|
getTopicsForConfig,
|
|
26
26
|
metricsTopicStrToLabels,
|
|
27
27
|
} from '@aztec/stdlib/p2p';
|
|
28
|
+
import { ConsensusTimetable, getDefaultCheckpointProposalSyncGrace } from '@aztec/stdlib/timetable';
|
|
28
29
|
import { MerkleTreeId } from '@aztec/stdlib/trees';
|
|
29
|
-
import { Tx, type
|
|
30
|
+
import { Tx, type TxValidationResult } from '@aztec/stdlib/tx';
|
|
30
31
|
import type { UInt64 } from '@aztec/stdlib/types';
|
|
31
32
|
import { compressComponentVersions } from '@aztec/stdlib/versioning';
|
|
32
33
|
import {
|
|
@@ -59,6 +60,7 @@ import { ENR } from '@nethermindeth/enr';
|
|
|
59
60
|
import { createLibp2p } from 'libp2p';
|
|
60
61
|
|
|
61
62
|
import type { P2PConfig } from '../../config.js';
|
|
63
|
+
import { CheckpointProposalReceivedCallbackNotRegisteredError } from '../../errors/p2p-service.error.js';
|
|
62
64
|
import type { MemPools } from '../../mem_pools/interface.js';
|
|
63
65
|
import {
|
|
64
66
|
BlockProposalValidator,
|
|
@@ -74,38 +76,34 @@ import {
|
|
|
74
76
|
createFirstStageTxValidationsForGossipedTransactions,
|
|
75
77
|
createSecondStageTxValidationsForGossipedTransactions,
|
|
76
78
|
createTxValidatorForBlockProposalReceivedTxs,
|
|
77
|
-
createTxValidatorForReqResponseReceivedTxs,
|
|
78
79
|
} from '../../msg_validators/tx_validator/factory.js';
|
|
80
|
+
import { TxValidationCache } from '../../msg_validators/tx_validator/tx_validation_cache.js';
|
|
79
81
|
import { GossipSubEvent } from '../../types/index.js';
|
|
80
82
|
import { type PubSubLibp2p, convertToMultiaddr } from '../../util.js';
|
|
81
83
|
import { getVersions } from '../../versioning.js';
|
|
82
84
|
import { AztecDatastore } from '../data_store.js';
|
|
83
85
|
import { DiscV5Service } from '../discv5/discV5_service.js';
|
|
84
|
-
import { SnappyTransform,
|
|
86
|
+
import { SnappyTransform, getMsgIdFn, msgIdToStrFn } from '../encoding.js';
|
|
85
87
|
import { APP_SPECIFIC_WEIGHT, gossipScoreThresholds } from '../gossipsub/scoring.js';
|
|
86
88
|
import { createAllTopicScoreParams } from '../gossipsub/topic_score_params.js';
|
|
87
89
|
import type { PeerManagerInterface } from '../peer-manager/interface.js';
|
|
88
90
|
import { PeerManager } from '../peer-manager/peer_manager.js';
|
|
89
91
|
import { PeerScoring } from '../peer-manager/peer_scoring.js';
|
|
90
92
|
import type { BatchTxRequesterLibP2PService } from '../reqresp/batch-tx-requester/interface.js';
|
|
91
|
-
import type
|
|
93
|
+
import { type P2PReqRespConfig, YAMUX_MAX_MESSAGE_SIZE_BYTES } from '../reqresp/config.js';
|
|
92
94
|
import {
|
|
93
95
|
AuthRequest,
|
|
94
96
|
BlockTxsRequest,
|
|
95
97
|
BlockTxsResponse,
|
|
96
|
-
DEFAULT_SUB_PROTOCOL_VALIDATORS,
|
|
97
98
|
type ReqRespInterface,
|
|
98
99
|
type ReqRespResponse,
|
|
99
100
|
ReqRespSubProtocol,
|
|
100
101
|
type ReqRespSubProtocolHandler,
|
|
101
102
|
type ReqRespSubProtocolHandlers,
|
|
102
|
-
type ReqRespSubProtocolValidators,
|
|
103
103
|
StatusMessage,
|
|
104
|
-
type SubProtocolMap,
|
|
105
104
|
ValidationError,
|
|
106
105
|
pingHandler,
|
|
107
106
|
reqGoodbyeHandler,
|
|
108
|
-
reqRespBlockHandler,
|
|
109
107
|
reqRespBlockTxsHandler,
|
|
110
108
|
reqRespStatusHandler,
|
|
111
109
|
reqRespTxHandler,
|
|
@@ -113,13 +111,33 @@ import {
|
|
|
113
111
|
import { ReqResp } from '../reqresp/reqresp.js';
|
|
114
112
|
import type {
|
|
115
113
|
P2PBlockReceivedCallback,
|
|
114
|
+
P2PCheckpointAttestationCallback,
|
|
116
115
|
P2PCheckpointReceivedCallback,
|
|
117
116
|
P2PDuplicateAttestationCallback,
|
|
117
|
+
P2POversizedProposalCallback,
|
|
118
118
|
P2PService,
|
|
119
119
|
PeerDiscoveryService,
|
|
120
120
|
} from '../service.js';
|
|
121
121
|
import { P2PInstrumentation } from './instrumentation.js';
|
|
122
122
|
|
|
123
|
+
/**
|
|
124
|
+
* Builds the {@link ConsensusTimetable} shared by the gossip validators for proposal/attestation receive-window
|
|
125
|
+
* bounds. Derived purely from protocol slot-timing constants plus the block sub-slot duration and the consensus
|
|
126
|
+
* materialization grace, so every node agrees on these bounds without depending on proposer operational budgets.
|
|
127
|
+
*/
|
|
128
|
+
function buildConsensusTimetable(
|
|
129
|
+
config: P2PConfig,
|
|
130
|
+
l1Constants: ReturnType<EpochCacheInterface['getL1Constants']>,
|
|
131
|
+
): ConsensusTimetable {
|
|
132
|
+
const blockDuration = config.blockDurationMs / 1000;
|
|
133
|
+
return new ConsensusTimetable({
|
|
134
|
+
l1Constants,
|
|
135
|
+
blockDuration,
|
|
136
|
+
checkpointProposalSyncGrace:
|
|
137
|
+
config.checkpointProposalSyncGraceSeconds ?? getDefaultCheckpointProposalSyncGrace(blockDuration),
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
|
|
123
141
|
interface ValidationResult {
|
|
124
142
|
name: string;
|
|
125
143
|
isValid: TxValidationResult;
|
|
@@ -148,8 +166,6 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
148
166
|
private protocolVersion = '';
|
|
149
167
|
private topicStrings: Record<TopicType, string> = {} as Record<TopicType, string>;
|
|
150
168
|
|
|
151
|
-
private feesCache: { blockNumber: BlockNumber; gasFees: GasFees } | undefined;
|
|
152
|
-
|
|
153
169
|
/** Callback invoked when a duplicate proposal is detected (triggers slashing). */
|
|
154
170
|
private duplicateProposalCallback?: (info: {
|
|
155
171
|
slot: SlotNumber;
|
|
@@ -157,9 +173,15 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
157
173
|
type: 'checkpoint' | 'block';
|
|
158
174
|
}) => void;
|
|
159
175
|
|
|
176
|
+
/** Callback invoked when an oversized block proposal is stored as slashing evidence (triggers slashing). */
|
|
177
|
+
private oversizedProposalCallback?: P2POversizedProposalCallback;
|
|
178
|
+
|
|
160
179
|
/** Callback invoked when a duplicate attestation is detected (triggers slashing). */
|
|
161
180
|
private duplicateAttestationCallback?: P2PDuplicateAttestationCallback;
|
|
162
181
|
|
|
182
|
+
/** Callback invoked when a valid checkpoint attestation is accepted into the pool. */
|
|
183
|
+
private checkpointAttestationCallback?: P2PCheckpointAttestationCallback;
|
|
184
|
+
|
|
163
185
|
/**
|
|
164
186
|
* Callback for when a block is received from a peer.
|
|
165
187
|
* @param block - The block received from the peer.
|
|
@@ -172,12 +194,17 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
172
194
|
* @param checkpoint - The checkpoint proposal received from the peer.
|
|
173
195
|
* @returns The attestations for the checkpoint, if any.
|
|
174
196
|
*/
|
|
175
|
-
private
|
|
197
|
+
private allNodesCheckpointReceivedCallback: P2PCheckpointReceivedCallback;
|
|
198
|
+
/**
|
|
199
|
+
* Callback for when a checkpoint proposal is received - specifically for validators - from a peer.
|
|
200
|
+
* @param checkpoint - The checkpoint proposal received from the peer.
|
|
201
|
+
* @returns The attestations for the checkpoint, if any.
|
|
202
|
+
*/
|
|
203
|
+
private validatorCheckpointReceivedCallback: P2PCheckpointReceivedCallback;
|
|
176
204
|
|
|
177
205
|
private gossipSubEventHandler: (e: CustomEvent<GossipsubMessage>) => void;
|
|
178
|
-
private ipChangedHandler?: (ip: string) => void;
|
|
179
206
|
|
|
180
|
-
|
|
207
|
+
private ipChangedHandler?: (ip: string) => void;
|
|
181
208
|
private discoveredP2pIp?: string;
|
|
182
209
|
|
|
183
210
|
private instrumentation: P2PInstrumentation;
|
|
@@ -197,8 +224,10 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
197
224
|
private epochCache: EpochCacheInterface,
|
|
198
225
|
private proofVerifier: ClientProtocolCircuitVerifier,
|
|
199
226
|
private worldStateSynchronizer: WorldStateSynchronizer,
|
|
227
|
+
private blockMinFeesProvider: BlockMinFeesProvider,
|
|
200
228
|
telemetry: TelemetryClient,
|
|
201
229
|
logger: Logger = createLogger('p2p:libp2p_service'),
|
|
230
|
+
private txValidationCache?: TxValidationCache,
|
|
202
231
|
) {
|
|
203
232
|
super(telemetry, 'LibP2PService');
|
|
204
233
|
this.telemetry = telemetry;
|
|
@@ -228,15 +257,39 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
228
257
|
this.protocolVersion,
|
|
229
258
|
);
|
|
230
259
|
|
|
260
|
+
// Build the consensus timetable once from protocol slot-timing constants and inject it into every
|
|
261
|
+
// validator so they share one set of receive-window bounds, independent of proposer operational budgets.
|
|
262
|
+
const consensusTimetable = buildConsensusTimetable(config, epochCache.getL1Constants());
|
|
231
263
|
const proposalValidatorOpts = {
|
|
232
264
|
txsPermitted: !config.disableTransactions,
|
|
233
265
|
maxTxsPerBlock: config.validateMaxTxsPerBlock ?? config.validateMaxTxsPerCheckpoint,
|
|
266
|
+
maxBlocksPerCheckpoint: config.maxBlocksPerCheckpoint,
|
|
267
|
+
skipSlotValidation: config.skipProposalSlotValidation,
|
|
268
|
+
signatureContext: {
|
|
269
|
+
chainId: config.l1ChainId,
|
|
270
|
+
rollupAddress: config.rollupAddress,
|
|
271
|
+
},
|
|
272
|
+
clockDisparityMs: config.maxGossipClockDisparityMs,
|
|
273
|
+
};
|
|
274
|
+
this.blockProposalValidator = new BlockProposalValidator(epochCache, consensusTimetable, proposalValidatorOpts);
|
|
275
|
+
this.checkpointProposalValidator = new CheckpointProposalValidator(
|
|
276
|
+
epochCache,
|
|
277
|
+
consensusTimetable,
|
|
278
|
+
proposalValidatorOpts,
|
|
279
|
+
);
|
|
280
|
+
const attestationValidatorOpts = {
|
|
281
|
+
signatureContext: proposalValidatorOpts.signatureContext,
|
|
282
|
+
clockDisparityMs: config.maxGossipClockDisparityMs,
|
|
234
283
|
};
|
|
235
|
-
this.blockProposalValidator = new BlockProposalValidator(epochCache, proposalValidatorOpts);
|
|
236
|
-
this.checkpointProposalValidator = new CheckpointProposalValidator(epochCache, proposalValidatorOpts);
|
|
237
284
|
this.checkpointAttestationValidator = config.fishermanMode
|
|
238
|
-
? new FishermanAttestationValidator(
|
|
239
|
-
|
|
285
|
+
? new FishermanAttestationValidator(
|
|
286
|
+
epochCache,
|
|
287
|
+
consensusTimetable,
|
|
288
|
+
mempools.attestationPool,
|
|
289
|
+
telemetry,
|
|
290
|
+
attestationValidatorOpts,
|
|
291
|
+
)
|
|
292
|
+
: new CheckpointAttestationValidator(epochCache, consensusTimetable, attestationValidatorOpts);
|
|
240
293
|
|
|
241
294
|
this.gossipSubEventHandler = this.handleGossipSubEvent.bind(this);
|
|
242
295
|
|
|
@@ -248,18 +301,22 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
248
301
|
return true;
|
|
249
302
|
};
|
|
250
303
|
|
|
251
|
-
this.
|
|
252
|
-
|
|
304
|
+
this.allNodesCheckpointReceivedCallback = (
|
|
305
|
+
_checkpoint: CheckpointProposalCore,
|
|
306
|
+
): Promise<CheckpointAttestation[] | undefined> => {
|
|
307
|
+
throw new CheckpointProposalReceivedCallbackNotRegisteredError();
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
this.validatorCheckpointReceivedCallback = (
|
|
311
|
+
_checkpoint: CheckpointProposalCore,
|
|
253
312
|
): Promise<CheckpointAttestation[] | undefined> => {
|
|
254
|
-
this.logger.debug(
|
|
255
|
-
`Handler not yet registered: Checkpoint received callback not set. Received checkpoint for slot ${checkpoint.slotNumber} from peer.`,
|
|
256
|
-
);
|
|
257
313
|
return Promise.resolve(undefined);
|
|
258
314
|
};
|
|
259
315
|
}
|
|
260
316
|
|
|
261
|
-
public updateConfig(config: Partial<P2PReqRespConfig
|
|
317
|
+
public updateConfig(config: Partial<P2PReqRespConfig & Pick<P2PConfig, 'skipIncomingProposals'>>) {
|
|
262
318
|
this.reqresp.updateConfig(config);
|
|
319
|
+
this.config = merge(this.config, config);
|
|
263
320
|
}
|
|
264
321
|
|
|
265
322
|
/**
|
|
@@ -278,9 +335,11 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
278
335
|
proofVerifier: ClientProtocolCircuitVerifier;
|
|
279
336
|
worldStateSynchronizer: WorldStateSynchronizer;
|
|
280
337
|
peerStore: AztecAsyncKVStore;
|
|
338
|
+
blockMinFeesProvider: BlockMinFeesProvider;
|
|
281
339
|
telemetry: TelemetryClient;
|
|
282
340
|
logger: Logger;
|
|
283
341
|
packageVersion: string;
|
|
342
|
+
txValidationCache?: TxValidationCache;
|
|
284
343
|
},
|
|
285
344
|
) {
|
|
286
345
|
const {
|
|
@@ -290,9 +349,11 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
290
349
|
mempools,
|
|
291
350
|
proofVerifier,
|
|
292
351
|
peerStore,
|
|
352
|
+
blockMinFeesProvider,
|
|
293
353
|
telemetry,
|
|
294
354
|
logger,
|
|
295
355
|
packageVersion,
|
|
356
|
+
txValidationCache,
|
|
296
357
|
} = deps;
|
|
297
358
|
const { p2pPort, maxPeerCount, listenAddress } = config;
|
|
298
359
|
const bindAddrTcp = convertToMultiaddr(listenAddress, p2pPort, 'tcp');
|
|
@@ -307,6 +368,7 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
307
368
|
packageVersion,
|
|
308
369
|
telemetry,
|
|
309
370
|
createLogger(`${logger.module}:discv5_service`, logger.getBindings()),
|
|
371
|
+
peerStore,
|
|
310
372
|
);
|
|
311
373
|
|
|
312
374
|
// Seed libp2p's bootstrap discovery with private and trusted peers
|
|
@@ -321,34 +383,49 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
321
383
|
const protocolVersion = compressComponentVersions(versions);
|
|
322
384
|
|
|
323
385
|
const preferredPeersEnrs: ENR[] = config.preferredPeers.map(enr => ENR.decodeTxt(enr));
|
|
324
|
-
const directPeers = (
|
|
386
|
+
const directPeers = compactArray(
|
|
325
387
|
await Promise.all(
|
|
326
388
|
preferredPeersEnrs.map(async enr => {
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
389
|
+
try {
|
|
390
|
+
const peerId = await enr.peerId();
|
|
391
|
+
const address = enr.getLocationMultiaddr('tcp');
|
|
392
|
+
if (address === undefined) {
|
|
393
|
+
throw new Error(`Direct peer ${peerId.toString()} has no TCP address, ENR: ${enr.encodeTxt()}`);
|
|
394
|
+
}
|
|
395
|
+
return {
|
|
396
|
+
id: peerId,
|
|
397
|
+
addrs: [address],
|
|
398
|
+
};
|
|
399
|
+
} catch (err) {
|
|
400
|
+
// A malformed configured ENR shouldn't abort node setup — skip it and log.
|
|
401
|
+
logger.warn(`Skipping preferred peer with invalid ENR`, { err });
|
|
402
|
+
return undefined;
|
|
331
403
|
}
|
|
332
|
-
return {
|
|
333
|
-
id: peerId,
|
|
334
|
-
addrs: [address],
|
|
335
|
-
};
|
|
336
404
|
}),
|
|
337
|
-
)
|
|
338
|
-
)
|
|
405
|
+
),
|
|
406
|
+
);
|
|
339
407
|
|
|
340
408
|
const announceTcpMultiaddr = config.p2pIp ? [convertToMultiaddr(config.p2pIp, p2pPort, 'tcp')] : [];
|
|
341
409
|
|
|
342
|
-
// Create dynamic topic score params based on network configuration
|
|
410
|
+
// Create dynamic topic score params based on network configuration. Scoring uses the network-wide
|
|
411
|
+
// max-blocks-per-checkpoint config value directly to size expected per-slot message rates; these are
|
|
412
|
+
// peer-rate thresholds, not consensus deadlines, so they need no proposer operational budgets.
|
|
343
413
|
const l1Constants = epochCache.getL1Constants();
|
|
344
414
|
const topicScoreParams = createAllTopicScoreParams(protocolVersion, {
|
|
345
415
|
slotDurationMs: l1Constants.slotDuration * 1000,
|
|
346
416
|
heartbeatIntervalMs: config.gossipsubInterval,
|
|
347
417
|
targetCommitteeSize: l1Constants.targetCommitteeSize,
|
|
348
|
-
|
|
418
|
+
maxBlocksPerCheckpoint: config.maxBlocksPerCheckpoint ?? DEFAULT_MAX_BLOCKS_PER_CHECKPOINT,
|
|
349
419
|
expectedBlockProposalsPerSlot: config.expectedBlockProposalsPerSlot,
|
|
350
420
|
});
|
|
351
421
|
|
|
422
|
+
// Restrict gossipsub to exactly the topics we subscribe to. Without this, an arbitrary-topic
|
|
423
|
+
// message is transformed, msg-id'd and inserted into the seenCache before the subscription check,
|
|
424
|
+
// so a crafted topic colliding on msg id can suppress a real message as a duplicate.
|
|
425
|
+
const allowedTopics = getTopicsForConfig(config.disableTransactions).map(topic =>
|
|
426
|
+
createTopicString(topic, protocolVersion),
|
|
427
|
+
);
|
|
428
|
+
|
|
352
429
|
const node = await createLibp2p({
|
|
353
430
|
start: false,
|
|
354
431
|
peerId,
|
|
@@ -380,7 +457,8 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
380
457
|
],
|
|
381
458
|
datastore,
|
|
382
459
|
peerDiscovery,
|
|
383
|
-
|
|
460
|
+
// Pin the yamux frame size: MAX_REQRESP_REQUEST_SIZE_BYTES relies on a reqresp request fitting in one frame.
|
|
461
|
+
streamMuxers: [yamux({ maxMessageSize: YAMUX_MAX_MESSAGE_SIZE_BYTES }), mplex()],
|
|
384
462
|
connectionEncryption: [noise()],
|
|
385
463
|
connectionManager: {
|
|
386
464
|
minConnections: 0, // Disable libp2p peer dialing, we do it manually
|
|
@@ -394,7 +472,7 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
394
472
|
},
|
|
395
473
|
connectionGater: {
|
|
396
474
|
denyInboundConnection: (maConn: MultiaddrConnection) => {
|
|
397
|
-
const allowed = peerManager.
|
|
475
|
+
const allowed = peerManager.isAddressAllowedToConnect(maConn.remoteAddr.nodeAddress().address);
|
|
398
476
|
if (allowed) {
|
|
399
477
|
return false;
|
|
400
478
|
}
|
|
@@ -405,7 +483,7 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
405
483
|
denyInboundEncryptedConnection: (peerId: PeerId, _maConn: MultiaddrConnection) => {
|
|
406
484
|
//NOTE: it is not necessary to check address here because this was already done by
|
|
407
485
|
// denyInboundConnection
|
|
408
|
-
const allowed = peerManager.
|
|
486
|
+
const allowed = peerManager.isPeerAllowedToConnect(peerId);
|
|
409
487
|
if (allowed) {
|
|
410
488
|
return false;
|
|
411
489
|
}
|
|
@@ -433,9 +511,13 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
433
511
|
mcacheLength: config.gossipsubMcacheLength,
|
|
434
512
|
mcacheGossip: config.gossipsubMcacheGossip,
|
|
435
513
|
seenTTL: config.gossipsubSeenTTL,
|
|
514
|
+
allowedTopics,
|
|
515
|
+
// No fastMsgIdFn: the fast-path dedup cache keys on a non-cryptographic 64-bit hash of the
|
|
516
|
+
// raw data only (no topic), so a collision — accidental or engineered via a weak seed — drops
|
|
517
|
+
// a different message with no fallback to the full id. Dedup instead rests solely on the
|
|
518
|
+
// cryptographic, topic-framed msgIdFn below.
|
|
436
519
|
msgIdFn: getMsgIdFn,
|
|
437
520
|
msgIdToStrFn: msgIdToStrFn,
|
|
438
|
-
fastMsgIdFn: fastMsgIdFn,
|
|
439
521
|
dataTransform: new SnappyTransform(),
|
|
440
522
|
metricsRegister: otelMetricsAdapter,
|
|
441
523
|
metricsTopicStrToLabel: metricsTopicStrToLabels(protocolVersion),
|
|
@@ -471,6 +553,9 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
471
553
|
epochCache,
|
|
472
554
|
);
|
|
473
555
|
|
|
556
|
+
// Gate req/resp data protocols for unauthenticated peers when p2pAllowOnlyValidators is enabled
|
|
557
|
+
reqresp.setShouldRejectPeer(peerId => peerManager.shouldDisableP2PGossip(peerId));
|
|
558
|
+
|
|
474
559
|
// Configure application-specific scoring for gossipsub.
|
|
475
560
|
// The weight scales app score to align with gossipsub thresholds:
|
|
476
561
|
// - Disconnect (-50) × 10 = -500 = gossipThreshold (stops receiving gossip)
|
|
@@ -491,8 +576,10 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
491
576
|
epochCache,
|
|
492
577
|
proofVerifier,
|
|
493
578
|
worldStateSynchronizer,
|
|
579
|
+
blockMinFeesProvider,
|
|
494
580
|
telemetry,
|
|
495
581
|
logger,
|
|
582
|
+
txValidationCache,
|
|
496
583
|
);
|
|
497
584
|
}
|
|
498
585
|
|
|
@@ -506,24 +593,21 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
506
593
|
throw new Error('P2P service already started');
|
|
507
594
|
}
|
|
508
595
|
|
|
509
|
-
// Get listen & announce addresses for logging
|
|
510
596
|
const { p2pIp, p2pPort } = this.config;
|
|
511
597
|
if (!p2pIp && !this.config.queryForIp) {
|
|
512
|
-
throw new Error('Announce address not provided.');
|
|
598
|
+
throw new Error('Announce address not provided and queryForIp is not enabled.');
|
|
513
599
|
}
|
|
514
600
|
const announceTcpMultiaddr = p2pIp ? convertToMultiaddr(p2pIp, p2pPort, 'tcp') : undefined;
|
|
515
601
|
|
|
516
602
|
// Create request response protocol handlers
|
|
517
603
|
const txHandler = reqRespTxHandler(this.mempools);
|
|
518
604
|
const goodbyeHandler = reqGoodbyeHandler(this.peerManager);
|
|
519
|
-
const blockHandler = reqRespBlockHandler(this.archiver);
|
|
520
605
|
const statusHandler = reqRespStatusHandler(this.protocolVersion, this.worldStateSynchronizer, this.logger);
|
|
521
606
|
|
|
522
607
|
const requestResponseHandlers: Partial<ReqRespSubProtocolHandlers> = {
|
|
523
608
|
[ReqRespSubProtocol.PING]: pingHandler,
|
|
524
609
|
[ReqRespSubProtocol.STATUS]: statusHandler.bind(this),
|
|
525
610
|
[ReqRespSubProtocol.GOODBYE]: goodbyeHandler.bind(this),
|
|
526
|
-
[ReqRespSubProtocol.BLOCK]: blockHandler.bind(this),
|
|
527
611
|
};
|
|
528
612
|
|
|
529
613
|
if (!this.config.disableTransactions) {
|
|
@@ -539,17 +623,9 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
539
623
|
requestResponseHandlers[ReqRespSubProtocol.TX] = txHandler.bind(this);
|
|
540
624
|
}
|
|
541
625
|
|
|
542
|
-
// Define the sub protocol validators - This is done within this start() method to gain a callback to the existing validateTx function
|
|
543
|
-
const reqrespSubProtocolValidators = {
|
|
544
|
-
...DEFAULT_SUB_PROTOCOL_VALIDATORS,
|
|
545
|
-
[ReqRespSubProtocol.TX]: this.validateRequestedTxs.bind(this),
|
|
546
|
-
[ReqRespSubProtocol.BLOCK_TXS]: this.validateRequestedBlockTxs.bind(this),
|
|
547
|
-
[ReqRespSubProtocol.BLOCK]: this.validateRequestedBlock.bind(this),
|
|
548
|
-
};
|
|
549
|
-
|
|
550
626
|
await this.peerManager.initializePeers();
|
|
551
627
|
|
|
552
|
-
await this.reqresp.start(requestResponseHandlers
|
|
628
|
+
await this.reqresp.start(requestResponseHandlers);
|
|
553
629
|
|
|
554
630
|
await this.node.start();
|
|
555
631
|
|
|
@@ -566,26 +642,33 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
566
642
|
await this.peerDiscoveryService.start();
|
|
567
643
|
}
|
|
568
644
|
|
|
569
|
-
//
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
if (this.config.queryForIp && !p2pIp) {
|
|
645
|
+
// Bridge discv5 IP changes to libp2p's AddressManager so peers see the updated address
|
|
646
|
+
if (this.config.queryForIp) {
|
|
647
|
+
this.discoveredP2pIp = this.config.p2pIp;
|
|
648
|
+
this.logger.info('IP change tracking enabled, bridging discv5 IP updates to libp2p AddressManager');
|
|
574
649
|
this.ipChangedHandler = (ip: string) => {
|
|
575
650
|
const addressManager = this.node.services.components.addressManager;
|
|
576
651
|
const newAddr = multiaddr(convertToMultiaddr(ip, this.config.p2pPort, 'tcp'));
|
|
652
|
+
const previousIp = this.discoveredP2pIp;
|
|
577
653
|
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
const oldAddr = multiaddr(convertToMultiaddr(this.discoveredP2pIp, this.config.p2pPort, 'tcp'));
|
|
654
|
+
if (previousIp) {
|
|
655
|
+
const oldAddr = multiaddr(convertToMultiaddr(previousIp, this.config.p2pPort, 'tcp'));
|
|
581
656
|
addressManager.removeObservedAddr(oldAddr);
|
|
657
|
+
this.logger.info('Libp2p announce address updated due to IP change', {
|
|
658
|
+
previousIp,
|
|
659
|
+
newIp: ip,
|
|
660
|
+
newMultiaddr: newAddr.toString(),
|
|
661
|
+
});
|
|
662
|
+
} else {
|
|
663
|
+
this.logger.info('Libp2p announce address set from initial discv5 IP discovery', {
|
|
664
|
+
ip,
|
|
665
|
+
multiaddr: newAddr.toString(),
|
|
666
|
+
});
|
|
582
667
|
}
|
|
583
668
|
|
|
584
669
|
addressManager.addObservedAddr(newAddr);
|
|
585
670
|
addressManager.confirmObservedAddr(newAddr);
|
|
586
|
-
// Store discovered IP
|
|
587
671
|
this.discoveredP2pIp = ip;
|
|
588
|
-
this.logger.info('Public IP discovered via discv5', { ip });
|
|
589
672
|
};
|
|
590
673
|
this.peerDiscoveryService.on('ip:changed', this.ipChangedHandler);
|
|
591
674
|
}
|
|
@@ -602,7 +685,7 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
602
685
|
this.logger.info(`Started P2P service`, {
|
|
603
686
|
listen: this.config.listenAddress,
|
|
604
687
|
port: this.config.p2pPort,
|
|
605
|
-
announce: announceTcpMultiaddr
|
|
688
|
+
announce: announceTcpMultiaddr,
|
|
606
689
|
peerId: this.node.peerId.toString(),
|
|
607
690
|
});
|
|
608
691
|
}
|
|
@@ -615,9 +698,8 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
615
698
|
// Remove gossip sub listener
|
|
616
699
|
this.node.services.pubsub.removeEventListener(GossipSubEvent.MESSAGE, this.gossipSubEventHandler);
|
|
617
700
|
|
|
618
|
-
// Remove ip:changed listener if registered
|
|
619
701
|
if (this.ipChangedHandler) {
|
|
620
|
-
this.peerDiscoveryService.
|
|
702
|
+
this.peerDiscoveryService.removeListener('ip:changed', this.ipChangedHandler);
|
|
621
703
|
this.ipChangedHandler = undefined;
|
|
622
704
|
}
|
|
623
705
|
|
|
@@ -635,12 +717,8 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
635
717
|
this.logger.info('LibP2P service stopped');
|
|
636
718
|
}
|
|
637
719
|
|
|
638
|
-
addReqRespSubProtocol(
|
|
639
|
-
subProtocol
|
|
640
|
-
handler: ReqRespSubProtocolHandler,
|
|
641
|
-
validator?: ReqRespSubProtocolValidators[ReqRespSubProtocol],
|
|
642
|
-
): Promise<void> {
|
|
643
|
-
return this.reqresp.addSubProtocol(subProtocol, handler, validator);
|
|
720
|
+
addReqRespSubProtocol(subProtocol: ReqRespSubProtocol, handler: ReqRespSubProtocolHandler): Promise<void> {
|
|
721
|
+
return this.reqresp.addSubProtocol(subProtocol, handler);
|
|
644
722
|
}
|
|
645
723
|
|
|
646
724
|
public registerThisValidatorAddresses(address: EthAddress[]): void {
|
|
@@ -668,20 +746,6 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
668
746
|
setImmediate(() => void safeJob());
|
|
669
747
|
}
|
|
670
748
|
|
|
671
|
-
/**
|
|
672
|
-
* Send a batch of requests to peers, and return the responses
|
|
673
|
-
* @param protocol - The request response protocol to use
|
|
674
|
-
* @param requests - The requests to send to the peers
|
|
675
|
-
* @returns The responses to the requests
|
|
676
|
-
*/
|
|
677
|
-
sendBatchRequest<SubProtocol extends ReqRespSubProtocol>(
|
|
678
|
-
protocol: SubProtocol,
|
|
679
|
-
requests: InstanceType<SubProtocolMap[SubProtocol]['request']>[],
|
|
680
|
-
pinnedPeerId: PeerId | undefined,
|
|
681
|
-
): Promise<InstanceType<SubProtocolMap[SubProtocol]['response']>[]> {
|
|
682
|
-
return this.reqresp.sendBatchRequest(protocol, requests, pinnedPeerId);
|
|
683
|
-
}
|
|
684
|
-
|
|
685
749
|
public sendRequestToPeer(
|
|
686
750
|
peerId: PeerId,
|
|
687
751
|
subProtocol: ReqRespSubProtocol,
|
|
@@ -703,8 +767,12 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
703
767
|
this.blockReceivedCallback = callback;
|
|
704
768
|
}
|
|
705
769
|
|
|
706
|
-
public
|
|
707
|
-
this.
|
|
770
|
+
public registerValidatorCheckpointReceivedCallback(callback: P2PCheckpointReceivedCallback) {
|
|
771
|
+
this.validatorCheckpointReceivedCallback = callback;
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
public registerAllNodesCheckpointReceivedCallback(callback: P2PCheckpointReceivedCallback) {
|
|
775
|
+
this.allNodesCheckpointReceivedCallback = callback;
|
|
708
776
|
}
|
|
709
777
|
|
|
710
778
|
/**
|
|
@@ -717,6 +785,13 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
717
785
|
this.duplicateProposalCallback = callback;
|
|
718
786
|
}
|
|
719
787
|
|
|
788
|
+
/**
|
|
789
|
+
* Registers a callback to be invoked when an oversized block proposal is stored as slashing evidence.
|
|
790
|
+
*/
|
|
791
|
+
public registerOversizedProposalCallback(callback: P2POversizedProposalCallback): void {
|
|
792
|
+
this.oversizedProposalCallback = callback;
|
|
793
|
+
}
|
|
794
|
+
|
|
720
795
|
/**
|
|
721
796
|
* Registers a callback to be invoked when a duplicate attestation is detected.
|
|
722
797
|
* A validator signing attestations for different proposals at the same slot.
|
|
@@ -726,6 +801,10 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
726
801
|
this.duplicateAttestationCallback = callback;
|
|
727
802
|
}
|
|
728
803
|
|
|
804
|
+
public registerCheckpointAttestationCallback(callback: P2PCheckpointAttestationCallback): void {
|
|
805
|
+
this.checkpointAttestationCallback = callback;
|
|
806
|
+
}
|
|
807
|
+
|
|
729
808
|
/**
|
|
730
809
|
* Subscribes to a topic.
|
|
731
810
|
* @param topic - The topic to subscribe to.
|
|
@@ -854,6 +933,15 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
854
933
|
|
|
855
934
|
// Process the message, optionally within a linked span for trace propagation
|
|
856
935
|
const processMessage = async () => {
|
|
936
|
+
if (
|
|
937
|
+
this.config.skipIncomingProposals &&
|
|
938
|
+
(msg.topic === this.topicStrings[TopicType.block_proposal] ||
|
|
939
|
+
msg.topic === this.topicStrings[TopicType.checkpoint_proposal])
|
|
940
|
+
) {
|
|
941
|
+
this.logger.warn(`Ignoring incoming proposal (skipIncomingProposals is set)`, { topic: msg.topic });
|
|
942
|
+
this.node.services.pubsub.reportMessageValidationResult(msgId, source.toString(), TopicValidatorResult.Ignore);
|
|
943
|
+
return;
|
|
944
|
+
}
|
|
857
945
|
if (msg.topic === this.topicStrings[TopicType.tx]) {
|
|
858
946
|
await this.handleGossipedTx(p2pMessage.payload, msgId, source);
|
|
859
947
|
} else if (msg.topic === this.topicStrings[TopicType.checkpoint_attestation]) {
|
|
@@ -931,6 +1019,17 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
931
1019
|
this.logger.error(`Error validating gossipsub message`, err, { msgId, source: source.toString(), topicType });
|
|
932
1020
|
}
|
|
933
1021
|
|
|
1022
|
+
const validationTimeMs = timer.ms();
|
|
1023
|
+
const mcacheWindowMs = this.config.gossipsubMcacheLength * this.config.gossipsubInterval;
|
|
1024
|
+
if (validationTimeMs > mcacheWindowMs * 0.75) {
|
|
1025
|
+
this.instrumentation.incSlowValidation(topicType);
|
|
1026
|
+
this.logger.warn(
|
|
1027
|
+
`Gossip validation for ${topicType} took ${validationTimeMs}ms, approaching mcache eviction window of ${mcacheWindowMs}ms. ` +
|
|
1028
|
+
`Message forwarding may be skipped if validation exceeds the window.`,
|
|
1029
|
+
{ msgId, source: source.toString(), topicType, validationTimeMs, mcacheWindowMs },
|
|
1030
|
+
);
|
|
1031
|
+
}
|
|
1032
|
+
|
|
934
1033
|
if (resultAndObj.result === TopicValidatorResult.Accept) {
|
|
935
1034
|
this.logger.debug(`Message ${topicType} accepted by validator`, { msgId, source: source.toString(), topicType });
|
|
936
1035
|
this.instrumentation.recordMessageValidation(topicType, timer);
|
|
@@ -1166,6 +1265,7 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1166
1265
|
}
|
|
1167
1266
|
|
|
1168
1267
|
// Attestation was added successfully - accept it so other nodes can also detect the equivocation
|
|
1268
|
+
this.checkpointAttestationCallback?.(attestation);
|
|
1169
1269
|
return { result: TopicValidatorResult.Accept, obj: attestation };
|
|
1170
1270
|
}
|
|
1171
1271
|
|
|
@@ -1173,16 +1273,17 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1173
1273
|
const {
|
|
1174
1274
|
result,
|
|
1175
1275
|
obj: block,
|
|
1176
|
-
metadata: { isEquivocated } = {},
|
|
1177
|
-
} = await this.validateReceivedMessage<BlockProposal, { isEquivocated: boolean }>(
|
|
1276
|
+
metadata: { isEquivocated, isOversized } = {},
|
|
1277
|
+
} = await this.validateReceivedMessage<BlockProposal, { isEquivocated: boolean; isOversized: boolean }>(
|
|
1178
1278
|
() => this.validateAndStoreBlockProposal(source, BlockProposal.fromBuffer(payloadData)),
|
|
1179
1279
|
msgId,
|
|
1180
1280
|
source,
|
|
1181
1281
|
TopicType.block_proposal,
|
|
1182
1282
|
);
|
|
1183
1283
|
|
|
1184
|
-
// If not accepted or
|
|
1185
|
-
|
|
1284
|
+
// If not accepted, equivocated, or oversized, return. Oversized proposals are re-broadcast as
|
|
1285
|
+
// slashing evidence but never attested or processed.
|
|
1286
|
+
if (result !== TopicValidatorResult.Accept || !block || isEquivocated || isOversized) {
|
|
1186
1287
|
return;
|
|
1187
1288
|
}
|
|
1188
1289
|
|
|
@@ -1197,7 +1298,7 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1197
1298
|
protected async validateAndStoreBlockProposal(
|
|
1198
1299
|
peerId: PeerId,
|
|
1199
1300
|
block: BlockProposal,
|
|
1200
|
-
): Promise<ReceivedMessageValidationResult<BlockProposal, { isEquivocated: boolean }>> {
|
|
1301
|
+
): Promise<ReceivedMessageValidationResult<BlockProposal, { isEquivocated: boolean; isOversized: boolean }>> {
|
|
1201
1302
|
const validationResult = await this.blockProposalValidator.validate(block);
|
|
1202
1303
|
|
|
1203
1304
|
if (validationResult.result === 'reject') {
|
|
@@ -1212,6 +1313,12 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1212
1313
|
// Try to add the proposal: this handles existence check, cap check, and adding in one call
|
|
1213
1314
|
const { added, alreadyExists, count } = await this.mempools.attestationPool.tryAddBlockProposal(block);
|
|
1214
1315
|
const isEquivocated = count !== undefined && count > 1;
|
|
1316
|
+
// An oversized proposal (index at or beyond the consensus per-checkpoint limit) is structurally valid
|
|
1317
|
+
// proposer misbehavior: it is stored and re-broadcast as slashing evidence but never processed or
|
|
1318
|
+
// attested to. No-ops when maxBlocksPerCheckpoint is unset (local/test).
|
|
1319
|
+
const isOversized =
|
|
1320
|
+
this.config.maxBlocksPerCheckpoint !== undefined &&
|
|
1321
|
+
block.indexWithinCheckpoint >= this.config.maxBlocksPerCheckpoint;
|
|
1215
1322
|
|
|
1216
1323
|
// Duplicate proposal received, no need to re-broadcast
|
|
1217
1324
|
if (alreadyExists) {
|
|
@@ -1221,7 +1328,7 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1221
1328
|
proposer: block.getSender()?.toString(),
|
|
1222
1329
|
source: peerId.toString(),
|
|
1223
1330
|
});
|
|
1224
|
-
return { result: TopicValidatorResult.Ignore, obj: block, metadata: { isEquivocated } };
|
|
1331
|
+
return { result: TopicValidatorResult.Ignore, obj: block, metadata: { isEquivocated, isOversized } };
|
|
1225
1332
|
}
|
|
1226
1333
|
|
|
1227
1334
|
// Too many blocks received for this slot and index, penalize peer and do not re-broadcast
|
|
@@ -1235,11 +1342,27 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1235
1342
|
});
|
|
1236
1343
|
return {
|
|
1237
1344
|
result: TopicValidatorResult.Reject,
|
|
1238
|
-
metadata: { isEquivocated },
|
|
1345
|
+
metadata: { isEquivocated, isOversized },
|
|
1239
1346
|
severity: PeerErrorSeverity.HighToleranceError,
|
|
1240
1347
|
};
|
|
1241
1348
|
}
|
|
1242
1349
|
|
|
1350
|
+
// The proposal was stored: if oversized, invoke the oversized callback so the proposer can be
|
|
1351
|
+
// slashed. Fired alongside (not instead of) equivocation detection below.
|
|
1352
|
+
if (isOversized) {
|
|
1353
|
+
const proposer = block.getSender();
|
|
1354
|
+
if (proposer) {
|
|
1355
|
+
this.logger.warn(`Detected oversized block proposal at slot ${block.slotNumber}`, {
|
|
1356
|
+
...block.toBlockInfo(),
|
|
1357
|
+
indexWithinCheckpoint: block.indexWithinCheckpoint,
|
|
1358
|
+
maxBlocksPerCheckpoint: this.config.maxBlocksPerCheckpoint,
|
|
1359
|
+
source: peerId.toString(),
|
|
1360
|
+
proposer: proposer.toString(),
|
|
1361
|
+
});
|
|
1362
|
+
this.oversizedProposalCallback?.({ slot: block.slotNumber, proposer });
|
|
1363
|
+
}
|
|
1364
|
+
}
|
|
1365
|
+
|
|
1243
1366
|
// If this was a duplicate proposal, do not process it, but do invoke the duplicate callback,
|
|
1244
1367
|
// and do re-broadcast it so other nodes in the network know to slash the proposer
|
|
1245
1368
|
if (isEquivocated) {
|
|
@@ -1253,11 +1376,11 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1253
1376
|
if (proposer && count === 2) {
|
|
1254
1377
|
this.duplicateProposalCallback?.({ slot: block.slotNumber, proposer, type: 'block' });
|
|
1255
1378
|
}
|
|
1256
|
-
return { result: TopicValidatorResult.Accept, obj: block, metadata: { isEquivocated } };
|
|
1379
|
+
return { result: TopicValidatorResult.Accept, obj: block, metadata: { isEquivocated, isOversized } };
|
|
1257
1380
|
}
|
|
1258
1381
|
|
|
1259
1382
|
// Otherwise, we're good to go!
|
|
1260
|
-
return { result: TopicValidatorResult.Accept, obj: block };
|
|
1383
|
+
return { result: TopicValidatorResult.Accept, obj: block, metadata: { isEquivocated: false, isOversized } };
|
|
1261
1384
|
}
|
|
1262
1385
|
|
|
1263
1386
|
// REFACTOR(palla): This method should be moved to the p2p_client or to a separate component,
|
|
@@ -1283,6 +1406,9 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1283
1406
|
const isValid = await this.blockReceivedCallback(block, sender);
|
|
1284
1407
|
if (!isValid) {
|
|
1285
1408
|
this.logger.info(`Block proposal validation failed for block ${block.blockNumber}`, block.toBlockInfo());
|
|
1409
|
+
// Release the protections this proposal created so its txs return to pending. Only entries still
|
|
1410
|
+
// keyed to this slot are cleared, so a tx referenced by a live proposal at another slot stays protected.
|
|
1411
|
+
await this.mempools.txPool.unprotectTxs(block.txHashes, slot);
|
|
1286
1412
|
}
|
|
1287
1413
|
}
|
|
1288
1414
|
|
|
@@ -1294,25 +1420,45 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1294
1420
|
const {
|
|
1295
1421
|
result,
|
|
1296
1422
|
obj: checkpoint,
|
|
1297
|
-
metadata: { isEquivocated, processBlock } = {},
|
|
1298
|
-
} = await this.validateReceivedMessage<
|
|
1423
|
+
metadata: { isEquivocated, processBlock, isOversized } = {},
|
|
1424
|
+
} = await this.validateReceivedMessage<
|
|
1425
|
+
CheckpointProposal,
|
|
1426
|
+
{ isEquivocated: boolean; processBlock: boolean; isOversized: boolean }
|
|
1427
|
+
>(
|
|
1299
1428
|
() => this.validateAndStoreCheckpointProposal(source, CheckpointProposal.fromBuffer(payloadData)),
|
|
1300
1429
|
msgId,
|
|
1301
1430
|
source,
|
|
1302
1431
|
TopicType.checkpoint_proposal,
|
|
1303
1432
|
);
|
|
1304
1433
|
|
|
1434
|
+
// An oversized checkpoint is re-broadcast as slashing evidence but never attested or processed.
|
|
1435
|
+
// Process checkpoint proposal if valid and neither equivocated nor oversized.
|
|
1436
|
+
const processCheckpointFn = () =>
|
|
1437
|
+
result === TopicValidatorResult.Accept && checkpoint && !isEquivocated && !isOversized
|
|
1438
|
+
? this.processValidCheckpointProposal(checkpoint.toCore(), source)
|
|
1439
|
+
: Promise.resolve();
|
|
1440
|
+
|
|
1305
1441
|
// If the checkpoint contained a valid last block, we process it even if the checkpoint itself is to be rejected
|
|
1306
1442
|
// TODO(palla/mbps): Is this ok? Should we be considering a block from a checkpoint that was equivocated?
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1443
|
+
const processBlockFn = () =>
|
|
1444
|
+
processBlock && checkpoint && checkpoint.getBlockProposal()
|
|
1445
|
+
? this.processValidBlockProposal(checkpoint.getBlockProposal()!, source)
|
|
1446
|
+
: Promise.resolve();
|
|
1447
|
+
|
|
1448
|
+
// A node that skips checkpoint validation attests without re-executing the embedded last block, so run
|
|
1449
|
+
// the checkpoint callback first: this creates and broadcasts the attestation before the block is
|
|
1450
|
+
// processed. Otherwise the block's re-execution — which can stall until the re-execution deadline
|
|
1451
|
+
// waiting for a parent that may never arrive — would delay the attestation past the slot's attestation
|
|
1452
|
+
// window, after which peers reject it as stale.
|
|
1453
|
+
if (this.config.skipCheckpointProposalValidation) {
|
|
1454
|
+
await processCheckpointFn();
|
|
1455
|
+
await processBlockFn();
|
|
1312
1456
|
return;
|
|
1313
1457
|
}
|
|
1314
1458
|
|
|
1315
|
-
|
|
1459
|
+
// Process the block first, since it's required for the checkpoint proposal validation.
|
|
1460
|
+
await processBlockFn();
|
|
1461
|
+
await processCheckpointFn();
|
|
1316
1462
|
}
|
|
1317
1463
|
|
|
1318
1464
|
/**
|
|
@@ -1325,7 +1471,12 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1325
1471
|
protected async validateAndStoreCheckpointProposal(
|
|
1326
1472
|
peerId: PeerId,
|
|
1327
1473
|
checkpoint: CheckpointProposal,
|
|
1328
|
-
): Promise<
|
|
1474
|
+
): Promise<
|
|
1475
|
+
ReceivedMessageValidationResult<
|
|
1476
|
+
CheckpointProposal,
|
|
1477
|
+
{ isEquivocated: boolean; processBlock: boolean; isOversized: boolean }
|
|
1478
|
+
>
|
|
1479
|
+
> {
|
|
1329
1480
|
const validationResult = await this.checkpointProposalValidator.validate(checkpoint);
|
|
1330
1481
|
|
|
1331
1482
|
if (validationResult.result === 'reject') {
|
|
@@ -1340,13 +1491,16 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1340
1491
|
// Extract and try to add the block proposal first if present
|
|
1341
1492
|
const blockProposal = checkpoint.getBlockProposal();
|
|
1342
1493
|
let processBlock = false;
|
|
1494
|
+
let isOversized = false;
|
|
1343
1495
|
if (blockProposal) {
|
|
1344
1496
|
this.logger.debug(`Validating block proposal from propagated checkpoint`, {
|
|
1345
1497
|
[Attributes.SLOT_NUMBER]: checkpoint.slotNumber.toString(),
|
|
1346
1498
|
[Attributes.P2P_ID]: peerId.toString(),
|
|
1347
1499
|
});
|
|
1348
1500
|
const blockProposalResult = await this.validateAndStoreBlockProposal(peerId, blockProposal);
|
|
1349
|
-
const { obj, metadata: { isEquivocated } = {} } = blockProposalResult;
|
|
1501
|
+
const { obj, metadata: { isEquivocated, isOversized: blockIsOversized } = {} } = blockProposalResult;
|
|
1502
|
+
isOversized = blockIsOversized ?? false;
|
|
1503
|
+
|
|
1350
1504
|
if (blockProposalResult.result === TopicValidatorResult.Reject || !obj || isEquivocated) {
|
|
1351
1505
|
this.logger.debug(`Rejecting checkpoint due to invalid last block proposal`, {
|
|
1352
1506
|
[Attributes.SLOT_NUMBER]: checkpoint.slotNumber.toString(),
|
|
@@ -1359,7 +1513,8 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1359
1513
|
severity:
|
|
1360
1514
|
'severity' in blockProposalResult ? blockProposalResult.severity : PeerErrorSeverity.MidToleranceError,
|
|
1361
1515
|
};
|
|
1362
|
-
} else if (blockProposalResult.result === TopicValidatorResult.Accept && obj && !isEquivocated) {
|
|
1516
|
+
} else if (blockProposalResult.result === TopicValidatorResult.Accept && obj && !isEquivocated && !isOversized) {
|
|
1517
|
+
// An oversized terminal block is re-broadcast as slashing evidence but never processed.
|
|
1363
1518
|
processBlock = true;
|
|
1364
1519
|
}
|
|
1365
1520
|
}
|
|
@@ -1379,11 +1534,11 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1379
1534
|
return {
|
|
1380
1535
|
result: TopicValidatorResult.Ignore,
|
|
1381
1536
|
obj: checkpoint,
|
|
1382
|
-
metadata: { isEquivocated, processBlock },
|
|
1537
|
+
metadata: { isEquivocated, processBlock, isOversized },
|
|
1383
1538
|
};
|
|
1384
1539
|
}
|
|
1385
1540
|
|
|
1386
|
-
// Too many checkpoint proposals received for this slot, penalize peer and do not re-broadcast
|
|
1541
|
+
// Too many checkpoint proposals received for this slot, penalize peer and do not re-broadcast.
|
|
1387
1542
|
// Note: We still return the checkpoint obj so the lastBlock can be processed if valid
|
|
1388
1543
|
if (!added) {
|
|
1389
1544
|
this.logger.warn(`Penalizing peer for checkpoint proposal exceeding per-slot cap`, {
|
|
@@ -1394,7 +1549,7 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1394
1549
|
return {
|
|
1395
1550
|
result: TopicValidatorResult.Reject,
|
|
1396
1551
|
obj: checkpoint,
|
|
1397
|
-
metadata: { isEquivocated, processBlock },
|
|
1552
|
+
metadata: { isEquivocated, processBlock, isOversized },
|
|
1398
1553
|
severity: PeerErrorSeverity.HighToleranceError,
|
|
1399
1554
|
};
|
|
1400
1555
|
}
|
|
@@ -1415,12 +1570,16 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1415
1570
|
return {
|
|
1416
1571
|
result: TopicValidatorResult.Accept,
|
|
1417
1572
|
obj: checkpoint,
|
|
1418
|
-
metadata: { isEquivocated, processBlock },
|
|
1573
|
+
metadata: { isEquivocated, processBlock, isOversized },
|
|
1419
1574
|
};
|
|
1420
1575
|
}
|
|
1421
1576
|
|
|
1422
1577
|
// Otherwise, we're good to go!
|
|
1423
|
-
return {
|
|
1578
|
+
return {
|
|
1579
|
+
result: TopicValidatorResult.Accept,
|
|
1580
|
+
obj: checkpoint,
|
|
1581
|
+
metadata: { processBlock, isEquivocated, isOversized },
|
|
1582
|
+
};
|
|
1424
1583
|
}
|
|
1425
1584
|
|
|
1426
1585
|
/**
|
|
@@ -1441,9 +1600,11 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1441
1600
|
source: sender.toString(),
|
|
1442
1601
|
});
|
|
1443
1602
|
|
|
1603
|
+
await this.allNodesCheckpointReceivedCallback(checkpoint, sender);
|
|
1604
|
+
|
|
1444
1605
|
// Call the checkpoint received callback with the core version (without lastBlock)
|
|
1445
1606
|
// to validate and potentially generate attestations
|
|
1446
|
-
const attestations = await this.
|
|
1607
|
+
const attestations = await this.validatorCheckpointReceivedCallback(checkpoint, sender);
|
|
1447
1608
|
if (attestations && attestations.length > 0) {
|
|
1448
1609
|
// If the callback returned attestations, add them to the pool and propagate them
|
|
1449
1610
|
await this.mempools.attestationPool.addOwnCheckpointAttestations(attestations);
|
|
@@ -1466,82 +1627,87 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1466
1627
|
}
|
|
1467
1628
|
|
|
1468
1629
|
/**
|
|
1469
|
-
* Validate the requested block transactions
|
|
1630
|
+
* Validate the requested block transactions request-response consistency.
|
|
1631
|
+
* It does NOT validate the transactions themselves.
|
|
1470
1632
|
* @param request - The block transactions request.
|
|
1471
1633
|
* @param response - The block transactions response.
|
|
1472
1634
|
* @param peerId - The ID of the peer that made the request.
|
|
1473
|
-
* @returns True if the
|
|
1635
|
+
* @returns True if the request-response is consistent, false otherwise.
|
|
1474
1636
|
*/
|
|
1475
|
-
@trackSpan('Libp2pService.
|
|
1637
|
+
@trackSpan('Libp2pService.validateRequestedBlockTxsConsistency', request => ({
|
|
1476
1638
|
[Attributes.BLOCK_ARCHIVE]: request.archiveRoot.toString(),
|
|
1477
1639
|
}))
|
|
1478
|
-
protected async
|
|
1640
|
+
protected async validateRequestedBlockTxsConsistency(
|
|
1479
1641
|
request: BlockTxsRequest,
|
|
1480
1642
|
response: BlockTxsResponse,
|
|
1481
1643
|
peerId: PeerId,
|
|
1482
1644
|
): Promise<boolean> {
|
|
1483
|
-
const requestedTxValidator = this.createRequestedTxValidator();
|
|
1484
|
-
|
|
1485
1645
|
try {
|
|
1486
|
-
|
|
1646
|
+
// Check for duplicates txs (or hashes) in the response.
|
|
1647
|
+
const returnedHashes = response.txs.map(tx => tx.getTxHash().toString());
|
|
1648
|
+
const uniqueReturned = new Set(returnedHashes.map(h => h.toString()));
|
|
1649
|
+
if (uniqueReturned.size !== returnedHashes.length) {
|
|
1487
1650
|
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
1488
|
-
throw new ValidationError(
|
|
1489
|
-
|
|
1651
|
+
throw new ValidationError(`Received duplicate txs in block txs response`);
|
|
1652
|
+
}
|
|
1653
|
+
|
|
1654
|
+
// We get the block tx hashes from the proposal or the archiver.
|
|
1655
|
+
const proposal = await this.mempools.attestationPool.getBlockProposalByArchive(request.archiveRoot.toString());
|
|
1656
|
+
const blockTxHashes =
|
|
1657
|
+
proposal?.txHashes ??
|
|
1658
|
+
(await this.archiver.getBlock({ archive: request.archiveRoot }))?.body.txEffects.map(e => e.txHash);
|
|
1659
|
+
|
|
1660
|
+
// If we don't have the block, we can't verify membership/order of the returned txs.
|
|
1661
|
+
if (!blockTxHashes) {
|
|
1662
|
+
// This shouldn't happen, since we asked for the block (proposal).
|
|
1663
|
+
// Neither a local proposal nor an archived block: we cannot verify membership/order of the
|
|
1664
|
+
// returned txs. This is a local-state gap, not a peer fault, so we do not penalize.
|
|
1665
|
+
this.logger.warn(
|
|
1666
|
+
`Block ${request.archiveRoot.toString()} not found in attestation pool or archiver; cannot validate membership/order of returned txs`,
|
|
1490
1667
|
);
|
|
1668
|
+
// NOTE: We mark the response as invalid, given the limitations of a true/false return value.
|
|
1669
|
+
return false;
|
|
1491
1670
|
}
|
|
1492
1671
|
|
|
1493
|
-
|
|
1494
|
-
|
|
1672
|
+
// Verify that the returned tx hashes are a subset of (tx hashes by index) U (explicitly requested tx hashes).
|
|
1673
|
+
const uniqueRequestedHashes = new Set([
|
|
1674
|
+
// tx hashes requested by index.
|
|
1675
|
+
...request.txIndices.getTrueIndices().map(i => blockTxHashes[i].toString()),
|
|
1676
|
+
// explicitly requested tx hashes.
|
|
1677
|
+
...request.txHashes.map(h => h.toString()),
|
|
1678
|
+
]);
|
|
1679
|
+
if (!returnedHashes.every(h => uniqueRequestedHashes.has(h))) {
|
|
1680
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
|
|
1495
1681
|
throw new ValidationError(
|
|
1496
|
-
|
|
1682
|
+
'Returned txs should be a subset of (tx hashes by index) U (explicitly requested tx hashes)',
|
|
1497
1683
|
);
|
|
1498
1684
|
}
|
|
1499
1685
|
|
|
1500
|
-
//
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
const returnedHashes = await Promise.all(response.txs.map(tx => tx.getTxHash().toString()));
|
|
1506
|
-
const uniqueReturned = new Set(returnedHashes.map(h => h.toString()));
|
|
1507
|
-
if (uniqueReturned.size !== returnedHashes.length) {
|
|
1508
|
-
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
1509
|
-
throw new ValidationError(`Received duplicate txs in block txs response`);
|
|
1686
|
+
// Tx indices information is optional, but if present, we need to verify a few things.
|
|
1687
|
+
if (!response.peerHasBlock()) {
|
|
1688
|
+
this.logger.debug(`Peer ${peerId.toString()} signalled missing block`);
|
|
1689
|
+
return true;
|
|
1510
1690
|
}
|
|
1511
|
-
|
|
1691
|
+
|
|
1692
|
+
// If the response has a non-empty bitvector, it needs to be consistent with the number of txs in the block.
|
|
1693
|
+
if (response.txIndices.getLength() !== blockTxHashes.length) {
|
|
1512
1694
|
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
1513
1695
|
throw new ValidationError(
|
|
1514
|
-
`Received
|
|
1696
|
+
`Received block txs with mismatched bitvector length: expected ${blockTxHashes.length}, got ${response.txIndices.getLength()}`,
|
|
1515
1697
|
);
|
|
1516
1698
|
}
|
|
1517
1699
|
|
|
1518
|
-
//
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
);
|
|
1528
|
-
const allowedIndexSet = new Set(intersectIdx);
|
|
1529
|
-
const indices = returnedHashes.map(h => hashToIndexInProposal.get(h));
|
|
1530
|
-
const allAllowed = indices.every(idx => idx !== undefined && allowedIndexSet.has(idx));
|
|
1531
|
-
const strictlyIncreasing = indices.every((idx, i) => (i === 0 ? idx !== undefined : idx! > indices[i - 1]!));
|
|
1532
|
-
if (!allAllowed || !strictlyIncreasing) {
|
|
1533
|
-
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
|
|
1534
|
-
throw new ValidationError('Returned txs do not match expected subset/order for requested indices');
|
|
1535
|
-
}
|
|
1536
|
-
} else {
|
|
1537
|
-
// No local proposal, cannot check the membership/order of the returned txs
|
|
1538
|
-
this.logger.warn(
|
|
1539
|
-
`Block proposal not found for archive root ${request.archiveRoot.toString()}; cannot validate membership/order of returned txs`,
|
|
1540
|
-
);
|
|
1541
|
-
return false;
|
|
1700
|
+
// For every index we requested that the peer claims to have (per its bitvector), the
|
|
1701
|
+
// corresponding tx must be present in the response. A peer advertising availability but
|
|
1702
|
+
// withholding the tx is inconsistent.
|
|
1703
|
+
const returnedHashSet = new Set(returnedHashes);
|
|
1704
|
+
const expectedIndices = request.txIndices.getTrueIndices().filter(i => response.txIndices.isSet(i));
|
|
1705
|
+
const missingExpected = expectedIndices.some(i => !returnedHashSet.has(blockTxHashes[i].toString()));
|
|
1706
|
+
if (missingExpected) {
|
|
1707
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
|
|
1708
|
+
throw new ValidationError('Peer advertised requested txs via indices but did not return them');
|
|
1542
1709
|
}
|
|
1543
1710
|
|
|
1544
|
-
await Promise.all(response.txs.map(tx => this.validateRequestedTx(tx, peerId, requestedTxValidator)));
|
|
1545
1711
|
return true;
|
|
1546
1712
|
} catch (e: any) {
|
|
1547
1713
|
if (e instanceof ValidationError) {
|
|
@@ -1554,125 +1720,8 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1554
1720
|
}
|
|
1555
1721
|
}
|
|
1556
1722
|
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
*
|
|
1560
|
-
* The core component of this validator is that each tx hash MUST match the requested tx hash,
|
|
1561
|
-
* In order to perform this check, the tx proof must be verified.
|
|
1562
|
-
*
|
|
1563
|
-
* Note: This function is called from within `ReqResp.sendRequest` as part of the
|
|
1564
|
-
* ReqRespSubProtocol.TX subprotocol validation.
|
|
1565
|
-
*
|
|
1566
|
-
* @param requestedTxHash - The collection of the txs that was requested.
|
|
1567
|
-
* @param responseTx - The collection of txs that was received as a response to the request.
|
|
1568
|
-
* @param peerId - The peer ID of the peer that sent the tx.
|
|
1569
|
-
* @returns True if the whole collection of txs is valid, false otherwise.
|
|
1570
|
-
*/
|
|
1571
|
-
@trackSpan('Libp2pService.validateRequestedTx', (requestedTxHash, _responseTx) => ({
|
|
1572
|
-
[Attributes.TX_HASH]: requestedTxHash.toString(),
|
|
1573
|
-
}))
|
|
1574
|
-
private async validateRequestedTxs(requestedTxHash: TxHash[], responseTx: Tx[], peerId: PeerId): Promise<boolean> {
|
|
1575
|
-
const requested = new Set(requestedTxHash.map(h => h.toString()));
|
|
1576
|
-
const requestedTxValidator = this.createRequestedTxValidator();
|
|
1577
|
-
|
|
1578
|
-
//TODO: (mralj) - this is somewhat naive implementation, if single tx is invalid we consider the whole response invalid.
|
|
1579
|
-
// I think we should still extract the valid txs and return them, so that we can still use the response.
|
|
1580
|
-
try {
|
|
1581
|
-
await Promise.all(responseTx.map(tx => this.validateRequestedTx(tx, peerId, requestedTxValidator, requested)));
|
|
1582
|
-
return true;
|
|
1583
|
-
} catch (e: any) {
|
|
1584
|
-
if (e instanceof ValidationError) {
|
|
1585
|
-
this.logger.warn(`Failed to validate requested txs from peer ${peerId.toString()}, reason ${e.message}`);
|
|
1586
|
-
} else {
|
|
1587
|
-
this.logger.error(`Error during validation of requested txs`, e);
|
|
1588
|
-
}
|
|
1589
|
-
|
|
1590
|
-
return false;
|
|
1591
|
-
}
|
|
1592
|
-
}
|
|
1593
|
-
|
|
1594
|
-
/**
|
|
1595
|
-
* Validates a BLOCK response.
|
|
1596
|
-
*
|
|
1597
|
-
* If a local copy exists, enforces hash equality. If missing, rejects (no penalty) since the hash cannot be verified.
|
|
1598
|
-
* Penalizes on block number mismatch or hash mismatch.
|
|
1599
|
-
*
|
|
1600
|
-
* @param requestedBlockNumber - The requested block number.
|
|
1601
|
-
* @param responseBlock - The block returned by the peer.
|
|
1602
|
-
* @param peerId - The peer that returned the block.
|
|
1603
|
-
* @returns True if the response is valid, false otherwise.
|
|
1604
|
-
*/
|
|
1605
|
-
@trackSpan('Libp2pService.validateRequestedBlock', (requestedBlockNumber, _responseBlock) => ({
|
|
1606
|
-
[Attributes.BLOCK_NUMBER]: requestedBlockNumber.toString(),
|
|
1607
|
-
}))
|
|
1608
|
-
protected async validateRequestedBlock(
|
|
1609
|
-
requestedBlockNumber: Fr,
|
|
1610
|
-
responseBlock: L2Block,
|
|
1611
|
-
peerId: PeerId,
|
|
1612
|
-
): Promise<boolean> {
|
|
1613
|
-
try {
|
|
1614
|
-
const reqNum = Number(requestedBlockNumber.toString());
|
|
1615
|
-
if (responseBlock.number !== reqNum) {
|
|
1616
|
-
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
|
|
1617
|
-
return false;
|
|
1618
|
-
}
|
|
1619
|
-
|
|
1620
|
-
const local = await this.archiver.getBlock(BlockNumber(reqNum));
|
|
1621
|
-
if (!local) {
|
|
1622
|
-
// We are missing the local block; we cannot verify the hash yet. Reject without penalizing.
|
|
1623
|
-
// TODO: Consider extending this validator to accept an expected hash or
|
|
1624
|
-
// performing quorum-based checks when using P2P syncing prior to L1 sync.
|
|
1625
|
-
this.logger.warn(`Local block ${reqNum} not found; rejecting BLOCK response without hash verification`);
|
|
1626
|
-
return false;
|
|
1627
|
-
}
|
|
1628
|
-
const [localHash, respHash] = await Promise.all([local.hash(), responseBlock.hash()]);
|
|
1629
|
-
if (!localHash.equals(respHash)) {
|
|
1630
|
-
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
1631
|
-
return false;
|
|
1632
|
-
}
|
|
1633
|
-
|
|
1634
|
-
return true;
|
|
1635
|
-
} catch (e) {
|
|
1636
|
-
this.logger.warn(`Error validating requested block`, e);
|
|
1637
|
-
return false;
|
|
1638
|
-
}
|
|
1639
|
-
}
|
|
1640
|
-
|
|
1641
|
-
protected async validateRequestedTx(
|
|
1642
|
-
tx: Tx,
|
|
1643
|
-
peerId: PeerId,
|
|
1644
|
-
txValidator: TxValidator,
|
|
1645
|
-
requested?: Set<`0x${string}`>,
|
|
1646
|
-
) {
|
|
1647
|
-
const penalize = (severity: PeerErrorSeverity) => this.peerManager.penalizePeer(peerId, severity);
|
|
1648
|
-
if (requested && !requested.has(tx.getTxHash().toString())) {
|
|
1649
|
-
penalize(PeerErrorSeverity.MidToleranceError);
|
|
1650
|
-
throw new ValidationError(`Received tx with hash ${tx.getTxHash().toString()} that was not requested.`);
|
|
1651
|
-
}
|
|
1652
|
-
|
|
1653
|
-
const { result } = await txValidator.validateTx(tx);
|
|
1654
|
-
if (result === 'invalid') {
|
|
1655
|
-
penalize(PeerErrorSeverity.LowToleranceError);
|
|
1656
|
-
throw new ValidationError(`Received tx with hash ${tx.getTxHash().toString()} that is invalid.`);
|
|
1657
|
-
}
|
|
1658
|
-
}
|
|
1659
|
-
|
|
1660
|
-
protected createRequestedTxValidator(): TxValidator {
|
|
1661
|
-
return createTxValidatorForReqResponseReceivedTxs(this.proofVerifier, {
|
|
1662
|
-
l1ChainId: this.config.l1ChainId,
|
|
1663
|
-
rollupVersion: this.config.rollupVersion,
|
|
1664
|
-
});
|
|
1665
|
-
}
|
|
1666
|
-
|
|
1667
|
-
private async getGasFees(blockNumber: BlockNumber): Promise<GasFees> {
|
|
1668
|
-
if (blockNumber === this.feesCache?.blockNumber) {
|
|
1669
|
-
return this.feesCache.gasFees;
|
|
1670
|
-
}
|
|
1671
|
-
|
|
1672
|
-
const header = await this.archiver.getBlockHeader(blockNumber);
|
|
1673
|
-
const gasFees = header?.globalVariables.gasFees ?? GasFees.empty();
|
|
1674
|
-
this.feesCache = { blockNumber, gasFees };
|
|
1675
|
-
return gasFees;
|
|
1723
|
+
private getGasFees(): Promise<GasFees> {
|
|
1724
|
+
return this.blockMinFeesProvider.getCurrentMinFees();
|
|
1676
1725
|
}
|
|
1677
1726
|
|
|
1678
1727
|
/**
|
|
@@ -1686,8 +1735,10 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1686
1735
|
l1ChainId: this.config.l1ChainId,
|
|
1687
1736
|
rollupVersion: this.config.rollupVersion,
|
|
1688
1737
|
proofVerifier: this.proofVerifier,
|
|
1738
|
+
txValidationCache: this.txValidationCache,
|
|
1689
1739
|
},
|
|
1690
1740
|
peerScoring: this.peerManager,
|
|
1741
|
+
validateRequestedBlockTxsConsistency: this.validateRequestedBlockTxsConsistency.bind(this),
|
|
1691
1742
|
};
|
|
1692
1743
|
}
|
|
1693
1744
|
|
|
@@ -1696,6 +1747,7 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1696
1747
|
this.proofVerifier,
|
|
1697
1748
|
{ l1ChainId: this.config.l1ChainId, rollupVersion: this.config.rollupVersion },
|
|
1698
1749
|
this.logger.getBindings(),
|
|
1750
|
+
this.txValidationCache,
|
|
1699
1751
|
);
|
|
1700
1752
|
|
|
1701
1753
|
const results = await Promise.all(
|
|
@@ -1714,13 +1766,14 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1714
1766
|
currentBlockNumber: BlockNumber,
|
|
1715
1767
|
nextSlotTimestamp: UInt64,
|
|
1716
1768
|
): Promise<Record<string, TransactionValidator>> {
|
|
1717
|
-
const gasFees = await this.getGasFees(
|
|
1769
|
+
const gasFees = await this.getGasFees();
|
|
1718
1770
|
const allowedInSetup = [
|
|
1719
1771
|
...(await getDefaultAllowedSetupFunctions()),
|
|
1720
1772
|
...(this.config.txPublicSetupAllowListExtend ?? []),
|
|
1721
1773
|
];
|
|
1722
1774
|
const blockNumber = BlockNumber(currentBlockNumber + 1);
|
|
1723
1775
|
const l1Constants = await this.archiver.getL1Constants();
|
|
1776
|
+
const networkTxGasLimits = getNetworkTxGasLimits(this.config, l1Constants);
|
|
1724
1777
|
|
|
1725
1778
|
return createFirstStageTxValidationsForGossipedTransactions(
|
|
1726
1779
|
nextSlotTimestamp,
|
|
@@ -1735,9 +1788,8 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1735
1788
|
allowedInSetup,
|
|
1736
1789
|
this.logger.getBindings(),
|
|
1737
1790
|
{
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
maxBlockDAGas: this.config.validateMaxDABlockGas,
|
|
1791
|
+
maxTxL2Gas: networkTxGasLimits.l2Gas,
|
|
1792
|
+
maxTxDAGas: networkTxGasLimits.daGas,
|
|
1741
1793
|
},
|
|
1742
1794
|
);
|
|
1743
1795
|
}
|