@aztec/p2p 4.0.0-nightly.20250907 → 4.0.0-nightly.20260108
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 +13 -36
- package/dest/client/p2p_client.d.ts.map +1 -1
- package/dest/client/p2p_client.js +460 -63
- 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 +33 -72
- package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
- package/dest/services/libp2p/libp2p_service.js +841 -175
- 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 +2 -33
- package/dest/services/peer-manager/peer_manager.d.ts.map +1 -1
- package/dest/services/peer-manager/peer_manager.js +29 -22
- 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 +106 -106
- 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 +494 -169
- package/src/services/peer-manager/metrics.ts +32 -0
- package/src/services/peer-manager/peer_manager.ts +25 -16
- 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,18 @@ 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
|
-
import {
|
|
31
|
+
import {
|
|
32
|
+
Attributes,
|
|
33
|
+
OtelMetricsAdapter,
|
|
34
|
+
SpanStatusCode,
|
|
35
|
+
type TelemetryClient,
|
|
36
|
+
WithTracer,
|
|
37
|
+
trackSpan,
|
|
38
|
+
} from '@aztec/telemetry-client';
|
|
30
39
|
|
|
31
|
-
import { ENR } from '@chainsafe/enr';
|
|
32
40
|
import {
|
|
33
41
|
type GossipSub,
|
|
34
42
|
type GossipSubComponents,
|
|
@@ -43,18 +51,29 @@ import { bootstrap } from '@libp2p/bootstrap';
|
|
|
43
51
|
import { identify } from '@libp2p/identify';
|
|
44
52
|
import { type Message, type MultiaddrConnection, type PeerId, TopicValidatorResult } from '@libp2p/interface';
|
|
45
53
|
import type { ConnectionManager } from '@libp2p/interface-internal';
|
|
46
|
-
import '@libp2p/kad-dht';
|
|
47
54
|
import { mplex } from '@libp2p/mplex';
|
|
48
55
|
import { tcp } from '@libp2p/tcp';
|
|
56
|
+
import { ENR } from '@nethermindeth/enr';
|
|
49
57
|
import { createLibp2p } from 'libp2p';
|
|
50
58
|
|
|
51
59
|
import type { P2PConfig } from '../../config.js';
|
|
60
|
+
import { ProposalSlotCapExceededError } from '../../errors/attestation-pool.error.js';
|
|
52
61
|
import type { MemPools } from '../../mem_pools/interface.js';
|
|
53
|
-
import {
|
|
62
|
+
import {
|
|
63
|
+
AttestationValidator,
|
|
64
|
+
BlockProposalValidator,
|
|
65
|
+
FishermanAttestationValidator,
|
|
66
|
+
} from '../../msg_validators/index.js';
|
|
54
67
|
import { MessageSeenValidator } from '../../msg_validators/msg_seen_validator/msg_seen_validator.js';
|
|
55
68
|
import { getDefaultAllowedSetupFunctions } from '../../msg_validators/tx_validator/allowed_public_setup.js';
|
|
56
69
|
import { type MessageValidator, createTxMessageValidators } from '../../msg_validators/tx_validator/factory.js';
|
|
57
|
-
import {
|
|
70
|
+
import {
|
|
71
|
+
AggregateTxValidator,
|
|
72
|
+
DataTxValidator,
|
|
73
|
+
DoubleSpendTxValidator,
|
|
74
|
+
MetadataTxValidator,
|
|
75
|
+
TxProofValidator,
|
|
76
|
+
} from '../../msg_validators/tx_validator/index.js';
|
|
58
77
|
import { GossipSubEvent } from '../../types/index.js';
|
|
59
78
|
import { type PubSubLibp2p, convertToMultiaddr } from '../../util.js';
|
|
60
79
|
import { getVersions } from '../../versioning.js';
|
|
@@ -80,6 +99,8 @@ import { reqRespBlockTxsHandler } from '../reqresp/protocols/block_txs/block_txs
|
|
|
80
99
|
import { reqGoodbyeHandler } from '../reqresp/protocols/goodbye.js';
|
|
81
100
|
import {
|
|
82
101
|
AuthRequest,
|
|
102
|
+
BlockTxsRequest,
|
|
103
|
+
BlockTxsResponse,
|
|
83
104
|
StatusMessage,
|
|
84
105
|
pingHandler,
|
|
85
106
|
reqRespBlockHandler,
|
|
@@ -98,11 +119,15 @@ interface ValidationResult {
|
|
|
98
119
|
|
|
99
120
|
type ValidationOutcome = { allPassed: true } | { allPassed: false; failure: ValidationResult };
|
|
100
121
|
|
|
122
|
+
// REFACTOR: Unify with the type above
|
|
123
|
+
type ReceivedMessageValidationResult<T> =
|
|
124
|
+
| { obj: T; result: Exclude<TopicValidatorResult, TopicValidatorResult.Reject> }
|
|
125
|
+
| { obj?: undefined; result: TopicValidatorResult.Reject };
|
|
126
|
+
|
|
101
127
|
/**
|
|
102
128
|
* Lib P2P implementation of the P2PService interface.
|
|
103
129
|
*/
|
|
104
130
|
export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends WithTracer implements P2PService {
|
|
105
|
-
private jobQueue: SerialQueue = new SerialQueue();
|
|
106
131
|
private discoveryRunningPromise?: RunningPromise;
|
|
107
132
|
private msgIdSeenValidators: Record<TopicType, MessageSeenValidator> = {} as Record<TopicType, MessageSeenValidator>;
|
|
108
133
|
|
|
@@ -113,7 +138,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
113
138
|
private protocolVersion = '';
|
|
114
139
|
private topicStrings: Record<TopicType, string> = {} as Record<TopicType, string>;
|
|
115
140
|
|
|
116
|
-
private feesCache: { blockNumber:
|
|
141
|
+
private feesCache: { blockNumber: BlockNumber; gasFees: GasFees } | undefined;
|
|
117
142
|
|
|
118
143
|
/**
|
|
119
144
|
* Callback for when a block is received from a peer.
|
|
@@ -126,6 +151,10 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
126
151
|
|
|
127
152
|
private instrumentation: P2PInstrumentation;
|
|
128
153
|
|
|
154
|
+
private telemetry: TelemetryClient;
|
|
155
|
+
|
|
156
|
+
protected logger: Logger;
|
|
157
|
+
|
|
129
158
|
constructor(
|
|
130
159
|
private clientType: T,
|
|
131
160
|
private config: P2PConfig,
|
|
@@ -133,15 +162,19 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
133
162
|
private peerDiscoveryService: PeerDiscoveryService,
|
|
134
163
|
private reqresp: ReqRespInterface,
|
|
135
164
|
private peerManager: PeerManagerInterface,
|
|
136
|
-
protected mempools: MemPools
|
|
165
|
+
protected mempools: MemPools,
|
|
137
166
|
private archiver: L2BlockSource & ContractDataSource,
|
|
138
167
|
private epochCache: EpochCacheInterface,
|
|
139
168
|
private proofVerifier: ClientProtocolCircuitVerifier,
|
|
140
169
|
private worldStateSynchronizer: WorldStateSynchronizer,
|
|
141
170
|
telemetry: TelemetryClient,
|
|
142
|
-
|
|
171
|
+
logger: Logger = createLogger('p2p:libp2p_service'),
|
|
143
172
|
) {
|
|
144
173
|
super(telemetry, 'LibP2PService');
|
|
174
|
+
this.telemetry = telemetry;
|
|
175
|
+
|
|
176
|
+
// Create child logger with fisherman prefix if in fisherman mode
|
|
177
|
+
this.logger = config.fishermanMode ? logger.createChild('[FISHERMAN]') : logger;
|
|
145
178
|
|
|
146
179
|
this.instrumentation = new P2PInstrumentation(telemetry, 'LibP2PService');
|
|
147
180
|
|
|
@@ -160,15 +193,18 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
160
193
|
this.protocolVersion,
|
|
161
194
|
);
|
|
162
195
|
|
|
163
|
-
|
|
164
|
-
this.
|
|
196
|
+
// Use FishermanAttestationValidator in fisherman mode to validate attestation payloads against proposals
|
|
197
|
+
this.attestationValidator = config.fishermanMode
|
|
198
|
+
? new FishermanAttestationValidator(epochCache, mempools.attestationPool, telemetry)
|
|
199
|
+
: new AttestationValidator(epochCache);
|
|
200
|
+
this.blockProposalValidator = new BlockProposalValidator(epochCache, { txsPermitted: !config.disableTransactions });
|
|
165
201
|
|
|
166
202
|
this.gossipSubEventHandler = this.handleGossipSubEvent.bind(this);
|
|
167
203
|
|
|
168
204
|
this.blockReceivedCallback = async (block: BlockProposal): Promise<BlockAttestation[] | undefined> => {
|
|
169
205
|
this.logger.debug(
|
|
170
|
-
`Handler not yet registered: Block received callback not set. Received block for slot ${block.slotNumber
|
|
171
|
-
{ p2pMessageIdentifier: await block.
|
|
206
|
+
`Handler not yet registered: Block received callback not set. Received block for slot ${block.slotNumber} from peer.`,
|
|
207
|
+
{ p2pMessageIdentifier: await block.p2pMessageLoggingIdentifier() },
|
|
172
208
|
);
|
|
173
209
|
return undefined;
|
|
174
210
|
};
|
|
@@ -189,7 +225,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
189
225
|
config: P2PConfig,
|
|
190
226
|
peerId: PeerId,
|
|
191
227
|
deps: {
|
|
192
|
-
mempools: MemPools
|
|
228
|
+
mempools: MemPools;
|
|
193
229
|
l2BlockSource: L2BlockSource & ContractDataSource;
|
|
194
230
|
epochCache: EpochCacheInterface;
|
|
195
231
|
proofVerifier: ClientProtocolCircuitVerifier;
|
|
@@ -273,7 +309,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
273
309
|
// 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
310
|
// If we hit the limit, the connection will be temporarily accepted and immediately dropped.
|
|
275
311
|
// Docs: https://nodejs.org/api/net.html#servermaxconnections
|
|
276
|
-
maxConnections:
|
|
312
|
+
maxConnections: maxPeerCount * 2,
|
|
277
313
|
// socket option: the maximum length of the queue of pending connections
|
|
278
314
|
// https://nodejs.org/dist/latest-v22.x/docs/api/net.html#serverlisten
|
|
279
315
|
// it's not safe if we increase this number
|
|
@@ -284,7 +320,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
284
320
|
// In case closeAbove is reached, the server stops listening altogether
|
|
285
321
|
// It's important that there is enough difference between closeAbove and listenAbove,
|
|
286
322
|
// otherwise the server.listener will flap between being closed and open potentially degrading perf even more
|
|
287
|
-
closeAbove: maxPeerCount *
|
|
323
|
+
closeAbove: maxPeerCount * 3,
|
|
288
324
|
listenBelow: Math.floor(maxPeerCount * 0.9),
|
|
289
325
|
},
|
|
290
326
|
}),
|
|
@@ -294,8 +330,10 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
294
330
|
streamMuxers: [yamux(), mplex()],
|
|
295
331
|
connectionEncryption: [noise()],
|
|
296
332
|
connectionManager: {
|
|
297
|
-
minConnections: 0,
|
|
298
|
-
maxConnections
|
|
333
|
+
minConnections: 0, // Disable libp2p peer dialing, we do it manually
|
|
334
|
+
// We set maxConnections above maxPeerCount because if we hit limit of maxPeerCount
|
|
335
|
+
// libp2p will start aggressively rejecting all new connections, preventing network discovery and crawling.
|
|
336
|
+
maxConnections: maxPeerCount * 2,
|
|
299
337
|
maxParallelDials: 100,
|
|
300
338
|
dialTimeout: 30_000,
|
|
301
339
|
maxPeerAddrsToDial: 5,
|
|
@@ -379,7 +417,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
379
417
|
logger: createLibp2pComponentLogger(logger.module),
|
|
380
418
|
});
|
|
381
419
|
|
|
382
|
-
const peerScoring = new PeerScoring(config);
|
|
420
|
+
const peerScoring = new PeerScoring(config, telemetry);
|
|
383
421
|
const reqresp = new ReqResp(config, node, peerScoring, createLogger(`${logger.module}:reqresp`));
|
|
384
422
|
|
|
385
423
|
const peerManager = new PeerManager(
|
|
@@ -434,9 +472,6 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
434
472
|
}
|
|
435
473
|
const announceTcpMultiaddr = convertToMultiaddr(p2pIp, p2pPort, 'tcp');
|
|
436
474
|
|
|
437
|
-
// Start job queue, peer discovery service and libp2p node
|
|
438
|
-
this.jobQueue.start();
|
|
439
|
-
|
|
440
475
|
await this.peerManager.initializePeers();
|
|
441
476
|
if (!this.config.p2pDiscoveryDisabled) {
|
|
442
477
|
await this.peerDiscoveryService.start();
|
|
@@ -453,10 +488,6 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
453
488
|
const goodbyeHandler = reqGoodbyeHandler(this.peerManager);
|
|
454
489
|
const blockHandler = reqRespBlockHandler(this.archiver);
|
|
455
490
|
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
491
|
|
|
461
492
|
const requestResponseHandlers: Partial<ReqRespSubProtocolHandlers> = {
|
|
462
493
|
[ReqRespSubProtocol.PING]: pingHandler,
|
|
@@ -465,8 +496,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
465
496
|
[ReqRespSubProtocol.BLOCK]: blockHandler.bind(this),
|
|
466
497
|
};
|
|
467
498
|
|
|
468
|
-
|
|
469
|
-
if (this.mempools.attestationPool) {
|
|
499
|
+
if (!this.config.disableTransactions) {
|
|
470
500
|
const blockTxsHandler = reqRespBlockTxsHandler(this.mempools.attestationPool, this.mempools.txPool);
|
|
471
501
|
requestResponseHandlers[ReqRespSubProtocol.BLOCK_TXS] = blockTxsHandler.bind(this);
|
|
472
502
|
}
|
|
@@ -478,9 +508,11 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
478
508
|
// add GossipSub listener
|
|
479
509
|
this.node.services.pubsub.addEventListener(GossipSubEvent.MESSAGE, this.gossipSubEventHandler);
|
|
480
510
|
|
|
481
|
-
// Start running promise for peer discovery
|
|
511
|
+
// Start running promise for peer discovery and metrics collection
|
|
482
512
|
this.discoveryRunningPromise = new RunningPromise(
|
|
483
|
-
() =>
|
|
513
|
+
async () => {
|
|
514
|
+
await this.peerManager.heartbeat();
|
|
515
|
+
},
|
|
484
516
|
this.logger,
|
|
485
517
|
this.config.peerCheckIntervalMS,
|
|
486
518
|
);
|
|
@@ -489,8 +521,9 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
489
521
|
// Define the sub protocol validators - This is done within this start() method to gain a callback to the existing validateTx function
|
|
490
522
|
const reqrespSubProtocolValidators = {
|
|
491
523
|
...DEFAULT_SUB_PROTOCOL_VALIDATORS,
|
|
492
|
-
|
|
493
|
-
[ReqRespSubProtocol.
|
|
524
|
+
[ReqRespSubProtocol.TX]: this.validateRequestedTxs.bind(this),
|
|
525
|
+
[ReqRespSubProtocol.BLOCK_TXS]: this.validateRequestedBlockTxs.bind(this),
|
|
526
|
+
[ReqRespSubProtocol.BLOCK]: this.validateRequestedBlock.bind(this),
|
|
494
527
|
};
|
|
495
528
|
await this.reqresp.start(requestResponseHandlers, reqrespSubProtocolValidators);
|
|
496
529
|
this.logger.info(`Started P2P service`, {
|
|
@@ -512,9 +545,6 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
512
545
|
// Stop peer manager
|
|
513
546
|
this.logger.debug('Stopping peer manager...');
|
|
514
547
|
await this.peerManager.stop();
|
|
515
|
-
|
|
516
|
-
this.logger.debug('Stopping job queue...');
|
|
517
|
-
await this.jobQueue.end();
|
|
518
548
|
this.logger.debug('Stopping running promise...');
|
|
519
549
|
await this.discoveryRunningPromise?.stop();
|
|
520
550
|
this.logger.debug('Stopping peer discovery service...');
|
|
@@ -602,16 +632,19 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
602
632
|
if (!this.node.services.pubsub) {
|
|
603
633
|
throw new Error('Pubsub service not available.');
|
|
604
634
|
}
|
|
605
|
-
const
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
});
|
|
635
|
+
const isBlockProposal = topic === this.topicStrings[TopicType.block_proposal];
|
|
636
|
+
const traceContext =
|
|
637
|
+
this.config.debugP2PInstrumentMessages && isBlockProposal ? this.telemetry.getTraceContext() : undefined;
|
|
638
|
+
const p2pMessage = P2PMessage.fromGossipable(message, this.config.debugP2PInstrumentMessages, traceContext);
|
|
610
639
|
const result = await this.node.services.pubsub.publish(topic, p2pMessage.toMessageData());
|
|
611
|
-
|
|
612
640
|
return result.recipients.length;
|
|
613
641
|
}
|
|
614
642
|
|
|
643
|
+
/**
|
|
644
|
+
* Checks if this message has already been seen, based on its msgId computed from hashing the message data.
|
|
645
|
+
* Note that we do not rely on the seenCache from gossipsub since we want to keep a longer history of seen
|
|
646
|
+
* messages to avoid tx echoes across the network.
|
|
647
|
+
*/
|
|
615
648
|
protected preValidateReceivedMessage(
|
|
616
649
|
msg: Message,
|
|
617
650
|
msgId: string,
|
|
@@ -647,82 +680,169 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
647
680
|
return { result: true, topicType };
|
|
648
681
|
}
|
|
649
682
|
|
|
683
|
+
/**
|
|
684
|
+
* Safely deserializes a P2PMessage from raw message data.
|
|
685
|
+
* @param msgId - The message ID.
|
|
686
|
+
* @param source - The peer ID of the message source.
|
|
687
|
+
* @param data - The raw message data.
|
|
688
|
+
* @returns The deserialized P2PMessage or undefined if deserialization fails.
|
|
689
|
+
*/
|
|
690
|
+
private safelyDeserializeP2PMessage(msgId: string, source: PeerId, data: Uint8Array): P2PMessage | undefined {
|
|
691
|
+
try {
|
|
692
|
+
return P2PMessage.fromMessageData(Buffer.from(data), this.config.debugP2PInstrumentMessages);
|
|
693
|
+
} catch (err) {
|
|
694
|
+
this.logger.error(`Error deserializing P2PMessage`, err, {
|
|
695
|
+
msgId,
|
|
696
|
+
source: source.toString(),
|
|
697
|
+
});
|
|
698
|
+
this.node.services.pubsub.reportMessageValidationResult(msgId, source.toString(), TopicValidatorResult.Reject);
|
|
699
|
+
this.peerManager.penalizePeer(source, PeerErrorSeverity.LowToleranceError);
|
|
700
|
+
return undefined;
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
|
|
650
704
|
/**
|
|
651
705
|
* Handles a new gossip message that was received by the client.
|
|
652
706
|
* @param topic - The message's topic.
|
|
653
707
|
* @param data - The message data
|
|
654
708
|
*/
|
|
655
709
|
protected async handleNewGossipMessage(msg: Message, msgId: string, source: PeerId) {
|
|
656
|
-
const
|
|
657
|
-
|
|
658
|
-
const
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
messageLatency,
|
|
663
|
-
});
|
|
710
|
+
const msgReceivedTime = Date.now();
|
|
711
|
+
let topicType: TopicType | undefined;
|
|
712
|
+
const p2pMessage = this.safelyDeserializeP2PMessage(msgId, source, msg.data);
|
|
713
|
+
if (!p2pMessage) {
|
|
714
|
+
return;
|
|
715
|
+
}
|
|
664
716
|
|
|
665
717
|
const preValidationResult = this.preValidateReceivedMessage(msg, msgId, source);
|
|
666
718
|
|
|
667
719
|
if (!preValidationResult.result) {
|
|
668
720
|
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
721
|
}
|
|
675
722
|
|
|
723
|
+
// Determine topic type for attributes
|
|
676
724
|
if (msg.topic === this.topicStrings[TopicType.tx]) {
|
|
677
|
-
|
|
725
|
+
topicType = TopicType.tx;
|
|
726
|
+
} else if (msg.topic === this.topicStrings[TopicType.block_attestation]) {
|
|
727
|
+
topicType = TopicType.block_attestation;
|
|
728
|
+
} else if (msg.topic === this.topicStrings[TopicType.block_proposal]) {
|
|
729
|
+
topicType = TopicType.block_proposal;
|
|
678
730
|
}
|
|
679
|
-
|
|
680
|
-
|
|
731
|
+
|
|
732
|
+
// Process the message, optionally within a linked span for trace propagation
|
|
733
|
+
const processMessage = async () => {
|
|
734
|
+
if (msg.topic === this.topicStrings[TopicType.tx]) {
|
|
735
|
+
await this.handleGossipedTx(p2pMessage.payload, msgId, source);
|
|
736
|
+
}
|
|
737
|
+
if (msg.topic === this.topicStrings[TopicType.block_attestation]) {
|
|
738
|
+
if (this.clientType === P2PClientType.Full) {
|
|
739
|
+
await this.processAttestationFromPeer(p2pMessage.payload, msgId, source);
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
if (msg.topic === this.topicStrings[TopicType.block_proposal]) {
|
|
743
|
+
await this.processBlockFromPeer(p2pMessage.payload, msgId, source);
|
|
744
|
+
}
|
|
745
|
+
};
|
|
746
|
+
|
|
747
|
+
const latency = p2pMessage.timestamp !== undefined ? msgReceivedTime - p2pMessage.timestamp.getTime() : undefined;
|
|
748
|
+
const propagatedContext = p2pMessage.traceContext
|
|
749
|
+
? this.telemetry.extractPropagatedContext(p2pMessage.traceContext)
|
|
750
|
+
: undefined;
|
|
751
|
+
|
|
752
|
+
if (propagatedContext) {
|
|
753
|
+
await this.tracer.startActiveSpan(
|
|
754
|
+
'LibP2PService.processMessage',
|
|
755
|
+
{
|
|
756
|
+
attributes: {
|
|
757
|
+
[Attributes.TOPIC_NAME]: topicType!,
|
|
758
|
+
[Attributes.PEER_ID]: source.toString(),
|
|
759
|
+
},
|
|
760
|
+
},
|
|
761
|
+
propagatedContext,
|
|
762
|
+
async span => {
|
|
763
|
+
try {
|
|
764
|
+
await processMessage();
|
|
765
|
+
span.setStatus({
|
|
766
|
+
code: SpanStatusCode.OK,
|
|
767
|
+
});
|
|
768
|
+
} catch (err) {
|
|
769
|
+
span.setStatus({
|
|
770
|
+
code: SpanStatusCode.ERROR,
|
|
771
|
+
message: String(err),
|
|
772
|
+
});
|
|
773
|
+
if (typeof err === 'string' || (err && err instanceof Error)) {
|
|
774
|
+
span.recordException(err);
|
|
775
|
+
}
|
|
776
|
+
throw err;
|
|
777
|
+
} finally {
|
|
778
|
+
span.end();
|
|
779
|
+
}
|
|
780
|
+
},
|
|
781
|
+
);
|
|
782
|
+
} else {
|
|
783
|
+
await processMessage();
|
|
681
784
|
}
|
|
682
|
-
|
|
683
|
-
|
|
785
|
+
|
|
786
|
+
if (latency !== undefined && topicType !== undefined) {
|
|
787
|
+
this.instrumentation.recordMessageLatency(topicType, latency);
|
|
684
788
|
}
|
|
685
789
|
|
|
686
790
|
return;
|
|
687
791
|
}
|
|
688
792
|
|
|
689
793
|
protected async validateReceivedMessage<T>(
|
|
690
|
-
validationFunc: () => Promise<
|
|
794
|
+
validationFunc: () => Promise<ReceivedMessageValidationResult<T>>,
|
|
691
795
|
msgId: string,
|
|
692
796
|
source: PeerId,
|
|
693
797
|
topicType: TopicType,
|
|
694
|
-
): Promise<
|
|
695
|
-
let resultAndObj:
|
|
798
|
+
): Promise<ReceivedMessageValidationResult<T>> {
|
|
799
|
+
let resultAndObj: ReceivedMessageValidationResult<T> = { result: TopicValidatorResult.Reject };
|
|
696
800
|
const timer = new Timer();
|
|
697
801
|
try {
|
|
698
802
|
resultAndObj = await validationFunc();
|
|
699
803
|
} catch (err) {
|
|
700
|
-
this.
|
|
804
|
+
this.peerManager.penalizePeer(source, PeerErrorSeverity.LowToleranceError);
|
|
805
|
+
this.logger.error(`Error deserializing and validating gossipsub message`, err, {
|
|
806
|
+
msgId,
|
|
807
|
+
source: source.toString(),
|
|
808
|
+
topicType,
|
|
809
|
+
});
|
|
701
810
|
}
|
|
702
811
|
|
|
703
|
-
if (resultAndObj.result) {
|
|
812
|
+
if (resultAndObj.result === TopicValidatorResult.Accept) {
|
|
704
813
|
this.instrumentation.recordMessageValidation(topicType, timer);
|
|
705
814
|
}
|
|
706
815
|
|
|
707
|
-
this.node.services.pubsub.reportMessageValidationResult(
|
|
708
|
-
msgId,
|
|
709
|
-
source.toString(),
|
|
710
|
-
resultAndObj.result && resultAndObj.obj ? TopicValidatorResult.Accept : TopicValidatorResult.Reject,
|
|
711
|
-
);
|
|
816
|
+
this.node.services.pubsub.reportMessageValidationResult(msgId, source.toString(), resultAndObj.result);
|
|
712
817
|
return resultAndObj;
|
|
713
818
|
}
|
|
714
819
|
|
|
715
820
|
protected async handleGossipedTx(payloadData: Buffer, msgId: string, source: PeerId) {
|
|
716
|
-
const validationFunc = async () => {
|
|
821
|
+
const validationFunc: () => Promise<ReceivedMessageValidationResult<Tx>> = async () => {
|
|
717
822
|
const tx = Tx.fromBuffer(payloadData);
|
|
718
|
-
const
|
|
719
|
-
|
|
823
|
+
const isValid = await this.validatePropagatedTx(tx, source);
|
|
824
|
+
const exists = isValid && (await this.mempools.txPool.hasTx(tx.getTxHash()));
|
|
825
|
+
|
|
826
|
+
this.logger.trace(`Validate propagated tx`, {
|
|
827
|
+
isValid,
|
|
828
|
+
exists,
|
|
829
|
+
[Attributes.P2P_ID]: source.toString(),
|
|
830
|
+
});
|
|
831
|
+
|
|
832
|
+
if (!isValid) {
|
|
833
|
+
return { result: TopicValidatorResult.Reject };
|
|
834
|
+
} else if (exists) {
|
|
835
|
+
return { result: TopicValidatorResult.Ignore, obj: tx };
|
|
836
|
+
} else {
|
|
837
|
+
return { result: TopicValidatorResult.Accept, obj: tx };
|
|
838
|
+
}
|
|
720
839
|
};
|
|
721
840
|
|
|
722
841
|
const { result, obj: tx } = await this.validateReceivedMessage<Tx>(validationFunc, msgId, source, TopicType.tx);
|
|
723
|
-
if (
|
|
842
|
+
if (result !== TopicValidatorResult.Accept || !tx) {
|
|
724
843
|
return;
|
|
725
844
|
}
|
|
845
|
+
|
|
726
846
|
const txHash = tx.getTxHash();
|
|
727
847
|
const txHashString = txHash.toString();
|
|
728
848
|
this.logger.verbose(`Received tx ${txHashString} from external peer ${source.toString()} via gossip`, {
|
|
@@ -731,10 +851,11 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
731
851
|
});
|
|
732
852
|
|
|
733
853
|
if (this.config.dropTransactions && randomInt(1000) < this.config.dropTransactionsProbability * 1000) {
|
|
734
|
-
this.logger.
|
|
854
|
+
this.logger.warn(`Intentionally dropping tx ${txHashString} (probability rule)`);
|
|
735
855
|
return;
|
|
736
856
|
}
|
|
737
857
|
|
|
858
|
+
this.instrumentation.incrementTxReceived(1);
|
|
738
859
|
await this.mempools.txPool.addTxs([tx]);
|
|
739
860
|
}
|
|
740
861
|
|
|
@@ -745,14 +866,42 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
745
866
|
* @param attestation - The attestation to process.
|
|
746
867
|
*/
|
|
747
868
|
private async processAttestationFromPeer(payloadData: Buffer, msgId: string, source: PeerId): Promise<void> {
|
|
748
|
-
const validationFunc = async () => {
|
|
869
|
+
const validationFunc: () => Promise<ReceivedMessageValidationResult<BlockAttestation>> = async () => {
|
|
749
870
|
const attestation = BlockAttestation.fromBuffer(payloadData);
|
|
750
|
-
const
|
|
751
|
-
this.
|
|
871
|
+
const pool = this.mempools.attestationPool;
|
|
872
|
+
const isValid = await this.validateAttestation(source, attestation);
|
|
873
|
+
const exists = isValid && (await pool.hasAttestation(attestation));
|
|
874
|
+
|
|
875
|
+
let canAdd = true;
|
|
876
|
+
if (isValid && !exists) {
|
|
877
|
+
const slot = attestation.payload.header.slotNumber;
|
|
878
|
+
const { committee } = await this.epochCache.getCommittee(slot);
|
|
879
|
+
const committeeSize = committee?.length ?? 0;
|
|
880
|
+
canAdd = await pool.canAddAttestation(attestation, committeeSize);
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
this.logger.trace(`Validate propagated block attestation`, {
|
|
884
|
+
isValid,
|
|
885
|
+
exists,
|
|
886
|
+
canAdd,
|
|
752
887
|
[Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber.toString(),
|
|
753
888
|
[Attributes.P2P_ID]: source.toString(),
|
|
754
889
|
});
|
|
755
|
-
|
|
890
|
+
|
|
891
|
+
if (!isValid) {
|
|
892
|
+
return { result: TopicValidatorResult.Reject };
|
|
893
|
+
} else if (exists) {
|
|
894
|
+
return { result: TopicValidatorResult.Ignore, obj: attestation };
|
|
895
|
+
} else if (!canAdd) {
|
|
896
|
+
this.logger.warn(`Dropping block attestation due to per-(slot, proposalId) attestation cap`, {
|
|
897
|
+
slot: attestation.payload.header.slotNumber.toString(),
|
|
898
|
+
archive: attestation.archive.toString(),
|
|
899
|
+
source: source.toString(),
|
|
900
|
+
});
|
|
901
|
+
return { result: TopicValidatorResult.Ignore, obj: attestation };
|
|
902
|
+
} else {
|
|
903
|
+
return { result: TopicValidatorResult.Accept, obj: attestation };
|
|
904
|
+
}
|
|
756
905
|
};
|
|
757
906
|
|
|
758
907
|
const { result, obj: attestation } = await this.validateReceivedMessage<BlockAttestation>(
|
|
@@ -761,31 +910,56 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
761
910
|
source,
|
|
762
911
|
TopicType.block_attestation,
|
|
763
912
|
);
|
|
764
|
-
|
|
913
|
+
|
|
914
|
+
if (result !== TopicValidatorResult.Accept || !attestation) {
|
|
765
915
|
return;
|
|
766
916
|
}
|
|
917
|
+
|
|
767
918
|
this.logger.debug(
|
|
768
|
-
`Received attestation for
|
|
919
|
+
`Received attestation for slot ${attestation.slotNumber} from external peer ${source.toString()}`,
|
|
769
920
|
{
|
|
770
|
-
p2pMessageIdentifier: await attestation.
|
|
771
|
-
slot: attestation.slotNumber
|
|
921
|
+
p2pMessageIdentifier: await attestation.p2pMessageLoggingIdentifier(),
|
|
922
|
+
slot: attestation.slotNumber,
|
|
772
923
|
archive: attestation.archive.toString(),
|
|
773
|
-
block: attestation.blockNumber,
|
|
774
924
|
source: source.toString(),
|
|
775
925
|
},
|
|
776
926
|
);
|
|
777
|
-
|
|
927
|
+
|
|
928
|
+
await this.mempools.attestationPool.addAttestations([attestation]);
|
|
778
929
|
}
|
|
779
930
|
|
|
780
931
|
private async processBlockFromPeer(payloadData: Buffer, msgId: string, source: PeerId): Promise<void> {
|
|
781
|
-
const validationFunc = async () => {
|
|
932
|
+
const validationFunc: () => Promise<ReceivedMessageValidationResult<BlockProposal>> = async () => {
|
|
782
933
|
const block = BlockProposal.fromBuffer(payloadData);
|
|
783
|
-
const
|
|
784
|
-
this.
|
|
934
|
+
const isValid = await this.validateBlockProposal(source, block);
|
|
935
|
+
const pool = this.mempools.attestationPool;
|
|
936
|
+
|
|
937
|
+
const exists = isValid && (await pool.hasBlockProposal(block));
|
|
938
|
+
const canAdd = isValid && (await pool.canAddProposal(block));
|
|
939
|
+
|
|
940
|
+
this.logger.trace(`Validate propagated block proposal`, {
|
|
941
|
+
isValid,
|
|
942
|
+
exists,
|
|
943
|
+
canAdd,
|
|
785
944
|
[Attributes.SLOT_NUMBER]: block.payload.header.slotNumber.toString(),
|
|
786
945
|
[Attributes.P2P_ID]: source.toString(),
|
|
787
946
|
});
|
|
788
|
-
|
|
947
|
+
|
|
948
|
+
if (!isValid) {
|
|
949
|
+
return { result: TopicValidatorResult.Reject };
|
|
950
|
+
} else if (exists) {
|
|
951
|
+
return { result: TopicValidatorResult.Ignore, obj: block };
|
|
952
|
+
} else if (!canAdd) {
|
|
953
|
+
this.peerManager.penalizePeer(source, PeerErrorSeverity.MidToleranceError);
|
|
954
|
+
this.logger.warn(`Penalizing peer for block proposal exceeding per-slot cap`, {
|
|
955
|
+
slot: block.slotNumber.toString(),
|
|
956
|
+
archive: block.archive.toString(),
|
|
957
|
+
source: source.toString(),
|
|
958
|
+
});
|
|
959
|
+
return { result: TopicValidatorResult.Reject };
|
|
960
|
+
} else {
|
|
961
|
+
return { result: TopicValidatorResult.Accept, obj: block };
|
|
962
|
+
}
|
|
789
963
|
};
|
|
790
964
|
|
|
791
965
|
const { result, obj: block } = await this.validateReceivedMessage<BlockProposal>(
|
|
@@ -794,6 +968,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
794
968
|
source,
|
|
795
969
|
TopicType.block_proposal,
|
|
796
970
|
);
|
|
971
|
+
|
|
797
972
|
if (!result || !block) {
|
|
798
973
|
return;
|
|
799
974
|
}
|
|
@@ -803,48 +978,49 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
803
978
|
|
|
804
979
|
// REVIEW: callback pattern https://github.com/AztecProtocol/aztec-packages/issues/7963
|
|
805
980
|
@trackSpan('Libp2pService.processValidBlockProposal', async block => ({
|
|
806
|
-
[Attributes.
|
|
807
|
-
[Attributes.SLOT_NUMBER]: block.slotNumber.toNumber(),
|
|
981
|
+
[Attributes.SLOT_NUMBER]: block.slotNumber,
|
|
808
982
|
[Attributes.BLOCK_ARCHIVE]: block.archive.toString(),
|
|
809
|
-
[Attributes.P2P_ID]: await block.
|
|
983
|
+
[Attributes.P2P_ID]: await block.p2pMessageLoggingIdentifier().then(i => i.toString()),
|
|
810
984
|
}))
|
|
811
985
|
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
|
-
}
|
|
986
|
+
const slot = block.slotNumber;
|
|
987
|
+
const previousSlot = SlotNumber(slot - 1);
|
|
988
|
+
this.logger.verbose(`Received block proposal for slot ${slot} from external peer ${sender.toString()}.`, {
|
|
989
|
+
p2pMessageIdentifier: await block.p2pMessageLoggingIdentifier(),
|
|
990
|
+
slot: block.slotNumber,
|
|
991
|
+
archive: block.archive.toString(),
|
|
992
|
+
source: sender.toString(),
|
|
993
|
+
});
|
|
994
|
+
const attestationsForPreviousSlot = await this.mempools.attestationPool.getAttestationsForSlot(previousSlot);
|
|
995
|
+
this.logger.verbose(`Received ${attestationsForPreviousSlot.length} attestations for slot ${previousSlot}`);
|
|
829
996
|
|
|
830
|
-
//
|
|
997
|
+
// Attempt to add proposal, then mark the txs in this proposal as non-evictable
|
|
998
|
+
try {
|
|
999
|
+
await this.mempools.attestationPool.addBlockProposal(block);
|
|
1000
|
+
} catch (err: unknown) {
|
|
1001
|
+
// Drop proposals if we hit per-slot cap in the attestation pool; rethrow unknown errors
|
|
1002
|
+
if (err instanceof ProposalSlotCapExceededError) {
|
|
1003
|
+
this.logger.warn(`Dropping block proposal due to per-slot proposal cap`, {
|
|
1004
|
+
slot: String(slot),
|
|
1005
|
+
archive: block.archive.toString(),
|
|
1006
|
+
error: (err as Error).message,
|
|
1007
|
+
});
|
|
1008
|
+
return;
|
|
1009
|
+
}
|
|
1010
|
+
throw err;
|
|
1011
|
+
}
|
|
831
1012
|
await this.mempools.txPool.markTxsAsNonEvictable(block.txHashes);
|
|
832
|
-
await this.mempools.attestationPool?.addBlockProposal(block);
|
|
833
1013
|
const attestations = await this.blockReceivedCallback(block, sender);
|
|
834
1014
|
|
|
835
1015
|
// 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
|
|
1016
|
+
// The attestation can be undefined if no handler is registered / the validator deems the block invalid / in fisherman mode
|
|
837
1017
|
if (attestations?.length) {
|
|
838
1018
|
for (const attestation of attestations) {
|
|
839
|
-
this.logger.verbose(
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
archive: attestation.archive.toString(),
|
|
845
|
-
block: attestation.blockNumber,
|
|
846
|
-
},
|
|
847
|
-
);
|
|
1019
|
+
this.logger.verbose(`Broadcasting attestation for slot ${attestation.slotNumber}`, {
|
|
1020
|
+
p2pMessageIdentifier: await attestation.p2pMessageLoggingIdentifier(),
|
|
1021
|
+
slot: attestation.slotNumber,
|
|
1022
|
+
archive: attestation.archive.toString(),
|
|
1023
|
+
});
|
|
848
1024
|
await this.broadcastAttestation(attestation);
|
|
849
1025
|
}
|
|
850
1026
|
}
|
|
@@ -855,10 +1031,9 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
855
1031
|
* @param attestation - The attestation to broadcast.
|
|
856
1032
|
*/
|
|
857
1033
|
@trackSpan('Libp2pService.broadcastAttestation', async attestation => ({
|
|
858
|
-
[Attributes.
|
|
859
|
-
[Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber.toNumber(),
|
|
1034
|
+
[Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber,
|
|
860
1035
|
[Attributes.BLOCK_ARCHIVE]: attestation.archive.toString(),
|
|
861
|
-
[Attributes.P2P_ID]: await attestation.
|
|
1036
|
+
[Attributes.P2P_ID]: await attestation.p2pMessageLoggingIdentifier().then(i => i.toString()),
|
|
862
1037
|
}))
|
|
863
1038
|
private async broadcastAttestation(attestation: BlockAttestation) {
|
|
864
1039
|
await this.propagate(attestation);
|
|
@@ -869,15 +1044,100 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
869
1044
|
* @param message - The message to propagate.
|
|
870
1045
|
*/
|
|
871
1046
|
public async propagate<T extends Gossipable>(message: T) {
|
|
872
|
-
const p2pMessageIdentifier = await message.
|
|
1047
|
+
const p2pMessageIdentifier = await message.p2pMessageLoggingIdentifier();
|
|
873
1048
|
this.logger.trace(`Message ${p2pMessageIdentifier} queued`, { p2pMessageIdentifier });
|
|
874
|
-
void this.
|
|
875
|
-
.
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
1049
|
+
void this.sendToPeers(message).catch(error => {
|
|
1050
|
+
this.logger.error(`Error propagating message ${p2pMessageIdentifier}`, { error });
|
|
1051
|
+
});
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
/**
|
|
1055
|
+
* Validate the requested block transactions. Allow partial returns.
|
|
1056
|
+
* @param request - The block transactions request.
|
|
1057
|
+
* @param response - The block transactions response.
|
|
1058
|
+
* @param peerId - The ID of the peer that made the request.
|
|
1059
|
+
* @returns True if the requested block transactions are valid, false otherwise.
|
|
1060
|
+
*/
|
|
1061
|
+
@trackSpan('Libp2pService.validateRequestedBlockTxs', request => ({
|
|
1062
|
+
[Attributes.BLOCK_HASH]: request.blockHash.toString(),
|
|
1063
|
+
}))
|
|
1064
|
+
private async validateRequestedBlockTxs(
|
|
1065
|
+
request: BlockTxsRequest,
|
|
1066
|
+
response: BlockTxsResponse,
|
|
1067
|
+
peerId: PeerId,
|
|
1068
|
+
): Promise<boolean> {
|
|
1069
|
+
const requestedTxValidator = this.createRequestedTxValidator();
|
|
1070
|
+
|
|
1071
|
+
try {
|
|
1072
|
+
if (!response.blockHash.equals(request.blockHash)) {
|
|
1073
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
1074
|
+
throw new ValidationError(
|
|
1075
|
+
`Received block txs for unexpected block: expected ${request.blockHash.toString()}, got ${response.blockHash.toString()}`,
|
|
1076
|
+
);
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
if (response.txIndices.getLength() !== request.txIndices.getLength()) {
|
|
1080
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
1081
|
+
throw new ValidationError(
|
|
1082
|
+
`Received block txs with mismatched bitvector length: expected ${request.txIndices.getLength()}, got ${response.txIndices.getLength()}`,
|
|
1083
|
+
);
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
// Check no duplicates and not exceeding returnable count
|
|
1087
|
+
const requestedIndices = new Set(request.txIndices.getTrueIndices());
|
|
1088
|
+
const availableIndices = new Set(response.txIndices.getTrueIndices());
|
|
1089
|
+
const maxReturnable = [...requestedIndices].filter(i => availableIndices.has(i)).length;
|
|
1090
|
+
|
|
1091
|
+
const returnedHashes = await Promise.all(response.txs.map(tx => tx.getTxHash().toString()));
|
|
1092
|
+
const uniqueReturned = new Set(returnedHashes.map(h => h.toString()));
|
|
1093
|
+
if (uniqueReturned.size !== returnedHashes.length) {
|
|
1094
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
1095
|
+
throw new ValidationError(`Received duplicate txs in block txs response`);
|
|
1096
|
+
}
|
|
1097
|
+
if (response.txs.length > maxReturnable) {
|
|
1098
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
1099
|
+
throw new ValidationError(
|
|
1100
|
+
`Received more txs (${response.txs.length}) than requested-and-available (${maxReturnable})`,
|
|
1101
|
+
);
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
// Given proposal (should have locally), ensure returned txs are valid subset and match request indices
|
|
1105
|
+
const proposal = await this.mempools.attestationPool.getBlockProposal(request.blockHash.toString());
|
|
1106
|
+
if (proposal) {
|
|
1107
|
+
// Build intersected indices
|
|
1108
|
+
const intersectIdx = request.txIndices.getTrueIndices().filter(i => response.txIndices.isSet(i));
|
|
1109
|
+
|
|
1110
|
+
// Enforce subset membership and preserve increasing order by index.
|
|
1111
|
+
const hashToIndexInProposal = new Map<string, number>(
|
|
1112
|
+
proposal.txHashes.map((h, i) => [h.toString(), i] as [string, number]),
|
|
1113
|
+
);
|
|
1114
|
+
const allowedIndexSet = new Set(intersectIdx);
|
|
1115
|
+
const indices = returnedHashes.map(h => hashToIndexInProposal.get(h));
|
|
1116
|
+
const allAllowed = indices.every(idx => idx !== undefined && allowedIndexSet.has(idx));
|
|
1117
|
+
const strictlyIncreasing = indices.every((idx, i) => (i === 0 ? idx !== undefined : idx! > indices[i - 1]!));
|
|
1118
|
+
if (!allAllowed || !strictlyIncreasing) {
|
|
1119
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
|
|
1120
|
+
throw new ValidationError('Returned txs do not match expected subset/order for requested indices');
|
|
1121
|
+
}
|
|
1122
|
+
} else {
|
|
1123
|
+
// No local proposal, cannot check the membership/order of the returned txs
|
|
1124
|
+
this.logger.warn(
|
|
1125
|
+
`Block proposal not found for block hash ${request.blockHash.toString()}; cannot validate membership/order of returned txs`,
|
|
1126
|
+
);
|
|
1127
|
+
return false;
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
await Promise.all(response.txs.map(tx => this.validateRequestedTx(tx, peerId, requestedTxValidator)));
|
|
1131
|
+
return true;
|
|
1132
|
+
} catch (e: any) {
|
|
1133
|
+
if (e instanceof ValidationError) {
|
|
1134
|
+
this.logger.warn(`Failed validation for requested block txs from peer ${peerId.toString()}`);
|
|
1135
|
+
} else {
|
|
1136
|
+
this.logger.error(`Error during validation of requested block txs`, e);
|
|
1137
|
+
}
|
|
1138
|
+
|
|
1139
|
+
return false;
|
|
1140
|
+
}
|
|
881
1141
|
}
|
|
882
1142
|
|
|
883
1143
|
/**
|
|
@@ -890,47 +1150,113 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
890
1150
|
* ReqRespSubProtocol.TX subprotocol validation.
|
|
891
1151
|
*
|
|
892
1152
|
* @param requestedTxHash - The collection of the txs that was requested.
|
|
893
|
-
* @param responseTx - The
|
|
1153
|
+
* @param responseTx - The collection of txs that was received as a response to the request.
|
|
894
1154
|
* @param peerId - The peer ID of the peer that sent the tx.
|
|
895
1155
|
* @returns True if the whole collection of txs is valid, false otherwise.
|
|
896
1156
|
*/
|
|
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
1157
|
@trackSpan('Libp2pService.validateRequestedTx', (requestedTxHash, _responseTx) => ({
|
|
900
1158
|
[Attributes.TX_HASH]: requestedTxHash.toString(),
|
|
901
1159
|
}))
|
|
902
|
-
private async
|
|
1160
|
+
private async validateRequestedTxs(requestedTxHash: TxHash[], responseTx: Tx[], peerId: PeerId): Promise<boolean> {
|
|
903
1161
|
const requested = new Set(requestedTxHash.map(h => h.toString()));
|
|
1162
|
+
const requestedTxValidator = this.createRequestedTxValidator();
|
|
904
1163
|
|
|
905
|
-
|
|
906
|
-
|
|
1164
|
+
//TODO: (mralj) - this is somewhat naive implementation, if single tx is invlid we consider the whole response invalid.
|
|
1165
|
+
// I think we should still extract the valid txs and return them, so that we can still use the response.
|
|
907
1166
|
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
|
-
);
|
|
1167
|
+
await Promise.all(responseTx.map(tx => this.validateRequestedTx(tx, peerId, requestedTxValidator, requested)));
|
|
922
1168
|
return true;
|
|
923
1169
|
} catch (e: any) {
|
|
924
1170
|
if (e instanceof ValidationError) {
|
|
925
|
-
this.logger.
|
|
1171
|
+
this.logger.warn(`Failed to validate requested txs from peer ${peerId.toString()}, reason ${e.message}`);
|
|
926
1172
|
} else {
|
|
927
|
-
this.logger.
|
|
1173
|
+
this.logger.error(`Error during validation of requested txs`, e);
|
|
928
1174
|
}
|
|
929
1175
|
|
|
930
1176
|
return false;
|
|
931
1177
|
}
|
|
932
1178
|
}
|
|
933
1179
|
|
|
1180
|
+
/**
|
|
1181
|
+
* Validates a BLOCK response.
|
|
1182
|
+
*
|
|
1183
|
+
* If a local copy exists, enforces hash equality. If missing, rejects (no penalty) since the hash cannot be verified.
|
|
1184
|
+
* Penalizes on block number mismatch or hash mismatch.
|
|
1185
|
+
*
|
|
1186
|
+
* @param requestedBlockNumber - The requested block number.
|
|
1187
|
+
* @param responseBlock - The block returned by the peer.
|
|
1188
|
+
* @param peerId - The peer that returned the block.
|
|
1189
|
+
* @returns True if the response is valid, false otherwise.
|
|
1190
|
+
*/
|
|
1191
|
+
@trackSpan('Libp2pService.validateRequestedBlock', (requestedBlockNumber, _responseBlock) => ({
|
|
1192
|
+
[Attributes.BLOCK_NUMBER]: requestedBlockNumber.toString(),
|
|
1193
|
+
}))
|
|
1194
|
+
private async validateRequestedBlock(
|
|
1195
|
+
requestedBlockNumber: Fr,
|
|
1196
|
+
responseBlock: L2Block,
|
|
1197
|
+
peerId: PeerId,
|
|
1198
|
+
): Promise<boolean> {
|
|
1199
|
+
try {
|
|
1200
|
+
const reqNum = Number(requestedBlockNumber.toString());
|
|
1201
|
+
if (responseBlock.number !== reqNum) {
|
|
1202
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
|
|
1203
|
+
return false;
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1206
|
+
const local = await this.archiver.getBlock(BlockNumber(reqNum));
|
|
1207
|
+
if (!local) {
|
|
1208
|
+
// We are missing the local block; we cannot verify the hash yet. Reject without penalizing.
|
|
1209
|
+
// TODO: Consider extending this validator to accept an expected hash or
|
|
1210
|
+
// performing quorum-based checks when using P2P syncing prior to L1 sync.
|
|
1211
|
+
this.logger.warn(`Local block ${reqNum} not found; rejecting BLOCK response without hash verification`);
|
|
1212
|
+
return false;
|
|
1213
|
+
}
|
|
1214
|
+
const [localHash, respHash] = await Promise.all([local.hash(), responseBlock.hash()]);
|
|
1215
|
+
if (!localHash.equals(respHash)) {
|
|
1216
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
1217
|
+
return false;
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1220
|
+
return true;
|
|
1221
|
+
} catch (e) {
|
|
1222
|
+
this.logger.warn(`Error validating requested block`, e);
|
|
1223
|
+
return false;
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1226
|
+
|
|
1227
|
+
private createRequestedTxValidator(): TxValidator {
|
|
1228
|
+
return new AggregateTxValidator(
|
|
1229
|
+
new DataTxValidator(),
|
|
1230
|
+
new MetadataTxValidator({
|
|
1231
|
+
l1ChainId: new Fr(this.config.l1ChainId),
|
|
1232
|
+
rollupVersion: new Fr(this.config.rollupVersion),
|
|
1233
|
+
protocolContractsHash,
|
|
1234
|
+
vkTreeRoot: getVKTreeRoot(),
|
|
1235
|
+
}),
|
|
1236
|
+
new TxProofValidator(this.proofVerifier),
|
|
1237
|
+
);
|
|
1238
|
+
}
|
|
1239
|
+
|
|
1240
|
+
private async validateRequestedTx(tx: Tx, peerId: PeerId, txValidator: TxValidator, requested?: Set<`0x${string}`>) {
|
|
1241
|
+
const penalize = (severity: PeerErrorSeverity) => this.peerManager.penalizePeer(peerId, severity);
|
|
1242
|
+
|
|
1243
|
+
if (!(await tx.validateTxHash())) {
|
|
1244
|
+
penalize(PeerErrorSeverity.MidToleranceError);
|
|
1245
|
+
throw new ValidationError(`Received tx with invalid hash ${tx.getTxHash().toString()}.`);
|
|
1246
|
+
}
|
|
1247
|
+
|
|
1248
|
+
if (requested && !requested.has(tx.getTxHash().toString())) {
|
|
1249
|
+
penalize(PeerErrorSeverity.MidToleranceError);
|
|
1250
|
+
throw new ValidationError(`Received tx with hash ${tx.getTxHash().toString()} that was not requested.`);
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1253
|
+
const { result } = await txValidator.validateTx(tx);
|
|
1254
|
+
if (result === 'invalid') {
|
|
1255
|
+
penalize(PeerErrorSeverity.LowToleranceError);
|
|
1256
|
+
throw new ValidationError(`Received tx with hash ${tx.getTxHash().toString()} that is invalid.`);
|
|
1257
|
+
}
|
|
1258
|
+
}
|
|
1259
|
+
|
|
934
1260
|
@trackSpan('Libp2pService.validatePropagatedTx', tx => ({
|
|
935
1261
|
[Attributes.TX_HASH]: tx.getTxHash().toString(),
|
|
936
1262
|
}))
|
|
@@ -952,7 +1278,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
952
1278
|
|
|
953
1279
|
// Double spend validator has a special case handler
|
|
954
1280
|
if (name === 'doubleSpendValidator') {
|
|
955
|
-
const txBlockNumber = currentBlockNumber + 1; // tx is expected to be in the next block
|
|
1281
|
+
const txBlockNumber = BlockNumber(currentBlockNumber + 1); // tx is expected to be in the next block
|
|
956
1282
|
severity = await this.handleDoubleSpendFailure(tx, txBlockNumber);
|
|
957
1283
|
}
|
|
958
1284
|
|
|
@@ -962,7 +1288,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
962
1288
|
return true;
|
|
963
1289
|
}
|
|
964
1290
|
|
|
965
|
-
private async getGasFees(blockNumber:
|
|
1291
|
+
private async getGasFees(blockNumber: BlockNumber): Promise<GasFees> {
|
|
966
1292
|
if (blockNumber === this.feesCache?.blockNumber) {
|
|
967
1293
|
return this.feesCache.gasFees;
|
|
968
1294
|
}
|
|
@@ -1003,13 +1329,13 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1003
1329
|
* @returns The message validators.
|
|
1004
1330
|
*/
|
|
1005
1331
|
private async createMessageValidators(
|
|
1006
|
-
currentBlockNumber:
|
|
1332
|
+
currentBlockNumber: BlockNumber,
|
|
1007
1333
|
nextSlotTimestamp: UInt64,
|
|
1008
1334
|
): Promise<Record<string, MessageValidator>[]> {
|
|
1009
1335
|
const gasFees = await this.getGasFees(currentBlockNumber);
|
|
1010
1336
|
const allowedInSetup = this.config.txPublicSetupAllowList ?? (await getDefaultAllowedSetupFunctions());
|
|
1011
1337
|
|
|
1012
|
-
const blockNumberInWhichTheTxIsConsideredToBeIncluded = currentBlockNumber + 1;
|
|
1338
|
+
const blockNumberInWhichTheTxIsConsideredToBeIncluded = BlockNumber(currentBlockNumber + 1);
|
|
1013
1339
|
|
|
1014
1340
|
return createTxMessageValidators(
|
|
1015
1341
|
nextSlotTimestamp,
|
|
@@ -1018,7 +1344,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1018
1344
|
gasFees,
|
|
1019
1345
|
this.config.l1ChainId,
|
|
1020
1346
|
this.config.rollupVersion,
|
|
1021
|
-
|
|
1347
|
+
protocolContractsHash,
|
|
1022
1348
|
this.archiver,
|
|
1023
1349
|
this.proofVerifier,
|
|
1024
1350
|
!this.config.disableTransactions,
|
|
@@ -1071,7 +1397,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1071
1397
|
* @param peerId - The peer ID of the peer that sent the tx.
|
|
1072
1398
|
* @returns Severity
|
|
1073
1399
|
*/
|
|
1074
|
-
private async handleDoubleSpendFailure(tx: Tx, blockNumber:
|
|
1400
|
+
private async handleDoubleSpendFailure(tx: Tx, blockNumber: BlockNumber): Promise<PeerErrorSeverity> {
|
|
1075
1401
|
if (blockNumber <= this.config.doubleSpendSeverePeerPenaltyWindow) {
|
|
1076
1402
|
return PeerErrorSeverity.HighToleranceError;
|
|
1077
1403
|
}
|
|
@@ -1079,7 +1405,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1079
1405
|
const snapshotValidator = new DoubleSpendTxValidator({
|
|
1080
1406
|
nullifiersExist: async (nullifiers: Buffer[]) => {
|
|
1081
1407
|
const merkleTree = this.worldStateSynchronizer.getSnapshot(
|
|
1082
|
-
blockNumber - this.config.doubleSpendSeverePeerPenaltyWindow,
|
|
1408
|
+
BlockNumber(blockNumber - this.config.doubleSpendSeverePeerPenaltyWindow),
|
|
1083
1409
|
);
|
|
1084
1410
|
const indices = await merkleTree.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, nullifiers);
|
|
1085
1411
|
return indices.map(index => index !== undefined);
|
|
@@ -1101,10 +1427,9 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1101
1427
|
* @returns True if the attestation is valid, false otherwise.
|
|
1102
1428
|
*/
|
|
1103
1429
|
@trackSpan('Libp2pService.validateAttestation', async (_, attestation) => ({
|
|
1104
|
-
[Attributes.
|
|
1105
|
-
[Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber.toNumber(),
|
|
1430
|
+
[Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber,
|
|
1106
1431
|
[Attributes.BLOCK_ARCHIVE]: attestation.archive.toString(),
|
|
1107
|
-
[Attributes.P2P_ID]: await attestation.
|
|
1432
|
+
[Attributes.P2P_ID]: await attestation.p2pMessageLoggingIdentifier().then(i => i.toString()),
|
|
1108
1433
|
}))
|
|
1109
1434
|
public async validateAttestation(peerId: PeerId, attestation: BlockAttestation): Promise<boolean> {
|
|
1110
1435
|
const severity = await this.attestationValidator.validate(attestation);
|
|
@@ -1147,7 +1472,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1147
1472
|
private async sendToPeers<T extends Gossipable>(message: T) {
|
|
1148
1473
|
const parent = message.constructor as typeof Gossipable;
|
|
1149
1474
|
|
|
1150
|
-
const identifier = await message.
|
|
1475
|
+
const identifier = await message.p2pMessageLoggingIdentifier().then(i => i.toString());
|
|
1151
1476
|
this.logger.trace(`Sending message ${identifier}`, { p2pMessageIdentifier: identifier });
|
|
1152
1477
|
|
|
1153
1478
|
const recipientsNum = await this.publishToTopic(this.topicStrings[parent.p2pTopic], message);
|