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