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