@aztec/p2p 0.0.0-test.1 → 0.0.1-commit.03f7ef2
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 +22 -9
- package/dest/client/factory.d.ts +15 -5
- package/dest/client/factory.d.ts.map +1 -1
- package/dest/client/factory.js +60 -25
- package/dest/client/index.d.ts +2 -1
- package/dest/client/index.d.ts.map +1 -1
- package/dest/client/index.js +1 -0
- package/dest/client/interface.d.ts +157 -0
- package/dest/client/interface.d.ts.map +1 -0
- package/dest/client/interface.js +9 -0
- package/dest/client/p2p_client.d.ts +75 -190
- package/dest/client/p2p_client.d.ts.map +1 -1
- package/dest/client/p2p_client.js +381 -183
- package/dest/config.d.ts +151 -125
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +183 -34
- package/dest/enr/generate-enr.d.ts +11 -3
- package/dest/enr/generate-enr.d.ts.map +1 -1
- package/dest/enr/generate-enr.js +27 -5
- 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 +4 -1
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +2 -0
- package/dest/mem_pools/attestation_pool/attestation_pool.d.ts +68 -8
- 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 +216 -65
- package/dest/mem_pools/attestation_pool/index.d.ts +1 -1
- package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts +21 -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 +127 -26
- package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts +19 -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 +111 -21
- package/dest/mem_pools/attestation_pool/mocks.d.ts +227 -7
- package/dest/mem_pools/attestation_pool/mocks.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/mocks.js +10 -16
- package/dest/mem_pools/index.d.ts +1 -1
- package/dest/mem_pools/instrumentation.d.ts +16 -12
- package/dest/mem_pools/instrumentation.d.ts.map +1 -1
- package/dest/mem_pools/instrumentation.js +57 -35
- 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 +64 -14
- 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 +472 -97
- package/dest/mem_pools/tx_pool/index.d.ts +1 -1
- package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts +36 -11
- package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/memory_tx_pool.js +137 -36
- package/dest/mem_pools/tx_pool/priority.d.ts +1 -1
- package/dest/mem_pools/tx_pool/priority.js +1 -1
- package/dest/mem_pools/tx_pool/tx_pool.d.ts +67 -10
- 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 +273 -42
- 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 +45 -9
- 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 +6 -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 +73 -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 +10 -0
- package/dest/msg_validators/msg_seen_validator/msg_seen_validator.d.ts.map +1 -0
- package/dest/msg_validators/msg_seen_validator/msg_seen_validator.js +36 -0
- 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 +3 -0
- package/dest/msg_validators/tx_validator/allowed_public_setup.d.ts.map +1 -0
- package/dest/msg_validators/tx_validator/allowed_public_setup.js +27 -0
- package/dest/msg_validators/tx_validator/archive_cache.d.ts +14 -0
- package/dest/msg_validators/tx_validator/archive_cache.d.ts.map +1 -0
- package/dest/msg_validators/tx_validator/archive_cache.js +22 -0
- 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 +4 -4
- 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/data_validator.js +56 -86
- package/dest/msg_validators/tx_validator/double_spend_validator.d.ts +1 -3
- package/dest/msg_validators/tx_validator/double_spend_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/double_spend_validator.js +21 -27
- package/dest/msg_validators/tx_validator/factory.d.ts +16 -0
- package/dest/msg_validators/tx_validator/factory.d.ts.map +1 -0
- package/dest/msg_validators/tx_validator/factory.js +74 -0
- package/dest/msg_validators/tx_validator/gas_validator.d.ts +11 -0
- package/dest/msg_validators/tx_validator/gas_validator.d.ts.map +1 -0
- package/dest/msg_validators/tx_validator/gas_validator.js +115 -0
- package/dest/msg_validators/tx_validator/index.d.ts +8 -1
- package/dest/msg_validators/tx_validator/index.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/index.js +7 -0
- package/dest/msg_validators/tx_validator/metadata_validator.d.ts +9 -5
- package/dest/msg_validators/tx_validator/metadata_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/metadata_validator.js +39 -20
- package/dest/msg_validators/tx_validator/phases_validator.d.ts +14 -0
- package/dest/msg_validators/tx_validator/phases_validator.d.ts.map +1 -0
- package/dest/msg_validators/tx_validator/phases_validator.js +93 -0
- package/dest/msg_validators/tx_validator/test_utils.d.ts +17 -0
- package/dest/msg_validators/tx_validator/test_utils.d.ts.map +1 -0
- package/dest/msg_validators/tx_validator/test_utils.js +22 -0
- 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 +8 -0
- package/dest/msg_validators/tx_validator/tx_permitted_validator.d.ts.map +1 -0
- package/dest/msg_validators/tx_validator/tx_permitted_validator.js +24 -0
- 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/msg_validators/tx_validator/tx_proof_validator.js +6 -5
- 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 +10 -9
- package/dest/services/discv5/discV5_service.d.ts.map +1 -1
- package/dest/services/discv5/discV5_service.js +63 -36
- package/dest/services/dummy_service.d.ts +50 -11
- package/dest/services/dummy_service.d.ts.map +1 -1
- package/dest/services/dummy_service.js +88 -5
- package/dest/services/encoding.d.ts +26 -7
- 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 +5 -1
- package/dest/services/index.d.ts.map +1 -1
- package/dest/services/index.js +4 -0
- package/dest/services/libp2p/instrumentation.d.ts +20 -0
- package/dest/services/libp2p/instrumentation.d.ts.map +1 -0
- package/dest/services/libp2p/instrumentation.js +164 -0
- package/dest/services/libp2p/libp2p_service.d.ts +78 -89
- package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
- package/dest/services/libp2p/libp2p_service.js +695 -248
- package/dest/services/peer-manager/interface.d.ts +23 -0
- package/dest/services/peer-manager/interface.d.ts.map +1 -0
- package/dest/services/peer-manager/interface.js +1 -0
- package/dest/services/peer-manager/metrics.d.ts +6 -2
- package/dest/services/peer-manager/metrics.d.ts.map +1 -1
- package/dest/services/peer-manager/metrics.js +22 -2
- package/dest/services/peer-manager/peer_manager.d.ts +102 -22
- package/dest/services/peer-manager/peer_manager.d.ts.map +1 -1
- package/dest/services/peer-manager/peer_manager.js +549 -72
- 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 +11 -9
- package/dest/services/reqresp/config.d.ts.map +1 -1
- package/dest/services/reqresp/config.js +18 -4
- package/dest/services/reqresp/connection-sampler/batch_connection_sampler.d.ts +2 -2
- package/dest/services/reqresp/connection-sampler/batch_connection_sampler.d.ts.map +1 -1
- package/dest/services/reqresp/connection-sampler/batch_connection_sampler.js +10 -6
- package/dest/services/reqresp/connection-sampler/connection_sampler.d.ts +31 -17
- package/dest/services/reqresp/connection-sampler/connection_sampler.d.ts.map +1 -1
- package/dest/services/reqresp/connection-sampler/connection_sampler.js +142 -84
- package/dest/services/reqresp/index.d.ts +3 -2
- package/dest/services/reqresp/index.d.ts.map +1 -1
- package/dest/services/reqresp/index.js +2 -1
- package/dest/services/reqresp/interface.d.ts +73 -24
- package/dest/services/reqresp/interface.d.ts.map +1 -1
- package/dest/services/reqresp/interface.js +46 -27
- 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 +43 -0
- package/dest/services/reqresp/protocols/auth.d.ts.map +1 -0
- package/dest/services/reqresp/protocols/auth.js +71 -0
- package/dest/services/reqresp/protocols/block.d.ts +6 -1
- package/dest/services/reqresp/protocols/block.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/block.js +30 -6
- package/dest/services/reqresp/protocols/block_txs/bitvector.d.ts +30 -0
- package/dest/services/reqresp/protocols/block_txs/bitvector.d.ts.map +1 -0
- package/dest/services/reqresp/protocols/block_txs/bitvector.js +75 -0
- package/dest/services/reqresp/protocols/block_txs/block_txs_handler.d.ts +11 -0
- package/dest/services/reqresp/protocols/block_txs/block_txs_handler.d.ts.map +1 -0
- package/dest/services/reqresp/protocols/block_txs/block_txs_handler.js +39 -0
- package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.d.ts +47 -0
- package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.d.ts.map +1 -0
- package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.js +75 -0
- package/dest/services/reqresp/protocols/block_txs/index.d.ts +4 -0
- package/dest/services/reqresp/protocols/block_txs/index.d.ts.map +1 -0
- package/dest/services/reqresp/protocols/block_txs/index.js +3 -0
- package/dest/services/reqresp/protocols/goodbye.d.ts +3 -5
- package/dest/services/reqresp/protocols/goodbye.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/goodbye.js +7 -7
- package/dest/services/reqresp/protocols/index.d.ts +3 -1
- package/dest/services/reqresp/protocols/index.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/index.js +2 -0
- package/dest/services/reqresp/protocols/ping.d.ts +1 -3
- package/dest/services/reqresp/protocols/ping.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/status.d.ts +40 -7
- package/dest/services/reqresp/protocols/status.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/status.js +73 -5
- package/dest/services/reqresp/protocols/tx.d.ts +14 -4
- package/dest/services/reqresp/protocols/tx.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/tx.js +34 -6
- package/dest/services/reqresp/rate-limiter/index.d.ts +1 -1
- package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts +6 -4
- package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts.map +1 -1
- package/dest/services/reqresp/rate-limiter/rate_limiter.js +10 -2
- package/dest/services/reqresp/rate-limiter/rate_limits.d.ts +1 -1
- package/dest/services/reqresp/rate-limiter/rate_limits.d.ts.map +1 -1
- package/dest/services/reqresp/rate-limiter/rate_limits.js +21 -1
- package/dest/services/reqresp/reqresp.d.ts +24 -66
- package/dest/services/reqresp/reqresp.d.ts.map +1 -1
- package/dest/services/reqresp/reqresp.js +298 -207
- package/dest/services/reqresp/status.d.ts +10 -4
- package/dest/services/reqresp/status.d.ts.map +1 -1
- package/dest/services/reqresp/status.js +9 -2
- package/dest/services/service.d.ts +23 -19
- package/dest/services/service.d.ts.map +1 -1
- package/dest/services/tx_collection/config.d.ts +25 -0
- package/dest/services/tx_collection/config.d.ts.map +1 -0
- package/dest/services/tx_collection/config.js +58 -0
- package/dest/services/tx_collection/fast_tx_collection.d.ts +51 -0
- package/dest/services/tx_collection/fast_tx_collection.d.ts.map +1 -0
- package/dest/services/tx_collection/fast_tx_collection.js +300 -0
- package/dest/services/tx_collection/index.d.ts +3 -0
- package/dest/services/tx_collection/index.d.ts.map +1 -0
- package/dest/services/tx_collection/index.js +2 -0
- package/dest/services/tx_collection/instrumentation.d.ts +10 -0
- package/dest/services/tx_collection/instrumentation.d.ts.map +1 -0
- package/dest/services/tx_collection/instrumentation.js +34 -0
- package/dest/services/tx_collection/slow_tx_collection.d.ts +53 -0
- package/dest/services/tx_collection/slow_tx_collection.d.ts.map +1 -0
- package/dest/services/tx_collection/slow_tx_collection.js +177 -0
- package/dest/services/tx_collection/tx_collection.d.ts +110 -0
- package/dest/services/tx_collection/tx_collection.d.ts.map +1 -0
- package/dest/services/tx_collection/tx_collection.js +128 -0
- package/dest/services/tx_collection/tx_collection_sink.d.ts +30 -0
- package/dest/services/tx_collection/tx_collection_sink.d.ts.map +1 -0
- package/dest/services/tx_collection/tx_collection_sink.js +111 -0
- package/dest/services/tx_collection/tx_source.d.ts +18 -0
- package/dest/services/tx_collection/tx_source.d.ts.map +1 -0
- package/dest/services/tx_collection/tx_source.js +31 -0
- package/dest/services/tx_provider.d.ts +51 -0
- package/dest/services/tx_provider.d.ts.map +1 -0
- package/dest/services/tx_provider.js +217 -0
- package/dest/services/tx_provider_instrumentation.d.ts +16 -0
- package/dest/services/tx_provider_instrumentation.d.ts.map +1 -0
- package/dest/services/tx_provider_instrumentation.js +47 -0
- 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 +2 -1
- package/dest/test-helpers/index.d.ts.map +1 -1
- package/dest/test-helpers/index.js +1 -0
- package/dest/test-helpers/make-enrs.d.ts +1 -1
- package/dest/test-helpers/make-enrs.d.ts.map +1 -1
- package/dest/test-helpers/make-enrs.js +4 -5
- package/dest/test-helpers/make-test-p2p-clients.d.ts +33 -5
- package/dest/test-helpers/make-test-p2p-clients.d.ts.map +1 -1
- package/dest/test-helpers/make-test-p2p-clients.js +86 -16
- package/dest/test-helpers/mock-pubsub.d.ts +59 -0
- package/dest/test-helpers/mock-pubsub.d.ts.map +1 -0
- package/dest/test-helpers/mock-pubsub.js +130 -0
- 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 +15 -11
- package/dest/test-helpers/reqresp-nodes.d.ts.map +1 -1
- package/dest/test-helpers/reqresp-nodes.js +62 -28
- package/dest/testbench/p2p_client_testbench_worker.d.ts +1 -1
- package/dest/testbench/p2p_client_testbench_worker.js +103 -29
- package/dest/testbench/parse_log_file.d.ts +1 -1
- package/dest/testbench/parse_log_file.js +4 -4
- package/dest/testbench/testbench.d.ts +1 -1
- package/dest/testbench/testbench.js +4 -4
- package/dest/testbench/worker_client_manager.d.ts +1 -6
- package/dest/testbench/worker_client_manager.d.ts.map +1 -1
- package/dest/testbench/worker_client_manager.js +11 -19
- package/dest/types/index.d.ts +4 -2
- package/dest/types/index.d.ts.map +1 -1
- package/dest/types/index.js +2 -0
- package/dest/util.d.ts +24 -16
- package/dest/util.d.ts.map +1 -1
- package/dest/util.js +75 -69
- package/dest/versioning.d.ts +4 -4
- package/dest/versioning.d.ts.map +1 -1
- package/dest/versioning.js +8 -3
- package/package.json +32 -27
- package/src/bootstrap/bootstrap.ts +27 -11
- package/src/client/factory.ts +139 -53
- package/src/client/index.ts +1 -0
- package/src/client/interface.ts +198 -0
- package/src/client/p2p_client.ts +484 -348
- package/src/config.ts +305 -134
- package/src/enr/generate-enr.ts +39 -6
- package/src/errors/attestation-pool.error.ts +13 -0
- package/src/index.ts +4 -0
- package/src/mem_pools/attestation_pool/attestation_pool.ts +75 -7
- package/src/mem_pools/attestation_pool/attestation_pool_test_suite.ts +266 -67
- package/src/mem_pools/attestation_pool/kv_attestation_pool.ts +174 -35
- package/src/mem_pools/attestation_pool/memory_attestation_pool.ts +156 -30
- package/src/mem_pools/attestation_pool/mocks.ts +13 -12
- package/src/mem_pools/instrumentation.ts +70 -40
- package/src/mem_pools/interface.ts +2 -4
- package/src/mem_pools/tx_pool/aztec_kv_tx_pool.ts +555 -110
- package/src/mem_pools/tx_pool/memory_tx_pool.ts +160 -46
- package/src/mem_pools/tx_pool/priority.ts +1 -1
- package/src/mem_pools/tx_pool/tx_pool.ts +69 -9
- package/src/mem_pools/tx_pool/tx_pool_test_suite.ts +224 -35
- package/src/msg_validators/attestation_validator/attestation_validator.ts +54 -11
- 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 +82 -14
- package/src/msg_validators/msg_seen_validator/msg_seen_validator.ts +36 -0
- package/src/msg_validators/tx_validator/allowed_public_setup.ts +35 -0
- package/src/msg_validators/tx_validator/archive_cache.ts +28 -0
- package/src/msg_validators/tx_validator/block_header_validator.ts +5 -5
- package/src/msg_validators/tx_validator/data_validator.ts +81 -69
- package/src/msg_validators/tx_validator/double_spend_validator.ts +19 -17
- package/src/msg_validators/tx_validator/factory.ts +110 -0
- package/src/msg_validators/tx_validator/gas_validator.ts +134 -0
- package/src/msg_validators/tx_validator/index.ts +7 -0
- package/src/msg_validators/tx_validator/metadata_validator.ts +59 -22
- package/src/msg_validators/tx_validator/phases_validator.ts +116 -0
- package/src/msg_validators/tx_validator/test_utils.ts +43 -0
- package/src/msg_validators/tx_validator/timestamp_validator.ts +47 -0
- package/src/msg_validators/tx_validator/tx_permitted_validator.ts +17 -0
- package/src/msg_validators/tx_validator/tx_proof_validator.ts +6 -5
- package/src/services/discv5/discV5_service.ts +84 -38
- package/src/services/dummy_service.ts +147 -9
- package/src/services/encoding.ts +81 -6
- package/src/services/index.ts +4 -0
- package/src/services/libp2p/instrumentation.ts +167 -0
- package/src/services/libp2p/libp2p_service.ts +865 -298
- package/src/services/peer-manager/interface.ts +29 -0
- package/src/services/peer-manager/metrics.ts +26 -1
- package/src/services/peer-manager/peer_manager.ts +654 -78
- package/src/services/peer-manager/peer_scoring.ts +46 -3
- package/src/services/reqresp/config.ts +26 -9
- package/src/services/reqresp/connection-sampler/batch_connection_sampler.ts +12 -6
- package/src/services/reqresp/connection-sampler/connection_sampler.ts +148 -95
- package/src/services/reqresp/index.ts +2 -0
- package/src/services/reqresp/interface.ts +92 -37
- package/src/services/reqresp/metrics.ts +4 -1
- package/src/services/reqresp/protocols/auth.ts +83 -0
- package/src/services/reqresp/protocols/block.ts +26 -4
- package/src/services/reqresp/protocols/block_txs/bitvector.ts +90 -0
- package/src/services/reqresp/protocols/block_txs/block_txs_handler.ts +53 -0
- package/src/services/reqresp/protocols/block_txs/block_txs_reqresp.ts +79 -0
- package/src/services/reqresp/protocols/block_txs/index.ts +3 -0
- package/src/services/reqresp/protocols/goodbye.ts +9 -7
- package/src/services/reqresp/protocols/index.ts +2 -0
- package/src/services/reqresp/protocols/status.ts +118 -5
- package/src/services/reqresp/protocols/tx.ts +36 -8
- package/src/services/reqresp/rate-limiter/rate_limiter.ts +12 -3
- package/src/services/reqresp/rate-limiter/rate_limits.ts +21 -1
- package/src/services/reqresp/reqresp.ts +387 -256
- package/src/services/reqresp/status.ts +12 -3
- package/src/services/service.ts +45 -21
- package/src/services/tx_collection/config.ts +84 -0
- package/src/services/tx_collection/fast_tx_collection.ts +341 -0
- package/src/services/tx_collection/index.ts +2 -0
- package/src/services/tx_collection/instrumentation.ts +43 -0
- package/src/services/tx_collection/slow_tx_collection.ts +233 -0
- package/src/services/tx_collection/tx_collection.ts +216 -0
- package/src/services/tx_collection/tx_collection_sink.ts +129 -0
- package/src/services/tx_collection/tx_source.ts +37 -0
- package/src/services/tx_provider.ts +229 -0
- package/src/services/tx_provider_instrumentation.ts +61 -0
- package/src/test-helpers/index.ts +1 -0
- package/src/test-helpers/make-enrs.ts +4 -5
- package/src/test-helpers/make-test-p2p-clients.ts +111 -21
- package/src/test-helpers/mock-pubsub.ts +188 -0
- package/src/test-helpers/mock-tx-helpers.ts +24 -0
- package/src/test-helpers/reqresp-nodes.ts +87 -36
- package/src/testbench/p2p_client_testbench_worker.ts +151 -25
- package/src/testbench/parse_log_file.ts +4 -4
- package/src/testbench/testbench.ts +4 -4
- package/src/testbench/worker_client_manager.ts +17 -23
- package/src/types/index.ts +2 -0
- package/src/util.ts +105 -91
- package/src/versioning.ts +11 -4
|
@@ -4,13 +4,19 @@ function _ts_decorate(decorators, target, key, desc) {
|
|
|
4
4
|
else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
}
|
|
7
|
-
import {
|
|
7
|
+
import { BlockNumber, SlotNumber } from '@aztec/foundation/branded-types';
|
|
8
|
+
import { randomInt } from '@aztec/foundation/crypto/random';
|
|
9
|
+
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
8
10
|
import { createLibp2pComponentLogger, createLogger } from '@aztec/foundation/log';
|
|
9
|
-
import { SerialQueue } from '@aztec/foundation/queue';
|
|
10
11
|
import { RunningPromise } from '@aztec/foundation/running-promise';
|
|
11
|
-
import {
|
|
12
|
+
import { Timer } from '@aztec/foundation/timer';
|
|
13
|
+
import { getVKTreeRoot } from '@aztec/noir-protocol-circuits-types/vk-tree';
|
|
14
|
+
import { protocolContractsHash } from '@aztec/protocol-contracts';
|
|
15
|
+
import { GasFees } from '@aztec/stdlib/gas';
|
|
16
|
+
import { BlockAttestation, BlockProposal, P2PClientType, P2PMessage, PeerErrorSeverity, TopicType, createTopicString, getTopicsForClientAndConfig, metricsTopicStrToLabels } from '@aztec/stdlib/p2p';
|
|
12
17
|
import { MerkleTreeId } from '@aztec/stdlib/trees';
|
|
13
18
|
import { Tx } from '@aztec/stdlib/tx';
|
|
19
|
+
import { compressComponentVersions } from '@aztec/stdlib/versioning';
|
|
14
20
|
import { Attributes, OtelMetricsAdapter, WithTracer, trackSpan } from '@aztec/telemetry-client';
|
|
15
21
|
import { gossipsub } from '@chainsafe/libp2p-gossipsub';
|
|
16
22
|
import { createPeerScoreParams, createTopicScoreParams } from '@chainsafe/libp2p-gossipsub/score';
|
|
@@ -20,23 +26,31 @@ import { yamux } from '@chainsafe/libp2p-yamux';
|
|
|
20
26
|
import { bootstrap } from '@libp2p/bootstrap';
|
|
21
27
|
import { identify } from '@libp2p/identify';
|
|
22
28
|
import { TopicValidatorResult } from '@libp2p/interface';
|
|
23
|
-
import '@libp2p/kad-dht';
|
|
24
29
|
import { mplex } from '@libp2p/mplex';
|
|
25
30
|
import { tcp } from '@libp2p/tcp';
|
|
31
|
+
import { ENR } from '@nethermindeth/enr';
|
|
26
32
|
import { createLibp2p } from 'libp2p';
|
|
27
|
-
import {
|
|
28
|
-
import {
|
|
33
|
+
import { ProposalSlotCapExceededError } from '../../errors/attestation-pool.error.js';
|
|
34
|
+
import { AttestationValidator, BlockProposalValidator, FishermanAttestationValidator } from '../../msg_validators/index.js';
|
|
35
|
+
import { MessageSeenValidator } from '../../msg_validators/msg_seen_validator/msg_seen_validator.js';
|
|
36
|
+
import { getDefaultAllowedSetupFunctions } from '../../msg_validators/tx_validator/allowed_public_setup.js';
|
|
37
|
+
import { createTxMessageValidators } from '../../msg_validators/tx_validator/factory.js';
|
|
38
|
+
import { AggregateTxValidator, DataTxValidator, DoubleSpendTxValidator, MetadataTxValidator, TxProofValidator } from '../../msg_validators/tx_validator/index.js';
|
|
29
39
|
import { GossipSubEvent } from '../../types/index.js';
|
|
30
40
|
import { convertToMultiaddr } from '../../util.js';
|
|
41
|
+
import { getVersions } from '../../versioning.js';
|
|
31
42
|
import { AztecDatastore } from '../data_store.js';
|
|
43
|
+
import { DiscV5Service } from '../discv5/discV5_service.js';
|
|
32
44
|
import { SnappyTransform, fastMsgIdFn, getMsgIdFn, msgIdToStrFn } from '../encoding.js';
|
|
33
45
|
import { gossipScoreThresholds } from '../gossipsub/scoring.js';
|
|
34
46
|
import { PeerManager } from '../peer-manager/peer_manager.js';
|
|
35
47
|
import { PeerScoring } from '../peer-manager/peer_scoring.js';
|
|
36
|
-
import { DEFAULT_SUB_PROTOCOL_VALIDATORS, ReqRespSubProtocol } from '../reqresp/interface.js';
|
|
48
|
+
import { DEFAULT_SUB_PROTOCOL_VALIDATORS, ReqRespSubProtocol, ValidationError } from '../reqresp/interface.js';
|
|
49
|
+
import { reqRespBlockTxsHandler } from '../reqresp/protocols/block_txs/block_txs_handler.js';
|
|
37
50
|
import { reqGoodbyeHandler } from '../reqresp/protocols/goodbye.js';
|
|
38
|
-
import { pingHandler, reqRespBlockHandler,
|
|
51
|
+
import { pingHandler, reqRespBlockHandler, reqRespStatusHandler, reqRespTxHandler } from '../reqresp/protocols/index.js';
|
|
39
52
|
import { ReqResp } from '../reqresp/reqresp.js';
|
|
53
|
+
import { P2PInstrumentation } from './instrumentation.js';
|
|
40
54
|
/**
|
|
41
55
|
* Lib P2P implementation of the P2PService interface.
|
|
42
56
|
*/ export class LibP2PService extends WithTracer {
|
|
@@ -44,62 +58,104 @@ import { ReqResp } from '../reqresp/reqresp.js';
|
|
|
44
58
|
config;
|
|
45
59
|
node;
|
|
46
60
|
peerDiscoveryService;
|
|
61
|
+
reqresp;
|
|
62
|
+
peerManager;
|
|
47
63
|
mempools;
|
|
48
|
-
|
|
64
|
+
archiver;
|
|
65
|
+
epochCache;
|
|
49
66
|
proofVerifier;
|
|
50
67
|
worldStateSynchronizer;
|
|
51
|
-
logger;
|
|
52
|
-
jobQueue;
|
|
53
|
-
peerManager;
|
|
54
68
|
discoveryRunningPromise;
|
|
69
|
+
msgIdSeenValidators;
|
|
55
70
|
// Message validators
|
|
56
71
|
attestationValidator;
|
|
57
72
|
blockProposalValidator;
|
|
58
|
-
|
|
59
|
-
|
|
73
|
+
protocolVersion;
|
|
74
|
+
topicStrings;
|
|
75
|
+
feesCache;
|
|
60
76
|
/**
|
|
61
77
|
* Callback for when a block is received from a peer.
|
|
62
78
|
* @param block - The block received from the peer.
|
|
63
79
|
* @returns The attestation for the block, if any.
|
|
64
80
|
*/ blockReceivedCallback;
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
this.
|
|
70
|
-
//
|
|
71
|
-
this.
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
this.
|
|
75
|
-
this.
|
|
76
|
-
|
|
81
|
+
gossipSubEventHandler;
|
|
82
|
+
instrumentation;
|
|
83
|
+
logger;
|
|
84
|
+
constructor(clientType, config, node, peerDiscoveryService, reqresp, peerManager, mempools, archiver, epochCache, proofVerifier, worldStateSynchronizer, telemetry, logger = createLogger('p2p:libp2p_service')){
|
|
85
|
+
super(telemetry, 'LibP2PService'), this.clientType = clientType, this.config = config, this.node = node, this.peerDiscoveryService = peerDiscoveryService, this.reqresp = reqresp, this.peerManager = peerManager, this.mempools = mempools, this.archiver = archiver, this.epochCache = epochCache, this.proofVerifier = proofVerifier, this.worldStateSynchronizer = worldStateSynchronizer, this.msgIdSeenValidators = {}, this.protocolVersion = '', this.topicStrings = {};
|
|
86
|
+
// Create child logger with fisherman prefix if in fisherman mode
|
|
87
|
+
this.logger = config.fishermanMode ? logger.createChild('[FISHERMAN]') : logger;
|
|
88
|
+
this.instrumentation = new P2PInstrumentation(telemetry, 'LibP2PService');
|
|
89
|
+
this.msgIdSeenValidators[TopicType.tx] = new MessageSeenValidator(config.seenMessageCacheSize);
|
|
90
|
+
this.msgIdSeenValidators[TopicType.block_proposal] = new MessageSeenValidator(config.seenMessageCacheSize);
|
|
91
|
+
this.msgIdSeenValidators[TopicType.block_attestation] = new MessageSeenValidator(config.seenMessageCacheSize);
|
|
92
|
+
const versions = getVersions(config);
|
|
93
|
+
this.protocolVersion = compressComponentVersions(versions);
|
|
94
|
+
logger.info(`Started libp2p service with protocol version ${this.protocolVersion}`);
|
|
95
|
+
this.topicStrings[TopicType.tx] = createTopicString(TopicType.tx, this.protocolVersion);
|
|
96
|
+
this.topicStrings[TopicType.block_proposal] = createTopicString(TopicType.block_proposal, this.protocolVersion);
|
|
97
|
+
this.topicStrings[TopicType.block_attestation] = createTopicString(TopicType.block_attestation, this.protocolVersion);
|
|
98
|
+
// Use FishermanAttestationValidator in fisherman mode to validate attestation payloads against proposals
|
|
99
|
+
this.attestationValidator = config.fishermanMode ? new FishermanAttestationValidator(epochCache, mempools.attestationPool, telemetry) : new AttestationValidator(epochCache);
|
|
100
|
+
this.blockProposalValidator = new BlockProposalValidator(epochCache, {
|
|
101
|
+
txsPermitted: !config.disableTransactions
|
|
102
|
+
});
|
|
103
|
+
this.gossipSubEventHandler = this.handleGossipSubEvent.bind(this);
|
|
77
104
|
this.blockReceivedCallback = async (block)=>{
|
|
78
|
-
this.logger.debug(`Handler not yet registered: Block received callback not set. Received block for slot ${block.slotNumber
|
|
79
|
-
p2pMessageIdentifier: await block.
|
|
105
|
+
this.logger.debug(`Handler not yet registered: Block received callback not set. Received block for slot ${block.slotNumber} from peer.`, {
|
|
106
|
+
p2pMessageIdentifier: await block.p2pMessageLoggingIdentifier()
|
|
80
107
|
});
|
|
81
108
|
return undefined;
|
|
82
109
|
};
|
|
83
110
|
}
|
|
111
|
+
updateConfig(config) {
|
|
112
|
+
this.reqresp.updateConfig(config);
|
|
113
|
+
}
|
|
84
114
|
/**
|
|
85
115
|
* Creates an instance of the LibP2P service.
|
|
86
116
|
* @param config - The configuration to use when creating the service.
|
|
87
117
|
* @param txPool - The transaction pool to be accessed by the service.
|
|
88
118
|
* @returns The new service.
|
|
89
|
-
*/ static async new(clientType, config,
|
|
90
|
-
const {
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
const
|
|
94
|
-
const datastore = new AztecDatastore(store);
|
|
119
|
+
*/ static async new(clientType, config, peerId, deps) {
|
|
120
|
+
const { worldStateSynchronizer, epochCache, l2BlockSource, mempools, proofVerifier, peerStore, telemetry, logger, packageVersion } = deps;
|
|
121
|
+
const { p2pPort, maxPeerCount, listenAddress } = config;
|
|
122
|
+
const bindAddrTcp = convertToMultiaddr(listenAddress, p2pPort, 'tcp');
|
|
123
|
+
const datastore = new AztecDatastore(peerStore);
|
|
95
124
|
const otelMetricsAdapter = new OtelMetricsAdapter(telemetry);
|
|
96
|
-
|
|
125
|
+
const peerDiscoveryService = new DiscV5Service(peerId, config, packageVersion, telemetry, createLogger(`${logger.module}:discv5_service`));
|
|
126
|
+
// Seed libp2p's bootstrap discovery with private and trusted peers
|
|
127
|
+
const bootstrapNodes = [
|
|
128
|
+
...config.privatePeers,
|
|
129
|
+
...config.trustedPeers
|
|
130
|
+
];
|
|
97
131
|
const peerDiscovery = [];
|
|
98
|
-
if (
|
|
132
|
+
if (bootstrapNodes.length > 0) {
|
|
99
133
|
peerDiscovery.push(bootstrap({
|
|
100
|
-
list:
|
|
134
|
+
list: bootstrapNodes
|
|
101
135
|
}));
|
|
102
136
|
}
|
|
137
|
+
const versions = getVersions(config);
|
|
138
|
+
const protocolVersion = compressComponentVersions(versions);
|
|
139
|
+
const txTopic = createTopicString(TopicType.tx, protocolVersion);
|
|
140
|
+
const blockProposalTopic = createTopicString(TopicType.block_proposal, protocolVersion);
|
|
141
|
+
const blockAttestationTopic = createTopicString(TopicType.block_attestation, protocolVersion);
|
|
142
|
+
const preferredPeersEnrs = config.preferredPeers.map((enr)=>ENR.decodeTxt(enr));
|
|
143
|
+
const directPeers = (await Promise.all(preferredPeersEnrs.map(async (enr)=>{
|
|
144
|
+
const peerId = await enr.peerId();
|
|
145
|
+
const address = enr.getLocationMultiaddr('tcp');
|
|
146
|
+
if (address === undefined) {
|
|
147
|
+
throw new Error(`Direct peer ${peerId.toString()} has no TCP address, ENR: ${enr.encodeTxt()}`);
|
|
148
|
+
}
|
|
149
|
+
return {
|
|
150
|
+
id: peerId,
|
|
151
|
+
addrs: [
|
|
152
|
+
address
|
|
153
|
+
]
|
|
154
|
+
};
|
|
155
|
+
}))).filter((peer)=>peer !== undefined);
|
|
156
|
+
const announceTcpMultiaddr = config.p2pIp ? [
|
|
157
|
+
convertToMultiaddr(config.p2pIp, p2pPort, 'tcp')
|
|
158
|
+
] : [];
|
|
103
159
|
const node = await createLibp2p({
|
|
104
160
|
start: false,
|
|
105
161
|
peerId,
|
|
@@ -107,44 +163,76 @@ import { ReqResp } from '../reqresp/reqresp.js';
|
|
|
107
163
|
listen: [
|
|
108
164
|
bindAddrTcp
|
|
109
165
|
],
|
|
110
|
-
announce:
|
|
111
|
-
announceAddrTcp
|
|
112
|
-
]
|
|
166
|
+
announce: announceTcpMultiaddr
|
|
113
167
|
},
|
|
114
168
|
transports: [
|
|
115
169
|
tcp({
|
|
116
|
-
|
|
170
|
+
// It's better to have this number a bit higher than our maxPeerCount because it's sets the limit on transport (TCP) layer
|
|
171
|
+
// 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
|
|
172
|
+
// If we hit the limit, the connection will be temporarily accepted and immediately dropped.
|
|
173
|
+
// Docs: https://nodejs.org/api/net.html#servermaxconnections
|
|
174
|
+
maxConnections: maxPeerCount * 2,
|
|
117
175
|
// socket option: the maximum length of the queue of pending connections
|
|
118
|
-
// https://nodejs.org/dist/latest-
|
|
176
|
+
// https://nodejs.org/dist/latest-v22.x/docs/api/net.html#serverlisten
|
|
119
177
|
// it's not safe if we increase this number
|
|
120
178
|
backlog: 5,
|
|
121
179
|
closeServerOnMaxConnections: {
|
|
122
|
-
|
|
123
|
-
|
|
180
|
+
// The property `maxConnections` will protect us against the most DDOS attack
|
|
181
|
+
// This property protects us in case of burst of new connections where server is not able to close them quickly enough
|
|
182
|
+
// In case closeAbove is reached, the server stops listening altogether
|
|
183
|
+
// It's important that there is enough difference between closeAbove and listenAbove,
|
|
184
|
+
// otherwise the server.listener will flap between being closed and open potentially degrading perf even more
|
|
185
|
+
closeAbove: maxPeerCount * 3,
|
|
186
|
+
listenBelow: Math.floor(maxPeerCount * 0.9)
|
|
124
187
|
}
|
|
125
188
|
})
|
|
126
189
|
],
|
|
127
190
|
datastore,
|
|
128
191
|
peerDiscovery,
|
|
129
192
|
streamMuxers: [
|
|
130
|
-
|
|
131
|
-
|
|
193
|
+
yamux(),
|
|
194
|
+
mplex()
|
|
132
195
|
],
|
|
133
196
|
connectionEncryption: [
|
|
134
197
|
noise()
|
|
135
198
|
],
|
|
136
199
|
connectionManager: {
|
|
137
200
|
minConnections: 0,
|
|
201
|
+
// We set maxConnections above maxPeerCount because if we hit limit of maxPeerCount
|
|
202
|
+
// libp2p will start aggressively rejecting all new connections, preventing network discovery and crawling.
|
|
203
|
+
maxConnections: maxPeerCount * 2,
|
|
138
204
|
maxParallelDials: 100,
|
|
139
205
|
dialTimeout: 30_000,
|
|
140
206
|
maxPeerAddrsToDial: 5,
|
|
141
207
|
maxIncomingPendingConnections: 5
|
|
142
208
|
},
|
|
209
|
+
connectionGater: {
|
|
210
|
+
denyInboundConnection: (maConn)=>{
|
|
211
|
+
const allowed = peerManager.isNodeAllowedToConnect(maConn.remoteAddr.nodeAddress().address);
|
|
212
|
+
if (allowed) {
|
|
213
|
+
return false;
|
|
214
|
+
}
|
|
215
|
+
logger.debug(`Connection gater: Denying inbound connection from ${maConn.remoteAddr.toString()}`);
|
|
216
|
+
return true;
|
|
217
|
+
},
|
|
218
|
+
denyInboundEncryptedConnection: (peerId, _maConn)=>{
|
|
219
|
+
//NOTE: it is not necessary to check address here because this was already done by
|
|
220
|
+
// denyInboundConnection
|
|
221
|
+
const allowed = peerManager.isNodeAllowedToConnect(peerId);
|
|
222
|
+
if (allowed) {
|
|
223
|
+
return false;
|
|
224
|
+
}
|
|
225
|
+
logger.debug(`Connection gater: Denying inbound encrypted connection from ${peerId.toString()}`);
|
|
226
|
+
return true;
|
|
227
|
+
}
|
|
228
|
+
},
|
|
143
229
|
services: {
|
|
144
230
|
identify: identify({
|
|
145
|
-
protocolPrefix: 'aztec'
|
|
231
|
+
protocolPrefix: 'aztec',
|
|
232
|
+
runOnConnectionOpen: true
|
|
146
233
|
}),
|
|
147
234
|
pubsub: gossipsub({
|
|
235
|
+
directPeers,
|
|
148
236
|
debugName: 'gossipsub',
|
|
149
237
|
globalSignaturePolicy: SignaturePolicy.StrictNoSign,
|
|
150
238
|
allowPublishToZeroTopicPeers: true,
|
|
@@ -156,29 +244,30 @@ import { ReqResp } from '../reqresp/reqresp.js';
|
|
|
156
244
|
heartbeatInterval: config.gossipsubInterval,
|
|
157
245
|
mcacheLength: config.gossipsubMcacheLength,
|
|
158
246
|
mcacheGossip: config.gossipsubMcacheGossip,
|
|
247
|
+
seenTTL: config.gossipsubSeenTTL,
|
|
159
248
|
msgIdFn: getMsgIdFn,
|
|
160
249
|
msgIdToStrFn: msgIdToStrFn,
|
|
161
250
|
fastMsgIdFn: fastMsgIdFn,
|
|
162
251
|
dataTransform: new SnappyTransform(),
|
|
163
252
|
metricsRegister: otelMetricsAdapter,
|
|
164
|
-
metricsTopicStrToLabel: metricsTopicStrToLabels(),
|
|
253
|
+
metricsTopicStrToLabel: metricsTopicStrToLabels(protocolVersion),
|
|
165
254
|
asyncValidation: true,
|
|
166
255
|
scoreThresholds: gossipScoreThresholds,
|
|
167
256
|
scoreParams: createPeerScoreParams({
|
|
168
257
|
// IPColocation factor can be disabled for local testing - default to -5
|
|
169
258
|
IPColocationFactorWeight: config.debugDisableColocationPenalty ? 0 : -5.0,
|
|
170
259
|
topics: {
|
|
171
|
-
[
|
|
260
|
+
[txTopic]: createTopicScoreParams({
|
|
172
261
|
topicWeight: 1,
|
|
173
262
|
invalidMessageDeliveriesWeight: -20,
|
|
174
263
|
invalidMessageDeliveriesDecay: 0.5
|
|
175
264
|
}),
|
|
176
|
-
[
|
|
265
|
+
[blockAttestationTopic]: createTopicScoreParams({
|
|
177
266
|
topicWeight: 1,
|
|
178
267
|
invalidMessageDeliveriesWeight: -20,
|
|
179
268
|
invalidMessageDeliveriesDecay: 0.5
|
|
180
269
|
}),
|
|
181
|
-
[
|
|
270
|
+
[blockProposalTopic]: createTopicScoreParams({
|
|
182
271
|
topicWeight: 1,
|
|
183
272
|
invalidMessageDeliveriesWeight: -20,
|
|
184
273
|
invalidMessageDeliveriesDecay: 0.5
|
|
@@ -192,7 +281,13 @@ import { ReqResp } from '../reqresp/reqresp.js';
|
|
|
192
281
|
},
|
|
193
282
|
logger: createLibp2pComponentLogger(logger.module)
|
|
194
283
|
});
|
|
195
|
-
|
|
284
|
+
const peerScoring = new PeerScoring(config, telemetry);
|
|
285
|
+
const reqresp = new ReqResp(config, node, peerScoring, createLogger(`${logger.module}:reqresp`));
|
|
286
|
+
const peerManager = new PeerManager(node, peerDiscoveryService, config, telemetry, createLogger(`${logger.module}:peer_manager`), peerScoring, reqresp, worldStateSynchronizer, protocolVersion, epochCache);
|
|
287
|
+
// Update gossipsub score params
|
|
288
|
+
node.services.pubsub.score.params.appSpecificWeight = 10;
|
|
289
|
+
node.services.pubsub.score.params.appSpecificScore = (peerId)=>peerManager.shouldDisableP2PGossip(peerId) ? -Infinity : peerManager.getPeerScore(peerId);
|
|
290
|
+
return new LibP2PService(clientType, config, node, peerDiscoveryService, reqresp, peerManager, mempools, l2BlockSource, epochCache, proofVerifier, worldStateSynchronizer, telemetry, logger);
|
|
196
291
|
}
|
|
197
292
|
/**
|
|
198
293
|
* Starts the LibP2P service.
|
|
@@ -203,44 +298,56 @@ import { ReqResp } from '../reqresp/reqresp.js';
|
|
|
203
298
|
throw new Error('P2P service already started');
|
|
204
299
|
}
|
|
205
300
|
// Get listen & announce addresses for logging
|
|
206
|
-
const {
|
|
207
|
-
if (!
|
|
301
|
+
const { p2pIp, p2pPort } = this.config;
|
|
302
|
+
if (!p2pIp) {
|
|
208
303
|
throw new Error('Announce address not provided.');
|
|
209
304
|
}
|
|
210
|
-
const announceTcpMultiaddr = convertToMultiaddr(
|
|
211
|
-
|
|
212
|
-
this.
|
|
213
|
-
|
|
305
|
+
const announceTcpMultiaddr = convertToMultiaddr(p2pIp, p2pPort, 'tcp');
|
|
306
|
+
await this.peerManager.initializePeers();
|
|
307
|
+
if (!this.config.p2pDiscoveryDisabled) {
|
|
308
|
+
await this.peerDiscoveryService.start();
|
|
309
|
+
}
|
|
214
310
|
await this.node.start();
|
|
215
311
|
// Subscribe to standard GossipSub topics by default
|
|
216
|
-
for (const topic of
|
|
217
|
-
this.subscribeToTopic(
|
|
312
|
+
for (const topic of getTopicsForClientAndConfig(this.clientType, this.config.disableTransactions)){
|
|
313
|
+
this.subscribeToTopic(this.topicStrings[topic]);
|
|
218
314
|
}
|
|
219
315
|
// Create request response protocol handlers
|
|
220
316
|
const txHandler = reqRespTxHandler(this.mempools);
|
|
221
317
|
const goodbyeHandler = reqGoodbyeHandler(this.peerManager);
|
|
222
|
-
const blockHandler = reqRespBlockHandler(this.
|
|
318
|
+
const blockHandler = reqRespBlockHandler(this.archiver);
|
|
319
|
+
const statusHandler = reqRespStatusHandler(this.protocolVersion, this.worldStateSynchronizer, this.logger);
|
|
223
320
|
const requestResponseHandlers = {
|
|
224
321
|
[ReqRespSubProtocol.PING]: pingHandler,
|
|
225
|
-
[ReqRespSubProtocol.STATUS]: statusHandler,
|
|
226
|
-
[ReqRespSubProtocol.TX]: txHandler.bind(this),
|
|
322
|
+
[ReqRespSubProtocol.STATUS]: statusHandler.bind(this),
|
|
227
323
|
[ReqRespSubProtocol.GOODBYE]: goodbyeHandler.bind(this),
|
|
228
324
|
[ReqRespSubProtocol.BLOCK]: blockHandler.bind(this)
|
|
229
325
|
};
|
|
326
|
+
if (!this.config.disableTransactions) {
|
|
327
|
+
const blockTxsHandler = reqRespBlockTxsHandler(this.mempools.attestationPool, this.mempools.txPool);
|
|
328
|
+
requestResponseHandlers[ReqRespSubProtocol.BLOCK_TXS] = blockTxsHandler.bind(this);
|
|
329
|
+
}
|
|
330
|
+
if (!this.config.disableTransactions) {
|
|
331
|
+
requestResponseHandlers[ReqRespSubProtocol.TX] = txHandler.bind(this);
|
|
332
|
+
}
|
|
230
333
|
// add GossipSub listener
|
|
231
|
-
this.node.services.pubsub.addEventListener(GossipSubEvent.MESSAGE, this.
|
|
232
|
-
// Start running promise for peer discovery
|
|
233
|
-
this.discoveryRunningPromise = new RunningPromise(()=>
|
|
334
|
+
this.node.services.pubsub.addEventListener(GossipSubEvent.MESSAGE, this.gossipSubEventHandler);
|
|
335
|
+
// Start running promise for peer discovery and metrics collection
|
|
336
|
+
this.discoveryRunningPromise = new RunningPromise(async ()=>{
|
|
337
|
+
await this.peerManager.heartbeat();
|
|
338
|
+
}, this.logger, this.config.peerCheckIntervalMS);
|
|
234
339
|
this.discoveryRunningPromise.start();
|
|
235
340
|
// Define the sub protocol validators - This is done within this start() method to gain a callback to the existing validateTx function
|
|
236
341
|
const reqrespSubProtocolValidators = {
|
|
237
342
|
...DEFAULT_SUB_PROTOCOL_VALIDATORS,
|
|
238
|
-
|
|
239
|
-
[ReqRespSubProtocol.
|
|
343
|
+
[ReqRespSubProtocol.TX]: this.validateRequestedTxs.bind(this),
|
|
344
|
+
[ReqRespSubProtocol.BLOCK_TXS]: this.validateRequestedBlockTxs.bind(this),
|
|
345
|
+
[ReqRespSubProtocol.BLOCK]: this.validateRequestedBlock.bind(this)
|
|
240
346
|
};
|
|
241
347
|
await this.reqresp.start(requestResponseHandlers, reqrespSubProtocolValidators);
|
|
242
348
|
this.logger.info(`Started P2P service`, {
|
|
243
|
-
listen:
|
|
349
|
+
listen: this.config.listenAddress,
|
|
350
|
+
port: this.config.p2pPort,
|
|
244
351
|
announce: announceTcpMultiaddr,
|
|
245
352
|
peerId: this.node.peerId.toString()
|
|
246
353
|
});
|
|
@@ -250,12 +357,10 @@ import { ReqResp } from '../reqresp/reqresp.js';
|
|
|
250
357
|
* @returns An empty promise.
|
|
251
358
|
*/ async stop() {
|
|
252
359
|
// Remove gossip sub listener
|
|
253
|
-
this.node.services.pubsub.removeEventListener(GossipSubEvent.MESSAGE, this.
|
|
360
|
+
this.node.services.pubsub.removeEventListener(GossipSubEvent.MESSAGE, this.gossipSubEventHandler);
|
|
254
361
|
// Stop peer manager
|
|
255
362
|
this.logger.debug('Stopping peer manager...');
|
|
256
363
|
await this.peerManager.stop();
|
|
257
|
-
this.logger.debug('Stopping job queue...');
|
|
258
|
-
await this.jobQueue.end();
|
|
259
364
|
this.logger.debug('Stopping running promise...');
|
|
260
365
|
await this.discoveryRunningPromise?.stop();
|
|
261
366
|
this.logger.debug('Stopping peer discovery service...');
|
|
@@ -266,6 +371,12 @@ import { ReqResp } from '../reqresp/reqresp.js';
|
|
|
266
371
|
await this.stopLibP2P();
|
|
267
372
|
this.logger.info('LibP2P service stopped');
|
|
268
373
|
}
|
|
374
|
+
addReqRespSubProtocol(subProtocol, handler, validator) {
|
|
375
|
+
return this.reqresp.addSubProtocol(subProtocol, handler, validator);
|
|
376
|
+
}
|
|
377
|
+
registerThisValidatorAddresses(address) {
|
|
378
|
+
this.peerManager.registerThisValidatorAddresses(address);
|
|
379
|
+
}
|
|
269
380
|
getPeers(includePending) {
|
|
270
381
|
return this.peerManager.getPeers(includePending);
|
|
271
382
|
}
|
|
@@ -281,24 +392,12 @@ import { ReqResp } from '../reqresp/reqresp.js';
|
|
|
281
392
|
setImmediate(()=>void safeJob());
|
|
282
393
|
}
|
|
283
394
|
/**
|
|
284
|
-
* Send Request via the ReqResp service
|
|
285
|
-
* The subprotocol defined will determine the request and response types
|
|
286
|
-
*
|
|
287
|
-
* See the subProtocolMap for the mapping of subprotocols to request/response types in `interface.ts`
|
|
288
|
-
*
|
|
289
|
-
* @param protocol The request response protocol to use
|
|
290
|
-
* @param request The request type to send
|
|
291
|
-
* @returns
|
|
292
|
-
*/ sendRequest(protocol, request) {
|
|
293
|
-
return this.reqresp.sendRequest(protocol, request);
|
|
294
|
-
}
|
|
295
|
-
/**
|
|
296
395
|
* Send a batch of requests to peers, and return the responses
|
|
297
396
|
* @param protocol - The request response protocol to use
|
|
298
397
|
* @param requests - The requests to send to the peers
|
|
299
398
|
* @returns The responses to the requests
|
|
300
|
-
*/ sendBatchRequest(protocol, requests) {
|
|
301
|
-
return this.reqresp.sendBatchRequest(protocol, requests);
|
|
399
|
+
*/ sendBatchRequest(protocol, requests, pinnedPeerId) {
|
|
400
|
+
return this.reqresp.sendBatchRequest(protocol, requests, pinnedPeerId);
|
|
302
401
|
}
|
|
303
402
|
/**
|
|
304
403
|
* Get the ENR of the node
|
|
@@ -308,7 +407,6 @@ import { ReqResp } from '../reqresp/reqresp.js';
|
|
|
308
407
|
}
|
|
309
408
|
registerBlockReceivedCallback(callback) {
|
|
310
409
|
this.blockReceivedCallback = callback;
|
|
311
|
-
this.logger.verbose('Block received callback registered');
|
|
312
410
|
}
|
|
313
411
|
/**
|
|
314
412
|
* Subscribes to a topic.
|
|
@@ -322,133 +420,322 @@ import { ReqResp } from '../reqresp/reqresp.js';
|
|
|
322
420
|
/**
|
|
323
421
|
* Publishes data to a topic.
|
|
324
422
|
* @param topic - The topic to publish to.
|
|
325
|
-
* @param data - The
|
|
423
|
+
* @param data - The message to publish.
|
|
326
424
|
* @returns The number of recipients the data was sent to.
|
|
327
|
-
*/ async publishToTopic(topic,
|
|
425
|
+
*/ async publishToTopic(topic, message) {
|
|
328
426
|
if (!this.node.services.pubsub) {
|
|
329
427
|
throw new Error('Pubsub service not available.');
|
|
330
428
|
}
|
|
331
|
-
const
|
|
429
|
+
const p2pMessage = P2PMessage.fromGossipable(message, this.config.debugP2PInstrumentMessages);
|
|
430
|
+
const result = await this.node.services.pubsub.publish(topic, p2pMessage.toMessageData());
|
|
332
431
|
return result.recipients.length;
|
|
333
432
|
}
|
|
334
433
|
/**
|
|
434
|
+
* Checks if this message has already been seen, based on its msgId computed from hashing the message data.
|
|
435
|
+
* Note that we do not rely on the seenCache from gossipsub since we want to keep a longer history of seen
|
|
436
|
+
* messages to avoid tx echoes across the network.
|
|
437
|
+
*/ preValidateReceivedMessage(msg, msgId, source) {
|
|
438
|
+
let topicType;
|
|
439
|
+
switch(msg.topic){
|
|
440
|
+
case this.topicStrings[TopicType.tx]:
|
|
441
|
+
topicType = TopicType.tx;
|
|
442
|
+
break;
|
|
443
|
+
case this.topicStrings[TopicType.block_attestation]:
|
|
444
|
+
topicType = TopicType.block_attestation;
|
|
445
|
+
break;
|
|
446
|
+
case this.topicStrings[TopicType.block_proposal]:
|
|
447
|
+
topicType = TopicType.block_proposal;
|
|
448
|
+
break;
|
|
449
|
+
default:
|
|
450
|
+
this.logger.error(`Received message on unknown topic: ${msg.topic}`);
|
|
451
|
+
break;
|
|
452
|
+
}
|
|
453
|
+
const validator = topicType ? this.msgIdSeenValidators[topicType] : undefined;
|
|
454
|
+
if (!validator || !validator.addMessage(msgId)) {
|
|
455
|
+
this.instrumentation.incMessagePrevalidationStatus(false, topicType);
|
|
456
|
+
this.node.services.pubsub.reportMessageValidationResult(msgId, source.toString(), TopicValidatorResult.Ignore);
|
|
457
|
+
return {
|
|
458
|
+
result: false,
|
|
459
|
+
topicType
|
|
460
|
+
};
|
|
461
|
+
}
|
|
462
|
+
this.instrumentation.incMessagePrevalidationStatus(true, topicType);
|
|
463
|
+
return {
|
|
464
|
+
result: true,
|
|
465
|
+
topicType
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
/**
|
|
469
|
+
* Safely deserializes a P2PMessage from raw message data.
|
|
470
|
+
* @param msgId - The message ID.
|
|
471
|
+
* @param source - The peer ID of the message source.
|
|
472
|
+
* @param data - The raw message data.
|
|
473
|
+
* @returns The deserialized P2PMessage or undefined if deserialization fails.
|
|
474
|
+
*/ safelyDeserializeP2PMessage(msgId, source, data) {
|
|
475
|
+
try {
|
|
476
|
+
return P2PMessage.fromMessageData(Buffer.from(data), this.config.debugP2PInstrumentMessages);
|
|
477
|
+
} catch (err) {
|
|
478
|
+
this.logger.error(`Error deserializing P2PMessage`, err, {
|
|
479
|
+
msgId,
|
|
480
|
+
source: source.toString()
|
|
481
|
+
});
|
|
482
|
+
this.node.services.pubsub.reportMessageValidationResult(msgId, source.toString(), TopicValidatorResult.Reject);
|
|
483
|
+
this.peerManager.penalizePeer(source, PeerErrorSeverity.LowToleranceError);
|
|
484
|
+
return undefined;
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
/**
|
|
335
488
|
* Handles a new gossip message that was received by the client.
|
|
336
489
|
* @param topic - The message's topic.
|
|
337
490
|
* @param data - The message data
|
|
338
491
|
*/ async handleNewGossipMessage(msg, msgId, source) {
|
|
339
|
-
|
|
340
|
-
|
|
492
|
+
const msgReceivedTime = Date.now();
|
|
493
|
+
let topicType;
|
|
494
|
+
const p2pMessage = this.safelyDeserializeP2PMessage(msgId, source, msg.data);
|
|
495
|
+
if (!p2pMessage) {
|
|
496
|
+
return;
|
|
497
|
+
}
|
|
498
|
+
const preValidationResult = this.preValidateReceivedMessage(msg, msgId, source);
|
|
499
|
+
if (!preValidationResult.result) {
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
502
|
+
if (msg.topic === this.topicStrings[TopicType.tx]) {
|
|
503
|
+
topicType = TopicType.tx;
|
|
504
|
+
await this.handleGossipedTx(p2pMessage.payload, msgId, source);
|
|
341
505
|
}
|
|
342
|
-
if (msg.topic ===
|
|
343
|
-
|
|
506
|
+
if (msg.topic === this.topicStrings[TopicType.block_attestation]) {
|
|
507
|
+
topicType = TopicType.block_attestation;
|
|
508
|
+
if (this.clientType === P2PClientType.Full) {
|
|
509
|
+
await this.processAttestationFromPeer(p2pMessage.payload, msgId, source);
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
if (msg.topic === this.topicStrings[TopicType.block_proposal]) {
|
|
513
|
+
topicType = TopicType.block_proposal;
|
|
514
|
+
await this.processBlockFromPeer(p2pMessage.payload, msgId, source);
|
|
344
515
|
}
|
|
345
|
-
if (
|
|
346
|
-
|
|
516
|
+
if (p2pMessage.timestamp !== undefined && topicType !== undefined) {
|
|
517
|
+
const latency = msgReceivedTime - p2pMessage.timestamp.getTime();
|
|
518
|
+
this.instrumentation.recordMessageLatency(topicType, latency);
|
|
347
519
|
}
|
|
348
520
|
return;
|
|
349
521
|
}
|
|
350
|
-
async validateReceivedMessage(validationFunc, msgId, source) {
|
|
522
|
+
async validateReceivedMessage(validationFunc, msgId, source, topicType) {
|
|
351
523
|
let resultAndObj = {
|
|
352
|
-
result:
|
|
353
|
-
obj: undefined
|
|
524
|
+
result: TopicValidatorResult.Reject
|
|
354
525
|
};
|
|
526
|
+
const timer = new Timer();
|
|
355
527
|
try {
|
|
356
528
|
resultAndObj = await validationFunc();
|
|
357
529
|
} catch (err) {
|
|
358
|
-
this.
|
|
530
|
+
this.peerManager.penalizePeer(source, PeerErrorSeverity.LowToleranceError);
|
|
531
|
+
this.logger.error(`Error deserializing and validating gossipsub message`, err, {
|
|
532
|
+
msgId,
|
|
533
|
+
source: source.toString(),
|
|
534
|
+
topicType
|
|
535
|
+
});
|
|
536
|
+
}
|
|
537
|
+
if (resultAndObj.result === TopicValidatorResult.Accept) {
|
|
538
|
+
this.instrumentation.recordMessageValidation(topicType, timer);
|
|
359
539
|
}
|
|
360
|
-
this.node.services.pubsub.reportMessageValidationResult(msgId, source.toString(), resultAndObj.result
|
|
540
|
+
this.node.services.pubsub.reportMessageValidationResult(msgId, source.toString(), resultAndObj.result);
|
|
361
541
|
return resultAndObj;
|
|
362
542
|
}
|
|
363
|
-
async handleGossipedTx(
|
|
543
|
+
async handleGossipedTx(payloadData, msgId, source) {
|
|
364
544
|
const validationFunc = async ()=>{
|
|
365
|
-
const tx = Tx.fromBuffer(
|
|
366
|
-
const
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
545
|
+
const tx = Tx.fromBuffer(payloadData);
|
|
546
|
+
const isValid = await this.validatePropagatedTx(tx, source);
|
|
547
|
+
const exists = isValid && await this.mempools.txPool.hasTx(tx.getTxHash());
|
|
548
|
+
this.logger.trace(`Validate propagated tx`, {
|
|
549
|
+
isValid,
|
|
550
|
+
exists,
|
|
551
|
+
[Attributes.P2P_ID]: source.toString()
|
|
552
|
+
});
|
|
553
|
+
if (!isValid) {
|
|
554
|
+
return {
|
|
555
|
+
result: TopicValidatorResult.Reject
|
|
556
|
+
};
|
|
557
|
+
} else if (exists) {
|
|
558
|
+
return {
|
|
559
|
+
result: TopicValidatorResult.Ignore,
|
|
560
|
+
obj: tx
|
|
561
|
+
};
|
|
562
|
+
} else {
|
|
563
|
+
return {
|
|
564
|
+
result: TopicValidatorResult.Accept,
|
|
565
|
+
obj: tx
|
|
566
|
+
};
|
|
567
|
+
}
|
|
371
568
|
};
|
|
372
|
-
const { result, obj: tx } = await this.validateReceivedMessage(validationFunc, msgId, source);
|
|
373
|
-
if (
|
|
569
|
+
const { result, obj: tx } = await this.validateReceivedMessage(validationFunc, msgId, source, TopicType.tx);
|
|
570
|
+
if (result !== TopicValidatorResult.Accept || !tx) {
|
|
374
571
|
return;
|
|
375
572
|
}
|
|
376
|
-
const txHash =
|
|
573
|
+
const txHash = tx.getTxHash();
|
|
377
574
|
const txHashString = txHash.toString();
|
|
378
|
-
this.logger.verbose(`Received tx ${txHashString} from external peer ${source.toString()}
|
|
575
|
+
this.logger.verbose(`Received tx ${txHashString} from external peer ${source.toString()} via gossip`, {
|
|
576
|
+
source: source.toString(),
|
|
577
|
+
txHash: txHashString
|
|
578
|
+
});
|
|
579
|
+
if (this.config.dropTransactions && randomInt(1000) < this.config.dropTransactionsProbability * 1000) {
|
|
580
|
+
this.logger.warn(`Intentionally dropping tx ${txHashString} (probability rule)`);
|
|
581
|
+
return;
|
|
582
|
+
}
|
|
583
|
+
this.instrumentation.incrementTxReceived(1);
|
|
379
584
|
await this.mempools.txPool.addTxs([
|
|
380
585
|
tx
|
|
381
586
|
]);
|
|
382
587
|
}
|
|
383
|
-
/**
|
|
588
|
+
/**
|
|
589
|
+
* Process Attestation From Peer
|
|
384
590
|
* When a proposal is received from a peer, we add it to the attestation pool, so it can be accessed by other services.
|
|
385
591
|
*
|
|
386
592
|
* @param attestation - The attestation to process.
|
|
387
|
-
*/ async processAttestationFromPeer(
|
|
593
|
+
*/ async processAttestationFromPeer(payloadData, msgId, source) {
|
|
388
594
|
const validationFunc = async ()=>{
|
|
389
|
-
const attestation = BlockAttestation.fromBuffer(
|
|
390
|
-
const
|
|
391
|
-
this.
|
|
392
|
-
|
|
595
|
+
const attestation = BlockAttestation.fromBuffer(payloadData);
|
|
596
|
+
const pool = this.mempools.attestationPool;
|
|
597
|
+
const isValid = await this.validateAttestation(source, attestation);
|
|
598
|
+
const exists = isValid && await pool.hasAttestation(attestation);
|
|
599
|
+
let canAdd = true;
|
|
600
|
+
if (isValid && !exists) {
|
|
601
|
+
const slot = attestation.payload.header.slotNumber;
|
|
602
|
+
const { committee } = await this.epochCache.getCommittee(slot);
|
|
603
|
+
const committeeSize = committee?.length ?? 0;
|
|
604
|
+
canAdd = await pool.canAddAttestation(attestation, committeeSize);
|
|
605
|
+
}
|
|
606
|
+
this.logger.trace(`Validate propagated block attestation`, {
|
|
607
|
+
isValid,
|
|
608
|
+
exists,
|
|
609
|
+
canAdd,
|
|
610
|
+
[Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber.toString(),
|
|
393
611
|
[Attributes.P2P_ID]: source.toString()
|
|
394
612
|
});
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
613
|
+
if (!isValid) {
|
|
614
|
+
return {
|
|
615
|
+
result: TopicValidatorResult.Reject
|
|
616
|
+
};
|
|
617
|
+
} else if (exists) {
|
|
618
|
+
return {
|
|
619
|
+
result: TopicValidatorResult.Ignore,
|
|
620
|
+
obj: attestation
|
|
621
|
+
};
|
|
622
|
+
} else if (!canAdd) {
|
|
623
|
+
this.logger.warn(`Dropping block attestation due to per-(slot, proposalId) attestation cap`, {
|
|
624
|
+
slot: attestation.payload.header.slotNumber.toString(),
|
|
625
|
+
archive: attestation.archive.toString(),
|
|
626
|
+
source: source.toString()
|
|
627
|
+
});
|
|
628
|
+
return {
|
|
629
|
+
result: TopicValidatorResult.Ignore,
|
|
630
|
+
obj: attestation
|
|
631
|
+
};
|
|
632
|
+
} else {
|
|
633
|
+
return {
|
|
634
|
+
result: TopicValidatorResult.Accept,
|
|
635
|
+
obj: attestation
|
|
636
|
+
};
|
|
637
|
+
}
|
|
399
638
|
};
|
|
400
|
-
const { result, obj: attestation } = await this.validateReceivedMessage(validationFunc, msgId, source);
|
|
401
|
-
if (
|
|
639
|
+
const { result, obj: attestation } = await this.validateReceivedMessage(validationFunc, msgId, source, TopicType.block_attestation);
|
|
640
|
+
if (result !== TopicValidatorResult.Accept || !attestation) {
|
|
402
641
|
return;
|
|
403
642
|
}
|
|
404
|
-
this.logger.debug(`Received attestation for
|
|
405
|
-
p2pMessageIdentifier: await attestation.
|
|
406
|
-
slot: attestation.slotNumber
|
|
643
|
+
this.logger.debug(`Received attestation for slot ${attestation.slotNumber} from external peer ${source.toString()}`, {
|
|
644
|
+
p2pMessageIdentifier: await attestation.p2pMessageLoggingIdentifier(),
|
|
645
|
+
slot: attestation.slotNumber,
|
|
407
646
|
archive: attestation.archive.toString(),
|
|
408
|
-
|
|
647
|
+
source: source.toString()
|
|
409
648
|
});
|
|
410
649
|
await this.mempools.attestationPool.addAttestations([
|
|
411
650
|
attestation
|
|
412
651
|
]);
|
|
413
652
|
}
|
|
414
|
-
async processBlockFromPeer(
|
|
653
|
+
async processBlockFromPeer(payloadData, msgId, source) {
|
|
415
654
|
const validationFunc = async ()=>{
|
|
416
|
-
const block = BlockProposal.fromBuffer(
|
|
417
|
-
const
|
|
418
|
-
this.
|
|
419
|
-
|
|
655
|
+
const block = BlockProposal.fromBuffer(payloadData);
|
|
656
|
+
const isValid = await this.validateBlockProposal(source, block);
|
|
657
|
+
const pool = this.mempools.attestationPool;
|
|
658
|
+
const exists = isValid && await pool.hasBlockProposal(block);
|
|
659
|
+
const canAdd = isValid && await pool.canAddProposal(block);
|
|
660
|
+
this.logger.trace(`Validate propagated block proposal`, {
|
|
661
|
+
isValid,
|
|
662
|
+
exists,
|
|
663
|
+
canAdd,
|
|
664
|
+
[Attributes.SLOT_NUMBER]: block.payload.header.slotNumber.toString(),
|
|
420
665
|
[Attributes.P2P_ID]: source.toString()
|
|
421
666
|
});
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
667
|
+
if (!isValid) {
|
|
668
|
+
return {
|
|
669
|
+
result: TopicValidatorResult.Reject
|
|
670
|
+
};
|
|
671
|
+
} else if (exists) {
|
|
672
|
+
return {
|
|
673
|
+
result: TopicValidatorResult.Ignore,
|
|
674
|
+
obj: block
|
|
675
|
+
};
|
|
676
|
+
} else if (!canAdd) {
|
|
677
|
+
this.peerManager.penalizePeer(source, PeerErrorSeverity.MidToleranceError);
|
|
678
|
+
this.logger.warn(`Penalizing peer for block proposal exceeding per-slot cap`, {
|
|
679
|
+
slot: block.slotNumber.toString(),
|
|
680
|
+
archive: block.archive.toString(),
|
|
681
|
+
source: source.toString()
|
|
682
|
+
});
|
|
683
|
+
return {
|
|
684
|
+
result: TopicValidatorResult.Reject
|
|
685
|
+
};
|
|
686
|
+
} else {
|
|
687
|
+
return {
|
|
688
|
+
result: TopicValidatorResult.Accept,
|
|
689
|
+
obj: block
|
|
690
|
+
};
|
|
691
|
+
}
|
|
426
692
|
};
|
|
427
|
-
const { result, obj: block } = await this.validateReceivedMessage(validationFunc, msgId, source);
|
|
693
|
+
const { result, obj: block } = await this.validateReceivedMessage(validationFunc, msgId, source, TopicType.block_proposal);
|
|
428
694
|
if (!result || !block) {
|
|
429
695
|
return;
|
|
430
696
|
}
|
|
431
|
-
await this.processValidBlockProposal(block);
|
|
697
|
+
await this.processValidBlockProposal(block, source);
|
|
432
698
|
}
|
|
433
699
|
// REVIEW: callback pattern https://github.com/AztecProtocol/aztec-packages/issues/7963
|
|
434
|
-
async processValidBlockProposal(block) {
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
700
|
+
async processValidBlockProposal(block, sender) {
|
|
701
|
+
const slot = block.slotNumber;
|
|
702
|
+
const previousSlot = SlotNumber(slot - 1);
|
|
703
|
+
this.logger.verbose(`Received block proposal for slot ${slot} from external peer ${sender.toString()}.`, {
|
|
704
|
+
p2pMessageIdentifier: await block.p2pMessageLoggingIdentifier(),
|
|
705
|
+
slot: block.slotNumber,
|
|
438
706
|
archive: block.archive.toString(),
|
|
439
|
-
|
|
707
|
+
source: sender.toString()
|
|
440
708
|
});
|
|
441
|
-
const
|
|
709
|
+
const attestationsForPreviousSlot = await this.mempools.attestationPool.getAttestationsForSlot(previousSlot);
|
|
710
|
+
this.logger.verbose(`Received ${attestationsForPreviousSlot.length} attestations for slot ${previousSlot}`);
|
|
711
|
+
// Attempt to add proposal, then mark the txs in this proposal as non-evictable
|
|
712
|
+
try {
|
|
713
|
+
await this.mempools.attestationPool.addBlockProposal(block);
|
|
714
|
+
} catch (err) {
|
|
715
|
+
// Drop proposals if we hit per-slot cap in the attestation pool; rethrow unknown errors
|
|
716
|
+
if (err instanceof ProposalSlotCapExceededError) {
|
|
717
|
+
this.logger.warn(`Dropping block proposal due to per-slot proposal cap`, {
|
|
718
|
+
slot: String(slot),
|
|
719
|
+
archive: block.archive.toString(),
|
|
720
|
+
error: err.message
|
|
721
|
+
});
|
|
722
|
+
return;
|
|
723
|
+
}
|
|
724
|
+
throw err;
|
|
725
|
+
}
|
|
726
|
+
await this.mempools.txPool.markTxsAsNonEvictable(block.txHashes);
|
|
727
|
+
const attestations = await this.blockReceivedCallback(block, sender);
|
|
442
728
|
// TODO: fix up this pattern - the abstraction is not nice
|
|
443
|
-
// The attestation can be undefined if no handler is registered / the validator deems the block invalid
|
|
444
|
-
if (
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
729
|
+
// The attestation can be undefined if no handler is registered / the validator deems the block invalid / in fisherman mode
|
|
730
|
+
if (attestations?.length) {
|
|
731
|
+
for (const attestation of attestations){
|
|
732
|
+
this.logger.verbose(`Broadcasting attestation for slot ${attestation.slotNumber}`, {
|
|
733
|
+
p2pMessageIdentifier: await attestation.p2pMessageLoggingIdentifier(),
|
|
734
|
+
slot: attestation.slotNumber,
|
|
735
|
+
archive: attestation.archive.toString()
|
|
736
|
+
});
|
|
737
|
+
await this.broadcastAttestation(attestation);
|
|
738
|
+
}
|
|
452
739
|
}
|
|
453
740
|
}
|
|
454
741
|
/**
|
|
@@ -461,96 +748,242 @@ import { ReqResp } from '../reqresp/reqresp.js';
|
|
|
461
748
|
* Propagates provided message to peers.
|
|
462
749
|
* @param message - The message to propagate.
|
|
463
750
|
*/ async propagate(message) {
|
|
464
|
-
const p2pMessageIdentifier = await message.
|
|
751
|
+
const p2pMessageIdentifier = await message.p2pMessageLoggingIdentifier();
|
|
465
752
|
this.logger.trace(`Message ${p2pMessageIdentifier} queued`, {
|
|
466
753
|
p2pMessageIdentifier
|
|
467
754
|
});
|
|
468
|
-
void this.
|
|
469
|
-
await this.sendToPeers(message);
|
|
470
|
-
}).catch((error)=>{
|
|
755
|
+
void this.sendToPeers(message).catch((error)=>{
|
|
471
756
|
this.logger.error(`Error propagating message ${p2pMessageIdentifier}`, {
|
|
472
757
|
error
|
|
473
758
|
});
|
|
474
759
|
});
|
|
475
760
|
}
|
|
476
761
|
/**
|
|
477
|
-
* Validate
|
|
762
|
+
* Validate the requested block transactions. Allow partial returns.
|
|
763
|
+
* @param request - The block transactions request.
|
|
764
|
+
* @param response - The block transactions response.
|
|
765
|
+
* @param peerId - The ID of the peer that made the request.
|
|
766
|
+
* @returns True if the requested block transactions are valid, false otherwise.
|
|
767
|
+
*/ async validateRequestedBlockTxs(request, response, peerId) {
|
|
768
|
+
const requestedTxValidator = this.createRequestedTxValidator();
|
|
769
|
+
try {
|
|
770
|
+
if (!response.blockHash.equals(request.blockHash)) {
|
|
771
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
772
|
+
throw new ValidationError(`Received block txs for unexpected block: expected ${request.blockHash.toString()}, got ${response.blockHash.toString()}`);
|
|
773
|
+
}
|
|
774
|
+
if (response.txIndices.getLength() !== request.txIndices.getLength()) {
|
|
775
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
776
|
+
throw new ValidationError(`Received block txs with mismatched bitvector length: expected ${request.txIndices.getLength()}, got ${response.txIndices.getLength()}`);
|
|
777
|
+
}
|
|
778
|
+
// Check no duplicates and not exceeding returnable count
|
|
779
|
+
const requestedIndices = new Set(request.txIndices.getTrueIndices());
|
|
780
|
+
const availableIndices = new Set(response.txIndices.getTrueIndices());
|
|
781
|
+
const maxReturnable = [
|
|
782
|
+
...requestedIndices
|
|
783
|
+
].filter((i)=>availableIndices.has(i)).length;
|
|
784
|
+
const returnedHashes = await Promise.all(response.txs.map((tx)=>tx.getTxHash().toString()));
|
|
785
|
+
const uniqueReturned = new Set(returnedHashes.map((h)=>h.toString()));
|
|
786
|
+
if (uniqueReturned.size !== returnedHashes.length) {
|
|
787
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
788
|
+
throw new ValidationError(`Received duplicate txs in block txs response`);
|
|
789
|
+
}
|
|
790
|
+
if (response.txs.length > maxReturnable) {
|
|
791
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
792
|
+
throw new ValidationError(`Received more txs (${response.txs.length}) than requested-and-available (${maxReturnable})`);
|
|
793
|
+
}
|
|
794
|
+
// Given proposal (should have locally), ensure returned txs are valid subset and match request indices
|
|
795
|
+
const proposal = await this.mempools.attestationPool.getBlockProposal(request.blockHash.toString());
|
|
796
|
+
if (proposal) {
|
|
797
|
+
// Build intersected indices
|
|
798
|
+
const intersectIdx = request.txIndices.getTrueIndices().filter((i)=>response.txIndices.isSet(i));
|
|
799
|
+
// Enforce subset membership and preserve increasing order by index.
|
|
800
|
+
const hashToIndexInProposal = new Map(proposal.txHashes.map((h, i)=>[
|
|
801
|
+
h.toString(),
|
|
802
|
+
i
|
|
803
|
+
]));
|
|
804
|
+
const allowedIndexSet = new Set(intersectIdx);
|
|
805
|
+
const indices = returnedHashes.map((h)=>hashToIndexInProposal.get(h));
|
|
806
|
+
const allAllowed = indices.every((idx)=>idx !== undefined && allowedIndexSet.has(idx));
|
|
807
|
+
const strictlyIncreasing = indices.every((idx, i)=>i === 0 ? idx !== undefined : idx > indices[i - 1]);
|
|
808
|
+
if (!allAllowed || !strictlyIncreasing) {
|
|
809
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
|
|
810
|
+
throw new ValidationError('Returned txs do not match expected subset/order for requested indices');
|
|
811
|
+
}
|
|
812
|
+
} else {
|
|
813
|
+
// No local proposal, cannot check the membership/order of the returned txs
|
|
814
|
+
this.logger.warn(`Block proposal not found for block hash ${request.blockHash.toString()}; cannot validate membership/order of returned txs`);
|
|
815
|
+
return false;
|
|
816
|
+
}
|
|
817
|
+
await Promise.all(response.txs.map((tx)=>this.validateRequestedTx(tx, peerId, requestedTxValidator)));
|
|
818
|
+
return true;
|
|
819
|
+
} catch (e) {
|
|
820
|
+
if (e instanceof ValidationError) {
|
|
821
|
+
this.logger.warn(`Failed validation for requested block txs from peer ${peerId.toString()}`);
|
|
822
|
+
} else {
|
|
823
|
+
this.logger.error(`Error during validation of requested block txs`, e);
|
|
824
|
+
}
|
|
825
|
+
return false;
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
/**
|
|
829
|
+
* Validate a collection of txs that has been requested from a peer.
|
|
478
830
|
*
|
|
479
|
-
* The core component of this validator is that
|
|
831
|
+
* The core component of this validator is that each tx hash MUST match the requested tx hash,
|
|
480
832
|
* In order to perform this check, the tx proof must be verified.
|
|
481
833
|
*
|
|
482
834
|
* Note: This function is called from within `ReqResp.sendRequest` as part of the
|
|
483
835
|
* ReqRespSubProtocol.TX subprotocol validation.
|
|
484
836
|
*
|
|
485
|
-
* @param requestedTxHash - The
|
|
486
|
-
* @param responseTx - The
|
|
837
|
+
* @param requestedTxHash - The collection of the txs that was requested.
|
|
838
|
+
* @param responseTx - The collection of txs that was received as a response to the request.
|
|
487
839
|
* @param peerId - The peer ID of the peer that sent the tx.
|
|
488
|
-
* @returns True if the
|
|
489
|
-
*/ async
|
|
490
|
-
const
|
|
491
|
-
const
|
|
492
|
-
//
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
840
|
+
* @returns True if the whole collection of txs is valid, false otherwise.
|
|
841
|
+
*/ async validateRequestedTxs(requestedTxHash, responseTx, peerId) {
|
|
842
|
+
const requested = new Set(requestedTxHash.map((h)=>h.toString()));
|
|
843
|
+
const requestedTxValidator = this.createRequestedTxValidator();
|
|
844
|
+
//TODO: (mralj) - this is somewhat naive implementation, if single tx is invlid we consider the whole response invalid.
|
|
845
|
+
// I think we should still extract the valid txs and return them, so that we can still use the response.
|
|
846
|
+
try {
|
|
847
|
+
await Promise.all(responseTx.map((tx)=>this.validateRequestedTx(tx, peerId, requestedTxValidator, requested)));
|
|
848
|
+
return true;
|
|
849
|
+
} catch (e) {
|
|
850
|
+
if (e instanceof ValidationError) {
|
|
851
|
+
this.logger.warn(`Failed to validate requested txs from peer ${peerId.toString()}, reason ${e.message}`);
|
|
852
|
+
} else {
|
|
853
|
+
this.logger.error(`Error during validation of requested txs`, e);
|
|
854
|
+
}
|
|
496
855
|
return false;
|
|
497
856
|
}
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
857
|
+
}
|
|
858
|
+
/**
|
|
859
|
+
* Validates a BLOCK response.
|
|
860
|
+
*
|
|
861
|
+
* If a local copy exists, enforces hash equality. If missing, rejects (no penalty) since the hash cannot be verified.
|
|
862
|
+
* Penalizes on block number mismatch or hash mismatch.
|
|
863
|
+
*
|
|
864
|
+
* @param requestedBlockNumber - The requested block number.
|
|
865
|
+
* @param responseBlock - The block returned by the peer.
|
|
866
|
+
* @param peerId - The peer that returned the block.
|
|
867
|
+
* @returns True if the response is valid, false otherwise.
|
|
868
|
+
*/ async validateRequestedBlock(requestedBlockNumber, responseBlock, peerId) {
|
|
869
|
+
try {
|
|
870
|
+
const reqNum = Number(requestedBlockNumber.toString());
|
|
871
|
+
if (responseBlock.number !== reqNum) {
|
|
872
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
|
|
873
|
+
return false;
|
|
874
|
+
}
|
|
875
|
+
const local = await this.archiver.getBlock(BlockNumber(reqNum));
|
|
876
|
+
if (!local) {
|
|
877
|
+
// We are missing the local block; we cannot verify the hash yet. Reject without penalizing.
|
|
878
|
+
// TODO: Consider extending this validator to accept an expected hash or
|
|
879
|
+
// performing quorum-based checks when using P2P syncing prior to L1 sync.
|
|
880
|
+
this.logger.warn(`Local block ${reqNum} not found; rejecting BLOCK response without hash verification`);
|
|
881
|
+
return false;
|
|
882
|
+
}
|
|
883
|
+
const [localHash, respHash] = await Promise.all([
|
|
884
|
+
local.hash(),
|
|
885
|
+
responseBlock.hash()
|
|
886
|
+
]);
|
|
887
|
+
if (!localHash.equals(respHash)) {
|
|
888
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
889
|
+
return false;
|
|
890
|
+
}
|
|
891
|
+
return true;
|
|
892
|
+
} catch (e) {
|
|
893
|
+
this.logger.warn(`Error validating requested block`, e);
|
|
501
894
|
return false;
|
|
502
895
|
}
|
|
503
|
-
|
|
896
|
+
}
|
|
897
|
+
createRequestedTxValidator() {
|
|
898
|
+
return new AggregateTxValidator(new DataTxValidator(), new MetadataTxValidator({
|
|
899
|
+
l1ChainId: new Fr(this.config.l1ChainId),
|
|
900
|
+
rollupVersion: new Fr(this.config.rollupVersion),
|
|
901
|
+
protocolContractsHash,
|
|
902
|
+
vkTreeRoot: getVKTreeRoot()
|
|
903
|
+
}), new TxProofValidator(this.proofVerifier));
|
|
904
|
+
}
|
|
905
|
+
async validateRequestedTx(tx, peerId, txValidator, requested) {
|
|
906
|
+
const penalize = (severity)=>this.peerManager.penalizePeer(peerId, severity);
|
|
907
|
+
if (!await tx.validateTxHash()) {
|
|
908
|
+
penalize(PeerErrorSeverity.MidToleranceError);
|
|
909
|
+
throw new ValidationError(`Received tx with invalid hash ${tx.getTxHash().toString()}.`);
|
|
910
|
+
}
|
|
911
|
+
if (requested && !requested.has(tx.getTxHash().toString())) {
|
|
912
|
+
penalize(PeerErrorSeverity.MidToleranceError);
|
|
913
|
+
throw new ValidationError(`Received tx with hash ${tx.getTxHash().toString()} that was not requested.`);
|
|
914
|
+
}
|
|
915
|
+
const { result } = await txValidator.validateTx(tx);
|
|
916
|
+
if (result === 'invalid') {
|
|
917
|
+
penalize(PeerErrorSeverity.LowToleranceError);
|
|
918
|
+
throw new ValidationError(`Received tx with hash ${tx.getTxHash().toString()} that is invalid.`);
|
|
919
|
+
}
|
|
504
920
|
}
|
|
505
921
|
async validatePropagatedTx(tx, peerId) {
|
|
506
|
-
const
|
|
507
|
-
|
|
508
|
-
const
|
|
509
|
-
|
|
510
|
-
|
|
922
|
+
const currentBlockNumber = await this.archiver.getBlockNumber();
|
|
923
|
+
// We accept transactions if they are not expired by the next slot (checked based on the IncludeByTimestamp field)
|
|
924
|
+
const { ts: nextSlotTimestamp } = this.epochCache.getEpochAndSlotInNextL1Slot();
|
|
925
|
+
const messageValidators = await this.createMessageValidators(currentBlockNumber, nextSlotTimestamp);
|
|
926
|
+
for (const validator of messageValidators){
|
|
927
|
+
const outcome = await this.runValidations(tx, validator);
|
|
928
|
+
if (outcome.allPassed) {
|
|
929
|
+
continue;
|
|
930
|
+
}
|
|
931
|
+
const { name } = outcome.failure;
|
|
932
|
+
let { severity } = outcome.failure;
|
|
933
|
+
// Double spend validator has a special case handler
|
|
934
|
+
if (name === 'doubleSpendValidator') {
|
|
935
|
+
const txBlockNumber = BlockNumber(currentBlockNumber + 1); // tx is expected to be in the next block
|
|
936
|
+
severity = await this.handleDoubleSpendFailure(tx, txBlockNumber);
|
|
937
|
+
}
|
|
938
|
+
this.peerManager.penalizePeer(peerId, severity);
|
|
939
|
+
return false;
|
|
511
940
|
}
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
if (
|
|
516
|
-
|
|
941
|
+
return true;
|
|
942
|
+
}
|
|
943
|
+
async getGasFees(blockNumber) {
|
|
944
|
+
if (blockNumber === this.feesCache?.blockNumber) {
|
|
945
|
+
return this.feesCache.gasFees;
|
|
517
946
|
}
|
|
518
|
-
this.
|
|
519
|
-
|
|
947
|
+
const header = await this.archiver.getBlockHeader(blockNumber);
|
|
948
|
+
const gasFees = header?.globalVariables.gasFees ?? GasFees.empty();
|
|
949
|
+
this.feesCache = {
|
|
950
|
+
blockNumber,
|
|
951
|
+
gasFees
|
|
952
|
+
};
|
|
953
|
+
return gasFees;
|
|
954
|
+
}
|
|
955
|
+
async validate(txs) {
|
|
956
|
+
const currentBlockNumber = await this.archiver.getBlockNumber();
|
|
957
|
+
// We accept transactions if they are not expired by the next slot (checked based on the IncludeByTimestamp field)
|
|
958
|
+
const { ts: nextSlotTimestamp } = this.epochCache.getEpochAndSlotInNextL1Slot();
|
|
959
|
+
const messageValidators = await this.createMessageValidators(currentBlockNumber, nextSlotTimestamp);
|
|
960
|
+
await Promise.all(txs.map(async (tx)=>{
|
|
961
|
+
for (const validator of messageValidators){
|
|
962
|
+
const outcome = await this.runValidations(tx, validator);
|
|
963
|
+
if (!outcome.allPassed) {
|
|
964
|
+
throw new Error('Invalid tx detected', {
|
|
965
|
+
cause: {
|
|
966
|
+
outcome
|
|
967
|
+
}
|
|
968
|
+
});
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
}));
|
|
520
972
|
}
|
|
521
973
|
/**
|
|
522
|
-
* Create message validators for the given block number.
|
|
974
|
+
* Create message validators for the given block number and timestamp.
|
|
523
975
|
*
|
|
524
976
|
* Each validator is a pair of a validator and a severity.
|
|
525
977
|
* If a validator fails, the peer is penalized with the severity of the validator.
|
|
526
978
|
*
|
|
527
|
-
* @param
|
|
979
|
+
* @param currentBlockNumber - The current synced block number.
|
|
980
|
+
* @param nextSlotTimestamp - The timestamp of the next slot (used to validate txs are not expired).
|
|
528
981
|
* @returns The message validators.
|
|
529
|
-
*/ createMessageValidators(
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
},
|
|
535
|
-
metadataValidator: {
|
|
536
|
-
validator: new MetadataTxValidator(new Fr(this.config.l1ChainId), new Fr(blockNumber)),
|
|
537
|
-
severity: PeerErrorSeverity.HighToleranceError
|
|
538
|
-
},
|
|
539
|
-
proofValidator: {
|
|
540
|
-
validator: new TxProofValidator(this.proofVerifier),
|
|
541
|
-
severity: PeerErrorSeverity.MidToleranceError
|
|
542
|
-
},
|
|
543
|
-
doubleSpendValidator: {
|
|
544
|
-
validator: new DoubleSpendTxValidator({
|
|
545
|
-
nullifiersExist: async (nullifiers)=>{
|
|
546
|
-
const merkleTree = this.worldStateSynchronizer.getCommitted();
|
|
547
|
-
const indices = await merkleTree.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, nullifiers);
|
|
548
|
-
return indices.map((index)=>index !== undefined);
|
|
549
|
-
}
|
|
550
|
-
}),
|
|
551
|
-
severity: PeerErrorSeverity.HighToleranceError
|
|
552
|
-
}
|
|
553
|
-
};
|
|
982
|
+
*/ async createMessageValidators(currentBlockNumber, nextSlotTimestamp) {
|
|
983
|
+
const gasFees = await this.getGasFees(currentBlockNumber);
|
|
984
|
+
const allowedInSetup = this.config.txPublicSetupAllowList ?? await getDefaultAllowedSetupFunctions();
|
|
985
|
+
const blockNumberInWhichTheTxIsConsideredToBeIncluded = BlockNumber(currentBlockNumber + 1);
|
|
986
|
+
return createTxMessageValidators(nextSlotTimestamp, blockNumberInWhichTheTxIsConsideredToBeIncluded, this.worldStateSynchronizer, gasFees, this.config.l1ChainId, this.config.rollupVersion, protocolContractsHash, this.archiver, this.proofVerifier, !this.config.disableTransactions, allowedInSetup);
|
|
554
987
|
}
|
|
555
988
|
/**
|
|
556
989
|
* Run validations on a tx.
|
|
@@ -562,29 +995,32 @@ import { ReqResp } from '../reqresp/reqresp.js';
|
|
|
562
995
|
const { result } = await validator.validateTx(tx);
|
|
563
996
|
return {
|
|
564
997
|
name,
|
|
565
|
-
isValid: result
|
|
998
|
+
isValid: result !== 'invalid',
|
|
566
999
|
severity
|
|
567
1000
|
};
|
|
568
1001
|
});
|
|
569
1002
|
// A promise that resolves when all validations have been run
|
|
570
|
-
const allValidations = Promise.all(validationPromises);
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
1003
|
+
const allValidations = await Promise.all(validationPromises);
|
|
1004
|
+
const failed = allValidations.find((x)=>!x.isValid);
|
|
1005
|
+
if (failed) {
|
|
1006
|
+
return {
|
|
1007
|
+
allPassed: false,
|
|
1008
|
+
failure: {
|
|
1009
|
+
isValid: {
|
|
1010
|
+
result: 'invalid',
|
|
1011
|
+
reason: [
|
|
1012
|
+
'Failed validation'
|
|
1013
|
+
]
|
|
1014
|
+
},
|
|
1015
|
+
name: failed.name,
|
|
1016
|
+
severity: failed.severity
|
|
1017
|
+
}
|
|
1018
|
+
};
|
|
1019
|
+
} else {
|
|
1020
|
+
return {
|
|
1021
|
+
allPassed: true
|
|
1022
|
+
};
|
|
1023
|
+
}
|
|
588
1024
|
}
|
|
589
1025
|
/**
|
|
590
1026
|
* Handle a double spend failure.
|
|
@@ -602,7 +1038,7 @@ import { ReqResp } from '../reqresp/reqresp.js';
|
|
|
602
1038
|
}
|
|
603
1039
|
const snapshotValidator = new DoubleSpendTxValidator({
|
|
604
1040
|
nullifiersExist: async (nullifiers)=>{
|
|
605
|
-
const merkleTree = this.worldStateSynchronizer.getSnapshot(blockNumber - this.config.doubleSpendSeverePeerPenaltyWindow);
|
|
1041
|
+
const merkleTree = this.worldStateSynchronizer.getSnapshot(BlockNumber(blockNumber - this.config.doubleSpendSeverePeerPenaltyWindow));
|
|
606
1042
|
const indices = await merkleTree.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, nullifiers);
|
|
607
1043
|
return indices.map((index)=>index !== undefined);
|
|
608
1044
|
}
|
|
@@ -634,6 +1070,7 @@ import { ReqResp } from '../reqresp/reqresp.js';
|
|
|
634
1070
|
*/ async validateBlockProposal(peerId, block) {
|
|
635
1071
|
const severity = await this.blockProposalValidator.validate(block);
|
|
636
1072
|
if (severity) {
|
|
1073
|
+
this.logger.debug(`Penalizing peer ${peerId} for block proposal validation failure`);
|
|
637
1074
|
this.peerManager.penalizePeer(peerId, severity);
|
|
638
1075
|
return false;
|
|
639
1076
|
}
|
|
@@ -642,13 +1079,16 @@ import { ReqResp } from '../reqresp/reqresp.js';
|
|
|
642
1079
|
getPeerScore(peerId) {
|
|
643
1080
|
return this.node.services.pubsub.score.score(peerId.toString());
|
|
644
1081
|
}
|
|
1082
|
+
handleAuthRequestFromPeer(authRequest, peerId) {
|
|
1083
|
+
return this.peerManager.handleAuthRequestFromPeer(authRequest, peerId);
|
|
1084
|
+
}
|
|
645
1085
|
async sendToPeers(message) {
|
|
646
1086
|
const parent = message.constructor;
|
|
647
|
-
const identifier = await message.
|
|
1087
|
+
const identifier = await message.p2pMessageLoggingIdentifier().then((i)=>i.toString());
|
|
648
1088
|
this.logger.trace(`Sending message ${identifier}`, {
|
|
649
1089
|
p2pMessageIdentifier: identifier
|
|
650
1090
|
});
|
|
651
|
-
const recipientsNum = await this.publishToTopic(parent.p2pTopic, message
|
|
1091
|
+
const recipientsNum = await this.publishToTopic(this.topicStrings[parent.p2pTopic], message);
|
|
652
1092
|
this.logger.debug(`Sent message ${identifier} to ${recipientsNum} peers`, {
|
|
653
1093
|
p2pMessageIdentifier: identifier,
|
|
654
1094
|
sourcePeer: this.node.peerId.toString()
|
|
@@ -673,40 +1113,47 @@ import { ReqResp } from '../reqresp/reqresp.js';
|
|
|
673
1113
|
}
|
|
674
1114
|
_ts_decorate([
|
|
675
1115
|
trackSpan('Libp2pService.processValidBlockProposal', async (block)=>({
|
|
676
|
-
[Attributes.
|
|
677
|
-
[Attributes.SLOT_NUMBER]: block.slotNumber.toNumber(),
|
|
1116
|
+
[Attributes.SLOT_NUMBER]: block.slotNumber,
|
|
678
1117
|
[Attributes.BLOCK_ARCHIVE]: block.archive.toString(),
|
|
679
|
-
[Attributes.P2P_ID]: await block.
|
|
1118
|
+
[Attributes.P2P_ID]: await block.p2pMessageLoggingIdentifier().then((i)=>i.toString())
|
|
680
1119
|
}))
|
|
681
1120
|
], LibP2PService.prototype, "processValidBlockProposal", null);
|
|
682
1121
|
_ts_decorate([
|
|
683
1122
|
trackSpan('Libp2pService.broadcastAttestation', async (attestation)=>({
|
|
684
|
-
[Attributes.
|
|
685
|
-
[Attributes.SLOT_NUMBER]: attestation.payload.header.globalVariables.slotNumber.toNumber(),
|
|
1123
|
+
[Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber,
|
|
686
1124
|
[Attributes.BLOCK_ARCHIVE]: attestation.archive.toString(),
|
|
687
|
-
[Attributes.P2P_ID]: await attestation.
|
|
1125
|
+
[Attributes.P2P_ID]: await attestation.p2pMessageLoggingIdentifier().then((i)=>i.toString())
|
|
688
1126
|
}))
|
|
689
1127
|
], LibP2PService.prototype, "broadcastAttestation", null);
|
|
1128
|
+
_ts_decorate([
|
|
1129
|
+
trackSpan('Libp2pService.validateRequestedBlockTxs', (request)=>({
|
|
1130
|
+
[Attributes.BLOCK_HASH]: request.blockHash.toString()
|
|
1131
|
+
}))
|
|
1132
|
+
], LibP2PService.prototype, "validateRequestedBlockTxs", null);
|
|
690
1133
|
_ts_decorate([
|
|
691
1134
|
trackSpan('Libp2pService.validateRequestedTx', (requestedTxHash, _responseTx)=>({
|
|
692
1135
|
[Attributes.TX_HASH]: requestedTxHash.toString()
|
|
693
1136
|
}))
|
|
694
|
-
], LibP2PService.prototype, "
|
|
1137
|
+
], LibP2PService.prototype, "validateRequestedTxs", null);
|
|
1138
|
+
_ts_decorate([
|
|
1139
|
+
trackSpan('Libp2pService.validateRequestedBlock', (requestedBlockNumber, _responseBlock)=>({
|
|
1140
|
+
[Attributes.BLOCK_NUMBER]: requestedBlockNumber.toString()
|
|
1141
|
+
}))
|
|
1142
|
+
], LibP2PService.prototype, "validateRequestedBlock", null);
|
|
695
1143
|
_ts_decorate([
|
|
696
|
-
trackSpan('Libp2pService.validatePropagatedTx',
|
|
697
|
-
[Attributes.TX_HASH]:
|
|
1144
|
+
trackSpan('Libp2pService.validatePropagatedTx', (tx)=>({
|
|
1145
|
+
[Attributes.TX_HASH]: tx.getTxHash().toString()
|
|
698
1146
|
}))
|
|
699
1147
|
], LibP2PService.prototype, "validatePropagatedTx", null);
|
|
700
1148
|
_ts_decorate([
|
|
701
1149
|
trackSpan('Libp2pService.validateAttestation', async (_, attestation)=>({
|
|
702
|
-
[Attributes.
|
|
703
|
-
[Attributes.SLOT_NUMBER]: attestation.payload.header.globalVariables.slotNumber.toNumber(),
|
|
1150
|
+
[Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber,
|
|
704
1151
|
[Attributes.BLOCK_ARCHIVE]: attestation.archive.toString(),
|
|
705
|
-
[Attributes.P2P_ID]: await attestation.
|
|
1152
|
+
[Attributes.P2P_ID]: await attestation.p2pMessageLoggingIdentifier().then((i)=>i.toString())
|
|
706
1153
|
}))
|
|
707
1154
|
], LibP2PService.prototype, "validateAttestation", null);
|
|
708
1155
|
_ts_decorate([
|
|
709
1156
|
trackSpan('Libp2pService.validateBlockProposal', (_peerId, block)=>({
|
|
710
|
-
[Attributes.SLOT_NUMBER]: block.payload.header.
|
|
1157
|
+
[Attributes.SLOT_NUMBER]: block.payload.header.slotNumber.toString()
|
|
711
1158
|
}))
|
|
712
1159
|
], LibP2PService.prototype, "validateBlockProposal", null);
|