@aztec/p2p 0.0.1-commit.3fd054f6 → 0.0.1-commit.431c48d
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 +35 -25
- package/dest/client/interface.d.ts +52 -12
- package/dest/client/interface.d.ts.map +1 -1
- package/dest/client/p2p_client.d.ts +36 -20
- package/dest/client/p2p_client.d.ts.map +1 -1
- package/dest/client/p2p_client.js +127 -54
- package/dest/config.d.ts +150 -107
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +77 -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 +10 -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 +29 -20
- 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/instrumentation.d.ts +11 -1
- package/dest/mem_pools/tx_pool_v2/instrumentation.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/instrumentation.js +24 -0
- 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 +16 -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 +83 -32
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts +50 -6
- 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 +243 -127
- 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 -23
- package/dest/services/discv5/persisted_enr_store.d.ts +38 -0
- package/dest/services/discv5/persisted_enr_store.d.ts.map +1 -0
- package/dest/services/discv5/persisted_enr_store.js +145 -0
- package/dest/services/dummy_service.d.ts +18 -16
- package/dest/services/dummy_service.d.ts.map +1 -1
- package/dest/services/dummy_service.js +21 -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 +6 -1
- package/dest/services/libp2p/instrumentation.d.ts.map +1 -1
- package/dest/services/libp2p/instrumentation.js +21 -0
- package/dest/services/libp2p/libp2p_service.d.ts +49 -44
- package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
- package/dest/services/libp2p/libp2p_service.js +388 -279
- package/dest/services/peer-manager/peer_manager.d.ts +31 -3
- package/dest/services/peer-manager/peer_manager.d.ts.map +1 -1
- package/dest/services/peer-manager/peer_manager.js +121 -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 +43 -18
- 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 +33 -9
- package/dest/test-helpers/mock-pubsub.d.ts.map +1 -1
- package/dest/test-helpers/mock-pubsub.js +57 -44
- 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 +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 +11 -6
- package/dest/util.d.ts.map +1 -1
- package/dest/util.js +35 -14
- package/dest/versioning.d.ts +3 -6
- package/dest/versioning.d.ts.map +1 -1
- package/dest/versioning.js +3 -24
- package/package.json +17 -17
- package/src/bootstrap/bootstrap.ts +17 -3
- package/src/client/factory.ts +53 -24
- package/src/client/interface.ts +48 -18
- package/src/client/p2p_client.ts +144 -86
- package/src/client/test/{tx_proposal_collector/README.md → p2p_client.batch_tx_requester.bench.README.md} +23 -53
- package/src/config.ts +159 -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 +30 -20
- 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/instrumentation.ts +27 -0
- 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 +94 -31
- package/src/mem_pools/tx_pool_v2/tx_pool_v2_impl.ts +270 -133
- 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/tx_proof_validator.ts +2 -0
- package/src/msg_validators/tx_validator/tx_validation_cache.ts +101 -0
- package/src/services/data_store.ts +5 -13
- package/src/services/discv5/discV5_service.ts +126 -14
- package/src/services/discv5/persisted_enr_store.ts +158 -0
- package/src/services/dummy_service.ts +26 -40
- 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 +22 -0
- package/src/services/libp2p/libp2p_service.ts +456 -305
- package/src/services/peer-manager/peer_manager.ts +133 -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 +51 -35
- 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 +61 -60
- 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 +108 -53
- package/src/testbench/worker_client_manager.ts +59 -20
- package/src/util.ts +32 -17
- 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
|
@@ -1,33 +1,41 @@
|
|
|
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';
|
|
13
|
-
import type {
|
|
12
|
+
import { type BlockMinFeesProvider, GasFees, getNetworkTxGasLimits } from '@aztec/stdlib/gas';
|
|
13
|
+
import type {
|
|
14
|
+
ClientProtocolCircuitVerifier,
|
|
15
|
+
P2PConnectivity,
|
|
16
|
+
PeerInfo,
|
|
17
|
+
WorldStateSynchronizer,
|
|
18
|
+
} from '@aztec/stdlib/interfaces/server';
|
|
14
19
|
import {
|
|
15
20
|
BlockProposal,
|
|
16
21
|
CheckpointAttestation,
|
|
17
22
|
CheckpointProposal,
|
|
18
|
-
type CheckpointProposalCore,
|
|
19
23
|
type Gossipable,
|
|
20
24
|
P2PMessage,
|
|
21
25
|
PeerErrorSeverity,
|
|
22
26
|
PeerErrorSeverityByHarshness,
|
|
23
27
|
TopicType,
|
|
28
|
+
ValidatedBlockProposal,
|
|
29
|
+
ValidatedCheckpointProposalCore,
|
|
24
30
|
createTopicString,
|
|
25
31
|
getTopicsForConfig,
|
|
26
32
|
metricsTopicStrToLabels,
|
|
27
33
|
} from '@aztec/stdlib/p2p';
|
|
34
|
+
import { ConsensusTimetable, getDefaultCheckpointProposalSyncGrace } from '@aztec/stdlib/timetable';
|
|
28
35
|
import { MerkleTreeId } from '@aztec/stdlib/trees';
|
|
29
|
-
import { Tx, type
|
|
36
|
+
import { Tx, type TxValidationResult } from '@aztec/stdlib/tx';
|
|
30
37
|
import type { UInt64 } from '@aztec/stdlib/types';
|
|
38
|
+
import { InvalidBlockProposalTxsError } from '@aztec/stdlib/validators';
|
|
31
39
|
import { compressComponentVersions } from '@aztec/stdlib/versioning';
|
|
32
40
|
import {
|
|
33
41
|
Attributes,
|
|
@@ -51,13 +59,15 @@ import { yamux } from '@chainsafe/libp2p-yamux';
|
|
|
51
59
|
import { bootstrap } from '@libp2p/bootstrap';
|
|
52
60
|
import { identify } from '@libp2p/identify';
|
|
53
61
|
import { type Message, type MultiaddrConnection, type PeerId, TopicValidatorResult } from '@libp2p/interface';
|
|
54
|
-
import type { ConnectionManager } from '@libp2p/interface-internal';
|
|
62
|
+
import type { AddressManager, ConnectionManager } from '@libp2p/interface-internal';
|
|
55
63
|
import { mplex } from '@libp2p/mplex';
|
|
56
64
|
import { tcp } from '@libp2p/tcp';
|
|
65
|
+
import { multiaddr } from '@multiformats/multiaddr';
|
|
57
66
|
import { ENR } from '@nethermindeth/enr';
|
|
58
67
|
import { createLibp2p } from 'libp2p';
|
|
59
68
|
|
|
60
69
|
import type { P2PConfig } from '../../config.js';
|
|
70
|
+
import { CheckpointProposalReceivedCallbackNotRegisteredError } from '../../errors/p2p-service.error.js';
|
|
61
71
|
import type { MemPools } from '../../mem_pools/interface.js';
|
|
62
72
|
import {
|
|
63
73
|
BlockProposalValidator,
|
|
@@ -73,38 +83,34 @@ import {
|
|
|
73
83
|
createFirstStageTxValidationsForGossipedTransactions,
|
|
74
84
|
createSecondStageTxValidationsForGossipedTransactions,
|
|
75
85
|
createTxValidatorForBlockProposalReceivedTxs,
|
|
76
|
-
createTxValidatorForReqResponseReceivedTxs,
|
|
77
86
|
} from '../../msg_validators/tx_validator/factory.js';
|
|
87
|
+
import { TxValidationCache } from '../../msg_validators/tx_validator/tx_validation_cache.js';
|
|
78
88
|
import { GossipSubEvent } from '../../types/index.js';
|
|
79
89
|
import { type PubSubLibp2p, convertToMultiaddr } from '../../util.js';
|
|
80
90
|
import { getVersions } from '../../versioning.js';
|
|
81
91
|
import { AztecDatastore } from '../data_store.js';
|
|
82
92
|
import { DiscV5Service } from '../discv5/discV5_service.js';
|
|
83
|
-
import { SnappyTransform,
|
|
93
|
+
import { SnappyTransform, getMsgIdFn, msgIdToStrFn } from '../encoding.js';
|
|
84
94
|
import { APP_SPECIFIC_WEIGHT, gossipScoreThresholds } from '../gossipsub/scoring.js';
|
|
85
95
|
import { createAllTopicScoreParams } from '../gossipsub/topic_score_params.js';
|
|
86
96
|
import type { PeerManagerInterface } from '../peer-manager/interface.js';
|
|
87
97
|
import { PeerManager } from '../peer-manager/peer_manager.js';
|
|
88
98
|
import { PeerScoring } from '../peer-manager/peer_scoring.js';
|
|
89
99
|
import type { BatchTxRequesterLibP2PService } from '../reqresp/batch-tx-requester/interface.js';
|
|
90
|
-
import type
|
|
100
|
+
import { type P2PReqRespConfig, YAMUX_MAX_MESSAGE_SIZE_BYTES } from '../reqresp/config.js';
|
|
91
101
|
import {
|
|
92
102
|
AuthRequest,
|
|
93
103
|
BlockTxsRequest,
|
|
94
104
|
BlockTxsResponse,
|
|
95
|
-
DEFAULT_SUB_PROTOCOL_VALIDATORS,
|
|
96
105
|
type ReqRespInterface,
|
|
97
106
|
type ReqRespResponse,
|
|
98
107
|
ReqRespSubProtocol,
|
|
99
108
|
type ReqRespSubProtocolHandler,
|
|
100
109
|
type ReqRespSubProtocolHandlers,
|
|
101
|
-
type ReqRespSubProtocolValidators,
|
|
102
110
|
StatusMessage,
|
|
103
|
-
type SubProtocolMap,
|
|
104
111
|
ValidationError,
|
|
105
112
|
pingHandler,
|
|
106
113
|
reqGoodbyeHandler,
|
|
107
|
-
reqRespBlockHandler,
|
|
108
114
|
reqRespBlockTxsHandler,
|
|
109
115
|
reqRespStatusHandler,
|
|
110
116
|
reqRespTxHandler,
|
|
@@ -112,13 +118,33 @@ import {
|
|
|
112
118
|
import { ReqResp } from '../reqresp/reqresp.js';
|
|
113
119
|
import type {
|
|
114
120
|
P2PBlockReceivedCallback,
|
|
121
|
+
P2PCheckpointAttestationCallback,
|
|
115
122
|
P2PCheckpointReceivedCallback,
|
|
116
123
|
P2PDuplicateAttestationCallback,
|
|
124
|
+
P2POversizedProposalCallback,
|
|
117
125
|
P2PService,
|
|
118
126
|
PeerDiscoveryService,
|
|
119
127
|
} from '../service.js';
|
|
120
128
|
import { P2PInstrumentation } from './instrumentation.js';
|
|
121
129
|
|
|
130
|
+
/**
|
|
131
|
+
* Builds the {@link ConsensusTimetable} shared by the gossip validators for proposal/attestation receive-window
|
|
132
|
+
* bounds. Derived purely from protocol slot-timing constants plus the block sub-slot duration and the consensus
|
|
133
|
+
* materialization grace, so every node agrees on these bounds without depending on proposer operational budgets.
|
|
134
|
+
*/
|
|
135
|
+
function buildConsensusTimetable(
|
|
136
|
+
config: P2PConfig,
|
|
137
|
+
l1Constants: ReturnType<EpochCacheInterface['getL1Constants']>,
|
|
138
|
+
): ConsensusTimetable {
|
|
139
|
+
const blockDuration = config.blockDurationMs / 1000;
|
|
140
|
+
return new ConsensusTimetable({
|
|
141
|
+
l1Constants,
|
|
142
|
+
blockDuration,
|
|
143
|
+
checkpointProposalSyncGrace:
|
|
144
|
+
config.checkpointProposalSyncGraceSeconds ?? getDefaultCheckpointProposalSyncGrace(blockDuration),
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
|
|
122
148
|
interface ValidationResult {
|
|
123
149
|
name: string;
|
|
124
150
|
isValid: TxValidationResult;
|
|
@@ -147,8 +173,6 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
147
173
|
private protocolVersion = '';
|
|
148
174
|
private topicStrings: Record<TopicType, string> = {} as Record<TopicType, string>;
|
|
149
175
|
|
|
150
|
-
private feesCache: { blockNumber: BlockNumber; gasFees: GasFees } | undefined;
|
|
151
|
-
|
|
152
176
|
/** Callback invoked when a duplicate proposal is detected (triggers slashing). */
|
|
153
177
|
private duplicateProposalCallback?: (info: {
|
|
154
178
|
slot: SlotNumber;
|
|
@@ -156,9 +180,15 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
156
180
|
type: 'checkpoint' | 'block';
|
|
157
181
|
}) => void;
|
|
158
182
|
|
|
183
|
+
/** Callback invoked when an oversized block proposal is stored as slashing evidence (triggers slashing). */
|
|
184
|
+
private oversizedProposalCallback?: P2POversizedProposalCallback;
|
|
185
|
+
|
|
159
186
|
/** Callback invoked when a duplicate attestation is detected (triggers slashing). */
|
|
160
187
|
private duplicateAttestationCallback?: P2PDuplicateAttestationCallback;
|
|
161
188
|
|
|
189
|
+
/** Callback invoked when a valid checkpoint attestation is accepted into the pool. */
|
|
190
|
+
private checkpointAttestationCallback?: P2PCheckpointAttestationCallback;
|
|
191
|
+
|
|
162
192
|
/**
|
|
163
193
|
* Callback for when a block is received from a peer.
|
|
164
194
|
* @param block - The block received from the peer.
|
|
@@ -171,10 +201,19 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
171
201
|
* @param checkpoint - The checkpoint proposal received from the peer.
|
|
172
202
|
* @returns The attestations for the checkpoint, if any.
|
|
173
203
|
*/
|
|
174
|
-
private
|
|
204
|
+
private allNodesCheckpointReceivedCallback: P2PCheckpointReceivedCallback;
|
|
205
|
+
/**
|
|
206
|
+
* Callback for when a checkpoint proposal is received - specifically for validators - from a peer.
|
|
207
|
+
* @param checkpoint - The checkpoint proposal received from the peer.
|
|
208
|
+
* @returns The attestations for the checkpoint, if any.
|
|
209
|
+
*/
|
|
210
|
+
private validatorCheckpointReceivedCallback: P2PCheckpointReceivedCallback;
|
|
175
211
|
|
|
176
212
|
private gossipSubEventHandler: (e: CustomEvent<GossipsubMessage>) => void;
|
|
177
213
|
|
|
214
|
+
private ipChangedHandler?: (ip: string) => void;
|
|
215
|
+
private discoveredP2pIp?: string;
|
|
216
|
+
|
|
178
217
|
private instrumentation: P2PInstrumentation;
|
|
179
218
|
|
|
180
219
|
private telemetry: TelemetryClient;
|
|
@@ -192,8 +231,10 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
192
231
|
private epochCache: EpochCacheInterface,
|
|
193
232
|
private proofVerifier: ClientProtocolCircuitVerifier,
|
|
194
233
|
private worldStateSynchronizer: WorldStateSynchronizer,
|
|
234
|
+
private blockMinFeesProvider: BlockMinFeesProvider,
|
|
195
235
|
telemetry: TelemetryClient,
|
|
196
236
|
logger: Logger = createLogger('p2p:libp2p_service'),
|
|
237
|
+
private txValidationCache?: TxValidationCache,
|
|
197
238
|
) {
|
|
198
239
|
super(telemetry, 'LibP2PService');
|
|
199
240
|
this.telemetry = telemetry;
|
|
@@ -223,15 +264,39 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
223
264
|
this.protocolVersion,
|
|
224
265
|
);
|
|
225
266
|
|
|
267
|
+
// Build the consensus timetable once from protocol slot-timing constants and inject it into every
|
|
268
|
+
// validator so they share one set of receive-window bounds, independent of proposer operational budgets.
|
|
269
|
+
const consensusTimetable = buildConsensusTimetable(config, epochCache.getL1Constants());
|
|
226
270
|
const proposalValidatorOpts = {
|
|
227
271
|
txsPermitted: !config.disableTransactions,
|
|
228
272
|
maxTxsPerBlock: config.validateMaxTxsPerBlock ?? config.validateMaxTxsPerCheckpoint,
|
|
273
|
+
maxBlocksPerCheckpoint: config.maxBlocksPerCheckpoint,
|
|
274
|
+
skipSlotValidation: config.skipProposalSlotValidation,
|
|
275
|
+
signatureContext: {
|
|
276
|
+
chainId: config.l1ChainId,
|
|
277
|
+
rollupAddress: config.rollupAddress,
|
|
278
|
+
},
|
|
279
|
+
clockDisparityMs: config.maxGossipClockDisparityMs,
|
|
280
|
+
};
|
|
281
|
+
this.blockProposalValidator = new BlockProposalValidator(epochCache, consensusTimetable, proposalValidatorOpts);
|
|
282
|
+
this.checkpointProposalValidator = new CheckpointProposalValidator(
|
|
283
|
+
epochCache,
|
|
284
|
+
consensusTimetable,
|
|
285
|
+
proposalValidatorOpts,
|
|
286
|
+
);
|
|
287
|
+
const attestationValidatorOpts = {
|
|
288
|
+
signatureContext: proposalValidatorOpts.signatureContext,
|
|
289
|
+
clockDisparityMs: config.maxGossipClockDisparityMs,
|
|
229
290
|
};
|
|
230
|
-
this.blockProposalValidator = new BlockProposalValidator(epochCache, proposalValidatorOpts);
|
|
231
|
-
this.checkpointProposalValidator = new CheckpointProposalValidator(epochCache, proposalValidatorOpts);
|
|
232
291
|
this.checkpointAttestationValidator = config.fishermanMode
|
|
233
|
-
? new FishermanAttestationValidator(
|
|
234
|
-
|
|
292
|
+
? new FishermanAttestationValidator(
|
|
293
|
+
epochCache,
|
|
294
|
+
consensusTimetable,
|
|
295
|
+
mempools.attestationPool,
|
|
296
|
+
telemetry,
|
|
297
|
+
attestationValidatorOpts,
|
|
298
|
+
)
|
|
299
|
+
: new CheckpointAttestationValidator(epochCache, consensusTimetable, attestationValidatorOpts);
|
|
235
300
|
|
|
236
301
|
this.gossipSubEventHandler = this.handleGossipSubEvent.bind(this);
|
|
237
302
|
|
|
@@ -243,18 +308,22 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
243
308
|
return true;
|
|
244
309
|
};
|
|
245
310
|
|
|
246
|
-
this.
|
|
247
|
-
|
|
311
|
+
this.allNodesCheckpointReceivedCallback = (
|
|
312
|
+
_checkpoint: ValidatedCheckpointProposalCore,
|
|
313
|
+
): Promise<CheckpointAttestation[] | undefined> => {
|
|
314
|
+
throw new CheckpointProposalReceivedCallbackNotRegisteredError();
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
this.validatorCheckpointReceivedCallback = (
|
|
318
|
+
_checkpoint: ValidatedCheckpointProposalCore,
|
|
248
319
|
): Promise<CheckpointAttestation[] | undefined> => {
|
|
249
|
-
this.logger.debug(
|
|
250
|
-
`Handler not yet registered: Checkpoint received callback not set. Received checkpoint for slot ${checkpoint.slotNumber} from peer.`,
|
|
251
|
-
);
|
|
252
320
|
return Promise.resolve(undefined);
|
|
253
321
|
};
|
|
254
322
|
}
|
|
255
323
|
|
|
256
|
-
public updateConfig(config: Partial<P2PReqRespConfig
|
|
324
|
+
public updateConfig(config: Partial<P2PReqRespConfig & Pick<P2PConfig, 'skipIncomingProposals'>>) {
|
|
257
325
|
this.reqresp.updateConfig(config);
|
|
326
|
+
this.config = merge(this.config, config);
|
|
258
327
|
}
|
|
259
328
|
|
|
260
329
|
/**
|
|
@@ -273,9 +342,11 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
273
342
|
proofVerifier: ClientProtocolCircuitVerifier;
|
|
274
343
|
worldStateSynchronizer: WorldStateSynchronizer;
|
|
275
344
|
peerStore: AztecAsyncKVStore;
|
|
345
|
+
blockMinFeesProvider: BlockMinFeesProvider;
|
|
276
346
|
telemetry: TelemetryClient;
|
|
277
347
|
logger: Logger;
|
|
278
348
|
packageVersion: string;
|
|
349
|
+
txValidationCache?: TxValidationCache;
|
|
279
350
|
},
|
|
280
351
|
) {
|
|
281
352
|
const {
|
|
@@ -285,9 +356,11 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
285
356
|
mempools,
|
|
286
357
|
proofVerifier,
|
|
287
358
|
peerStore,
|
|
359
|
+
blockMinFeesProvider,
|
|
288
360
|
telemetry,
|
|
289
361
|
logger,
|
|
290
362
|
packageVersion,
|
|
363
|
+
txValidationCache,
|
|
291
364
|
} = deps;
|
|
292
365
|
const { p2pPort, maxPeerCount, listenAddress } = config;
|
|
293
366
|
const bindAddrTcp = convertToMultiaddr(listenAddress, p2pPort, 'tcp');
|
|
@@ -302,6 +375,7 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
302
375
|
packageVersion,
|
|
303
376
|
telemetry,
|
|
304
377
|
createLogger(`${logger.module}:discv5_service`, logger.getBindings()),
|
|
378
|
+
peerStore,
|
|
305
379
|
);
|
|
306
380
|
|
|
307
381
|
// Seed libp2p's bootstrap discovery with private and trusted peers
|
|
@@ -316,34 +390,49 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
316
390
|
const protocolVersion = compressComponentVersions(versions);
|
|
317
391
|
|
|
318
392
|
const preferredPeersEnrs: ENR[] = config.preferredPeers.map(enr => ENR.decodeTxt(enr));
|
|
319
|
-
const directPeers = (
|
|
393
|
+
const directPeers = compactArray(
|
|
320
394
|
await Promise.all(
|
|
321
395
|
preferredPeersEnrs.map(async enr => {
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
396
|
+
try {
|
|
397
|
+
const peerId = await enr.peerId();
|
|
398
|
+
const address = enr.getLocationMultiaddr('tcp');
|
|
399
|
+
if (address === undefined) {
|
|
400
|
+
throw new Error(`Direct peer ${peerId.toString()} has no TCP address, ENR: ${enr.encodeTxt()}`);
|
|
401
|
+
}
|
|
402
|
+
return {
|
|
403
|
+
id: peerId,
|
|
404
|
+
addrs: [address],
|
|
405
|
+
};
|
|
406
|
+
} catch (err) {
|
|
407
|
+
// A malformed configured ENR shouldn't abort node setup — skip it and log.
|
|
408
|
+
logger.warn(`Skipping preferred peer with invalid ENR`, { err });
|
|
409
|
+
return undefined;
|
|
326
410
|
}
|
|
327
|
-
return {
|
|
328
|
-
id: peerId,
|
|
329
|
-
addrs: [address],
|
|
330
|
-
};
|
|
331
411
|
}),
|
|
332
|
-
)
|
|
333
|
-
)
|
|
412
|
+
),
|
|
413
|
+
);
|
|
334
414
|
|
|
335
415
|
const announceTcpMultiaddr = config.p2pIp ? [convertToMultiaddr(config.p2pIp, p2pPort, 'tcp')] : [];
|
|
336
416
|
|
|
337
|
-
// Create dynamic topic score params based on network configuration
|
|
417
|
+
// Create dynamic topic score params based on network configuration. Scoring uses the network-wide
|
|
418
|
+
// max-blocks-per-checkpoint config value directly to size expected per-slot message rates; these are
|
|
419
|
+
// peer-rate thresholds, not consensus deadlines, so they need no proposer operational budgets.
|
|
338
420
|
const l1Constants = epochCache.getL1Constants();
|
|
339
421
|
const topicScoreParams = createAllTopicScoreParams(protocolVersion, {
|
|
340
422
|
slotDurationMs: l1Constants.slotDuration * 1000,
|
|
341
423
|
heartbeatIntervalMs: config.gossipsubInterval,
|
|
342
424
|
targetCommitteeSize: l1Constants.targetCommitteeSize,
|
|
343
|
-
|
|
425
|
+
maxBlocksPerCheckpoint: config.maxBlocksPerCheckpoint ?? DEFAULT_MAX_BLOCKS_PER_CHECKPOINT,
|
|
344
426
|
expectedBlockProposalsPerSlot: config.expectedBlockProposalsPerSlot,
|
|
345
427
|
});
|
|
346
428
|
|
|
429
|
+
// Restrict gossipsub to exactly the topics we subscribe to. Without this, an arbitrary-topic
|
|
430
|
+
// message is transformed, msg-id'd and inserted into the seenCache before the subscription check,
|
|
431
|
+
// so a crafted topic colliding on msg id can suppress a real message as a duplicate.
|
|
432
|
+
const allowedTopics = getTopicsForConfig(config.disableTransactions).map(topic =>
|
|
433
|
+
createTopicString(topic, protocolVersion),
|
|
434
|
+
);
|
|
435
|
+
|
|
347
436
|
const node = await createLibp2p({
|
|
348
437
|
start: false,
|
|
349
438
|
peerId,
|
|
@@ -375,7 +464,8 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
375
464
|
],
|
|
376
465
|
datastore,
|
|
377
466
|
peerDiscovery,
|
|
378
|
-
|
|
467
|
+
// Pin the yamux frame size: MAX_REQRESP_REQUEST_SIZE_BYTES relies on a reqresp request fitting in one frame.
|
|
468
|
+
streamMuxers: [yamux({ maxMessageSize: YAMUX_MAX_MESSAGE_SIZE_BYTES }), mplex()],
|
|
379
469
|
connectionEncryption: [noise()],
|
|
380
470
|
connectionManager: {
|
|
381
471
|
minConnections: 0, // Disable libp2p peer dialing, we do it manually
|
|
@@ -389,7 +479,7 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
389
479
|
},
|
|
390
480
|
connectionGater: {
|
|
391
481
|
denyInboundConnection: (maConn: MultiaddrConnection) => {
|
|
392
|
-
const allowed = peerManager.
|
|
482
|
+
const allowed = peerManager.isAddressAllowedToConnect(maConn.remoteAddr.nodeAddress().address);
|
|
393
483
|
if (allowed) {
|
|
394
484
|
return false;
|
|
395
485
|
}
|
|
@@ -400,7 +490,7 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
400
490
|
denyInboundEncryptedConnection: (peerId: PeerId, _maConn: MultiaddrConnection) => {
|
|
401
491
|
//NOTE: it is not necessary to check address here because this was already done by
|
|
402
492
|
// denyInboundConnection
|
|
403
|
-
const allowed = peerManager.
|
|
493
|
+
const allowed = peerManager.isPeerAllowedToConnect(peerId);
|
|
404
494
|
if (allowed) {
|
|
405
495
|
return false;
|
|
406
496
|
}
|
|
@@ -428,9 +518,13 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
428
518
|
mcacheLength: config.gossipsubMcacheLength,
|
|
429
519
|
mcacheGossip: config.gossipsubMcacheGossip,
|
|
430
520
|
seenTTL: config.gossipsubSeenTTL,
|
|
521
|
+
allowedTopics,
|
|
522
|
+
// No fastMsgIdFn: the fast-path dedup cache keys on a non-cryptographic 64-bit hash of the
|
|
523
|
+
// raw data only (no topic), so a collision — accidental or engineered via a weak seed — drops
|
|
524
|
+
// a different message with no fallback to the full id. Dedup instead rests solely on the
|
|
525
|
+
// cryptographic, topic-framed msgIdFn below.
|
|
431
526
|
msgIdFn: getMsgIdFn,
|
|
432
527
|
msgIdToStrFn: msgIdToStrFn,
|
|
433
|
-
fastMsgIdFn: fastMsgIdFn,
|
|
434
528
|
dataTransform: new SnappyTransform(),
|
|
435
529
|
metricsRegister: otelMetricsAdapter,
|
|
436
530
|
metricsTopicStrToLabel: metricsTopicStrToLabels(protocolVersion),
|
|
@@ -442,8 +536,9 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
442
536
|
topics: topicScoreParams,
|
|
443
537
|
}),
|
|
444
538
|
}) as (components: GossipSubComponents) => GossipSub,
|
|
445
|
-
components: (components: { connectionManager: ConnectionManager }) => ({
|
|
539
|
+
components: (components: { connectionManager: ConnectionManager; addressManager: AddressManager }) => ({
|
|
446
540
|
connectionManager: components.connectionManager,
|
|
541
|
+
addressManager: components.addressManager,
|
|
447
542
|
}),
|
|
448
543
|
},
|
|
449
544
|
logger: createLibp2pComponentLogger(logger.module, logger.getBindings()),
|
|
@@ -465,6 +560,9 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
465
560
|
epochCache,
|
|
466
561
|
);
|
|
467
562
|
|
|
563
|
+
// Gate req/resp data protocols for unauthenticated peers when p2pAllowOnlyValidators is enabled
|
|
564
|
+
reqresp.setShouldRejectPeer(peerId => peerManager.shouldDisableP2PGossip(peerId));
|
|
565
|
+
|
|
468
566
|
// Configure application-specific scoring for gossipsub.
|
|
469
567
|
// The weight scales app score to align with gossipsub thresholds:
|
|
470
568
|
// - Disconnect (-50) × 10 = -500 = gossipThreshold (stops receiving gossip)
|
|
@@ -485,8 +583,10 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
485
583
|
epochCache,
|
|
486
584
|
proofVerifier,
|
|
487
585
|
worldStateSynchronizer,
|
|
586
|
+
blockMinFeesProvider,
|
|
488
587
|
telemetry,
|
|
489
588
|
logger,
|
|
589
|
+
txValidationCache,
|
|
490
590
|
);
|
|
491
591
|
}
|
|
492
592
|
|
|
@@ -500,24 +600,21 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
500
600
|
throw new Error('P2P service already started');
|
|
501
601
|
}
|
|
502
602
|
|
|
503
|
-
// Get listen & announce addresses for logging
|
|
504
603
|
const { p2pIp, p2pPort } = this.config;
|
|
505
|
-
if (!p2pIp) {
|
|
506
|
-
throw new Error('Announce address not provided.');
|
|
604
|
+
if (!p2pIp && !this.config.queryForIp) {
|
|
605
|
+
throw new Error('Announce address not provided and queryForIp is not enabled.');
|
|
507
606
|
}
|
|
508
|
-
const announceTcpMultiaddr = convertToMultiaddr(p2pIp, p2pPort, 'tcp');
|
|
607
|
+
const announceTcpMultiaddr = p2pIp ? convertToMultiaddr(p2pIp, p2pPort, 'tcp') : undefined;
|
|
509
608
|
|
|
510
609
|
// Create request response protocol handlers
|
|
511
610
|
const txHandler = reqRespTxHandler(this.mempools);
|
|
512
611
|
const goodbyeHandler = reqGoodbyeHandler(this.peerManager);
|
|
513
|
-
const blockHandler = reqRespBlockHandler(this.archiver);
|
|
514
612
|
const statusHandler = reqRespStatusHandler(this.protocolVersion, this.worldStateSynchronizer, this.logger);
|
|
515
613
|
|
|
516
614
|
const requestResponseHandlers: Partial<ReqRespSubProtocolHandlers> = {
|
|
517
615
|
[ReqRespSubProtocol.PING]: pingHandler,
|
|
518
616
|
[ReqRespSubProtocol.STATUS]: statusHandler.bind(this),
|
|
519
617
|
[ReqRespSubProtocol.GOODBYE]: goodbyeHandler.bind(this),
|
|
520
|
-
[ReqRespSubProtocol.BLOCK]: blockHandler.bind(this),
|
|
521
618
|
};
|
|
522
619
|
|
|
523
620
|
if (!this.config.disableTransactions) {
|
|
@@ -533,17 +630,9 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
533
630
|
requestResponseHandlers[ReqRespSubProtocol.TX] = txHandler.bind(this);
|
|
534
631
|
}
|
|
535
632
|
|
|
536
|
-
// Define the sub protocol validators - This is done within this start() method to gain a callback to the existing validateTx function
|
|
537
|
-
const reqrespSubProtocolValidators = {
|
|
538
|
-
...DEFAULT_SUB_PROTOCOL_VALIDATORS,
|
|
539
|
-
[ReqRespSubProtocol.TX]: this.validateRequestedTxs.bind(this),
|
|
540
|
-
[ReqRespSubProtocol.BLOCK_TXS]: this.validateRequestedBlockTxs.bind(this),
|
|
541
|
-
[ReqRespSubProtocol.BLOCK]: this.validateRequestedBlock.bind(this),
|
|
542
|
-
};
|
|
543
|
-
|
|
544
633
|
await this.peerManager.initializePeers();
|
|
545
634
|
|
|
546
|
-
await this.reqresp.start(requestResponseHandlers
|
|
635
|
+
await this.reqresp.start(requestResponseHandlers);
|
|
547
636
|
|
|
548
637
|
await this.node.start();
|
|
549
638
|
|
|
@@ -559,6 +648,38 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
559
648
|
if (!this.config.p2pDiscoveryDisabled) {
|
|
560
649
|
await this.peerDiscoveryService.start();
|
|
561
650
|
}
|
|
651
|
+
|
|
652
|
+
// Bridge discv5 IP changes to libp2p's AddressManager so peers see the updated address
|
|
653
|
+
if (this.config.queryForIp) {
|
|
654
|
+
this.discoveredP2pIp = this.config.p2pIp;
|
|
655
|
+
this.logger.info('IP change tracking enabled, bridging discv5 IP updates to libp2p AddressManager');
|
|
656
|
+
this.ipChangedHandler = (ip: string) => {
|
|
657
|
+
const addressManager = this.node.services.components.addressManager;
|
|
658
|
+
const newAddr = multiaddr(convertToMultiaddr(ip, this.config.p2pPort, 'tcp'));
|
|
659
|
+
const previousIp = this.discoveredP2pIp;
|
|
660
|
+
|
|
661
|
+
if (previousIp) {
|
|
662
|
+
const oldAddr = multiaddr(convertToMultiaddr(previousIp, this.config.p2pPort, 'tcp'));
|
|
663
|
+
addressManager.removeObservedAddr(oldAddr);
|
|
664
|
+
this.logger.info('Libp2p announce address updated due to IP change', {
|
|
665
|
+
previousIp,
|
|
666
|
+
newIp: ip,
|
|
667
|
+
newMultiaddr: newAddr.toString(),
|
|
668
|
+
});
|
|
669
|
+
} else {
|
|
670
|
+
this.logger.info('Libp2p announce address set from initial discv5 IP discovery', {
|
|
671
|
+
ip,
|
|
672
|
+
multiaddr: newAddr.toString(),
|
|
673
|
+
});
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
addressManager.addObservedAddr(newAddr);
|
|
677
|
+
addressManager.confirmObservedAddr(newAddr);
|
|
678
|
+
this.discoveredP2pIp = ip;
|
|
679
|
+
};
|
|
680
|
+
this.peerDiscoveryService.on('ip:changed', this.ipChangedHandler);
|
|
681
|
+
}
|
|
682
|
+
|
|
562
683
|
this.discoveryRunningPromise = new RunningPromise(
|
|
563
684
|
async () => {
|
|
564
685
|
await this.peerManager.heartbeat();
|
|
@@ -584,6 +705,11 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
584
705
|
// Remove gossip sub listener
|
|
585
706
|
this.node.services.pubsub.removeEventListener(GossipSubEvent.MESSAGE, this.gossipSubEventHandler);
|
|
586
707
|
|
|
708
|
+
if (this.ipChangedHandler) {
|
|
709
|
+
this.peerDiscoveryService.removeListener('ip:changed', this.ipChangedHandler);
|
|
710
|
+
this.ipChangedHandler = undefined;
|
|
711
|
+
}
|
|
712
|
+
|
|
587
713
|
// Stop peer manager
|
|
588
714
|
this.logger.debug('Stopping peer manager...');
|
|
589
715
|
await this.peerManager.stop();
|
|
@@ -598,12 +724,8 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
598
724
|
this.logger.info('LibP2P service stopped');
|
|
599
725
|
}
|
|
600
726
|
|
|
601
|
-
addReqRespSubProtocol(
|
|
602
|
-
subProtocol
|
|
603
|
-
handler: ReqRespSubProtocolHandler,
|
|
604
|
-
validator?: ReqRespSubProtocolValidators[ReqRespSubProtocol],
|
|
605
|
-
): Promise<void> {
|
|
606
|
-
return this.reqresp.addSubProtocol(subProtocol, handler, validator);
|
|
727
|
+
addReqRespSubProtocol(subProtocol: ReqRespSubProtocol, handler: ReqRespSubProtocolHandler): Promise<void> {
|
|
728
|
+
return this.reqresp.addSubProtocol(subProtocol, handler);
|
|
607
729
|
}
|
|
608
730
|
|
|
609
731
|
public registerThisValidatorAddresses(address: EthAddress[]): void {
|
|
@@ -614,6 +736,11 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
614
736
|
return this.peerManager.getPeers(includePending);
|
|
615
737
|
}
|
|
616
738
|
|
|
739
|
+
public getP2PConnectivity(): P2PConnectivity {
|
|
740
|
+
const connectedPeers = this.peerManager.getPeers().filter(peer => peer.status === 'connected').length;
|
|
741
|
+
return { enabled: true, connectedPeers };
|
|
742
|
+
}
|
|
743
|
+
|
|
617
744
|
public getGossipMeshPeerCount(topicType: TopicType): number {
|
|
618
745
|
return this.node.services.pubsub.getMeshPeers(this.topicStrings[topicType]).length;
|
|
619
746
|
}
|
|
@@ -631,20 +758,6 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
631
758
|
setImmediate(() => void safeJob());
|
|
632
759
|
}
|
|
633
760
|
|
|
634
|
-
/**
|
|
635
|
-
* Send a batch of requests to peers, and return the responses
|
|
636
|
-
* @param protocol - The request response protocol to use
|
|
637
|
-
* @param requests - The requests to send to the peers
|
|
638
|
-
* @returns The responses to the requests
|
|
639
|
-
*/
|
|
640
|
-
sendBatchRequest<SubProtocol extends ReqRespSubProtocol>(
|
|
641
|
-
protocol: SubProtocol,
|
|
642
|
-
requests: InstanceType<SubProtocolMap[SubProtocol]['request']>[],
|
|
643
|
-
pinnedPeerId: PeerId | undefined,
|
|
644
|
-
): Promise<InstanceType<SubProtocolMap[SubProtocol]['response']>[]> {
|
|
645
|
-
return this.reqresp.sendBatchRequest(protocol, requests, pinnedPeerId);
|
|
646
|
-
}
|
|
647
|
-
|
|
648
761
|
public sendRequestToPeer(
|
|
649
762
|
peerId: PeerId,
|
|
650
763
|
subProtocol: ReqRespSubProtocol,
|
|
@@ -666,8 +779,12 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
666
779
|
this.blockReceivedCallback = callback;
|
|
667
780
|
}
|
|
668
781
|
|
|
669
|
-
public
|
|
670
|
-
this.
|
|
782
|
+
public registerValidatorCheckpointReceivedCallback(callback: P2PCheckpointReceivedCallback) {
|
|
783
|
+
this.validatorCheckpointReceivedCallback = callback;
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
public registerAllNodesCheckpointReceivedCallback(callback: P2PCheckpointReceivedCallback) {
|
|
787
|
+
this.allNodesCheckpointReceivedCallback = callback;
|
|
671
788
|
}
|
|
672
789
|
|
|
673
790
|
/**
|
|
@@ -680,6 +797,13 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
680
797
|
this.duplicateProposalCallback = callback;
|
|
681
798
|
}
|
|
682
799
|
|
|
800
|
+
/**
|
|
801
|
+
* Registers a callback to be invoked when an oversized block proposal is stored as slashing evidence.
|
|
802
|
+
*/
|
|
803
|
+
public registerOversizedProposalCallback(callback: P2POversizedProposalCallback): void {
|
|
804
|
+
this.oversizedProposalCallback = callback;
|
|
805
|
+
}
|
|
806
|
+
|
|
683
807
|
/**
|
|
684
808
|
* Registers a callback to be invoked when a duplicate attestation is detected.
|
|
685
809
|
* A validator signing attestations for different proposals at the same slot.
|
|
@@ -689,6 +813,10 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
689
813
|
this.duplicateAttestationCallback = callback;
|
|
690
814
|
}
|
|
691
815
|
|
|
816
|
+
public registerCheckpointAttestationCallback(callback: P2PCheckpointAttestationCallback): void {
|
|
817
|
+
this.checkpointAttestationCallback = callback;
|
|
818
|
+
}
|
|
819
|
+
|
|
692
820
|
/**
|
|
693
821
|
* Subscribes to a topic.
|
|
694
822
|
* @param topic - The topic to subscribe to.
|
|
@@ -817,6 +945,15 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
817
945
|
|
|
818
946
|
// Process the message, optionally within a linked span for trace propagation
|
|
819
947
|
const processMessage = async () => {
|
|
948
|
+
if (
|
|
949
|
+
this.config.skipIncomingProposals &&
|
|
950
|
+
(msg.topic === this.topicStrings[TopicType.block_proposal] ||
|
|
951
|
+
msg.topic === this.topicStrings[TopicType.checkpoint_proposal])
|
|
952
|
+
) {
|
|
953
|
+
this.logger.warn(`Ignoring incoming proposal (skipIncomingProposals is set)`, { topic: msg.topic });
|
|
954
|
+
this.node.services.pubsub.reportMessageValidationResult(msgId, source.toString(), TopicValidatorResult.Ignore);
|
|
955
|
+
return;
|
|
956
|
+
}
|
|
820
957
|
if (msg.topic === this.topicStrings[TopicType.tx]) {
|
|
821
958
|
await this.handleGossipedTx(p2pMessage.payload, msgId, source);
|
|
822
959
|
} else if (msg.topic === this.topicStrings[TopicType.checkpoint_attestation]) {
|
|
@@ -881,6 +1018,7 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
881
1018
|
msgId: string,
|
|
882
1019
|
source: PeerId,
|
|
883
1020
|
topicType: TopicType,
|
|
1021
|
+
stageTimings?: Record<string, number>,
|
|
884
1022
|
): Promise<ReceivedMessageValidationResult<T, M>> {
|
|
885
1023
|
// Default to reject result with a penalty if validation function throws an error
|
|
886
1024
|
let resultAndObj: ReceivedMessageValidationResult<T, M> = {
|
|
@@ -894,8 +1032,25 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
894
1032
|
this.logger.error(`Error validating gossipsub message`, err, { msgId, source: source.toString(), topicType });
|
|
895
1033
|
}
|
|
896
1034
|
|
|
1035
|
+
const validationTimeMs = timer.ms();
|
|
1036
|
+
const mcacheWindowMs = this.config.gossipsubMcacheLength * this.config.gossipsubInterval;
|
|
1037
|
+
if (validationTimeMs > mcacheWindowMs * 0.75) {
|
|
1038
|
+
this.instrumentation.incSlowValidation(topicType);
|
|
1039
|
+
this.logger.warn(
|
|
1040
|
+
`Gossip validation for ${topicType} took ${validationTimeMs}ms, approaching mcache eviction window of ${mcacheWindowMs}ms. ` +
|
|
1041
|
+
`Message forwarding may be skipped if validation exceeds the window.`,
|
|
1042
|
+
{ msgId, source: source.toString(), topicType, validationTimeMs, mcacheWindowMs, stageTimings },
|
|
1043
|
+
);
|
|
1044
|
+
}
|
|
1045
|
+
|
|
897
1046
|
if (resultAndObj.result === TopicValidatorResult.Accept) {
|
|
898
|
-
this.logger.debug(`Message ${topicType} accepted by validator`, {
|
|
1047
|
+
this.logger.debug(`Message ${topicType} accepted by validator`, {
|
|
1048
|
+
msgId,
|
|
1049
|
+
source: source.toString(),
|
|
1050
|
+
topicType,
|
|
1051
|
+
validationTimeMs,
|
|
1052
|
+
stageTimings,
|
|
1053
|
+
});
|
|
899
1054
|
this.instrumentation.recordMessageValidation(topicType, timer);
|
|
900
1055
|
} else if (resultAndObj.result === TopicValidatorResult.Reject) {
|
|
901
1056
|
this.logger.warn(`Message ${topicType} rejected by validator with severity ${resultAndObj.severity}`, {
|
|
@@ -927,18 +1082,38 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
927
1082
|
}
|
|
928
1083
|
|
|
929
1084
|
protected async handleGossipedTx(payloadData: Buffer, msgId: string, source: PeerId) {
|
|
1085
|
+
// Per-stage timings so slow validations can be attributed to a specific stage (see A-1656).
|
|
1086
|
+
const stageTimings: Record<string, number> = {};
|
|
1087
|
+
const timed = async <T>(stage: string, fn: () => T | Promise<T>): Promise<T> => {
|
|
1088
|
+
const timer = new Timer();
|
|
1089
|
+
try {
|
|
1090
|
+
return await fn();
|
|
1091
|
+
} finally {
|
|
1092
|
+
const ms = timer.ms();
|
|
1093
|
+
stageTimings[stage] = Math.ceil(ms);
|
|
1094
|
+
this.instrumentation.recordTxValidationStage(stage, ms);
|
|
1095
|
+
}
|
|
1096
|
+
};
|
|
1097
|
+
|
|
930
1098
|
const validationFunc: () => Promise<ReceivedMessageValidationResult<Tx>> = async () => {
|
|
931
|
-
const tx = this.tryDeserialize(() => Tx.fromBuffer(payloadData), msgId, source);
|
|
1099
|
+
const tx = await timed('deserialize', () => this.tryDeserialize(() => Tx.fromBuffer(payloadData), msgId, source));
|
|
932
1100
|
if (!tx) {
|
|
933
1101
|
return { result: TopicValidatorResult.Reject, severity: PeerErrorSeverity.LowToleranceError };
|
|
934
1102
|
}
|
|
935
1103
|
|
|
936
|
-
|
|
937
|
-
const {
|
|
1104
|
+
// Stage 1 setup: chain tip, epoch info, gas fees, and L1 constants reads
|
|
1105
|
+
const { currentBlockNumber, firstStageValidators } = await timed('fast_validation_setup', async () => {
|
|
1106
|
+
const currentBlockNumber = await this.archiver.getBlockNumber();
|
|
1107
|
+
const { ts: nextSlotTimestamp } = this.epochCache.getEpochAndSlotInNextL1Slot();
|
|
1108
|
+
const firstStageValidators = await this.createFirstStageMessageValidators(
|
|
1109
|
+
currentBlockNumber,
|
|
1110
|
+
nextSlotTimestamp,
|
|
1111
|
+
);
|
|
1112
|
+
return { currentBlockNumber, firstStageValidators };
|
|
1113
|
+
});
|
|
938
1114
|
|
|
939
1115
|
// Stage 1: fast validators (metadata, data, timestamps, double-spend, gas, phases, block header)
|
|
940
|
-
const
|
|
941
|
-
const firstStageOutcome = await this.runValidations(tx, firstStageValidators);
|
|
1116
|
+
const firstStageOutcome = await timed('fast_validation', () => this.runValidations(tx, firstStageValidators));
|
|
942
1117
|
if (!firstStageOutcome.allPassed) {
|
|
943
1118
|
const { name } = firstStageOutcome.failure;
|
|
944
1119
|
let { severity } = firstStageOutcome.failure;
|
|
@@ -960,7 +1135,7 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
960
1135
|
}
|
|
961
1136
|
|
|
962
1137
|
// Pool pre-check: see if the pool would accept this tx before doing expensive proof verification
|
|
963
|
-
const canAdd = await this.mempools.txPool.canAddPendingTx(tx);
|
|
1138
|
+
const canAdd = await timed('pool_precheck', () => this.mempools.txPool.canAddPendingTx(tx));
|
|
964
1139
|
if (canAdd === 'ignored') {
|
|
965
1140
|
this.logger.verbose(`Ignoring gossiped tx ${tx.getTxHash().toString()}: pool pre-check returned ignored`, {
|
|
966
1141
|
source: source.toString(),
|
|
@@ -970,7 +1145,7 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
970
1145
|
|
|
971
1146
|
// Stage 2: expensive proof verification
|
|
972
1147
|
const secondStageValidators = this.createSecondStageMessageValidators();
|
|
973
|
-
const secondStageOutcome = await this.runValidations(tx, secondStageValidators);
|
|
1148
|
+
const secondStageOutcome = await timed('proof_verify', () => this.runValidations(tx, secondStageValidators));
|
|
974
1149
|
if (!secondStageOutcome.allPassed) {
|
|
975
1150
|
const { severity, name } = secondStageOutcome.failure;
|
|
976
1151
|
this.logger.verbose(`Rejecting gossiped tx ${tx.getTxHash().toString()}: stage 2 validation failed`, {
|
|
@@ -983,7 +1158,7 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
983
1158
|
|
|
984
1159
|
// Pool add: persist the tx
|
|
985
1160
|
const txHash = tx.getTxHash();
|
|
986
|
-
const addResult = await this.mempools.txPool.addPendingTxs([tx], { source: 'gossip' });
|
|
1161
|
+
const addResult = await timed('pool_add', () => this.mempools.txPool.addPendingTxs([tx], { source: 'gossip' }));
|
|
987
1162
|
|
|
988
1163
|
const wasAccepted = addResult.accepted.some(h => h.equals(txHash));
|
|
989
1164
|
const wasIgnored = addResult.ignored.some(h => h.equals(txHash));
|
|
@@ -1007,7 +1182,13 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1007
1182
|
}
|
|
1008
1183
|
};
|
|
1009
1184
|
|
|
1010
|
-
const { result, obj: tx } = await this.validateReceivedMessage<Tx>(
|
|
1185
|
+
const { result, obj: tx } = await this.validateReceivedMessage<Tx>(
|
|
1186
|
+
validationFunc,
|
|
1187
|
+
msgId,
|
|
1188
|
+
source,
|
|
1189
|
+
TopicType.tx,
|
|
1190
|
+
stageTimings,
|
|
1191
|
+
);
|
|
1011
1192
|
if (result !== TopicValidatorResult.Accept || !tx) {
|
|
1012
1193
|
return;
|
|
1013
1194
|
}
|
|
@@ -1129,6 +1310,7 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1129
1310
|
}
|
|
1130
1311
|
|
|
1131
1312
|
// Attestation was added successfully - accept it so other nodes can also detect the equivocation
|
|
1313
|
+
this.checkpointAttestationCallback?.(attestation);
|
|
1132
1314
|
return { result: TopicValidatorResult.Accept, obj: attestation };
|
|
1133
1315
|
}
|
|
1134
1316
|
|
|
@@ -1136,20 +1318,21 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1136
1318
|
const {
|
|
1137
1319
|
result,
|
|
1138
1320
|
obj: block,
|
|
1139
|
-
metadata: { isEquivocated } = {},
|
|
1140
|
-
} = await this.validateReceivedMessage<BlockProposal, { isEquivocated: boolean }>(
|
|
1321
|
+
metadata: { isEquivocated, isOversized } = {},
|
|
1322
|
+
} = await this.validateReceivedMessage<BlockProposal, { isEquivocated: boolean; isOversized: boolean }>(
|
|
1141
1323
|
() => this.validateAndStoreBlockProposal(source, BlockProposal.fromBuffer(payloadData)),
|
|
1142
1324
|
msgId,
|
|
1143
1325
|
source,
|
|
1144
1326
|
TopicType.block_proposal,
|
|
1145
1327
|
);
|
|
1146
1328
|
|
|
1147
|
-
// If not accepted or
|
|
1148
|
-
|
|
1329
|
+
// If not accepted, equivocated, or oversized, return. Oversized proposals are re-broadcast as
|
|
1330
|
+
// slashing evidence but never attested or processed.
|
|
1331
|
+
if (result !== TopicValidatorResult.Accept || !block || isEquivocated || isOversized) {
|
|
1149
1332
|
return;
|
|
1150
1333
|
}
|
|
1151
1334
|
|
|
1152
|
-
await this.processValidBlockProposal(block, source);
|
|
1335
|
+
await this.processValidBlockProposal(ValidatedBlockProposal(block), source);
|
|
1153
1336
|
}
|
|
1154
1337
|
|
|
1155
1338
|
/** Validates a block proposal. Triggers a penalization to the peer that sent it if invalid. Adds to the mempool if valid. */
|
|
@@ -1160,7 +1343,7 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1160
1343
|
protected async validateAndStoreBlockProposal(
|
|
1161
1344
|
peerId: PeerId,
|
|
1162
1345
|
block: BlockProposal,
|
|
1163
|
-
): Promise<ReceivedMessageValidationResult<BlockProposal, { isEquivocated: boolean }>> {
|
|
1346
|
+
): Promise<ReceivedMessageValidationResult<BlockProposal, { isEquivocated: boolean; isOversized: boolean }>> {
|
|
1164
1347
|
const validationResult = await this.blockProposalValidator.validate(block);
|
|
1165
1348
|
|
|
1166
1349
|
if (validationResult.result === 'reject') {
|
|
@@ -1175,6 +1358,12 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1175
1358
|
// Try to add the proposal: this handles existence check, cap check, and adding in one call
|
|
1176
1359
|
const { added, alreadyExists, count } = await this.mempools.attestationPool.tryAddBlockProposal(block);
|
|
1177
1360
|
const isEquivocated = count !== undefined && count > 1;
|
|
1361
|
+
// An oversized proposal (index at or beyond the consensus per-checkpoint limit) is structurally valid
|
|
1362
|
+
// proposer misbehavior: it is stored and re-broadcast as slashing evidence but never processed or
|
|
1363
|
+
// attested to. No-ops when maxBlocksPerCheckpoint is unset (local/test).
|
|
1364
|
+
const isOversized =
|
|
1365
|
+
this.config.maxBlocksPerCheckpoint !== undefined &&
|
|
1366
|
+
block.indexWithinCheckpoint >= this.config.maxBlocksPerCheckpoint;
|
|
1178
1367
|
|
|
1179
1368
|
// Duplicate proposal received, no need to re-broadcast
|
|
1180
1369
|
if (alreadyExists) {
|
|
@@ -1184,7 +1373,7 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1184
1373
|
proposer: block.getSender()?.toString(),
|
|
1185
1374
|
source: peerId.toString(),
|
|
1186
1375
|
});
|
|
1187
|
-
return { result: TopicValidatorResult.Ignore, obj: block, metadata: { isEquivocated } };
|
|
1376
|
+
return { result: TopicValidatorResult.Ignore, obj: block, metadata: { isEquivocated, isOversized } };
|
|
1188
1377
|
}
|
|
1189
1378
|
|
|
1190
1379
|
// Too many blocks received for this slot and index, penalize peer and do not re-broadcast
|
|
@@ -1198,11 +1387,27 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1198
1387
|
});
|
|
1199
1388
|
return {
|
|
1200
1389
|
result: TopicValidatorResult.Reject,
|
|
1201
|
-
metadata: { isEquivocated },
|
|
1390
|
+
metadata: { isEquivocated, isOversized },
|
|
1202
1391
|
severity: PeerErrorSeverity.HighToleranceError,
|
|
1203
1392
|
};
|
|
1204
1393
|
}
|
|
1205
1394
|
|
|
1395
|
+
// The proposal was stored: if oversized, invoke the oversized callback so the proposer can be
|
|
1396
|
+
// slashed. Fired alongside (not instead of) equivocation detection below.
|
|
1397
|
+
if (isOversized) {
|
|
1398
|
+
const proposer = block.getSender();
|
|
1399
|
+
if (proposer) {
|
|
1400
|
+
this.logger.warn(`Detected oversized block proposal at slot ${block.slotNumber}`, {
|
|
1401
|
+
...block.toBlockInfo(),
|
|
1402
|
+
indexWithinCheckpoint: block.indexWithinCheckpoint,
|
|
1403
|
+
maxBlocksPerCheckpoint: this.config.maxBlocksPerCheckpoint,
|
|
1404
|
+
source: peerId.toString(),
|
|
1405
|
+
proposer: proposer.toString(),
|
|
1406
|
+
});
|
|
1407
|
+
this.oversizedProposalCallback?.({ slot: block.slotNumber, proposer });
|
|
1408
|
+
}
|
|
1409
|
+
}
|
|
1410
|
+
|
|
1206
1411
|
// If this was a duplicate proposal, do not process it, but do invoke the duplicate callback,
|
|
1207
1412
|
// and do re-broadcast it so other nodes in the network know to slash the proposer
|
|
1208
1413
|
if (isEquivocated) {
|
|
@@ -1216,11 +1421,11 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1216
1421
|
if (proposer && count === 2) {
|
|
1217
1422
|
this.duplicateProposalCallback?.({ slot: block.slotNumber, proposer, type: 'block' });
|
|
1218
1423
|
}
|
|
1219
|
-
return { result: TopicValidatorResult.Accept, obj: block, metadata: { isEquivocated } };
|
|
1424
|
+
return { result: TopicValidatorResult.Accept, obj: block, metadata: { isEquivocated, isOversized } };
|
|
1220
1425
|
}
|
|
1221
1426
|
|
|
1222
1427
|
// Otherwise, we're good to go!
|
|
1223
|
-
return { result: TopicValidatorResult.Accept, obj: block };
|
|
1428
|
+
return { result: TopicValidatorResult.Accept, obj: block, metadata: { isEquivocated: false, isOversized } };
|
|
1224
1429
|
}
|
|
1225
1430
|
|
|
1226
1431
|
// REFACTOR(palla): This method should be moved to the p2p_client or to a separate component,
|
|
@@ -1230,7 +1435,7 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1230
1435
|
[Attributes.BLOCK_ARCHIVE]: block.archive.toString(),
|
|
1231
1436
|
[Attributes.P2P_ID]: await block.p2pMessageLoggingIdentifier().then(i => i.toString()),
|
|
1232
1437
|
}))
|
|
1233
|
-
protected async processValidBlockProposal(block:
|
|
1438
|
+
protected async processValidBlockProposal(block: ValidatedBlockProposal, sender: PeerId) {
|
|
1234
1439
|
const slot = block.slotNumber;
|
|
1235
1440
|
this.logger.verbose(`Received block proposal for slot ${slot} from external peer ${sender.toString()}.`, {
|
|
1236
1441
|
p2pMessageIdentifier: await block.p2pMessageLoggingIdentifier(),
|
|
@@ -1241,11 +1446,29 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1241
1446
|
// Mark the txs in this proposal as protected
|
|
1242
1447
|
await this.mempools.txPool.protectTxs(block.txHashes, block.blockHeader);
|
|
1243
1448
|
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1449
|
+
if (!(await this.tryBlockReceivedCallback(block, sender))) {
|
|
1450
|
+
// Release the protections this proposal created so its txs return to pending. Only entries still
|
|
1451
|
+
// keyed to this slot are cleared, so a tx referenced by a live proposal at another slot stays protected.
|
|
1452
|
+
await this.mempools.txPool.unprotectTxs(block.txHashes, slot);
|
|
1453
|
+
}
|
|
1454
|
+
}
|
|
1455
|
+
|
|
1456
|
+
/**
|
|
1457
|
+
* Runs the block received callback to validate a proposal, and returns whether it was accepted.
|
|
1458
|
+
* A callback that throws is reported as a rejection: the proposal is no more usable than one explicitly
|
|
1459
|
+
* rejected, and letting the error escape would leave the proposal's tx protections in place.
|
|
1460
|
+
* Note: Validators do NOT attest to individual blocks, only to checkpoint proposals.
|
|
1461
|
+
*/
|
|
1462
|
+
private async tryBlockReceivedCallback(block: ValidatedBlockProposal, sender: PeerId): Promise<boolean> {
|
|
1463
|
+
try {
|
|
1464
|
+
const isValid = await this.blockReceivedCallback(block, sender);
|
|
1465
|
+
if (!isValid) {
|
|
1466
|
+
this.logger.info(`Block proposal validation failed for block ${block.blockNumber}`, block.toBlockInfo());
|
|
1467
|
+
}
|
|
1468
|
+
return isValid;
|
|
1469
|
+
} catch (err) {
|
|
1470
|
+
this.logger.error(`Error validating block proposal for block ${block.blockNumber}`, err, block.toBlockInfo());
|
|
1471
|
+
return false;
|
|
1249
1472
|
}
|
|
1250
1473
|
}
|
|
1251
1474
|
|
|
@@ -1257,25 +1480,45 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1257
1480
|
const {
|
|
1258
1481
|
result,
|
|
1259
1482
|
obj: checkpoint,
|
|
1260
|
-
metadata: { isEquivocated, processBlock } = {},
|
|
1261
|
-
} = await this.validateReceivedMessage<
|
|
1483
|
+
metadata: { isEquivocated, processBlock, isOversized } = {},
|
|
1484
|
+
} = await this.validateReceivedMessage<
|
|
1485
|
+
CheckpointProposal,
|
|
1486
|
+
{ isEquivocated: boolean; processBlock: boolean; isOversized: boolean }
|
|
1487
|
+
>(
|
|
1262
1488
|
() => this.validateAndStoreCheckpointProposal(source, CheckpointProposal.fromBuffer(payloadData)),
|
|
1263
1489
|
msgId,
|
|
1264
1490
|
source,
|
|
1265
1491
|
TopicType.checkpoint_proposal,
|
|
1266
1492
|
);
|
|
1267
1493
|
|
|
1494
|
+
// An oversized checkpoint is re-broadcast as slashing evidence but never attested or processed.
|
|
1495
|
+
// Process checkpoint proposal if valid and neither equivocated nor oversized.
|
|
1496
|
+
const processCheckpointFn = () =>
|
|
1497
|
+
result === TopicValidatorResult.Accept && checkpoint && !isEquivocated && !isOversized
|
|
1498
|
+
? this.processValidCheckpointProposal(ValidatedCheckpointProposalCore(checkpoint.toCore()), source)
|
|
1499
|
+
: Promise.resolve();
|
|
1500
|
+
|
|
1268
1501
|
// If the checkpoint contained a valid last block, we process it even if the checkpoint itself is to be rejected
|
|
1269
1502
|
// TODO(palla/mbps): Is this ok? Should we be considering a block from a checkpoint that was equivocated?
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1503
|
+
const processBlockFn = () =>
|
|
1504
|
+
processBlock && checkpoint && checkpoint.getBlockProposal()
|
|
1505
|
+
? this.processValidBlockProposal(ValidatedBlockProposal(checkpoint.getBlockProposal()!), source)
|
|
1506
|
+
: Promise.resolve();
|
|
1507
|
+
|
|
1508
|
+
// A node that skips checkpoint validation attests without re-executing the embedded last block, so run
|
|
1509
|
+
// the checkpoint callback first: this creates and broadcasts the attestation before the block is
|
|
1510
|
+
// processed. Otherwise the block's re-execution — which can stall until the re-execution deadline
|
|
1511
|
+
// waiting for a parent that may never arrive — would delay the attestation past the slot's attestation
|
|
1512
|
+
// window, after which peers reject it as stale.
|
|
1513
|
+
if (this.config.skipCheckpointProposalValidation) {
|
|
1514
|
+
await processCheckpointFn();
|
|
1515
|
+
await processBlockFn();
|
|
1275
1516
|
return;
|
|
1276
1517
|
}
|
|
1277
1518
|
|
|
1278
|
-
|
|
1519
|
+
// Process the block first, since it's required for the checkpoint proposal validation.
|
|
1520
|
+
await processBlockFn();
|
|
1521
|
+
await processCheckpointFn();
|
|
1279
1522
|
}
|
|
1280
1523
|
|
|
1281
1524
|
/**
|
|
@@ -1288,7 +1531,12 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1288
1531
|
protected async validateAndStoreCheckpointProposal(
|
|
1289
1532
|
peerId: PeerId,
|
|
1290
1533
|
checkpoint: CheckpointProposal,
|
|
1291
|
-
): Promise<
|
|
1534
|
+
): Promise<
|
|
1535
|
+
ReceivedMessageValidationResult<
|
|
1536
|
+
CheckpointProposal,
|
|
1537
|
+
{ isEquivocated: boolean; processBlock: boolean; isOversized: boolean }
|
|
1538
|
+
>
|
|
1539
|
+
> {
|
|
1292
1540
|
const validationResult = await this.checkpointProposalValidator.validate(checkpoint);
|
|
1293
1541
|
|
|
1294
1542
|
if (validationResult.result === 'reject') {
|
|
@@ -1303,13 +1551,16 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1303
1551
|
// Extract and try to add the block proposal first if present
|
|
1304
1552
|
const blockProposal = checkpoint.getBlockProposal();
|
|
1305
1553
|
let processBlock = false;
|
|
1554
|
+
let isOversized = false;
|
|
1306
1555
|
if (blockProposal) {
|
|
1307
1556
|
this.logger.debug(`Validating block proposal from propagated checkpoint`, {
|
|
1308
1557
|
[Attributes.SLOT_NUMBER]: checkpoint.slotNumber.toString(),
|
|
1309
1558
|
[Attributes.P2P_ID]: peerId.toString(),
|
|
1310
1559
|
});
|
|
1311
1560
|
const blockProposalResult = await this.validateAndStoreBlockProposal(peerId, blockProposal);
|
|
1312
|
-
const { obj, metadata: { isEquivocated } = {} } = blockProposalResult;
|
|
1561
|
+
const { obj, metadata: { isEquivocated, isOversized: blockIsOversized } = {} } = blockProposalResult;
|
|
1562
|
+
isOversized = blockIsOversized ?? false;
|
|
1563
|
+
|
|
1313
1564
|
if (blockProposalResult.result === TopicValidatorResult.Reject || !obj || isEquivocated) {
|
|
1314
1565
|
this.logger.debug(`Rejecting checkpoint due to invalid last block proposal`, {
|
|
1315
1566
|
[Attributes.SLOT_NUMBER]: checkpoint.slotNumber.toString(),
|
|
@@ -1322,7 +1573,8 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1322
1573
|
severity:
|
|
1323
1574
|
'severity' in blockProposalResult ? blockProposalResult.severity : PeerErrorSeverity.MidToleranceError,
|
|
1324
1575
|
};
|
|
1325
|
-
} else if (blockProposalResult.result === TopicValidatorResult.Accept && obj && !isEquivocated) {
|
|
1576
|
+
} else if (blockProposalResult.result === TopicValidatorResult.Accept && obj && !isEquivocated && !isOversized) {
|
|
1577
|
+
// An oversized terminal block is re-broadcast as slashing evidence but never processed.
|
|
1326
1578
|
processBlock = true;
|
|
1327
1579
|
}
|
|
1328
1580
|
}
|
|
@@ -1342,11 +1594,11 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1342
1594
|
return {
|
|
1343
1595
|
result: TopicValidatorResult.Ignore,
|
|
1344
1596
|
obj: checkpoint,
|
|
1345
|
-
metadata: { isEquivocated, processBlock },
|
|
1597
|
+
metadata: { isEquivocated, processBlock, isOversized },
|
|
1346
1598
|
};
|
|
1347
1599
|
}
|
|
1348
1600
|
|
|
1349
|
-
// Too many checkpoint proposals received for this slot, penalize peer and do not re-broadcast
|
|
1601
|
+
// Too many checkpoint proposals received for this slot, penalize peer and do not re-broadcast.
|
|
1350
1602
|
// Note: We still return the checkpoint obj so the lastBlock can be processed if valid
|
|
1351
1603
|
if (!added) {
|
|
1352
1604
|
this.logger.warn(`Penalizing peer for checkpoint proposal exceeding per-slot cap`, {
|
|
@@ -1357,7 +1609,7 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1357
1609
|
return {
|
|
1358
1610
|
result: TopicValidatorResult.Reject,
|
|
1359
1611
|
obj: checkpoint,
|
|
1360
|
-
metadata: { isEquivocated, processBlock },
|
|
1612
|
+
metadata: { isEquivocated, processBlock, isOversized },
|
|
1361
1613
|
severity: PeerErrorSeverity.HighToleranceError,
|
|
1362
1614
|
};
|
|
1363
1615
|
}
|
|
@@ -1378,12 +1630,16 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1378
1630
|
return {
|
|
1379
1631
|
result: TopicValidatorResult.Accept,
|
|
1380
1632
|
obj: checkpoint,
|
|
1381
|
-
metadata: { isEquivocated, processBlock },
|
|
1633
|
+
metadata: { isEquivocated, processBlock, isOversized },
|
|
1382
1634
|
};
|
|
1383
1635
|
}
|
|
1384
1636
|
|
|
1385
1637
|
// Otherwise, we're good to go!
|
|
1386
|
-
return {
|
|
1638
|
+
return {
|
|
1639
|
+
result: TopicValidatorResult.Accept,
|
|
1640
|
+
obj: checkpoint,
|
|
1641
|
+
metadata: { processBlock, isEquivocated, isOversized },
|
|
1642
|
+
};
|
|
1387
1643
|
}
|
|
1388
1644
|
|
|
1389
1645
|
/**
|
|
@@ -1395,7 +1651,7 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1395
1651
|
[Attributes.BLOCK_ARCHIVE]: checkpoint.archive.toString(),
|
|
1396
1652
|
[Attributes.P2P_ID]: await checkpoint.p2pMessageLoggingIdentifier().then(i => i.toString()),
|
|
1397
1653
|
}))
|
|
1398
|
-
protected async processValidCheckpointProposal(checkpoint:
|
|
1654
|
+
protected async processValidCheckpointProposal(checkpoint: ValidatedCheckpointProposalCore, sender: PeerId) {
|
|
1399
1655
|
const slot = checkpoint.slotNumber;
|
|
1400
1656
|
this.logger.verbose(`Received checkpoint proposal for slot ${slot} from external peer ${sender.toString()}.`, {
|
|
1401
1657
|
p2pMessageIdentifier: await checkpoint.p2pMessageLoggingIdentifier(),
|
|
@@ -1404,9 +1660,11 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1404
1660
|
source: sender.toString(),
|
|
1405
1661
|
});
|
|
1406
1662
|
|
|
1663
|
+
await this.allNodesCheckpointReceivedCallback(checkpoint, sender);
|
|
1664
|
+
|
|
1407
1665
|
// Call the checkpoint received callback with the core version (without lastBlock)
|
|
1408
1666
|
// to validate and potentially generate attestations
|
|
1409
|
-
const attestations = await this.
|
|
1667
|
+
const attestations = await this.validatorCheckpointReceivedCallback(checkpoint, sender);
|
|
1410
1668
|
if (attestations && attestations.length > 0) {
|
|
1411
1669
|
// If the callback returned attestations, add them to the pool and propagate them
|
|
1412
1670
|
await this.mempools.attestationPool.addOwnCheckpointAttestations(attestations);
|
|
@@ -1429,82 +1687,87 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1429
1687
|
}
|
|
1430
1688
|
|
|
1431
1689
|
/**
|
|
1432
|
-
* Validate the requested block transactions
|
|
1690
|
+
* Validate the requested block transactions request-response consistency.
|
|
1691
|
+
* It does NOT validate the transactions themselves.
|
|
1433
1692
|
* @param request - The block transactions request.
|
|
1434
1693
|
* @param response - The block transactions response.
|
|
1435
1694
|
* @param peerId - The ID of the peer that made the request.
|
|
1436
|
-
* @returns True if the
|
|
1695
|
+
* @returns True if the request-response is consistent, false otherwise.
|
|
1437
1696
|
*/
|
|
1438
|
-
@trackSpan('Libp2pService.
|
|
1697
|
+
@trackSpan('Libp2pService.validateRequestedBlockTxsConsistency', request => ({
|
|
1439
1698
|
[Attributes.BLOCK_ARCHIVE]: request.archiveRoot.toString(),
|
|
1440
1699
|
}))
|
|
1441
|
-
protected async
|
|
1700
|
+
protected async validateRequestedBlockTxsConsistency(
|
|
1442
1701
|
request: BlockTxsRequest,
|
|
1443
1702
|
response: BlockTxsResponse,
|
|
1444
1703
|
peerId: PeerId,
|
|
1445
1704
|
): Promise<boolean> {
|
|
1446
|
-
const requestedTxValidator = this.createRequestedTxValidator();
|
|
1447
|
-
|
|
1448
1705
|
try {
|
|
1449
|
-
|
|
1706
|
+
// Check for duplicates txs (or hashes) in the response.
|
|
1707
|
+
const returnedHashes = response.txs.map(tx => tx.getTxHash().toString());
|
|
1708
|
+
const uniqueReturned = new Set(returnedHashes.map(h => h.toString()));
|
|
1709
|
+
if (uniqueReturned.size !== returnedHashes.length) {
|
|
1450
1710
|
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
1451
|
-
throw new ValidationError(
|
|
1452
|
-
|
|
1711
|
+
throw new ValidationError(`Received duplicate txs in block txs response`);
|
|
1712
|
+
}
|
|
1713
|
+
|
|
1714
|
+
// We get the block tx hashes from the proposal or the archiver.
|
|
1715
|
+
const proposal = await this.mempools.attestationPool.getBlockProposalByArchive(request.archiveRoot.toString());
|
|
1716
|
+
const blockTxHashes =
|
|
1717
|
+
proposal?.txHashes ??
|
|
1718
|
+
(await this.archiver.getBlock({ archive: request.archiveRoot }))?.body.txEffects.map(e => e.txHash);
|
|
1719
|
+
|
|
1720
|
+
// If we don't have the block, we can't verify membership/order of the returned txs.
|
|
1721
|
+
if (!blockTxHashes) {
|
|
1722
|
+
// This shouldn't happen, since we asked for the block (proposal).
|
|
1723
|
+
// Neither a local proposal nor an archived block: we cannot verify membership/order of the
|
|
1724
|
+
// returned txs. This is a local-state gap, not a peer fault, so we do not penalize.
|
|
1725
|
+
this.logger.warn(
|
|
1726
|
+
`Block ${request.archiveRoot.toString()} not found in attestation pool or archiver; cannot validate membership/order of returned txs`,
|
|
1453
1727
|
);
|
|
1728
|
+
// NOTE: We mark the response as invalid, given the limitations of a true/false return value.
|
|
1729
|
+
return false;
|
|
1454
1730
|
}
|
|
1455
1731
|
|
|
1456
|
-
|
|
1457
|
-
|
|
1732
|
+
// Verify that the returned tx hashes are a subset of (tx hashes by index) U (explicitly requested tx hashes).
|
|
1733
|
+
const uniqueRequestedHashes = new Set([
|
|
1734
|
+
// tx hashes requested by index.
|
|
1735
|
+
...request.txIndices.getTrueIndices().map(i => blockTxHashes[i].toString()),
|
|
1736
|
+
// explicitly requested tx hashes.
|
|
1737
|
+
...request.txHashes.map(h => h.toString()),
|
|
1738
|
+
]);
|
|
1739
|
+
if (!returnedHashes.every(h => uniqueRequestedHashes.has(h))) {
|
|
1740
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
|
|
1458
1741
|
throw new ValidationError(
|
|
1459
|
-
|
|
1742
|
+
'Returned txs should be a subset of (tx hashes by index) U (explicitly requested tx hashes)',
|
|
1460
1743
|
);
|
|
1461
1744
|
}
|
|
1462
1745
|
|
|
1463
|
-
//
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
const returnedHashes = await Promise.all(response.txs.map(tx => tx.getTxHash().toString()));
|
|
1469
|
-
const uniqueReturned = new Set(returnedHashes.map(h => h.toString()));
|
|
1470
|
-
if (uniqueReturned.size !== returnedHashes.length) {
|
|
1471
|
-
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
1472
|
-
throw new ValidationError(`Received duplicate txs in block txs response`);
|
|
1746
|
+
// Tx indices information is optional, but if present, we need to verify a few things.
|
|
1747
|
+
if (!response.peerHasBlock()) {
|
|
1748
|
+
this.logger.debug(`Peer ${peerId.toString()} signalled missing block`);
|
|
1749
|
+
return true;
|
|
1473
1750
|
}
|
|
1474
|
-
|
|
1751
|
+
|
|
1752
|
+
// If the response has a non-empty bitvector, it needs to be consistent with the number of txs in the block.
|
|
1753
|
+
if (response.txIndices.getLength() !== blockTxHashes.length) {
|
|
1475
1754
|
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
1476
1755
|
throw new ValidationError(
|
|
1477
|
-
`Received
|
|
1756
|
+
`Received block txs with mismatched bitvector length: expected ${blockTxHashes.length}, got ${response.txIndices.getLength()}`,
|
|
1478
1757
|
);
|
|
1479
1758
|
}
|
|
1480
1759
|
|
|
1481
|
-
//
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
);
|
|
1491
|
-
const allowedIndexSet = new Set(intersectIdx);
|
|
1492
|
-
const indices = returnedHashes.map(h => hashToIndexInProposal.get(h));
|
|
1493
|
-
const allAllowed = indices.every(idx => idx !== undefined && allowedIndexSet.has(idx));
|
|
1494
|
-
const strictlyIncreasing = indices.every((idx, i) => (i === 0 ? idx !== undefined : idx! > indices[i - 1]!));
|
|
1495
|
-
if (!allAllowed || !strictlyIncreasing) {
|
|
1496
|
-
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
|
|
1497
|
-
throw new ValidationError('Returned txs do not match expected subset/order for requested indices');
|
|
1498
|
-
}
|
|
1499
|
-
} else {
|
|
1500
|
-
// No local proposal, cannot check the membership/order of the returned txs
|
|
1501
|
-
this.logger.warn(
|
|
1502
|
-
`Block proposal not found for archive root ${request.archiveRoot.toString()}; cannot validate membership/order of returned txs`,
|
|
1503
|
-
);
|
|
1504
|
-
return false;
|
|
1760
|
+
// For every index we requested that the peer claims to have (per its bitvector), the
|
|
1761
|
+
// corresponding tx must be present in the response. A peer advertising availability but
|
|
1762
|
+
// withholding the tx is inconsistent.
|
|
1763
|
+
const returnedHashSet = new Set(returnedHashes);
|
|
1764
|
+
const expectedIndices = request.txIndices.getTrueIndices().filter(i => response.txIndices.isSet(i));
|
|
1765
|
+
const missingExpected = expectedIndices.some(i => !returnedHashSet.has(blockTxHashes[i].toString()));
|
|
1766
|
+
if (missingExpected) {
|
|
1767
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
|
|
1768
|
+
throw new ValidationError('Peer advertised requested txs via indices but did not return them');
|
|
1505
1769
|
}
|
|
1506
1770
|
|
|
1507
|
-
await Promise.all(response.txs.map(tx => this.validateRequestedTx(tx, peerId, requestedTxValidator)));
|
|
1508
1771
|
return true;
|
|
1509
1772
|
} catch (e: any) {
|
|
1510
1773
|
if (e instanceof ValidationError) {
|
|
@@ -1517,125 +1780,8 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1517
1780
|
}
|
|
1518
1781
|
}
|
|
1519
1782
|
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
*
|
|
1523
|
-
* The core component of this validator is that each tx hash MUST match the requested tx hash,
|
|
1524
|
-
* In order to perform this check, the tx proof must be verified.
|
|
1525
|
-
*
|
|
1526
|
-
* Note: This function is called from within `ReqResp.sendRequest` as part of the
|
|
1527
|
-
* ReqRespSubProtocol.TX subprotocol validation.
|
|
1528
|
-
*
|
|
1529
|
-
* @param requestedTxHash - The collection of the txs that was requested.
|
|
1530
|
-
* @param responseTx - The collection of txs that was received as a response to the request.
|
|
1531
|
-
* @param peerId - The peer ID of the peer that sent the tx.
|
|
1532
|
-
* @returns True if the whole collection of txs is valid, false otherwise.
|
|
1533
|
-
*/
|
|
1534
|
-
@trackSpan('Libp2pService.validateRequestedTx', (requestedTxHash, _responseTx) => ({
|
|
1535
|
-
[Attributes.TX_HASH]: requestedTxHash.toString(),
|
|
1536
|
-
}))
|
|
1537
|
-
private async validateRequestedTxs(requestedTxHash: TxHash[], responseTx: Tx[], peerId: PeerId): Promise<boolean> {
|
|
1538
|
-
const requested = new Set(requestedTxHash.map(h => h.toString()));
|
|
1539
|
-
const requestedTxValidator = this.createRequestedTxValidator();
|
|
1540
|
-
|
|
1541
|
-
//TODO: (mralj) - this is somewhat naive implementation, if single tx is invalid we consider the whole response invalid.
|
|
1542
|
-
// I think we should still extract the valid txs and return them, so that we can still use the response.
|
|
1543
|
-
try {
|
|
1544
|
-
await Promise.all(responseTx.map(tx => this.validateRequestedTx(tx, peerId, requestedTxValidator, requested)));
|
|
1545
|
-
return true;
|
|
1546
|
-
} catch (e: any) {
|
|
1547
|
-
if (e instanceof ValidationError) {
|
|
1548
|
-
this.logger.warn(`Failed to validate requested txs from peer ${peerId.toString()}, reason ${e.message}`);
|
|
1549
|
-
} else {
|
|
1550
|
-
this.logger.error(`Error during validation of requested txs`, e);
|
|
1551
|
-
}
|
|
1552
|
-
|
|
1553
|
-
return false;
|
|
1554
|
-
}
|
|
1555
|
-
}
|
|
1556
|
-
|
|
1557
|
-
/**
|
|
1558
|
-
* Validates a BLOCK response.
|
|
1559
|
-
*
|
|
1560
|
-
* If a local copy exists, enforces hash equality. If missing, rejects (no penalty) since the hash cannot be verified.
|
|
1561
|
-
* Penalizes on block number mismatch or hash mismatch.
|
|
1562
|
-
*
|
|
1563
|
-
* @param requestedBlockNumber - The requested block number.
|
|
1564
|
-
* @param responseBlock - The block returned by the peer.
|
|
1565
|
-
* @param peerId - The peer that returned the block.
|
|
1566
|
-
* @returns True if the response is valid, false otherwise.
|
|
1567
|
-
*/
|
|
1568
|
-
@trackSpan('Libp2pService.validateRequestedBlock', (requestedBlockNumber, _responseBlock) => ({
|
|
1569
|
-
[Attributes.BLOCK_NUMBER]: requestedBlockNumber.toString(),
|
|
1570
|
-
}))
|
|
1571
|
-
protected async validateRequestedBlock(
|
|
1572
|
-
requestedBlockNumber: Fr,
|
|
1573
|
-
responseBlock: L2Block,
|
|
1574
|
-
peerId: PeerId,
|
|
1575
|
-
): Promise<boolean> {
|
|
1576
|
-
try {
|
|
1577
|
-
const reqNum = Number(requestedBlockNumber.toString());
|
|
1578
|
-
if (responseBlock.number !== reqNum) {
|
|
1579
|
-
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
|
|
1580
|
-
return false;
|
|
1581
|
-
}
|
|
1582
|
-
|
|
1583
|
-
const local = await this.archiver.getBlock(BlockNumber(reqNum));
|
|
1584
|
-
if (!local) {
|
|
1585
|
-
// We are missing the local block; we cannot verify the hash yet. Reject without penalizing.
|
|
1586
|
-
// TODO: Consider extending this validator to accept an expected hash or
|
|
1587
|
-
// performing quorum-based checks when using P2P syncing prior to L1 sync.
|
|
1588
|
-
this.logger.warn(`Local block ${reqNum} not found; rejecting BLOCK response without hash verification`);
|
|
1589
|
-
return false;
|
|
1590
|
-
}
|
|
1591
|
-
const [localHash, respHash] = await Promise.all([local.hash(), responseBlock.hash()]);
|
|
1592
|
-
if (!localHash.equals(respHash)) {
|
|
1593
|
-
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
1594
|
-
return false;
|
|
1595
|
-
}
|
|
1596
|
-
|
|
1597
|
-
return true;
|
|
1598
|
-
} catch (e) {
|
|
1599
|
-
this.logger.warn(`Error validating requested block`, e);
|
|
1600
|
-
return false;
|
|
1601
|
-
}
|
|
1602
|
-
}
|
|
1603
|
-
|
|
1604
|
-
protected async validateRequestedTx(
|
|
1605
|
-
tx: Tx,
|
|
1606
|
-
peerId: PeerId,
|
|
1607
|
-
txValidator: TxValidator,
|
|
1608
|
-
requested?: Set<`0x${string}`>,
|
|
1609
|
-
) {
|
|
1610
|
-
const penalize = (severity: PeerErrorSeverity) => this.peerManager.penalizePeer(peerId, severity);
|
|
1611
|
-
if (requested && !requested.has(tx.getTxHash().toString())) {
|
|
1612
|
-
penalize(PeerErrorSeverity.MidToleranceError);
|
|
1613
|
-
throw new ValidationError(`Received tx with hash ${tx.getTxHash().toString()} that was not requested.`);
|
|
1614
|
-
}
|
|
1615
|
-
|
|
1616
|
-
const { result } = await txValidator.validateTx(tx);
|
|
1617
|
-
if (result === 'invalid') {
|
|
1618
|
-
penalize(PeerErrorSeverity.LowToleranceError);
|
|
1619
|
-
throw new ValidationError(`Received tx with hash ${tx.getTxHash().toString()} that is invalid.`);
|
|
1620
|
-
}
|
|
1621
|
-
}
|
|
1622
|
-
|
|
1623
|
-
protected createRequestedTxValidator(): TxValidator {
|
|
1624
|
-
return createTxValidatorForReqResponseReceivedTxs(this.proofVerifier, {
|
|
1625
|
-
l1ChainId: this.config.l1ChainId,
|
|
1626
|
-
rollupVersion: this.config.rollupVersion,
|
|
1627
|
-
});
|
|
1628
|
-
}
|
|
1629
|
-
|
|
1630
|
-
private async getGasFees(blockNumber: BlockNumber): Promise<GasFees> {
|
|
1631
|
-
if (blockNumber === this.feesCache?.blockNumber) {
|
|
1632
|
-
return this.feesCache.gasFees;
|
|
1633
|
-
}
|
|
1634
|
-
|
|
1635
|
-
const header = await this.archiver.getBlockHeader(blockNumber);
|
|
1636
|
-
const gasFees = header?.globalVariables.gasFees ?? GasFees.empty();
|
|
1637
|
-
this.feesCache = { blockNumber, gasFees };
|
|
1638
|
-
return gasFees;
|
|
1783
|
+
private getGasFees(): Promise<GasFees> {
|
|
1784
|
+
return this.blockMinFeesProvider.getCurrentMinFees();
|
|
1639
1785
|
}
|
|
1640
1786
|
|
|
1641
1787
|
/**
|
|
@@ -1649,8 +1795,10 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1649
1795
|
l1ChainId: this.config.l1ChainId,
|
|
1650
1796
|
rollupVersion: this.config.rollupVersion,
|
|
1651
1797
|
proofVerifier: this.proofVerifier,
|
|
1798
|
+
txValidationCache: this.txValidationCache,
|
|
1652
1799
|
},
|
|
1653
1800
|
peerScoring: this.peerManager,
|
|
1801
|
+
validateRequestedBlockTxsConsistency: this.validateRequestedBlockTxsConsistency.bind(this),
|
|
1654
1802
|
};
|
|
1655
1803
|
}
|
|
1656
1804
|
|
|
@@ -1659,16 +1807,19 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1659
1807
|
this.proofVerifier,
|
|
1660
1808
|
{ l1ChainId: this.config.l1ChainId, rollupVersion: this.config.rollupVersion },
|
|
1661
1809
|
this.logger.getBindings(),
|
|
1810
|
+
this.txValidationCache,
|
|
1662
1811
|
);
|
|
1663
1812
|
|
|
1664
1813
|
const results = await Promise.all(
|
|
1665
|
-
txs.map(async tx => {
|
|
1666
|
-
const result = await validator.validateTx(tx);
|
|
1667
|
-
return result.result !== 'invalid';
|
|
1668
|
-
}),
|
|
1814
|
+
txs.map(async tx => ({ txHash: tx.getTxHash(), result: await validator.validateTx(tx) })),
|
|
1669
1815
|
);
|
|
1670
|
-
|
|
1671
|
-
|
|
1816
|
+
|
|
1817
|
+
const invalidTxs = results.flatMap(({ txHash, result }) =>
|
|
1818
|
+
result.result === 'invalid' ? [{ txHash, reasons: result.reason }] : [],
|
|
1819
|
+
);
|
|
1820
|
+
|
|
1821
|
+
if (invalidTxs.length > 0) {
|
|
1822
|
+
throw new InvalidBlockProposalTxsError(invalidTxs);
|
|
1672
1823
|
}
|
|
1673
1824
|
}
|
|
1674
1825
|
|
|
@@ -1677,13 +1828,14 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1677
1828
|
currentBlockNumber: BlockNumber,
|
|
1678
1829
|
nextSlotTimestamp: UInt64,
|
|
1679
1830
|
): Promise<Record<string, TransactionValidator>> {
|
|
1680
|
-
const gasFees = await this.getGasFees(
|
|
1831
|
+
const gasFees = await this.getGasFees();
|
|
1681
1832
|
const allowedInSetup = [
|
|
1682
1833
|
...(await getDefaultAllowedSetupFunctions()),
|
|
1683
1834
|
...(this.config.txPublicSetupAllowListExtend ?? []),
|
|
1684
1835
|
];
|
|
1685
1836
|
const blockNumber = BlockNumber(currentBlockNumber + 1);
|
|
1686
1837
|
const l1Constants = await this.archiver.getL1Constants();
|
|
1838
|
+
const networkTxGasLimits = getNetworkTxGasLimits(this.config, l1Constants);
|
|
1687
1839
|
|
|
1688
1840
|
return createFirstStageTxValidationsForGossipedTransactions(
|
|
1689
1841
|
nextSlotTimestamp,
|
|
@@ -1698,9 +1850,8 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1698
1850
|
allowedInSetup,
|
|
1699
1851
|
this.logger.getBindings(),
|
|
1700
1852
|
{
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
maxBlockDAGas: this.config.validateMaxDABlockGas,
|
|
1853
|
+
maxTxL2Gas: networkTxGasLimits.l2Gas,
|
|
1854
|
+
maxTxDAGas: networkTxGasLimits.daGas,
|
|
1704
1855
|
},
|
|
1705
1856
|
);
|
|
1706
1857
|
}
|