@aztec/p2p 4.0.0-nightly.20250907 → 4.0.0-nightly.20260107
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/dest/bootstrap/bootstrap.d.ts +1 -1
- package/dest/bootstrap/bootstrap.d.ts.map +1 -1
- package/dest/bootstrap/bootstrap.js +14 -4
- package/dest/client/factory.d.ts +3 -2
- package/dest/client/factory.d.ts.map +1 -1
- package/dest/client/factory.js +9 -5
- package/dest/client/index.d.ts +1 -1
- package/dest/client/interface.d.ts +8 -6
- package/dest/client/interface.d.ts.map +1 -1
- package/dest/client/p2p_client.d.ts +12 -35
- package/dest/client/p2p_client.d.ts.map +1 -1
- package/dest/client/p2p_client.js +457 -61
- package/dest/config.d.ts +67 -61
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +28 -15
- package/dest/enr/generate-enr.d.ts +2 -2
- package/dest/enr/generate-enr.d.ts.map +1 -1
- package/dest/enr/generate-enr.js +1 -1
- package/dest/enr/index.d.ts +1 -1
- package/dest/errors/attestation-pool.error.d.ts +7 -0
- package/dest/errors/attestation-pool.error.d.ts.map +1 -0
- package/dest/errors/attestation-pool.error.js +12 -0
- package/dest/errors/reqresp.error.d.ts +1 -1
- package/dest/errors/reqresp.error.d.ts.map +1 -1
- package/dest/index.d.ts +1 -1
- package/dest/mem_pools/attestation_pool/attestation_pool.d.ts +43 -6
- package/dest/mem_pools/attestation_pool/attestation_pool.d.ts.map +1 -1
- 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 +72 -46
- package/dest/mem_pools/attestation_pool/index.d.ts +1 -1
- package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts +15 -6
- package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/kv_attestation_pool.js +73 -18
- package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts +13 -6
- package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/memory_attestation_pool.js +69 -11
- package/dest/mem_pools/attestation_pool/mocks.d.ts +226 -5
- package/dest/mem_pools/attestation_pool/mocks.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/mocks.js +9 -7
- package/dest/mem_pools/index.d.ts +1 -1
- package/dest/mem_pools/instrumentation.d.ts +9 -1
- package/dest/mem_pools/instrumentation.d.ts.map +1 -1
- package/dest/mem_pools/instrumentation.js +38 -2
- package/dest/mem_pools/interface.d.ts +3 -4
- package/dest/mem_pools/interface.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts +39 -58
- package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.js +314 -317
- package/dest/mem_pools/tx_pool/eviction/eviction_manager.d.ts +18 -0
- package/dest/mem_pools/tx_pool/eviction/eviction_manager.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool/eviction/eviction_manager.js +56 -0
- package/dest/mem_pools/tx_pool/eviction/eviction_strategy.d.ts +83 -0
- package/dest/mem_pools/tx_pool/eviction/eviction_strategy.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool/eviction/eviction_strategy.js +5 -0
- package/dest/mem_pools/tx_pool/eviction/insufficient_fee_payer_balance_rule.d.ts +15 -0
- package/dest/mem_pools/tx_pool/eviction/insufficient_fee_payer_balance_rule.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool/eviction/insufficient_fee_payer_balance_rule.js +88 -0
- package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.d.ts +17 -0
- package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.js +84 -0
- package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.d.ts +19 -0
- package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.js +76 -0
- package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.d.ts +26 -0
- package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.js +84 -0
- package/dest/mem_pools/tx_pool/index.d.ts +1 -2
- package/dest/mem_pools/tx_pool/index.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/index.js +0 -1
- package/dest/mem_pools/tx_pool/priority.d.ts +5 -1
- package/dest/mem_pools/tx_pool/priority.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/priority.js +6 -1
- package/dest/mem_pools/tx_pool/tx_pool.d.ts +28 -9
- package/dest/mem_pools/tx_pool/tx_pool.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts +1 -1
- package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/tx_pool_test_suite.js +155 -25
- package/dest/msg_validators/attestation_validator/attestation_validator.d.ts +4 -2
- package/dest/msg_validators/attestation_validator/attestation_validator.d.ts.map +1 -1
- package/dest/msg_validators/attestation_validator/attestation_validator.js +32 -5
- package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts +20 -0
- package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts.map +1 -0
- package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.js +67 -0
- package/dest/msg_validators/attestation_validator/index.d.ts +2 -1
- package/dest/msg_validators/attestation_validator/index.d.ts.map +1 -1
- package/dest/msg_validators/attestation_validator/index.js +1 -0
- package/dest/msg_validators/block_proposal_validator/block_proposal_validator.d.ts +5 -2
- package/dest/msg_validators/block_proposal_validator/block_proposal_validator.d.ts.map +1 -1
- package/dest/msg_validators/block_proposal_validator/block_proposal_validator.js +44 -12
- package/dest/msg_validators/block_proposal_validator/index.d.ts +1 -1
- package/dest/msg_validators/index.d.ts +1 -1
- package/dest/msg_validators/msg_seen_validator/msg_seen_validator.d.ts +1 -1
- package/dest/msg_validators/msg_seen_validator/msg_seen_validator.d.ts.map +1 -1
- 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/allowed_public_setup.d.ts +1 -1
- package/dest/msg_validators/tx_validator/archive_cache.d.ts +2 -2
- package/dest/msg_validators/tx_validator/archive_cache.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/block_header_validator.d.ts +2 -2
- package/dest/msg_validators/tx_validator/block_header_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/block_header_validator.js +1 -1
- package/dest/msg_validators/tx_validator/data_validator.d.ts +1 -1
- package/dest/msg_validators/tx_validator/data_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/double_spend_validator.d.ts +1 -1
- package/dest/msg_validators/tx_validator/double_spend_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/double_spend_validator.js +1 -1
- package/dest/msg_validators/tx_validator/factory.d.ts +4 -3
- package/dest/msg_validators/tx_validator/factory.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/factory.js +11 -5
- package/dest/msg_validators/tx_validator/gas_validator.d.ts +1 -1
- package/dest/msg_validators/tx_validator/gas_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/index.d.ts +2 -1
- package/dest/msg_validators/tx_validator/index.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/index.js +1 -0
- package/dest/msg_validators/tx_validator/metadata_validator.d.ts +3 -6
- package/dest/msg_validators/tx_validator/metadata_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/metadata_validator.js +6 -24
- package/dest/msg_validators/tx_validator/phases_validator.d.ts +1 -1
- package/dest/msg_validators/tx_validator/phases_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/phases_validator.js +3 -1
- package/dest/msg_validators/tx_validator/test_utils.d.ts +2 -2
- package/dest/msg_validators/tx_validator/test_utils.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/timestamp_validator.d.ts +13 -0
- package/dest/msg_validators/tx_validator/timestamp_validator.d.ts.map +1 -0
- package/dest/msg_validators/tx_validator/timestamp_validator.js +32 -0
- package/dest/msg_validators/tx_validator/tx_permitted_validator.d.ts +1 -1
- package/dest/msg_validators/tx_validator/tx_permitted_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/tx_proof_validator.d.ts +1 -1
- package/dest/msg_validators/tx_validator/tx_proof_validator.d.ts.map +1 -1
- package/dest/services/data_store.d.ts +1 -1
- package/dest/services/data_store.d.ts.map +1 -1
- package/dest/services/discv5/discV5_service.d.ts +3 -3
- package/dest/services/discv5/discV5_service.d.ts.map +1 -1
- package/dest/services/discv5/discV5_service.js +2 -2
- package/dest/services/dummy_service.d.ts +2 -2
- package/dest/services/dummy_service.d.ts.map +1 -1
- package/dest/services/encoding.d.ts +25 -4
- package/dest/services/encoding.d.ts.map +1 -1
- package/dest/services/encoding.js +74 -6
- package/dest/services/gossipsub/scoring.d.ts +1 -1
- package/dest/services/index.d.ts +1 -1
- 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 +9 -2
- package/dest/services/libp2p/libp2p_service.d.ts +32 -72
- package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
- package/dest/services/libp2p/libp2p_service.js +796 -171
- package/dest/services/peer-manager/interface.d.ts +1 -1
- package/dest/services/peer-manager/metrics.d.ts +8 -1
- package/dest/services/peer-manager/metrics.d.ts.map +1 -1
- package/dest/services/peer-manager/metrics.js +28 -0
- package/dest/services/peer-manager/peer_manager.d.ts +1 -32
- package/dest/services/peer-manager/peer_manager.d.ts.map +1 -1
- package/dest/services/peer-manager/peer_manager.js +412 -21
- package/dest/services/peer-manager/peer_scoring.d.ts +7 -2
- package/dest/services/peer-manager/peer_scoring.d.ts.map +1 -1
- package/dest/services/peer-manager/peer_scoring.js +40 -2
- package/dest/services/reqresp/config.d.ts +1 -1
- package/dest/services/reqresp/connection-sampler/batch_connection_sampler.d.ts +1 -1
- package/dest/services/reqresp/connection-sampler/batch_connection_sampler.d.ts.map +1 -1
- package/dest/services/reqresp/connection-sampler/connection_sampler.d.ts +1 -4
- package/dest/services/reqresp/connection-sampler/connection_sampler.d.ts.map +1 -1
- package/dest/services/reqresp/index.d.ts +1 -1
- package/dest/services/reqresp/interface.d.ts +2 -11
- package/dest/services/reqresp/interface.d.ts.map +1 -1
- package/dest/services/reqresp/interface.js +1 -18
- package/dest/services/reqresp/metrics.d.ts +1 -1
- package/dest/services/reqresp/metrics.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/auth.d.ts +2 -2
- package/dest/services/reqresp/protocols/auth.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/auth.js +2 -2
- package/dest/services/reqresp/protocols/block.d.ts +1 -1
- package/dest/services/reqresp/protocols/block.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/block.js +3 -2
- package/dest/services/reqresp/protocols/block_txs/bitvector.d.ts +1 -1
- package/dest/services/reqresp/protocols/block_txs/bitvector.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/block_txs/block_txs_handler.d.ts +1 -1
- package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.d.ts +4 -6
- 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 +1 -1
- package/dest/services/reqresp/protocols/block_txs/index.d.ts +1 -1
- package/dest/services/reqresp/protocols/goodbye.d.ts +1 -1
- package/dest/services/reqresp/protocols/goodbye.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/index.d.ts +1 -1
- package/dest/services/reqresp/protocols/ping.d.ts +1 -1
- package/dest/services/reqresp/protocols/status.d.ts +6 -5
- package/dest/services/reqresp/protocols/status.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/status.js +4 -3
- package/dest/services/reqresp/protocols/tx.d.ts +2 -3
- package/dest/services/reqresp/protocols/tx.d.ts.map +1 -1
- package/dest/services/reqresp/rate-limiter/index.d.ts +1 -1
- package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts +2 -2
- package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts.map +1 -1
- package/dest/services/reqresp/rate-limiter/rate_limits.d.ts +1 -1
- package/dest/services/reqresp/reqresp.d.ts +1 -41
- package/dest/services/reqresp/reqresp.d.ts.map +1 -1
- package/dest/services/reqresp/reqresp.js +416 -34
- package/dest/services/reqresp/status.d.ts +2 -2
- package/dest/services/reqresp/status.d.ts.map +1 -1
- package/dest/services/service.d.ts +2 -2
- package/dest/services/service.d.ts.map +1 -1
- package/dest/services/tx_collection/config.d.ts +1 -1
- package/dest/services/tx_collection/config.js +1 -1
- package/dest/services/tx_collection/fast_tx_collection.d.ts +4 -9
- package/dest/services/tx_collection/fast_tx_collection.d.ts.map +1 -1
- package/dest/services/tx_collection/fast_tx_collection.js +6 -1
- package/dest/services/tx_collection/index.d.ts +1 -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/slow_tx_collection.d.ts +6 -7
- package/dest/services/tx_collection/slow_tx_collection.d.ts.map +1 -1
- package/dest/services/tx_collection/slow_tx_collection.js +2 -1
- package/dest/services/tx_collection/tx_collection.d.ts +12 -11
- package/dest/services/tx_collection/tx_collection.d.ts.map +1 -1
- package/dest/services/tx_collection/tx_collection.js +3 -2
- package/dest/services/tx_collection/tx_collection_sink.d.ts +3 -3
- package/dest/services/tx_collection/tx_collection_sink.d.ts.map +1 -1
- package/dest/services/tx_collection/tx_collection_sink.js +34 -4
- 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 +2 -2
- package/dest/services/tx_provider.d.ts +6 -4
- package/dest/services/tx_provider.d.ts.map +1 -1
- package/dest/services/tx_provider.js +19 -6
- package/dest/services/tx_provider_instrumentation.d.ts +5 -2
- package/dest/services/tx_provider_instrumentation.d.ts.map +1 -1
- package/dest/services/tx_provider_instrumentation.js +14 -1
- package/dest/test-helpers/generate-peer-id-private-keys.d.ts +1 -1
- package/dest/test-helpers/get-ports.d.ts +1 -1
- package/dest/test-helpers/get-ports.d.ts.map +1 -1
- package/dest/test-helpers/index.d.ts +1 -1
- package/dest/test-helpers/make-enrs.d.ts +1 -1
- package/dest/test-helpers/make-enrs.js +1 -1
- package/dest/test-helpers/make-test-p2p-clients.d.ts +2 -2
- package/dest/test-helpers/make-test-p2p-clients.d.ts.map +1 -1
- package/dest/test-helpers/mock-pubsub.d.ts +4 -4
- package/dest/test-helpers/mock-pubsub.d.ts.map +1 -1
- package/dest/test-helpers/mock-tx-helpers.d.ts +12 -0
- package/dest/test-helpers/mock-tx-helpers.d.ts.map +1 -0
- package/dest/test-helpers/mock-tx-helpers.js +19 -0
- package/dest/test-helpers/reqresp-nodes.d.ts +3 -3
- package/dest/test-helpers/reqresp-nodes.d.ts.map +1 -1
- package/dest/test-helpers/reqresp-nodes.js +4 -3
- package/dest/testbench/p2p_client_testbench_worker.d.ts +1 -1
- package/dest/testbench/p2p_client_testbench_worker.js +17 -9
- package/dest/testbench/parse_log_file.d.ts +1 -1
- package/dest/testbench/testbench.d.ts +1 -1
- package/dest/testbench/testbench.js +2 -2
- package/dest/testbench/worker_client_manager.d.ts +1 -1
- package/dest/testbench/worker_client_manager.d.ts.map +1 -1
- package/dest/types/index.d.ts +1 -1
- package/dest/util.d.ts +2 -1
- package/dest/util.d.ts.map +1 -1
- package/dest/util.js +11 -2
- package/dest/versioning.d.ts +2 -2
- package/dest/versioning.d.ts.map +1 -1
- package/dest/versioning.js +2 -2
- package/package.json +21 -21
- package/src/bootstrap/bootstrap.ts +15 -4
- package/src/client/factory.ts +21 -12
- package/src/client/interface.ts +8 -5
- package/src/client/p2p_client.ts +97 -88
- package/src/config.ts +42 -21
- package/src/enr/generate-enr.ts +1 -1
- package/src/errors/attestation-pool.error.ts +13 -0
- package/src/mem_pools/attestation_pool/attestation_pool.ts +46 -5
- package/src/mem_pools/attestation_pool/attestation_pool_test_suite.ts +89 -48
- package/src/mem_pools/attestation_pool/kv_attestation_pool.ts +107 -24
- package/src/mem_pools/attestation_pool/memory_attestation_pool.ts +98 -19
- package/src/mem_pools/attestation_pool/mocks.ts +11 -8
- package/src/mem_pools/instrumentation.ts +46 -0
- package/src/mem_pools/interface.ts +2 -4
- package/src/mem_pools/tx_pool/README.md +255 -0
- package/src/mem_pools/tx_pool/aztec_kv_tx_pool.ts +368 -360
- package/src/mem_pools/tx_pool/eviction/eviction_manager.ts +71 -0
- package/src/mem_pools/tx_pool/eviction/eviction_strategy.ts +93 -0
- package/src/mem_pools/tx_pool/eviction/insufficient_fee_payer_balance_rule.ts +108 -0
- package/src/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.ts +104 -0
- package/src/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.ts +91 -0
- package/src/mem_pools/tx_pool/eviction/low_priority_eviction_rule.ts +106 -0
- package/src/mem_pools/tx_pool/index.ts +0 -1
- package/src/mem_pools/tx_pool/priority.ts +8 -1
- package/src/mem_pools/tx_pool/tx_pool.ts +28 -8
- package/src/mem_pools/tx_pool/tx_pool_test_suite.ts +131 -18
- package/src/msg_validators/attestation_validator/attestation_validator.ts +41 -6
- package/src/msg_validators/attestation_validator/fisherman_attestation_validator.ts +91 -0
- package/src/msg_validators/attestation_validator/index.ts +1 -0
- package/src/msg_validators/block_proposal_validator/block_proposal_validator.ts +53 -12
- package/src/msg_validators/tx_validator/archive_cache.ts +1 -1
- package/src/msg_validators/tx_validator/block_header_validator.ts +2 -2
- package/src/msg_validators/tx_validator/double_spend_validator.ts +1 -1
- package/src/msg_validators/tx_validator/factory.ts +13 -6
- package/src/msg_validators/tx_validator/index.ts +1 -0
- package/src/msg_validators/tx_validator/metadata_validator.ts +8 -42
- package/src/msg_validators/tx_validator/phases_validator.ts +3 -1
- package/src/msg_validators/tx_validator/test_utils.ts +1 -1
- package/src/msg_validators/tx_validator/timestamp_validator.ts +47 -0
- package/src/services/discv5/discV5_service.ts +2 -2
- package/src/services/dummy_service.ts +1 -1
- package/src/services/encoding.ts +81 -6
- package/src/services/libp2p/instrumentation.ts +10 -1
- package/src/services/libp2p/libp2p_service.ts +430 -165
- package/src/services/peer-manager/metrics.ts +32 -0
- package/src/services/peer-manager/peer_manager.ts +24 -14
- package/src/services/peer-manager/peer_scoring.ts +46 -3
- package/src/services/reqresp/interface.ts +1 -22
- package/src/services/reqresp/protocols/auth.ts +2 -2
- package/src/services/reqresp/protocols/block.ts +3 -2
- package/src/services/reqresp/protocols/block_txs/block_txs_reqresp.ts +1 -1
- package/src/services/reqresp/protocols/status.ts +9 -8
- package/src/services/reqresp/protocols/tx.ts +1 -2
- package/src/services/reqresp/reqresp.ts +15 -11
- package/src/services/service.ts +1 -1
- package/src/services/tx_collection/config.ts +1 -1
- package/src/services/tx_collection/fast_tx_collection.ts +8 -5
- package/src/services/tx_collection/slow_tx_collection.ts +7 -6
- package/src/services/tx_collection/tx_collection.ts +12 -10
- package/src/services/tx_collection/tx_collection_sink.ts +34 -3
- package/src/services/tx_collection/tx_source.ts +2 -2
- package/src/services/tx_provider.ts +26 -9
- package/src/services/tx_provider_instrumentation.ts +19 -2
- package/src/test-helpers/make-enrs.ts +1 -1
- package/src/test-helpers/mock-pubsub.ts +1 -1
- package/src/test-helpers/mock-tx-helpers.ts +24 -0
- package/src/test-helpers/reqresp-nodes.ts +4 -3
- package/src/testbench/p2p_client_testbench_worker.ts +14 -6
- package/src/testbench/testbench.ts +2 -2
- package/src/util.ts +12 -2
- package/src/versioning.ts +3 -3
- package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts +0 -68
- package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/memory_tx_pool.js +0 -160
- package/src/mem_pools/tx_pool/memory_tx_pool.ts +0 -199
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import type { EpochCacheInterface } from '@aztec/epoch-cache';
|
|
2
|
-
import {
|
|
2
|
+
import { BlockNumber, SlotNumber } from '@aztec/foundation/branded-types';
|
|
3
|
+
import { randomInt } from '@aztec/foundation/crypto/random';
|
|
4
|
+
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
3
5
|
import { type Logger, createLibp2pComponentLogger, createLogger } from '@aztec/foundation/log';
|
|
4
|
-
import { SerialQueue } from '@aztec/foundation/queue';
|
|
5
6
|
import { RunningPromise } from '@aztec/foundation/running-promise';
|
|
6
7
|
import { Timer } from '@aztec/foundation/timer';
|
|
7
8
|
import type { AztecAsyncKVStore } from '@aztec/kv-store';
|
|
8
|
-
import {
|
|
9
|
-
import
|
|
9
|
+
import { getVKTreeRoot } from '@aztec/noir-protocol-circuits-types/vk-tree';
|
|
10
|
+
import { protocolContractsHash } from '@aztec/protocol-contracts';
|
|
11
|
+
import type { EthAddress, L2Block, L2BlockSource } from '@aztec/stdlib/block';
|
|
10
12
|
import type { ContractDataSource } from '@aztec/stdlib/contract';
|
|
11
13
|
import { GasFees } from '@aztec/stdlib/gas';
|
|
12
14
|
import type { ClientProtocolCircuitVerifier, PeerInfo, WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
|
|
@@ -23,12 +25,11 @@ import {
|
|
|
23
25
|
metricsTopicStrToLabels,
|
|
24
26
|
} from '@aztec/stdlib/p2p';
|
|
25
27
|
import { MerkleTreeId } from '@aztec/stdlib/trees';
|
|
26
|
-
import { Tx, type TxHash, type TxValidationResult } from '@aztec/stdlib/tx';
|
|
28
|
+
import { Tx, type TxHash, type TxValidationResult, type TxValidator } from '@aztec/stdlib/tx';
|
|
27
29
|
import type { UInt64 } from '@aztec/stdlib/types';
|
|
28
30
|
import { compressComponentVersions } from '@aztec/stdlib/versioning';
|
|
29
31
|
import { Attributes, OtelMetricsAdapter, type TelemetryClient, WithTracer, trackSpan } from '@aztec/telemetry-client';
|
|
30
32
|
|
|
31
|
-
import { ENR } from '@chainsafe/enr';
|
|
32
33
|
import {
|
|
33
34
|
type GossipSub,
|
|
34
35
|
type GossipSubComponents,
|
|
@@ -43,18 +44,29 @@ import { bootstrap } from '@libp2p/bootstrap';
|
|
|
43
44
|
import { identify } from '@libp2p/identify';
|
|
44
45
|
import { type Message, type MultiaddrConnection, type PeerId, TopicValidatorResult } from '@libp2p/interface';
|
|
45
46
|
import type { ConnectionManager } from '@libp2p/interface-internal';
|
|
46
|
-
import '@libp2p/kad-dht';
|
|
47
47
|
import { mplex } from '@libp2p/mplex';
|
|
48
48
|
import { tcp } from '@libp2p/tcp';
|
|
49
|
+
import { ENR } from '@nethermindeth/enr';
|
|
49
50
|
import { createLibp2p } from 'libp2p';
|
|
50
51
|
|
|
51
52
|
import type { P2PConfig } from '../../config.js';
|
|
53
|
+
import { ProposalSlotCapExceededError } from '../../errors/attestation-pool.error.js';
|
|
52
54
|
import type { MemPools } from '../../mem_pools/interface.js';
|
|
53
|
-
import {
|
|
55
|
+
import {
|
|
56
|
+
AttestationValidator,
|
|
57
|
+
BlockProposalValidator,
|
|
58
|
+
FishermanAttestationValidator,
|
|
59
|
+
} from '../../msg_validators/index.js';
|
|
54
60
|
import { MessageSeenValidator } from '../../msg_validators/msg_seen_validator/msg_seen_validator.js';
|
|
55
61
|
import { getDefaultAllowedSetupFunctions } from '../../msg_validators/tx_validator/allowed_public_setup.js';
|
|
56
62
|
import { type MessageValidator, createTxMessageValidators } from '../../msg_validators/tx_validator/factory.js';
|
|
57
|
-
import {
|
|
63
|
+
import {
|
|
64
|
+
AggregateTxValidator,
|
|
65
|
+
DataTxValidator,
|
|
66
|
+
DoubleSpendTxValidator,
|
|
67
|
+
MetadataTxValidator,
|
|
68
|
+
TxProofValidator,
|
|
69
|
+
} from '../../msg_validators/tx_validator/index.js';
|
|
58
70
|
import { GossipSubEvent } from '../../types/index.js';
|
|
59
71
|
import { type PubSubLibp2p, convertToMultiaddr } from '../../util.js';
|
|
60
72
|
import { getVersions } from '../../versioning.js';
|
|
@@ -80,6 +92,8 @@ import { reqRespBlockTxsHandler } from '../reqresp/protocols/block_txs/block_txs
|
|
|
80
92
|
import { reqGoodbyeHandler } from '../reqresp/protocols/goodbye.js';
|
|
81
93
|
import {
|
|
82
94
|
AuthRequest,
|
|
95
|
+
BlockTxsRequest,
|
|
96
|
+
BlockTxsResponse,
|
|
83
97
|
StatusMessage,
|
|
84
98
|
pingHandler,
|
|
85
99
|
reqRespBlockHandler,
|
|
@@ -98,11 +112,15 @@ interface ValidationResult {
|
|
|
98
112
|
|
|
99
113
|
type ValidationOutcome = { allPassed: true } | { allPassed: false; failure: ValidationResult };
|
|
100
114
|
|
|
115
|
+
// REFACTOR: Unify with the type above
|
|
116
|
+
type ReceivedMessageValidationResult<T> =
|
|
117
|
+
| { obj: T; result: Exclude<TopicValidatorResult, TopicValidatorResult.Reject> }
|
|
118
|
+
| { obj?: undefined; result: TopicValidatorResult.Reject };
|
|
119
|
+
|
|
101
120
|
/**
|
|
102
121
|
* Lib P2P implementation of the P2PService interface.
|
|
103
122
|
*/
|
|
104
123
|
export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends WithTracer implements P2PService {
|
|
105
|
-
private jobQueue: SerialQueue = new SerialQueue();
|
|
106
124
|
private discoveryRunningPromise?: RunningPromise;
|
|
107
125
|
private msgIdSeenValidators: Record<TopicType, MessageSeenValidator> = {} as Record<TopicType, MessageSeenValidator>;
|
|
108
126
|
|
|
@@ -113,7 +131,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
113
131
|
private protocolVersion = '';
|
|
114
132
|
private topicStrings: Record<TopicType, string> = {} as Record<TopicType, string>;
|
|
115
133
|
|
|
116
|
-
private feesCache: { blockNumber:
|
|
134
|
+
private feesCache: { blockNumber: BlockNumber; gasFees: GasFees } | undefined;
|
|
117
135
|
|
|
118
136
|
/**
|
|
119
137
|
* Callback for when a block is received from a peer.
|
|
@@ -126,6 +144,8 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
126
144
|
|
|
127
145
|
private instrumentation: P2PInstrumentation;
|
|
128
146
|
|
|
147
|
+
protected logger: Logger;
|
|
148
|
+
|
|
129
149
|
constructor(
|
|
130
150
|
private clientType: T,
|
|
131
151
|
private config: P2PConfig,
|
|
@@ -133,16 +153,19 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
133
153
|
private peerDiscoveryService: PeerDiscoveryService,
|
|
134
154
|
private reqresp: ReqRespInterface,
|
|
135
155
|
private peerManager: PeerManagerInterface,
|
|
136
|
-
protected mempools: MemPools
|
|
156
|
+
protected mempools: MemPools,
|
|
137
157
|
private archiver: L2BlockSource & ContractDataSource,
|
|
138
158
|
private epochCache: EpochCacheInterface,
|
|
139
159
|
private proofVerifier: ClientProtocolCircuitVerifier,
|
|
140
160
|
private worldStateSynchronizer: WorldStateSynchronizer,
|
|
141
161
|
telemetry: TelemetryClient,
|
|
142
|
-
|
|
162
|
+
logger: Logger = createLogger('p2p:libp2p_service'),
|
|
143
163
|
) {
|
|
144
164
|
super(telemetry, 'LibP2PService');
|
|
145
165
|
|
|
166
|
+
// Create child logger with fisherman prefix if in fisherman mode
|
|
167
|
+
this.logger = config.fishermanMode ? logger.createChild('[FISHERMAN]') : logger;
|
|
168
|
+
|
|
146
169
|
this.instrumentation = new P2PInstrumentation(telemetry, 'LibP2PService');
|
|
147
170
|
|
|
148
171
|
this.msgIdSeenValidators[TopicType.tx] = new MessageSeenValidator(config.seenMessageCacheSize);
|
|
@@ -160,15 +183,18 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
160
183
|
this.protocolVersion,
|
|
161
184
|
);
|
|
162
185
|
|
|
163
|
-
|
|
164
|
-
this.
|
|
186
|
+
// Use FishermanAttestationValidator in fisherman mode to validate attestation payloads against proposals
|
|
187
|
+
this.attestationValidator = config.fishermanMode
|
|
188
|
+
? new FishermanAttestationValidator(epochCache, mempools.attestationPool, telemetry)
|
|
189
|
+
: new AttestationValidator(epochCache);
|
|
190
|
+
this.blockProposalValidator = new BlockProposalValidator(epochCache, { txsPermitted: !config.disableTransactions });
|
|
165
191
|
|
|
166
192
|
this.gossipSubEventHandler = this.handleGossipSubEvent.bind(this);
|
|
167
193
|
|
|
168
194
|
this.blockReceivedCallback = async (block: BlockProposal): Promise<BlockAttestation[] | undefined> => {
|
|
169
195
|
this.logger.debug(
|
|
170
|
-
`Handler not yet registered: Block received callback not set. Received block for slot ${block.slotNumber
|
|
171
|
-
{ p2pMessageIdentifier: await block.
|
|
196
|
+
`Handler not yet registered: Block received callback not set. Received block for slot ${block.slotNumber} from peer.`,
|
|
197
|
+
{ p2pMessageIdentifier: await block.p2pMessageLoggingIdentifier() },
|
|
172
198
|
);
|
|
173
199
|
return undefined;
|
|
174
200
|
};
|
|
@@ -189,7 +215,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
189
215
|
config: P2PConfig,
|
|
190
216
|
peerId: PeerId,
|
|
191
217
|
deps: {
|
|
192
|
-
mempools: MemPools
|
|
218
|
+
mempools: MemPools;
|
|
193
219
|
l2BlockSource: L2BlockSource & ContractDataSource;
|
|
194
220
|
epochCache: EpochCacheInterface;
|
|
195
221
|
proofVerifier: ClientProtocolCircuitVerifier;
|
|
@@ -273,7 +299,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
273
299
|
// The connection attempts to the node on TCP layer are not necessarily valid Aztec peers so we want to have a bit of leeway here
|
|
274
300
|
// If we hit the limit, the connection will be temporarily accepted and immediately dropped.
|
|
275
301
|
// Docs: https://nodejs.org/api/net.html#servermaxconnections
|
|
276
|
-
maxConnections:
|
|
302
|
+
maxConnections: maxPeerCount * 2,
|
|
277
303
|
// socket option: the maximum length of the queue of pending connections
|
|
278
304
|
// https://nodejs.org/dist/latest-v22.x/docs/api/net.html#serverlisten
|
|
279
305
|
// it's not safe if we increase this number
|
|
@@ -284,7 +310,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
284
310
|
// In case closeAbove is reached, the server stops listening altogether
|
|
285
311
|
// It's important that there is enough difference between closeAbove and listenAbove,
|
|
286
312
|
// otherwise the server.listener will flap between being closed and open potentially degrading perf even more
|
|
287
|
-
closeAbove: maxPeerCount *
|
|
313
|
+
closeAbove: maxPeerCount * 3,
|
|
288
314
|
listenBelow: Math.floor(maxPeerCount * 0.9),
|
|
289
315
|
},
|
|
290
316
|
}),
|
|
@@ -294,8 +320,10 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
294
320
|
streamMuxers: [yamux(), mplex()],
|
|
295
321
|
connectionEncryption: [noise()],
|
|
296
322
|
connectionManager: {
|
|
297
|
-
minConnections: 0,
|
|
298
|
-
maxConnections
|
|
323
|
+
minConnections: 0, // Disable libp2p peer dialing, we do it manually
|
|
324
|
+
// We set maxConnections above maxPeerCount because if we hit limit of maxPeerCount
|
|
325
|
+
// libp2p will start aggressively rejecting all new connections, preventing network discovery and crawling.
|
|
326
|
+
maxConnections: maxPeerCount * 2,
|
|
299
327
|
maxParallelDials: 100,
|
|
300
328
|
dialTimeout: 30_000,
|
|
301
329
|
maxPeerAddrsToDial: 5,
|
|
@@ -379,7 +407,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
379
407
|
logger: createLibp2pComponentLogger(logger.module),
|
|
380
408
|
});
|
|
381
409
|
|
|
382
|
-
const peerScoring = new PeerScoring(config);
|
|
410
|
+
const peerScoring = new PeerScoring(config, telemetry);
|
|
383
411
|
const reqresp = new ReqResp(config, node, peerScoring, createLogger(`${logger.module}:reqresp`));
|
|
384
412
|
|
|
385
413
|
const peerManager = new PeerManager(
|
|
@@ -434,9 +462,6 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
434
462
|
}
|
|
435
463
|
const announceTcpMultiaddr = convertToMultiaddr(p2pIp, p2pPort, 'tcp');
|
|
436
464
|
|
|
437
|
-
// Start job queue, peer discovery service and libp2p node
|
|
438
|
-
this.jobQueue.start();
|
|
439
|
-
|
|
440
465
|
await this.peerManager.initializePeers();
|
|
441
466
|
if (!this.config.p2pDiscoveryDisabled) {
|
|
442
467
|
await this.peerDiscoveryService.start();
|
|
@@ -453,10 +478,6 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
453
478
|
const goodbyeHandler = reqGoodbyeHandler(this.peerManager);
|
|
454
479
|
const blockHandler = reqRespBlockHandler(this.archiver);
|
|
455
480
|
const statusHandler = reqRespStatusHandler(this.protocolVersion, this.worldStateSynchronizer, this.logger);
|
|
456
|
-
// In case P2P client doesnt'have attestation pool,
|
|
457
|
-
// const blockTxsHandler = this.mempools.attestationPool
|
|
458
|
-
// ? reqRespBlockTxsHandler(this.mempools.attestationPool, this.mempools.txPool)
|
|
459
|
-
// : def;
|
|
460
481
|
|
|
461
482
|
const requestResponseHandlers: Partial<ReqRespSubProtocolHandlers> = {
|
|
462
483
|
[ReqRespSubProtocol.PING]: pingHandler,
|
|
@@ -465,8 +486,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
465
486
|
[ReqRespSubProtocol.BLOCK]: blockHandler.bind(this),
|
|
466
487
|
};
|
|
467
488
|
|
|
468
|
-
|
|
469
|
-
if (this.mempools.attestationPool) {
|
|
489
|
+
if (!this.config.disableTransactions) {
|
|
470
490
|
const blockTxsHandler = reqRespBlockTxsHandler(this.mempools.attestationPool, this.mempools.txPool);
|
|
471
491
|
requestResponseHandlers[ReqRespSubProtocol.BLOCK_TXS] = blockTxsHandler.bind(this);
|
|
472
492
|
}
|
|
@@ -478,9 +498,11 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
478
498
|
// add GossipSub listener
|
|
479
499
|
this.node.services.pubsub.addEventListener(GossipSubEvent.MESSAGE, this.gossipSubEventHandler);
|
|
480
500
|
|
|
481
|
-
// Start running promise for peer discovery
|
|
501
|
+
// Start running promise for peer discovery and metrics collection
|
|
482
502
|
this.discoveryRunningPromise = new RunningPromise(
|
|
483
|
-
() =>
|
|
503
|
+
async () => {
|
|
504
|
+
await this.peerManager.heartbeat();
|
|
505
|
+
},
|
|
484
506
|
this.logger,
|
|
485
507
|
this.config.peerCheckIntervalMS,
|
|
486
508
|
);
|
|
@@ -489,8 +511,9 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
489
511
|
// Define the sub protocol validators - This is done within this start() method to gain a callback to the existing validateTx function
|
|
490
512
|
const reqrespSubProtocolValidators = {
|
|
491
513
|
...DEFAULT_SUB_PROTOCOL_VALIDATORS,
|
|
492
|
-
|
|
493
|
-
[ReqRespSubProtocol.
|
|
514
|
+
[ReqRespSubProtocol.TX]: this.validateRequestedTxs.bind(this),
|
|
515
|
+
[ReqRespSubProtocol.BLOCK_TXS]: this.validateRequestedBlockTxs.bind(this),
|
|
516
|
+
[ReqRespSubProtocol.BLOCK]: this.validateRequestedBlock.bind(this),
|
|
494
517
|
};
|
|
495
518
|
await this.reqresp.start(requestResponseHandlers, reqrespSubProtocolValidators);
|
|
496
519
|
this.logger.info(`Started P2P service`, {
|
|
@@ -512,9 +535,6 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
512
535
|
// Stop peer manager
|
|
513
536
|
this.logger.debug('Stopping peer manager...');
|
|
514
537
|
await this.peerManager.stop();
|
|
515
|
-
|
|
516
|
-
this.logger.debug('Stopping job queue...');
|
|
517
|
-
await this.jobQueue.end();
|
|
518
538
|
this.logger.debug('Stopping running promise...');
|
|
519
539
|
await this.discoveryRunningPromise?.stop();
|
|
520
540
|
this.logger.debug('Stopping peer discovery service...');
|
|
@@ -602,16 +622,16 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
602
622
|
if (!this.node.services.pubsub) {
|
|
603
623
|
throw new Error('Pubsub service not available.');
|
|
604
624
|
}
|
|
605
|
-
const p2pMessage =
|
|
606
|
-
this.logger.debug(`Publishing message`, {
|
|
607
|
-
topic,
|
|
608
|
-
messageId: p2pMessage.id,
|
|
609
|
-
});
|
|
625
|
+
const p2pMessage = P2PMessage.fromGossipable(message, this.config.debugP2PInstrumentMessages);
|
|
610
626
|
const result = await this.node.services.pubsub.publish(topic, p2pMessage.toMessageData());
|
|
611
|
-
|
|
612
627
|
return result.recipients.length;
|
|
613
628
|
}
|
|
614
629
|
|
|
630
|
+
/**
|
|
631
|
+
* Checks if this message has already been seen, based on its msgId computed from hashing the message data.
|
|
632
|
+
* Note that we do not rely on the seenCache from gossipsub since we want to keep a longer history of seen
|
|
633
|
+
* messages to avoid tx echoes across the network.
|
|
634
|
+
*/
|
|
615
635
|
protected preValidateReceivedMessage(
|
|
616
636
|
msg: Message,
|
|
617
637
|
msgId: string,
|
|
@@ -647,82 +667,122 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
647
667
|
return { result: true, topicType };
|
|
648
668
|
}
|
|
649
669
|
|
|
670
|
+
/**
|
|
671
|
+
* Safely deserializes a P2PMessage from raw message data.
|
|
672
|
+
* @param msgId - The message ID.
|
|
673
|
+
* @param source - The peer ID of the message source.
|
|
674
|
+
* @param data - The raw message data.
|
|
675
|
+
* @returns The deserialized P2PMessage or undefined if deserialization fails.
|
|
676
|
+
*/
|
|
677
|
+
private safelyDeserializeP2PMessage(msgId: string, source: PeerId, data: Uint8Array): P2PMessage | undefined {
|
|
678
|
+
try {
|
|
679
|
+
return P2PMessage.fromMessageData(Buffer.from(data), this.config.debugP2PInstrumentMessages);
|
|
680
|
+
} catch (err) {
|
|
681
|
+
this.logger.error(`Error deserializing P2PMessage`, err, {
|
|
682
|
+
msgId,
|
|
683
|
+
source: source.toString(),
|
|
684
|
+
});
|
|
685
|
+
this.node.services.pubsub.reportMessageValidationResult(msgId, source.toString(), TopicValidatorResult.Reject);
|
|
686
|
+
this.peerManager.penalizePeer(source, PeerErrorSeverity.LowToleranceError);
|
|
687
|
+
return undefined;
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
|
|
650
691
|
/**
|
|
651
692
|
* Handles a new gossip message that was received by the client.
|
|
652
693
|
* @param topic - The message's topic.
|
|
653
694
|
* @param data - The message data
|
|
654
695
|
*/
|
|
655
696
|
protected async handleNewGossipMessage(msg: Message, msgId: string, source: PeerId) {
|
|
656
|
-
const
|
|
657
|
-
|
|
658
|
-
const
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
messageLatency,
|
|
663
|
-
});
|
|
697
|
+
const msgReceivedTime = Date.now();
|
|
698
|
+
let topicType: TopicType | undefined;
|
|
699
|
+
const p2pMessage = this.safelyDeserializeP2PMessage(msgId, source, msg.data);
|
|
700
|
+
if (!p2pMessage) {
|
|
701
|
+
return;
|
|
702
|
+
}
|
|
664
703
|
|
|
665
704
|
const preValidationResult = this.preValidateReceivedMessage(msg, msgId, source);
|
|
666
705
|
|
|
667
706
|
if (!preValidationResult.result) {
|
|
668
707
|
return;
|
|
669
|
-
} else if (preValidationResult.topicType !== undefined) {
|
|
670
|
-
// guard against clock skew & DST
|
|
671
|
-
if (messageLatency > 0) {
|
|
672
|
-
this.instrumentation.recordMessageLatency(preValidationResult.topicType, messageLatency);
|
|
673
|
-
}
|
|
674
708
|
}
|
|
675
709
|
|
|
676
710
|
if (msg.topic === this.topicStrings[TopicType.tx]) {
|
|
711
|
+
topicType = TopicType.tx;
|
|
677
712
|
await this.handleGossipedTx(p2pMessage.payload, msgId, source);
|
|
678
713
|
}
|
|
679
|
-
if (msg.topic === this.topicStrings[TopicType.block_attestation]
|
|
680
|
-
|
|
714
|
+
if (msg.topic === this.topicStrings[TopicType.block_attestation]) {
|
|
715
|
+
topicType = TopicType.block_attestation;
|
|
716
|
+
if (this.clientType === P2PClientType.Full) {
|
|
717
|
+
await this.processAttestationFromPeer(p2pMessage.payload, msgId, source);
|
|
718
|
+
}
|
|
681
719
|
}
|
|
682
720
|
if (msg.topic === this.topicStrings[TopicType.block_proposal]) {
|
|
721
|
+
topicType = TopicType.block_proposal;
|
|
683
722
|
await this.processBlockFromPeer(p2pMessage.payload, msgId, source);
|
|
684
723
|
}
|
|
685
724
|
|
|
725
|
+
if (p2pMessage.timestamp !== undefined && topicType !== undefined) {
|
|
726
|
+
const latency = msgReceivedTime - p2pMessage.timestamp.getTime();
|
|
727
|
+
this.instrumentation.recordMessageLatency(topicType, latency);
|
|
728
|
+
}
|
|
729
|
+
|
|
686
730
|
return;
|
|
687
731
|
}
|
|
688
732
|
|
|
689
733
|
protected async validateReceivedMessage<T>(
|
|
690
|
-
validationFunc: () => Promise<
|
|
734
|
+
validationFunc: () => Promise<ReceivedMessageValidationResult<T>>,
|
|
691
735
|
msgId: string,
|
|
692
736
|
source: PeerId,
|
|
693
737
|
topicType: TopicType,
|
|
694
|
-
): Promise<
|
|
695
|
-
let resultAndObj:
|
|
738
|
+
): Promise<ReceivedMessageValidationResult<T>> {
|
|
739
|
+
let resultAndObj: ReceivedMessageValidationResult<T> = { result: TopicValidatorResult.Reject };
|
|
696
740
|
const timer = new Timer();
|
|
697
741
|
try {
|
|
698
742
|
resultAndObj = await validationFunc();
|
|
699
743
|
} catch (err) {
|
|
700
|
-
this.
|
|
744
|
+
this.peerManager.penalizePeer(source, PeerErrorSeverity.LowToleranceError);
|
|
745
|
+
this.logger.error(`Error deserializing and validating gossipsub message`, err, {
|
|
746
|
+
msgId,
|
|
747
|
+
source: source.toString(),
|
|
748
|
+
topicType,
|
|
749
|
+
});
|
|
701
750
|
}
|
|
702
751
|
|
|
703
|
-
if (resultAndObj.result) {
|
|
752
|
+
if (resultAndObj.result === TopicValidatorResult.Accept) {
|
|
704
753
|
this.instrumentation.recordMessageValidation(topicType, timer);
|
|
705
754
|
}
|
|
706
755
|
|
|
707
|
-
this.node.services.pubsub.reportMessageValidationResult(
|
|
708
|
-
msgId,
|
|
709
|
-
source.toString(),
|
|
710
|
-
resultAndObj.result && resultAndObj.obj ? TopicValidatorResult.Accept : TopicValidatorResult.Reject,
|
|
711
|
-
);
|
|
756
|
+
this.node.services.pubsub.reportMessageValidationResult(msgId, source.toString(), resultAndObj.result);
|
|
712
757
|
return resultAndObj;
|
|
713
758
|
}
|
|
714
759
|
|
|
715
760
|
protected async handleGossipedTx(payloadData: Buffer, msgId: string, source: PeerId) {
|
|
716
|
-
const validationFunc = async () => {
|
|
761
|
+
const validationFunc: () => Promise<ReceivedMessageValidationResult<Tx>> = async () => {
|
|
717
762
|
const tx = Tx.fromBuffer(payloadData);
|
|
718
|
-
const
|
|
719
|
-
|
|
763
|
+
const isValid = await this.validatePropagatedTx(tx, source);
|
|
764
|
+
const exists = isValid && (await this.mempools.txPool.hasTx(tx.getTxHash()));
|
|
765
|
+
|
|
766
|
+
this.logger.trace(`Validate propagated tx`, {
|
|
767
|
+
isValid,
|
|
768
|
+
exists,
|
|
769
|
+
[Attributes.P2P_ID]: source.toString(),
|
|
770
|
+
});
|
|
771
|
+
|
|
772
|
+
if (!isValid) {
|
|
773
|
+
return { result: TopicValidatorResult.Reject };
|
|
774
|
+
} else if (exists) {
|
|
775
|
+
return { result: TopicValidatorResult.Ignore, obj: tx };
|
|
776
|
+
} else {
|
|
777
|
+
return { result: TopicValidatorResult.Accept, obj: tx };
|
|
778
|
+
}
|
|
720
779
|
};
|
|
721
780
|
|
|
722
781
|
const { result, obj: tx } = await this.validateReceivedMessage<Tx>(validationFunc, msgId, source, TopicType.tx);
|
|
723
|
-
if (
|
|
782
|
+
if (result !== TopicValidatorResult.Accept || !tx) {
|
|
724
783
|
return;
|
|
725
784
|
}
|
|
785
|
+
|
|
726
786
|
const txHash = tx.getTxHash();
|
|
727
787
|
const txHashString = txHash.toString();
|
|
728
788
|
this.logger.verbose(`Received tx ${txHashString} from external peer ${source.toString()} via gossip`, {
|
|
@@ -731,10 +791,11 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
731
791
|
});
|
|
732
792
|
|
|
733
793
|
if (this.config.dropTransactions && randomInt(1000) < this.config.dropTransactionsProbability * 1000) {
|
|
734
|
-
this.logger.
|
|
794
|
+
this.logger.warn(`Intentionally dropping tx ${txHashString} (probability rule)`);
|
|
735
795
|
return;
|
|
736
796
|
}
|
|
737
797
|
|
|
798
|
+
this.instrumentation.incrementTxReceived(1);
|
|
738
799
|
await this.mempools.txPool.addTxs([tx]);
|
|
739
800
|
}
|
|
740
801
|
|
|
@@ -745,14 +806,42 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
745
806
|
* @param attestation - The attestation to process.
|
|
746
807
|
*/
|
|
747
808
|
private async processAttestationFromPeer(payloadData: Buffer, msgId: string, source: PeerId): Promise<void> {
|
|
748
|
-
const validationFunc = async () => {
|
|
809
|
+
const validationFunc: () => Promise<ReceivedMessageValidationResult<BlockAttestation>> = async () => {
|
|
749
810
|
const attestation = BlockAttestation.fromBuffer(payloadData);
|
|
750
|
-
const
|
|
751
|
-
this.
|
|
811
|
+
const pool = this.mempools.attestationPool;
|
|
812
|
+
const isValid = await this.validateAttestation(source, attestation);
|
|
813
|
+
const exists = isValid && (await pool.hasAttestation(attestation));
|
|
814
|
+
|
|
815
|
+
let canAdd = true;
|
|
816
|
+
if (isValid && !exists) {
|
|
817
|
+
const slot = attestation.payload.header.slotNumber;
|
|
818
|
+
const { committee } = await this.epochCache.getCommittee(slot);
|
|
819
|
+
const committeeSize = committee?.length ?? 0;
|
|
820
|
+
canAdd = await pool.canAddAttestation(attestation, committeeSize);
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
this.logger.trace(`Validate propagated block attestation`, {
|
|
824
|
+
isValid,
|
|
825
|
+
exists,
|
|
826
|
+
canAdd,
|
|
752
827
|
[Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber.toString(),
|
|
753
828
|
[Attributes.P2P_ID]: source.toString(),
|
|
754
829
|
});
|
|
755
|
-
|
|
830
|
+
|
|
831
|
+
if (!isValid) {
|
|
832
|
+
return { result: TopicValidatorResult.Reject };
|
|
833
|
+
} else if (exists) {
|
|
834
|
+
return { result: TopicValidatorResult.Ignore, obj: attestation };
|
|
835
|
+
} else if (!canAdd) {
|
|
836
|
+
this.logger.warn(`Dropping block attestation due to per-(slot, proposalId) attestation cap`, {
|
|
837
|
+
slot: attestation.payload.header.slotNumber.toString(),
|
|
838
|
+
archive: attestation.archive.toString(),
|
|
839
|
+
source: source.toString(),
|
|
840
|
+
});
|
|
841
|
+
return { result: TopicValidatorResult.Ignore, obj: attestation };
|
|
842
|
+
} else {
|
|
843
|
+
return { result: TopicValidatorResult.Accept, obj: attestation };
|
|
844
|
+
}
|
|
756
845
|
};
|
|
757
846
|
|
|
758
847
|
const { result, obj: attestation } = await this.validateReceivedMessage<BlockAttestation>(
|
|
@@ -761,31 +850,56 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
761
850
|
source,
|
|
762
851
|
TopicType.block_attestation,
|
|
763
852
|
);
|
|
764
|
-
|
|
853
|
+
|
|
854
|
+
if (result !== TopicValidatorResult.Accept || !attestation) {
|
|
765
855
|
return;
|
|
766
856
|
}
|
|
857
|
+
|
|
767
858
|
this.logger.debug(
|
|
768
|
-
`Received attestation for
|
|
859
|
+
`Received attestation for slot ${attestation.slotNumber} from external peer ${source.toString()}`,
|
|
769
860
|
{
|
|
770
|
-
p2pMessageIdentifier: await attestation.
|
|
771
|
-
slot: attestation.slotNumber
|
|
861
|
+
p2pMessageIdentifier: await attestation.p2pMessageLoggingIdentifier(),
|
|
862
|
+
slot: attestation.slotNumber,
|
|
772
863
|
archive: attestation.archive.toString(),
|
|
773
|
-
block: attestation.blockNumber,
|
|
774
864
|
source: source.toString(),
|
|
775
865
|
},
|
|
776
866
|
);
|
|
777
|
-
|
|
867
|
+
|
|
868
|
+
await this.mempools.attestationPool.addAttestations([attestation]);
|
|
778
869
|
}
|
|
779
870
|
|
|
780
871
|
private async processBlockFromPeer(payloadData: Buffer, msgId: string, source: PeerId): Promise<void> {
|
|
781
|
-
const validationFunc = async () => {
|
|
872
|
+
const validationFunc: () => Promise<ReceivedMessageValidationResult<BlockProposal>> = async () => {
|
|
782
873
|
const block = BlockProposal.fromBuffer(payloadData);
|
|
783
|
-
const
|
|
784
|
-
this.
|
|
874
|
+
const isValid = await this.validateBlockProposal(source, block);
|
|
875
|
+
const pool = this.mempools.attestationPool;
|
|
876
|
+
|
|
877
|
+
const exists = isValid && (await pool.hasBlockProposal(block));
|
|
878
|
+
const canAdd = isValid && (await pool.canAddProposal(block));
|
|
879
|
+
|
|
880
|
+
this.logger.trace(`Validate propagated block proposal`, {
|
|
881
|
+
isValid,
|
|
882
|
+
exists,
|
|
883
|
+
canAdd,
|
|
785
884
|
[Attributes.SLOT_NUMBER]: block.payload.header.slotNumber.toString(),
|
|
786
885
|
[Attributes.P2P_ID]: source.toString(),
|
|
787
886
|
});
|
|
788
|
-
|
|
887
|
+
|
|
888
|
+
if (!isValid) {
|
|
889
|
+
return { result: TopicValidatorResult.Reject };
|
|
890
|
+
} else if (exists) {
|
|
891
|
+
return { result: TopicValidatorResult.Ignore, obj: block };
|
|
892
|
+
} else if (!canAdd) {
|
|
893
|
+
this.peerManager.penalizePeer(source, PeerErrorSeverity.MidToleranceError);
|
|
894
|
+
this.logger.warn(`Penalizing peer for block proposal exceeding per-slot cap`, {
|
|
895
|
+
slot: block.slotNumber.toString(),
|
|
896
|
+
archive: block.archive.toString(),
|
|
897
|
+
source: source.toString(),
|
|
898
|
+
});
|
|
899
|
+
return { result: TopicValidatorResult.Reject };
|
|
900
|
+
} else {
|
|
901
|
+
return { result: TopicValidatorResult.Accept, obj: block };
|
|
902
|
+
}
|
|
789
903
|
};
|
|
790
904
|
|
|
791
905
|
const { result, obj: block } = await this.validateReceivedMessage<BlockProposal>(
|
|
@@ -794,6 +908,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
794
908
|
source,
|
|
795
909
|
TopicType.block_proposal,
|
|
796
910
|
);
|
|
911
|
+
|
|
797
912
|
if (!result || !block) {
|
|
798
913
|
return;
|
|
799
914
|
}
|
|
@@ -803,48 +918,49 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
803
918
|
|
|
804
919
|
// REVIEW: callback pattern https://github.com/AztecProtocol/aztec-packages/issues/7963
|
|
805
920
|
@trackSpan('Libp2pService.processValidBlockProposal', async block => ({
|
|
806
|
-
[Attributes.
|
|
807
|
-
[Attributes.SLOT_NUMBER]: block.slotNumber.toNumber(),
|
|
921
|
+
[Attributes.SLOT_NUMBER]: block.slotNumber,
|
|
808
922
|
[Attributes.BLOCK_ARCHIVE]: block.archive.toString(),
|
|
809
|
-
[Attributes.P2P_ID]: await block.
|
|
923
|
+
[Attributes.P2P_ID]: await block.p2pMessageLoggingIdentifier().then(i => i.toString()),
|
|
810
924
|
}))
|
|
811
925
|
private async processValidBlockProposal(block: BlockProposal, sender: PeerId) {
|
|
812
|
-
const slot = block.slotNumber
|
|
813
|
-
const previousSlot = slot -
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
source: sender.toString(),
|
|
823
|
-
},
|
|
824
|
-
);
|
|
825
|
-
const attestationsForPreviousSlot = await this.mempools.attestationPool?.getAttestationsForSlot(previousSlot);
|
|
826
|
-
if (attestationsForPreviousSlot !== undefined) {
|
|
827
|
-
this.logger.verbose(`Received ${attestationsForPreviousSlot.length} attestations for slot ${previousSlot}`);
|
|
828
|
-
}
|
|
926
|
+
const slot = block.slotNumber;
|
|
927
|
+
const previousSlot = SlotNumber(slot - 1);
|
|
928
|
+
this.logger.verbose(`Received block proposal for slot ${slot} from external peer ${sender.toString()}.`, {
|
|
929
|
+
p2pMessageIdentifier: await block.p2pMessageLoggingIdentifier(),
|
|
930
|
+
slot: block.slotNumber,
|
|
931
|
+
archive: block.archive.toString(),
|
|
932
|
+
source: sender.toString(),
|
|
933
|
+
});
|
|
934
|
+
const attestationsForPreviousSlot = await this.mempools.attestationPool.getAttestationsForSlot(previousSlot);
|
|
935
|
+
this.logger.verbose(`Received ${attestationsForPreviousSlot.length} attestations for slot ${previousSlot}`);
|
|
829
936
|
|
|
830
|
-
//
|
|
937
|
+
// Attempt to add proposal, then mark the txs in this proposal as non-evictable
|
|
938
|
+
try {
|
|
939
|
+
await this.mempools.attestationPool.addBlockProposal(block);
|
|
940
|
+
} catch (err: unknown) {
|
|
941
|
+
// Drop proposals if we hit per-slot cap in the attestation pool; rethrow unknown errors
|
|
942
|
+
if (err instanceof ProposalSlotCapExceededError) {
|
|
943
|
+
this.logger.warn(`Dropping block proposal due to per-slot proposal cap`, {
|
|
944
|
+
slot: String(slot),
|
|
945
|
+
archive: block.archive.toString(),
|
|
946
|
+
error: (err as Error).message,
|
|
947
|
+
});
|
|
948
|
+
return;
|
|
949
|
+
}
|
|
950
|
+
throw err;
|
|
951
|
+
}
|
|
831
952
|
await this.mempools.txPool.markTxsAsNonEvictable(block.txHashes);
|
|
832
|
-
await this.mempools.attestationPool?.addBlockProposal(block);
|
|
833
953
|
const attestations = await this.blockReceivedCallback(block, sender);
|
|
834
954
|
|
|
835
955
|
// TODO: fix up this pattern - the abstraction is not nice
|
|
836
|
-
// The attestation can be undefined if no handler is registered / the validator deems the block invalid
|
|
956
|
+
// The attestation can be undefined if no handler is registered / the validator deems the block invalid / in fisherman mode
|
|
837
957
|
if (attestations?.length) {
|
|
838
958
|
for (const attestation of attestations) {
|
|
839
|
-
this.logger.verbose(
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
archive: attestation.archive.toString(),
|
|
845
|
-
block: attestation.blockNumber,
|
|
846
|
-
},
|
|
847
|
-
);
|
|
959
|
+
this.logger.verbose(`Broadcasting attestation for slot ${attestation.slotNumber}`, {
|
|
960
|
+
p2pMessageIdentifier: await attestation.p2pMessageLoggingIdentifier(),
|
|
961
|
+
slot: attestation.slotNumber,
|
|
962
|
+
archive: attestation.archive.toString(),
|
|
963
|
+
});
|
|
848
964
|
await this.broadcastAttestation(attestation);
|
|
849
965
|
}
|
|
850
966
|
}
|
|
@@ -855,10 +971,9 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
855
971
|
* @param attestation - The attestation to broadcast.
|
|
856
972
|
*/
|
|
857
973
|
@trackSpan('Libp2pService.broadcastAttestation', async attestation => ({
|
|
858
|
-
[Attributes.
|
|
859
|
-
[Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber.toNumber(),
|
|
974
|
+
[Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber,
|
|
860
975
|
[Attributes.BLOCK_ARCHIVE]: attestation.archive.toString(),
|
|
861
|
-
[Attributes.P2P_ID]: await attestation.
|
|
976
|
+
[Attributes.P2P_ID]: await attestation.p2pMessageLoggingIdentifier().then(i => i.toString()),
|
|
862
977
|
}))
|
|
863
978
|
private async broadcastAttestation(attestation: BlockAttestation) {
|
|
864
979
|
await this.propagate(attestation);
|
|
@@ -869,15 +984,100 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
869
984
|
* @param message - The message to propagate.
|
|
870
985
|
*/
|
|
871
986
|
public async propagate<T extends Gossipable>(message: T) {
|
|
872
|
-
const p2pMessageIdentifier = await message.
|
|
987
|
+
const p2pMessageIdentifier = await message.p2pMessageLoggingIdentifier();
|
|
873
988
|
this.logger.trace(`Message ${p2pMessageIdentifier} queued`, { p2pMessageIdentifier });
|
|
874
|
-
void this.
|
|
875
|
-
.
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
989
|
+
void this.sendToPeers(message).catch(error => {
|
|
990
|
+
this.logger.error(`Error propagating message ${p2pMessageIdentifier}`, { error });
|
|
991
|
+
});
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
/**
|
|
995
|
+
* Validate the requested block transactions. Allow partial returns.
|
|
996
|
+
* @param request - The block transactions request.
|
|
997
|
+
* @param response - The block transactions response.
|
|
998
|
+
* @param peerId - The ID of the peer that made the request.
|
|
999
|
+
* @returns True if the requested block transactions are valid, false otherwise.
|
|
1000
|
+
*/
|
|
1001
|
+
@trackSpan('Libp2pService.validateRequestedBlockTxs', request => ({
|
|
1002
|
+
[Attributes.BLOCK_HASH]: request.blockHash.toString(),
|
|
1003
|
+
}))
|
|
1004
|
+
private async validateRequestedBlockTxs(
|
|
1005
|
+
request: BlockTxsRequest,
|
|
1006
|
+
response: BlockTxsResponse,
|
|
1007
|
+
peerId: PeerId,
|
|
1008
|
+
): Promise<boolean> {
|
|
1009
|
+
const requestedTxValidator = this.createRequestedTxValidator();
|
|
1010
|
+
|
|
1011
|
+
try {
|
|
1012
|
+
if (!response.blockHash.equals(request.blockHash)) {
|
|
1013
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
1014
|
+
throw new ValidationError(
|
|
1015
|
+
`Received block txs for unexpected block: expected ${request.blockHash.toString()}, got ${response.blockHash.toString()}`,
|
|
1016
|
+
);
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
if (response.txIndices.getLength() !== request.txIndices.getLength()) {
|
|
1020
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
1021
|
+
throw new ValidationError(
|
|
1022
|
+
`Received block txs with mismatched bitvector length: expected ${request.txIndices.getLength()}, got ${response.txIndices.getLength()}`,
|
|
1023
|
+
);
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
// Check no duplicates and not exceeding returnable count
|
|
1027
|
+
const requestedIndices = new Set(request.txIndices.getTrueIndices());
|
|
1028
|
+
const availableIndices = new Set(response.txIndices.getTrueIndices());
|
|
1029
|
+
const maxReturnable = [...requestedIndices].filter(i => availableIndices.has(i)).length;
|
|
1030
|
+
|
|
1031
|
+
const returnedHashes = await Promise.all(response.txs.map(tx => tx.getTxHash().toString()));
|
|
1032
|
+
const uniqueReturned = new Set(returnedHashes.map(h => h.toString()));
|
|
1033
|
+
if (uniqueReturned.size !== returnedHashes.length) {
|
|
1034
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
1035
|
+
throw new ValidationError(`Received duplicate txs in block txs response`);
|
|
1036
|
+
}
|
|
1037
|
+
if (response.txs.length > maxReturnable) {
|
|
1038
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
1039
|
+
throw new ValidationError(
|
|
1040
|
+
`Received more txs (${response.txs.length}) than requested-and-available (${maxReturnable})`,
|
|
1041
|
+
);
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
// Given proposal (should have locally), ensure returned txs are valid subset and match request indices
|
|
1045
|
+
const proposal = await this.mempools.attestationPool.getBlockProposal(request.blockHash.toString());
|
|
1046
|
+
if (proposal) {
|
|
1047
|
+
// Build intersected indices
|
|
1048
|
+
const intersectIdx = request.txIndices.getTrueIndices().filter(i => response.txIndices.isSet(i));
|
|
1049
|
+
|
|
1050
|
+
// Enforce subset membership and preserve increasing order by index.
|
|
1051
|
+
const hashToIndexInProposal = new Map<string, number>(
|
|
1052
|
+
proposal.txHashes.map((h, i) => [h.toString(), i] as [string, number]),
|
|
1053
|
+
);
|
|
1054
|
+
const allowedIndexSet = new Set(intersectIdx);
|
|
1055
|
+
const indices = returnedHashes.map(h => hashToIndexInProposal.get(h));
|
|
1056
|
+
const allAllowed = indices.every(idx => idx !== undefined && allowedIndexSet.has(idx));
|
|
1057
|
+
const strictlyIncreasing = indices.every((idx, i) => (i === 0 ? idx !== undefined : idx! > indices[i - 1]!));
|
|
1058
|
+
if (!allAllowed || !strictlyIncreasing) {
|
|
1059
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
|
|
1060
|
+
throw new ValidationError('Returned txs do not match expected subset/order for requested indices');
|
|
1061
|
+
}
|
|
1062
|
+
} else {
|
|
1063
|
+
// No local proposal, cannot check the membership/order of the returned txs
|
|
1064
|
+
this.logger.warn(
|
|
1065
|
+
`Block proposal not found for block hash ${request.blockHash.toString()}; cannot validate membership/order of returned txs`,
|
|
1066
|
+
);
|
|
1067
|
+
return false;
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
await Promise.all(response.txs.map(tx => this.validateRequestedTx(tx, peerId, requestedTxValidator)));
|
|
1071
|
+
return true;
|
|
1072
|
+
} catch (e: any) {
|
|
1073
|
+
if (e instanceof ValidationError) {
|
|
1074
|
+
this.logger.warn(`Failed validation for requested block txs from peer ${peerId.toString()}`);
|
|
1075
|
+
} else {
|
|
1076
|
+
this.logger.error(`Error during validation of requested block txs`, e);
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
return false;
|
|
1080
|
+
}
|
|
881
1081
|
}
|
|
882
1082
|
|
|
883
1083
|
/**
|
|
@@ -890,47 +1090,113 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
890
1090
|
* ReqRespSubProtocol.TX subprotocol validation.
|
|
891
1091
|
*
|
|
892
1092
|
* @param requestedTxHash - The collection of the txs that was requested.
|
|
893
|
-
* @param responseTx - The
|
|
1093
|
+
* @param responseTx - The collection of txs that was received as a response to the request.
|
|
894
1094
|
* @param peerId - The peer ID of the peer that sent the tx.
|
|
895
1095
|
* @returns True if the whole collection of txs is valid, false otherwise.
|
|
896
1096
|
*/
|
|
897
|
-
//TODO: (mralj) - this is somewhat naive implementation, if single tx is invlid we consider the whole response invalid.
|
|
898
|
-
// I think we should still extract the valid txs and return them, so that we can still use the response.
|
|
899
1097
|
@trackSpan('Libp2pService.validateRequestedTx', (requestedTxHash, _responseTx) => ({
|
|
900
1098
|
[Attributes.TX_HASH]: requestedTxHash.toString(),
|
|
901
1099
|
}))
|
|
902
|
-
private async
|
|
1100
|
+
private async validateRequestedTxs(requestedTxHash: TxHash[], responseTx: Tx[], peerId: PeerId): Promise<boolean> {
|
|
903
1101
|
const requested = new Set(requestedTxHash.map(h => h.toString()));
|
|
1102
|
+
const requestedTxValidator = this.createRequestedTxValidator();
|
|
904
1103
|
|
|
905
|
-
|
|
906
|
-
|
|
1104
|
+
//TODO: (mralj) - this is somewhat naive implementation, if single tx is invlid we consider the whole response invalid.
|
|
1105
|
+
// I think we should still extract the valid txs and return them, so that we can still use the response.
|
|
907
1106
|
try {
|
|
908
|
-
await Promise.all(
|
|
909
|
-
responseTx.map(async tx => {
|
|
910
|
-
if (!requested.has(tx.getTxHash().toString())) {
|
|
911
|
-
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
912
|
-
throw new ValidationError(`Received tx with hash ${tx.getTxHash().toString()} that was not requested.`);
|
|
913
|
-
}
|
|
914
|
-
|
|
915
|
-
const { result } = await proofValidator.validateTx(tx);
|
|
916
|
-
if (result === 'invalid') {
|
|
917
|
-
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
|
|
918
|
-
throw new ValidationError(`Received tx with hash ${tx.getTxHash().toString()} that is invalid.`);
|
|
919
|
-
}
|
|
920
|
-
}),
|
|
921
|
-
);
|
|
1107
|
+
await Promise.all(responseTx.map(tx => this.validateRequestedTx(tx, peerId, requestedTxValidator, requested)));
|
|
922
1108
|
return true;
|
|
923
1109
|
} catch (e: any) {
|
|
924
1110
|
if (e instanceof ValidationError) {
|
|
925
|
-
this.logger.
|
|
1111
|
+
this.logger.warn(`Failed to validate requested txs from peer ${peerId.toString()}, reason ${e.message}`);
|
|
926
1112
|
} else {
|
|
927
|
-
this.logger.
|
|
1113
|
+
this.logger.error(`Error during validation of requested txs`, e);
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
return false;
|
|
1117
|
+
}
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
/**
|
|
1121
|
+
* Validates a BLOCK response.
|
|
1122
|
+
*
|
|
1123
|
+
* If a local copy exists, enforces hash equality. If missing, rejects (no penalty) since the hash cannot be verified.
|
|
1124
|
+
* Penalizes on block number mismatch or hash mismatch.
|
|
1125
|
+
*
|
|
1126
|
+
* @param requestedBlockNumber - The requested block number.
|
|
1127
|
+
* @param responseBlock - The block returned by the peer.
|
|
1128
|
+
* @param peerId - The peer that returned the block.
|
|
1129
|
+
* @returns True if the response is valid, false otherwise.
|
|
1130
|
+
*/
|
|
1131
|
+
@trackSpan('Libp2pService.validateRequestedBlock', (requestedBlockNumber, _responseBlock) => ({
|
|
1132
|
+
[Attributes.BLOCK_NUMBER]: requestedBlockNumber.toString(),
|
|
1133
|
+
}))
|
|
1134
|
+
private async validateRequestedBlock(
|
|
1135
|
+
requestedBlockNumber: Fr,
|
|
1136
|
+
responseBlock: L2Block,
|
|
1137
|
+
peerId: PeerId,
|
|
1138
|
+
): Promise<boolean> {
|
|
1139
|
+
try {
|
|
1140
|
+
const reqNum = Number(requestedBlockNumber.toString());
|
|
1141
|
+
if (responseBlock.number !== reqNum) {
|
|
1142
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
|
|
1143
|
+
return false;
|
|
928
1144
|
}
|
|
929
1145
|
|
|
1146
|
+
const local = await this.archiver.getBlock(BlockNumber(reqNum));
|
|
1147
|
+
if (!local) {
|
|
1148
|
+
// We are missing the local block; we cannot verify the hash yet. Reject without penalizing.
|
|
1149
|
+
// TODO: Consider extending this validator to accept an expected hash or
|
|
1150
|
+
// performing quorum-based checks when using P2P syncing prior to L1 sync.
|
|
1151
|
+
this.logger.warn(`Local block ${reqNum} not found; rejecting BLOCK response without hash verification`);
|
|
1152
|
+
return false;
|
|
1153
|
+
}
|
|
1154
|
+
const [localHash, respHash] = await Promise.all([local.hash(), responseBlock.hash()]);
|
|
1155
|
+
if (!localHash.equals(respHash)) {
|
|
1156
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
1157
|
+
return false;
|
|
1158
|
+
}
|
|
1159
|
+
|
|
1160
|
+
return true;
|
|
1161
|
+
} catch (e) {
|
|
1162
|
+
this.logger.warn(`Error validating requested block`, e);
|
|
930
1163
|
return false;
|
|
931
1164
|
}
|
|
932
1165
|
}
|
|
933
1166
|
|
|
1167
|
+
private createRequestedTxValidator(): TxValidator {
|
|
1168
|
+
return new AggregateTxValidator(
|
|
1169
|
+
new DataTxValidator(),
|
|
1170
|
+
new MetadataTxValidator({
|
|
1171
|
+
l1ChainId: new Fr(this.config.l1ChainId),
|
|
1172
|
+
rollupVersion: new Fr(this.config.rollupVersion),
|
|
1173
|
+
protocolContractsHash,
|
|
1174
|
+
vkTreeRoot: getVKTreeRoot(),
|
|
1175
|
+
}),
|
|
1176
|
+
new TxProofValidator(this.proofVerifier),
|
|
1177
|
+
);
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1180
|
+
private async validateRequestedTx(tx: Tx, peerId: PeerId, txValidator: TxValidator, requested?: Set<`0x${string}`>) {
|
|
1181
|
+
const penalize = (severity: PeerErrorSeverity) => this.peerManager.penalizePeer(peerId, severity);
|
|
1182
|
+
|
|
1183
|
+
if (!(await tx.validateTxHash())) {
|
|
1184
|
+
penalize(PeerErrorSeverity.MidToleranceError);
|
|
1185
|
+
throw new ValidationError(`Received tx with invalid hash ${tx.getTxHash().toString()}.`);
|
|
1186
|
+
}
|
|
1187
|
+
|
|
1188
|
+
if (requested && !requested.has(tx.getTxHash().toString())) {
|
|
1189
|
+
penalize(PeerErrorSeverity.MidToleranceError);
|
|
1190
|
+
throw new ValidationError(`Received tx with hash ${tx.getTxHash().toString()} that was not requested.`);
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
const { result } = await txValidator.validateTx(tx);
|
|
1194
|
+
if (result === 'invalid') {
|
|
1195
|
+
penalize(PeerErrorSeverity.LowToleranceError);
|
|
1196
|
+
throw new ValidationError(`Received tx with hash ${tx.getTxHash().toString()} that is invalid.`);
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1199
|
+
|
|
934
1200
|
@trackSpan('Libp2pService.validatePropagatedTx', tx => ({
|
|
935
1201
|
[Attributes.TX_HASH]: tx.getTxHash().toString(),
|
|
936
1202
|
}))
|
|
@@ -952,7 +1218,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
952
1218
|
|
|
953
1219
|
// Double spend validator has a special case handler
|
|
954
1220
|
if (name === 'doubleSpendValidator') {
|
|
955
|
-
const txBlockNumber = currentBlockNumber + 1; // tx is expected to be in the next block
|
|
1221
|
+
const txBlockNumber = BlockNumber(currentBlockNumber + 1); // tx is expected to be in the next block
|
|
956
1222
|
severity = await this.handleDoubleSpendFailure(tx, txBlockNumber);
|
|
957
1223
|
}
|
|
958
1224
|
|
|
@@ -962,7 +1228,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
962
1228
|
return true;
|
|
963
1229
|
}
|
|
964
1230
|
|
|
965
|
-
private async getGasFees(blockNumber:
|
|
1231
|
+
private async getGasFees(blockNumber: BlockNumber): Promise<GasFees> {
|
|
966
1232
|
if (blockNumber === this.feesCache?.blockNumber) {
|
|
967
1233
|
return this.feesCache.gasFees;
|
|
968
1234
|
}
|
|
@@ -1003,13 +1269,13 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1003
1269
|
* @returns The message validators.
|
|
1004
1270
|
*/
|
|
1005
1271
|
private async createMessageValidators(
|
|
1006
|
-
currentBlockNumber:
|
|
1272
|
+
currentBlockNumber: BlockNumber,
|
|
1007
1273
|
nextSlotTimestamp: UInt64,
|
|
1008
1274
|
): Promise<Record<string, MessageValidator>[]> {
|
|
1009
1275
|
const gasFees = await this.getGasFees(currentBlockNumber);
|
|
1010
1276
|
const allowedInSetup = this.config.txPublicSetupAllowList ?? (await getDefaultAllowedSetupFunctions());
|
|
1011
1277
|
|
|
1012
|
-
const blockNumberInWhichTheTxIsConsideredToBeIncluded = currentBlockNumber + 1;
|
|
1278
|
+
const blockNumberInWhichTheTxIsConsideredToBeIncluded = BlockNumber(currentBlockNumber + 1);
|
|
1013
1279
|
|
|
1014
1280
|
return createTxMessageValidators(
|
|
1015
1281
|
nextSlotTimestamp,
|
|
@@ -1018,7 +1284,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1018
1284
|
gasFees,
|
|
1019
1285
|
this.config.l1ChainId,
|
|
1020
1286
|
this.config.rollupVersion,
|
|
1021
|
-
|
|
1287
|
+
protocolContractsHash,
|
|
1022
1288
|
this.archiver,
|
|
1023
1289
|
this.proofVerifier,
|
|
1024
1290
|
!this.config.disableTransactions,
|
|
@@ -1071,7 +1337,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1071
1337
|
* @param peerId - The peer ID of the peer that sent the tx.
|
|
1072
1338
|
* @returns Severity
|
|
1073
1339
|
*/
|
|
1074
|
-
private async handleDoubleSpendFailure(tx: Tx, blockNumber:
|
|
1340
|
+
private async handleDoubleSpendFailure(tx: Tx, blockNumber: BlockNumber): Promise<PeerErrorSeverity> {
|
|
1075
1341
|
if (blockNumber <= this.config.doubleSpendSeverePeerPenaltyWindow) {
|
|
1076
1342
|
return PeerErrorSeverity.HighToleranceError;
|
|
1077
1343
|
}
|
|
@@ -1079,7 +1345,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1079
1345
|
const snapshotValidator = new DoubleSpendTxValidator({
|
|
1080
1346
|
nullifiersExist: async (nullifiers: Buffer[]) => {
|
|
1081
1347
|
const merkleTree = this.worldStateSynchronizer.getSnapshot(
|
|
1082
|
-
blockNumber - this.config.doubleSpendSeverePeerPenaltyWindow,
|
|
1348
|
+
BlockNumber(blockNumber - this.config.doubleSpendSeverePeerPenaltyWindow),
|
|
1083
1349
|
);
|
|
1084
1350
|
const indices = await merkleTree.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, nullifiers);
|
|
1085
1351
|
return indices.map(index => index !== undefined);
|
|
@@ -1101,10 +1367,9 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1101
1367
|
* @returns True if the attestation is valid, false otherwise.
|
|
1102
1368
|
*/
|
|
1103
1369
|
@trackSpan('Libp2pService.validateAttestation', async (_, attestation) => ({
|
|
1104
|
-
[Attributes.
|
|
1105
|
-
[Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber.toNumber(),
|
|
1370
|
+
[Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber,
|
|
1106
1371
|
[Attributes.BLOCK_ARCHIVE]: attestation.archive.toString(),
|
|
1107
|
-
[Attributes.P2P_ID]: await attestation.
|
|
1372
|
+
[Attributes.P2P_ID]: await attestation.p2pMessageLoggingIdentifier().then(i => i.toString()),
|
|
1108
1373
|
}))
|
|
1109
1374
|
public async validateAttestation(peerId: PeerId, attestation: BlockAttestation): Promise<boolean> {
|
|
1110
1375
|
const severity = await this.attestationValidator.validate(attestation);
|
|
@@ -1147,7 +1412,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1147
1412
|
private async sendToPeers<T extends Gossipable>(message: T) {
|
|
1148
1413
|
const parent = message.constructor as typeof Gossipable;
|
|
1149
1414
|
|
|
1150
|
-
const identifier = await message.
|
|
1415
|
+
const identifier = await message.p2pMessageLoggingIdentifier().then(i => i.toString());
|
|
1151
1416
|
this.logger.trace(`Sending message ${identifier}`, { p2pMessageIdentifier: identifier });
|
|
1152
1417
|
|
|
1153
1418
|
const recipientsNum = await this.publishToTopic(this.topicStrings[parent.p2pTopic], message);
|