@aztec/p2p 0.0.1-commit.e558bd1c → 0.0.1-commit.e57c76e
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +129 -3
- package/dest/bootstrap/bootstrap.d.ts +1 -1
- package/dest/bootstrap/bootstrap.d.ts.map +1 -1
- package/dest/bootstrap/bootstrap.js +9 -1
- package/dest/client/factory.d.ts +11 -10
- package/dest/client/factory.d.ts.map +1 -1
- package/dest/client/factory.js +58 -16
- package/dest/client/interface.d.ts +51 -36
- package/dest/client/interface.d.ts.map +1 -1
- package/dest/client/p2p_client.d.ts +48 -57
- package/dest/client/p2p_client.d.ts.map +1 -1
- package/dest/client/p2p_client.js +219 -236
- package/dest/config.d.ts +161 -94
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +150 -41
- package/dest/errors/p2p-service.error.d.ts +9 -0
- package/dest/errors/p2p-service.error.d.ts.map +1 -0
- package/dest/errors/p2p-service.error.js +10 -0
- package/dest/errors/reqresp.error.d.ts +1 -20
- package/dest/errors/reqresp.error.d.ts.map +1 -1
- package/dest/errors/reqresp.error.js +0 -21
- package/dest/errors/tx-pool.error.d.ts +8 -0
- package/dest/errors/tx-pool.error.d.ts.map +1 -0
- package/dest/errors/tx-pool.error.js +9 -0
- package/dest/index.d.ts +2 -2
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +1 -1
- package/dest/mem_pools/attestation_pool/attestation_pool.d.ts +104 -55
- package/dest/mem_pools/attestation_pool/attestation_pool.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/attestation_pool.js +295 -195
- 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 +231 -115
- package/dest/mem_pools/attestation_pool/index.d.ts +2 -2
- package/dest/mem_pools/attestation_pool/index.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/index.js +1 -1
- package/dest/mem_pools/attestation_pool/mocks.d.ts +2 -2
- package/dest/mem_pools/attestation_pool/mocks.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/mocks.js +7 -5
- package/dest/mem_pools/index.d.ts +2 -2
- package/dest/mem_pools/index.d.ts.map +1 -1
- package/dest/mem_pools/instrumentation.d.ts +4 -2
- package/dest/mem_pools/instrumentation.d.ts.map +1 -1
- package/dest/mem_pools/instrumentation.js +33 -15
- package/dest/mem_pools/interface.d.ts +3 -3
- package/dest/mem_pools/interface.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/archive/tx_archive.d.ts +1 -5
- package/dest/mem_pools/tx_pool_v2/archive/tx_archive.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/archive/tx_archive.js +1 -7
- package/dest/mem_pools/tx_pool_v2/deleted_pool.d.ts +104 -0
- package/dest/mem_pools/tx_pool_v2/deleted_pool.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/deleted_pool.js +251 -0
- package/dest/mem_pools/tx_pool_v2/eviction/eviction_manager.d.ts +3 -3
- package/dest/mem_pools/tx_pool_v2/eviction/eviction_manager.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/eviction_manager.js +18 -9
- package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.d.ts +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.js +7 -3
- package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.d.ts +3 -3
- package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.js +12 -4
- package/dest/mem_pools/tx_pool_v2/eviction/index.d.ts +3 -2
- package/dest/mem_pools/tx_pool_v2/eviction/index.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/index.js +2 -1
- package/dest/mem_pools/tx_pool_v2/eviction/insufficient_fee_per_gas_eviction_rule.d.ts +16 -0
- package/dest/mem_pools/tx_pool_v2/eviction/insufficient_fee_per_gas_eviction_rule.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/eviction/insufficient_fee_per_gas_eviction_rule.js +62 -0
- package/dest/mem_pools/tx_pool_v2/eviction/interfaces.d.ts +54 -5
- package/dest/mem_pools/tx_pool_v2/eviction/interfaces.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/interfaces.js +8 -0
- package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_mining_rule.js +7 -5
- package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.js +9 -7
- package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.d.ts +2 -2
- package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.js +14 -6
- package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.d.ts +4 -4
- package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.js +16 -4
- package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.d.ts +3 -3
- package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.js +3 -3
- package/dest/mem_pools/tx_pool_v2/index.d.ts +3 -2
- package/dest/mem_pools/tx_pool_v2/index.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/index.js +2 -1
- package/dest/mem_pools/tx_pool_v2/instrumentation.d.ts +15 -0
- package/dest/mem_pools/tx_pool_v2/instrumentation.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/instrumentation.js +43 -0
- package/dest/mem_pools/tx_pool_v2/interfaces.d.ts +33 -12
- package/dest/mem_pools/tx_pool_v2/interfaces.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/interfaces.js +5 -1
- package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts +81 -15
- package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/tx_metadata.js +147 -19
- package/dest/mem_pools/tx_pool_v2/tx_pool_indices.d.ts +12 -3
- package/dest/mem_pools/tx_pool_v2/tx_pool_indices.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/tx_pool_indices.js +50 -45
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts +12 -5
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2.js +17 -6
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts +14 -5
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.js +407 -241
- package/dest/msg_validators/attestation_validator/attestation_validator.d.ts +9 -3
- package/dest/msg_validators/attestation_validator/attestation_validator.d.ts.map +1 -1
- package/dest/msg_validators/attestation_validator/attestation_validator.js +37 -12
- package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts +7 -3
- package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts.map +1 -1
- package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.js +4 -5
- package/dest/msg_validators/clock_tolerance.d.ts +12 -1
- package/dest/msg_validators/clock_tolerance.d.ts.map +1 -1
- package/dest/msg_validators/clock_tolerance.js +56 -3
- package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts +10 -4
- package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts.map +1 -1
- package/dest/msg_validators/proposal_validator/block_proposal_validator.js +10 -2
- package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts +10 -4
- package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts.map +1 -1
- package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.js +16 -2
- package/dest/msg_validators/proposal_validator/proposal_validator.d.ts +21 -8
- package/dest/msg_validators/proposal_validator/proposal_validator.d.ts.map +1 -1
- package/dest/msg_validators/proposal_validator/proposal_validator.js +90 -44
- package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts +4 -4
- package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/aggregate_tx_validator.js +11 -18
- package/dest/msg_validators/tx_validator/allowed_public_setup.d.ts +2 -1
- package/dest/msg_validators/tx_validator/allowed_public_setup.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/allowed_public_setup.js +25 -21
- package/dest/msg_validators/tx_validator/allowed_setup_helpers.d.ts +17 -0
- package/dest/msg_validators/tx_validator/allowed_setup_helpers.d.ts.map +1 -0
- package/dest/msg_validators/tx_validator/allowed_setup_helpers.js +24 -0
- package/dest/msg_validators/tx_validator/archive_cache.js +1 -1
- package/dest/msg_validators/tx_validator/block_header_validator.d.ts +16 -3
- 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/cached_tx_validator.d.ts +15 -0
- package/dest/msg_validators/tx_validator/cached_tx_validator.d.ts.map +1 -0
- package/dest/msg_validators/tx_validator/cached_tx_validator.js +19 -0
- package/dest/msg_validators/tx_validator/contract_instance_validator.d.ts +9 -0
- package/dest/msg_validators/tx_validator/contract_instance_validator.d.ts.map +1 -0
- package/dest/msg_validators/tx_validator/contract_instance_validator.js +48 -0
- package/dest/msg_validators/tx_validator/data_validator.d.ts +2 -1
- package/dest/msg_validators/tx_validator/data_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/data_validator.js +36 -2
- package/dest/msg_validators/tx_validator/double_spend_validator.d.ts +13 -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 +4 -4
- package/dest/msg_validators/tx_validator/factory.d.ts +135 -7
- package/dest/msg_validators/tx_validator/factory.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/factory.js +252 -61
- package/dest/msg_validators/tx_validator/fee_payer_balance.d.ts +1 -1
- package/dest/msg_validators/tx_validator/fee_payer_balance.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/fee_payer_balance.js +6 -2
- package/dest/msg_validators/tx_validator/gas_validator.d.ts +99 -3
- package/dest/msg_validators/tx_validator/gas_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/gas_validator.js +137 -53
- package/dest/msg_validators/tx_validator/index.d.ts +5 -1
- package/dest/msg_validators/tx_validator/index.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/index.js +4 -0
- package/dest/msg_validators/tx_validator/metadata_validator.d.ts +1 -1
- package/dest/msg_validators/tx_validator/metadata_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/metadata_validator.js +4 -4
- package/dest/msg_validators/tx_validator/nullifier_cache.d.ts +14 -0
- package/dest/msg_validators/tx_validator/nullifier_cache.d.ts.map +1 -0
- package/dest/msg_validators/tx_validator/nullifier_cache.js +24 -0
- package/dest/msg_validators/tx_validator/phases_validator.d.ts +22 -2
- package/dest/msg_validators/tx_validator/phases_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/phases_validator.js +72 -24
- package/dest/msg_validators/tx_validator/timestamp_validator.d.ts +20 -4
- package/dest/msg_validators/tx_validator/timestamp_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/timestamp_validator.js +6 -6
- package/dest/msg_validators/tx_validator/tx_proof_validator.d.ts +2 -1
- package/dest/msg_validators/tx_validator/tx_proof_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/tx_proof_validator.js +2 -0
- package/dest/msg_validators/tx_validator/tx_validation_cache.d.ts +48 -0
- package/dest/msg_validators/tx_validator/tx_validation_cache.d.ts.map +1 -0
- package/dest/msg_validators/tx_validator/tx_validation_cache.js +68 -0
- package/dest/services/data_store.d.ts +1 -1
- package/dest/services/data_store.d.ts.map +1 -1
- package/dest/services/data_store.js +5 -5
- package/dest/services/discv5/discV5_service.d.ts +2 -1
- package/dest/services/discv5/discV5_service.d.ts.map +1 -1
- package/dest/services/discv5/discV5_service.js +35 -8
- package/dest/services/dummy_service.d.ts +18 -18
- package/dest/services/dummy_service.d.ts.map +1 -1
- package/dest/services/dummy_service.js +19 -20
- package/dest/services/encoding.d.ts +7 -3
- package/dest/services/encoding.d.ts.map +1 -1
- package/dest/services/encoding.js +18 -11
- package/dest/services/gossipsub/index.d.ts +3 -0
- package/dest/services/gossipsub/index.d.ts.map +1 -0
- package/dest/services/gossipsub/index.js +2 -0
- package/dest/services/gossipsub/scoring.d.ts +21 -3
- package/dest/services/gossipsub/scoring.d.ts.map +1 -1
- package/dest/services/gossipsub/scoring.js +24 -7
- package/dest/services/gossipsub/topic_score_params.d.ts +184 -0
- package/dest/services/gossipsub/topic_score_params.d.ts.map +1 -0
- package/dest/services/gossipsub/topic_score_params.js +363 -0
- package/dest/services/libp2p/instrumentation.d.ts +3 -1
- package/dest/services/libp2p/instrumentation.d.ts.map +1 -1
- package/dest/services/libp2p/instrumentation.js +14 -0
- package/dest/services/libp2p/libp2p_service.d.ts +56 -55
- package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
- package/dest/services/libp2p/libp2p_service.js +449 -397
- package/dest/services/peer-manager/metrics.d.ts +3 -1
- package/dest/services/peer-manager/metrics.d.ts.map +1 -1
- package/dest/services/peer-manager/metrics.js +6 -0
- package/dest/services/peer-manager/peer_manager.d.ts +6 -2
- package/dest/services/peer-manager/peer_manager.d.ts.map +1 -1
- package/dest/services/peer-manager/peer_manager.js +40 -11
- 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 +57 -12
- package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts +5 -8
- package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts.map +1 -1
- package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.js +95 -127
- package/dest/services/reqresp/batch-tx-requester/interface.d.ts +11 -11
- package/dest/services/reqresp/batch-tx-requester/interface.d.ts.map +1 -1
- package/dest/services/reqresp/batch-tx-requester/missing_txs.d.ts +11 -13
- package/dest/services/reqresp/batch-tx-requester/missing_txs.d.ts.map +1 -1
- package/dest/services/reqresp/batch-tx-requester/missing_txs.js +31 -46
- package/dest/services/reqresp/batch-tx-requester/peer_collection.d.ts +19 -11
- package/dest/services/reqresp/batch-tx-requester/peer_collection.d.ts.map +1 -1
- package/dest/services/reqresp/batch-tx-requester/peer_collection.js +52 -15
- package/dest/services/reqresp/batch-tx-requester/tx_validator.d.ts +5 -14
- package/dest/services/reqresp/batch-tx-requester/tx_validator.d.ts.map +1 -1
- package/dest/services/reqresp/batch-tx-requester/tx_validator.js +6 -20
- package/dest/services/reqresp/config.d.ts +3 -3
- package/dest/services/reqresp/config.d.ts.map +1 -1
- package/dest/services/reqresp/interface.d.ts +25 -18
- package/dest/services/reqresp/interface.d.ts.map +1 -1
- package/dest/services/reqresp/interface.js +23 -19
- package/dest/services/reqresp/metrics.d.ts +1 -1
- package/dest/services/reqresp/metrics.d.ts.map +1 -1
- package/dest/services/reqresp/metrics.js +0 -1
- package/dest/services/reqresp/protocols/block_txs/bitvector.d.ts +4 -3
- package/dest/services/reqresp/protocols/block_txs/bitvector.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/block_txs/bitvector.js +3 -2
- package/dest/services/reqresp/protocols/block_txs/block_txs_handler.d.ts +3 -3
- package/dest/services/reqresp/protocols/block_txs/block_txs_handler.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/block_txs/block_txs_handler.js +31 -28
- package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.d.ts +18 -7
- package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.js +57 -24
- package/dest/services/reqresp/protocols/index.d.ts +1 -2
- package/dest/services/reqresp/protocols/index.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/index.js +0 -1
- package/dest/services/reqresp/protocols/tx.d.ts +7 -1
- package/dest/services/reqresp/protocols/tx.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/tx.js +21 -3
- package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts +5 -4
- package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts.map +1 -1
- package/dest/services/reqresp/rate-limiter/rate_limiter.js +10 -8
- package/dest/services/reqresp/rate-limiter/rate_limits.d.ts +1 -1
- package/dest/services/reqresp/rate-limiter/rate_limits.d.ts.map +1 -1
- package/dest/services/reqresp/rate-limiter/rate_limits.js +0 -10
- package/dest/services/reqresp/reqresp.d.ts +7 -29
- package/dest/services/reqresp/reqresp.d.ts.map +1 -1
- package/dest/services/reqresp/reqresp.js +53 -218
- package/dest/services/service.d.ts +30 -14
- package/dest/services/service.d.ts.map +1 -1
- package/dest/services/tx_collection/config.d.ts +11 -14
- package/dest/services/tx_collection/config.d.ts.map +1 -1
- package/dest/services/tx_collection/config.js +26 -33
- package/dest/services/tx_collection/file_store_tx_collection.d.ts +37 -0
- package/dest/services/tx_collection/file_store_tx_collection.d.ts.map +1 -0
- package/dest/services/tx_collection/file_store_tx_collection.js +127 -0
- package/dest/services/tx_collection/file_store_tx_source.d.ts +38 -0
- package/dest/services/tx_collection/file_store_tx_source.d.ts.map +1 -0
- package/dest/services/tx_collection/file_store_tx_source.js +100 -0
- package/dest/services/tx_collection/index.d.ts +3 -3
- package/dest/services/tx_collection/index.d.ts.map +1 -1
- package/dest/services/tx_collection/index.js +1 -1
- package/dest/services/tx_collection/instrumentation.js +1 -2
- package/dest/services/tx_collection/request_tracker.d.ts +53 -0
- package/dest/services/tx_collection/request_tracker.d.ts.map +1 -0
- package/dest/services/tx_collection/request_tracker.js +84 -0
- package/dest/services/tx_collection/tx_collection.d.ts +45 -51
- package/dest/services/tx_collection/tx_collection.d.ts.map +1 -1
- package/dest/services/tx_collection/tx_collection.js +296 -68
- package/dest/services/tx_collection/tx_collection_sink.d.ts +19 -9
- package/dest/services/tx_collection/tx_collection_sink.d.ts.map +1 -1
- package/dest/services/tx_collection/tx_collection_sink.js +28 -31
- package/dest/services/tx_collection/tx_source.d.ts +13 -7
- package/dest/services/tx_collection/tx_source.d.ts.map +1 -1
- package/dest/services/tx_collection/tx_source.js +26 -7
- package/dest/services/tx_file_store/config.d.ts +1 -3
- package/dest/services/tx_file_store/config.d.ts.map +1 -1
- package/dest/services/tx_file_store/config.js +0 -4
- package/dest/services/tx_file_store/tx_file_store.d.ts +4 -5
- package/dest/services/tx_file_store/tx_file_store.d.ts.map +1 -1
- package/dest/services/tx_file_store/tx_file_store.js +13 -20
- 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 +12 -8
- package/dest/test-helpers/make-test-p2p-clients.d.ts +7 -8
- package/dest/test-helpers/make-test-p2p-clients.d.ts.map +1 -1
- package/dest/test-helpers/make-test-p2p-clients.js +5 -3
- package/dest/test-helpers/mock-pubsub.d.ts +46 -6
- package/dest/test-helpers/mock-pubsub.d.ts.map +1 -1
- package/dest/test-helpers/mock-pubsub.js +115 -14
- package/dest/test-helpers/reqresp-nodes.d.ts +5 -7
- package/dest/test-helpers/reqresp-nodes.d.ts.map +1 -1
- package/dest/test-helpers/reqresp-nodes.js +19 -20
- package/dest/test-helpers/test_tx_provider.d.ts +3 -1
- package/dest/test-helpers/test_tx_provider.d.ts.map +1 -1
- package/dest/test-helpers/test_tx_provider.js +3 -0
- package/dest/test-helpers/testbench-utils.d.ts +46 -37
- package/dest/test-helpers/testbench-utils.d.ts.map +1 -1
- package/dest/test-helpers/testbench-utils.js +142 -50
- package/dest/testbench/p2p_client_testbench_worker.d.ts +3 -5
- package/dest/testbench/p2p_client_testbench_worker.d.ts.map +1 -1
- package/dest/testbench/p2p_client_testbench_worker.js +93 -47
- package/dest/testbench/worker_client_manager.d.ts +12 -6
- package/dest/testbench/worker_client_manager.d.ts.map +1 -1
- package/dest/testbench/worker_client_manager.js +57 -11
- package/dest/util.d.ts +13 -8
- package/dest/util.d.ts.map +1 -1
- package/dest/util.js +35 -14
- package/dest/versioning.d.ts +3 -6
- package/dest/versioning.d.ts.map +1 -1
- package/dest/versioning.js +3 -24
- package/package.json +15 -14
- package/src/bootstrap/bootstrap.ts +9 -1
- package/src/client/factory.ts +124 -27
- package/src/client/interface.ts +58 -44
- package/src/client/p2p_client.ts +256 -299
- package/src/client/test/{tx_proposal_collector/README.md → p2p_client.batch_tx_requester.bench.README.md} +23 -53
- package/src/config.ts +260 -46
- package/src/errors/p2p-service.error.ts +11 -0
- package/src/errors/reqresp.error.ts +0 -25
- package/src/errors/tx-pool.error.ts +12 -0
- package/src/index.ts +1 -1
- package/src/mem_pools/attestation_pool/attestation_pool.ts +363 -236
- package/src/mem_pools/attestation_pool/attestation_pool_test_suite.ts +258 -118
- package/src/mem_pools/attestation_pool/index.ts +3 -3
- package/src/mem_pools/attestation_pool/mocks.ts +14 -8
- package/src/mem_pools/index.ts +1 -1
- package/src/mem_pools/instrumentation.ts +22 -14
- package/src/mem_pools/interface.ts +2 -2
- package/src/mem_pools/tx_pool_v2/README.md +85 -11
- package/src/mem_pools/tx_pool_v2/archive/tx_archive.ts +1 -9
- package/src/mem_pools/tx_pool_v2/deleted_pool.ts +321 -0
- package/src/mem_pools/tx_pool_v2/eviction/eviction_manager.ts +21 -8
- package/src/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.ts +7 -3
- package/src/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.ts +18 -4
- package/src/mem_pools/tx_pool_v2/eviction/index.ts +5 -0
- package/src/mem_pools/tx_pool_v2/eviction/insufficient_fee_per_gas_eviction_rule.ts +65 -0
- package/src/mem_pools/tx_pool_v2/eviction/interfaces.ts +59 -4
- package/src/mem_pools/tx_pool_v2/eviction/invalid_txs_after_mining_rule.ts +5 -5
- package/src/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.ts +8 -8
- package/src/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.ts +14 -9
- package/src/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.ts +33 -6
- package/src/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.ts +4 -3
- package/src/mem_pools/tx_pool_v2/index.ts +2 -1
- package/src/mem_pools/tx_pool_v2/instrumentation.ts +69 -0
- package/src/mem_pools/tx_pool_v2/interfaces.ts +35 -12
- package/src/mem_pools/tx_pool_v2/tx_metadata.ts +215 -27
- package/src/mem_pools/tx_pool_v2/tx_pool_indices.ts +58 -45
- package/src/mem_pools/tx_pool_v2/tx_pool_v2.ts +34 -8
- package/src/mem_pools/tx_pool_v2/tx_pool_v2_impl.ts +448 -240
- package/src/msg_validators/attestation_validator/README.md +49 -0
- package/src/msg_validators/attestation_validator/attestation_validator.ts +41 -9
- package/src/msg_validators/attestation_validator/fisherman_attestation_validator.ts +14 -7
- package/src/msg_validators/clock_tolerance.ts +73 -3
- package/src/msg_validators/proposal_validator/README.md +123 -0
- package/src/msg_validators/proposal_validator/block_proposal_validator.ts +24 -4
- package/src/msg_validators/proposal_validator/checkpoint_proposal_validator.ts +35 -7
- package/src/msg_validators/proposal_validator/proposal_validator.ts +114 -47
- package/src/msg_validators/tx_validator/README.md +127 -0
- package/src/msg_validators/tx_validator/aggregate_tx_validator.ts +8 -17
- package/src/msg_validators/tx_validator/allowed_public_setup.ts +22 -27
- package/src/msg_validators/tx_validator/allowed_setup_helpers.ts +31 -0
- package/src/msg_validators/tx_validator/archive_cache.ts +1 -1
- package/src/msg_validators/tx_validator/block_header_validator.ts +15 -3
- package/src/msg_validators/tx_validator/cached_tx_validator.ts +31 -0
- package/src/msg_validators/tx_validator/contract_instance_validator.ts +56 -0
- package/src/msg_validators/tx_validator/data_validator.ts +44 -1
- package/src/msg_validators/tx_validator/double_spend_validator.ts +11 -6
- package/src/msg_validators/tx_validator/factory.ts +407 -80
- package/src/msg_validators/tx_validator/fee_payer_balance.ts +6 -2
- package/src/msg_validators/tx_validator/gas_validator.ts +199 -54
- package/src/msg_validators/tx_validator/index.ts +4 -0
- package/src/msg_validators/tx_validator/metadata_validator.ts +12 -4
- package/src/msg_validators/tx_validator/nullifier_cache.ts +30 -0
- package/src/msg_validators/tx_validator/phases_validator.ts +82 -27
- package/src/msg_validators/tx_validator/timestamp_validator.ts +23 -18
- package/src/msg_validators/tx_validator/tx_proof_validator.ts +2 -0
- package/src/msg_validators/tx_validator/tx_validation_cache.ts +101 -0
- package/src/services/data_store.ts +5 -13
- package/src/services/discv5/discV5_service.ts +38 -5
- package/src/services/dummy_service.ts +26 -45
- package/src/services/encoding.ts +18 -10
- package/src/services/gossipsub/README.md +641 -0
- package/src/services/gossipsub/index.ts +2 -0
- package/src/services/gossipsub/scoring.ts +29 -5
- package/src/services/gossipsub/topic_score_params.ts +519 -0
- package/src/services/libp2p/instrumentation.ts +14 -0
- package/src/services/libp2p/libp2p_service.ts +497 -453
- package/src/services/peer-manager/metrics.ts +7 -0
- package/src/services/peer-manager/peer_manager.ts +46 -11
- package/src/services/peer-manager/peer_scoring.ts +52 -5
- package/src/services/reqresp/README.md +215 -0
- package/src/services/reqresp/batch-tx-requester/README.md +46 -7
- package/src/services/reqresp/batch-tx-requester/batch_tx_requester.ts +92 -138
- package/src/services/reqresp/batch-tx-requester/interface.ts +14 -10
- package/src/services/reqresp/batch-tx-requester/missing_txs.ts +30 -71
- package/src/services/reqresp/batch-tx-requester/peer_collection.ts +68 -24
- package/src/services/reqresp/batch-tx-requester/tx_validator.ts +12 -25
- package/src/services/reqresp/config.ts +2 -2
- package/src/services/reqresp/interface.ts +45 -46
- package/src/services/reqresp/metrics.ts +0 -1
- package/src/services/reqresp/protocols/block_txs/bitvector.ts +3 -2
- package/src/services/reqresp/protocols/block_txs/block_txs_handler.ts +36 -32
- package/src/services/reqresp/protocols/block_txs/block_txs_reqresp.ts +64 -20
- package/src/services/reqresp/protocols/index.ts +0 -1
- package/src/services/reqresp/protocols/tx.ts +23 -3
- package/src/services/reqresp/rate-limiter/rate_limiter.ts +13 -9
- package/src/services/reqresp/rate-limiter/rate_limits.ts +0 -10
- package/src/services/reqresp/reqresp.ts +61 -264
- package/src/services/service.ts +43 -30
- package/src/services/tx_collection/config.ts +40 -49
- package/src/services/tx_collection/file_store_tx_collection.ts +153 -0
- package/src/services/tx_collection/file_store_tx_source.ts +129 -0
- package/src/services/tx_collection/index.ts +2 -6
- package/src/services/tx_collection/instrumentation.ts +1 -1
- package/src/services/tx_collection/request_tracker.ts +127 -0
- package/src/services/tx_collection/tx_collection.ts +362 -110
- package/src/services/tx_collection/tx_collection_sink.ts +32 -36
- package/src/services/tx_collection/tx_source.ts +28 -8
- package/src/services/tx_file_store/config.ts +0 -6
- package/src/services/tx_file_store/tx_file_store.ts +15 -25
- package/src/services/tx_provider.ts +15 -9
- package/src/test-helpers/make-test-p2p-clients.ts +7 -6
- package/src/test-helpers/mock-pubsub.ts +137 -14
- package/src/test-helpers/reqresp-nodes.ts +17 -29
- package/src/test-helpers/test_tx_provider.ts +5 -0
- package/src/test-helpers/testbench-utils.ts +168 -68
- package/src/testbench/p2p_client_testbench_worker.ts +99 -62
- package/src/testbench/worker_client_manager.ts +72 -25
- package/src/util.ts +40 -19
- package/src/versioning.ts +3 -33
- package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.d.ts +0 -2
- package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.d.ts.map +0 -1
- package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.js +0 -305
- package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker_protocol.d.ts +0 -73
- package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker_protocol.d.ts.map +0 -1
- package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker_protocol.js +0 -8
- package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts +0 -125
- package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.js +0 -596
- package/dest/mem_pools/tx_pool/eviction/eviction_manager.d.ts +0 -32
- package/dest/mem_pools/tx_pool/eviction/eviction_manager.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/eviction/eviction_manager.js +0 -112
- package/dest/mem_pools/tx_pool/eviction/eviction_strategy.d.ts +0 -157
- package/dest/mem_pools/tx_pool/eviction/eviction_strategy.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/eviction/eviction_strategy.js +0 -52
- package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.d.ts +0 -16
- package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.js +0 -122
- package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.d.ts +0 -17
- package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.js +0 -84
- package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.d.ts +0 -19
- package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.js +0 -78
- package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.d.ts +0 -26
- package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.js +0 -84
- package/dest/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.d.ts +0 -25
- package/dest/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.js +0 -57
- package/dest/mem_pools/tx_pool/index.d.ts +0 -3
- package/dest/mem_pools/tx_pool/index.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/index.js +0 -2
- package/dest/mem_pools/tx_pool/priority.d.ts +0 -12
- package/dest/mem_pools/tx_pool/priority.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/priority.js +0 -15
- package/dest/mem_pools/tx_pool/tx_pool.d.ts +0 -127
- package/dest/mem_pools/tx_pool/tx_pool.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/tx_pool.js +0 -3
- package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts +0 -7
- package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/tx_pool_test_suite.js +0 -400
- package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.d.ts +0 -23
- package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.d.ts.map +0 -1
- package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.js +0 -212
- package/dest/services/reqresp/connection-sampler/batch_connection_sampler.d.ts +0 -64
- package/dest/services/reqresp/connection-sampler/batch_connection_sampler.d.ts.map +0 -1
- package/dest/services/reqresp/connection-sampler/batch_connection_sampler.js +0 -151
- package/dest/services/reqresp/protocols/block.d.ts +0 -9
- package/dest/services/reqresp/protocols/block.d.ts.map +0 -1
- package/dest/services/reqresp/protocols/block.js +0 -32
- package/dest/services/tx_collection/fast_tx_collection.d.ts +0 -52
- package/dest/services/tx_collection/fast_tx_collection.d.ts.map +0 -1
- package/dest/services/tx_collection/fast_tx_collection.js +0 -307
- package/dest/services/tx_collection/proposal_tx_collector.d.ts +0 -48
- package/dest/services/tx_collection/proposal_tx_collector.d.ts.map +0 -1
- package/dest/services/tx_collection/proposal_tx_collector.js +0 -49
- package/dest/services/tx_collection/slow_tx_collection.d.ts +0 -53
- package/dest/services/tx_collection/slow_tx_collection.d.ts.map +0 -1
- package/dest/services/tx_collection/slow_tx_collection.js +0 -177
- package/src/client/test/tx_proposal_collector/proposal_tx_collector_worker.ts +0 -336
- package/src/client/test/tx_proposal_collector/proposal_tx_collector_worker_protocol.ts +0 -43
- package/src/mem_pools/tx_pool/README.md +0 -270
- package/src/mem_pools/tx_pool/aztec_kv_tx_pool.ts +0 -746
- package/src/mem_pools/tx_pool/eviction/eviction_manager.ts +0 -132
- package/src/mem_pools/tx_pool/eviction/eviction_strategy.ts +0 -208
- package/src/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.ts +0 -162
- package/src/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.ts +0 -104
- package/src/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.ts +0 -93
- package/src/mem_pools/tx_pool/eviction/low_priority_eviction_rule.ts +0 -106
- package/src/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.ts +0 -75
- package/src/mem_pools/tx_pool/index.ts +0 -2
- package/src/mem_pools/tx_pool/priority.ts +0 -20
- package/src/mem_pools/tx_pool/tx_pool.ts +0 -141
- package/src/mem_pools/tx_pool/tx_pool_test_suite.ts +0 -319
- package/src/msg_validators/proposal_validator/proposal_validator_test_suite.ts +0 -230
- package/src/services/reqresp/connection-sampler/batch_connection_sampler.ts +0 -161
- package/src/services/reqresp/protocols/block.ts +0 -37
- package/src/services/tx_collection/fast_tx_collection.ts +0 -354
- package/src/services/tx_collection/proposal_tx_collector.ts +0 -112
- package/src/services/tx_collection/slow_tx_collection.ts +0 -233
|
@@ -370,21 +370,20 @@ function applyDecs2203RFactory() {
|
|
|
370
370
|
function _apply_decs_2203_r(targetClass, memberDecs, classDecs, parentClass) {
|
|
371
371
|
return (_apply_decs_2203_r = applyDecs2203RFactory())(targetClass, memberDecs, classDecs, parentClass);
|
|
372
372
|
}
|
|
373
|
-
var _dec, _dec1, _dec2, _dec3, _dec4, _dec5,
|
|
373
|
+
var _dec, _dec1, _dec2, _dec3, _dec4, _dec5, _initProto;
|
|
374
374
|
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
375
|
-
import {
|
|
375
|
+
import { maxBy, merge } from '@aztec/foundation/collection';
|
|
376
376
|
import { createLibp2pComponentLogger, createLogger } from '@aztec/foundation/log';
|
|
377
377
|
import { RunningPromise } from '@aztec/foundation/running-promise';
|
|
378
378
|
import { Timer } from '@aztec/foundation/timer';
|
|
379
379
|
import { protocolContractsHash } from '@aztec/protocol-contracts';
|
|
380
|
-
import {
|
|
381
|
-
import { BlockProposal, CheckpointAttestation, CheckpointProposal, P2PClientType, P2PMessage, PeerErrorSeverity, TopicType, createTopicString, getTopicsForClientAndConfig, metricsTopicStrToLabels } from '@aztec/stdlib/p2p';
|
|
380
|
+
import { BlockProposal, CheckpointAttestation, CheckpointProposal, P2PMessage, PeerErrorSeverity, PeerErrorSeverityByHarshness, TopicType, createTopicString, getTopicsForConfig, metricsTopicStrToLabels } from '@aztec/stdlib/p2p';
|
|
382
381
|
import { MerkleTreeId } from '@aztec/stdlib/trees';
|
|
383
382
|
import { Tx } from '@aztec/stdlib/tx';
|
|
384
383
|
import { compressComponentVersions } from '@aztec/stdlib/versioning';
|
|
385
384
|
import { Attributes, OtelMetricsAdapter, SpanStatusCode, WithTracer, trackSpan } from '@aztec/telemetry-client';
|
|
386
385
|
import { gossipsub } from '@chainsafe/libp2p-gossipsub';
|
|
387
|
-
import { createPeerScoreParams
|
|
386
|
+
import { createPeerScoreParams } from '@chainsafe/libp2p-gossipsub/score';
|
|
388
387
|
import { SignaturePolicy } from '@chainsafe/libp2p-gossipsub/types';
|
|
389
388
|
import { noise } from '@chainsafe/libp2p-noise';
|
|
390
389
|
import { yamux } from '@chainsafe/libp2p-yamux';
|
|
@@ -393,22 +392,24 @@ import { identify } from '@libp2p/identify';
|
|
|
393
392
|
import { TopicValidatorResult } from '@libp2p/interface';
|
|
394
393
|
import { mplex } from '@libp2p/mplex';
|
|
395
394
|
import { tcp } from '@libp2p/tcp';
|
|
395
|
+
import { multiaddr } from '@multiformats/multiaddr';
|
|
396
396
|
import { ENR } from '@nethermindeth/enr';
|
|
397
397
|
import { createLibp2p } from 'libp2p';
|
|
398
|
+
import { CheckpointProposalReceivedCallbackNotRegisteredError } from '../../errors/p2p-service.error.js';
|
|
398
399
|
import { BlockProposalValidator, CheckpointAttestationValidator, CheckpointProposalValidator, DoubleSpendTxValidator, FishermanAttestationValidator, getDefaultAllowedSetupFunctions } from '../../msg_validators/index.js';
|
|
399
400
|
import { MessageSeenValidator } from '../../msg_validators/msg_seen_validator/msg_seen_validator.js';
|
|
400
|
-
import {
|
|
401
|
+
import { createFirstStageTxValidationsForGossipedTransactions, createSecondStageTxValidationsForGossipedTransactions, createTxValidatorForBlockProposalReceivedTxs } from '../../msg_validators/tx_validator/factory.js';
|
|
401
402
|
import { GossipSubEvent } from '../../types/index.js';
|
|
402
403
|
import { convertToMultiaddr } from '../../util.js';
|
|
403
404
|
import { getVersions } from '../../versioning.js';
|
|
404
405
|
import { AztecDatastore } from '../data_store.js';
|
|
405
406
|
import { DiscV5Service } from '../discv5/discV5_service.js';
|
|
406
407
|
import { SnappyTransform, fastMsgIdFn, getMsgIdFn, msgIdToStrFn } from '../encoding.js';
|
|
407
|
-
import { gossipScoreThresholds } from '../gossipsub/scoring.js';
|
|
408
|
+
import { APP_SPECIFIC_WEIGHT, gossipScoreThresholds } from '../gossipsub/scoring.js';
|
|
409
|
+
import { createAllTopicScoreParams } from '../gossipsub/topic_score_params.js';
|
|
408
410
|
import { PeerManager } from '../peer-manager/peer_manager.js';
|
|
409
411
|
import { PeerScoring } from '../peer-manager/peer_scoring.js';
|
|
410
|
-
import {
|
|
411
|
-
import { pingHandler, reqGoodbyeHandler, reqRespBlockHandler, reqRespBlockTxsHandler, reqRespStatusHandler, reqRespTxHandler } from '../reqresp/index.js';
|
|
412
|
+
import { ReqRespSubProtocol, ValidationError, pingHandler, reqGoodbyeHandler, reqRespBlockTxsHandler, reqRespStatusHandler, reqRespTxHandler } from '../reqresp/index.js';
|
|
412
413
|
import { ReqResp } from '../reqresp/reqresp.js';
|
|
413
414
|
import { P2PInstrumentation } from './instrumentation.js';
|
|
414
415
|
_dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId, attestation)=>({
|
|
@@ -426,23 +427,12 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
426
427
|
[Attributes.SLOT_NUMBER]: checkpoint.slotNumber,
|
|
427
428
|
[Attributes.BLOCK_ARCHIVE]: checkpoint.archive.toString(),
|
|
428
429
|
[Attributes.P2P_ID]: await checkpoint.p2pMessageLoggingIdentifier().then((i)=>i.toString())
|
|
429
|
-
})), _dec5 = trackSpan('Libp2pService.
|
|
430
|
+
})), _dec5 = trackSpan('Libp2pService.validateRequestedBlockTxsConsistency', (request)=>({
|
|
430
431
|
[Attributes.BLOCK_ARCHIVE]: request.archiveRoot.toString()
|
|
431
|
-
})), _dec6 = trackSpan('Libp2pService.validateRequestedTx', (requestedTxHash, _responseTx)=>({
|
|
432
|
-
[Attributes.TX_HASH]: requestedTxHash.toString()
|
|
433
|
-
})), _dec7 = trackSpan('Libp2pService.validateRequestedBlock', (requestedBlockNumber, _responseBlock)=>({
|
|
434
|
-
[Attributes.BLOCK_NUMBER]: requestedBlockNumber.toString()
|
|
435
|
-
})), _dec8 = trackSpan('Libp2pService.validatePropagatedTx', (tx)=>({
|
|
436
|
-
[Attributes.TX_HASH]: tx.getTxHash().toString()
|
|
437
|
-
})), _dec9 = trackSpan('Libp2pService.validateCheckpointAttestation', async (_, attestation)=>({
|
|
438
|
-
[Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber,
|
|
439
|
-
[Attributes.BLOCK_ARCHIVE]: attestation.archive.toString(),
|
|
440
|
-
[Attributes.P2P_ID]: await attestation.p2pMessageLoggingIdentifier().then((i)=>i.toString())
|
|
441
432
|
}));
|
|
442
433
|
/**
|
|
443
434
|
* Lib P2P implementation of the P2PService interface.
|
|
444
435
|
*/ export class LibP2PService extends WithTracer {
|
|
445
|
-
clientType;
|
|
446
436
|
config;
|
|
447
437
|
node;
|
|
448
438
|
peerDiscoveryService;
|
|
@@ -453,6 +443,8 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
453
443
|
epochCache;
|
|
454
444
|
proofVerifier;
|
|
455
445
|
worldStateSynchronizer;
|
|
446
|
+
blockMinFeesProvider;
|
|
447
|
+
txValidationCache;
|
|
456
448
|
static{
|
|
457
449
|
({ e: [_initProto] } = _apply_decs_2203_r(this, [
|
|
458
450
|
[
|
|
@@ -483,27 +475,7 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
483
475
|
[
|
|
484
476
|
_dec5,
|
|
485
477
|
2,
|
|
486
|
-
"
|
|
487
|
-
],
|
|
488
|
-
[
|
|
489
|
-
_dec6,
|
|
490
|
-
2,
|
|
491
|
-
"validateRequestedTxs"
|
|
492
|
-
],
|
|
493
|
-
[
|
|
494
|
-
_dec7,
|
|
495
|
-
2,
|
|
496
|
-
"validateRequestedBlock"
|
|
497
|
-
],
|
|
498
|
-
[
|
|
499
|
-
_dec8,
|
|
500
|
-
2,
|
|
501
|
-
"validatePropagatedTx"
|
|
502
|
-
],
|
|
503
|
-
[
|
|
504
|
-
_dec9,
|
|
505
|
-
2,
|
|
506
|
-
"validateCheckpointAttestation"
|
|
478
|
+
"validateRequestedBlockTxsConsistency"
|
|
507
479
|
]
|
|
508
480
|
], []));
|
|
509
481
|
}
|
|
@@ -515,8 +487,9 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
515
487
|
checkpointAttestationValidator;
|
|
516
488
|
protocolVersion;
|
|
517
489
|
topicStrings;
|
|
518
|
-
feesCache;
|
|
519
490
|
/** Callback invoked when a duplicate proposal is detected (triggers slashing). */ duplicateProposalCallback;
|
|
491
|
+
/** Callback invoked when a duplicate attestation is detected (triggers slashing). */ duplicateAttestationCallback;
|
|
492
|
+
/** Callback invoked when a valid checkpoint attestation is accepted into the pool. */ checkpointAttestationCallback;
|
|
520
493
|
/**
|
|
521
494
|
* Callback for when a block is received from a peer.
|
|
522
495
|
* @param block - The block received from the peer.
|
|
@@ -526,13 +499,20 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
526
499
|
* Callback for when a checkpoint proposal is received from a peer.
|
|
527
500
|
* @param checkpoint - The checkpoint proposal received from the peer.
|
|
528
501
|
* @returns The attestations for the checkpoint, if any.
|
|
529
|
-
*/
|
|
502
|
+
*/ allNodesCheckpointReceivedCallback;
|
|
503
|
+
/**
|
|
504
|
+
* Callback for when a checkpoint proposal is received - specifically for validators - from a peer.
|
|
505
|
+
* @param checkpoint - The checkpoint proposal received from the peer.
|
|
506
|
+
* @returns The attestations for the checkpoint, if any.
|
|
507
|
+
*/ validatorCheckpointReceivedCallback;
|
|
530
508
|
gossipSubEventHandler;
|
|
509
|
+
ipChangedHandler;
|
|
510
|
+
discoveredP2pIp;
|
|
531
511
|
instrumentation;
|
|
532
512
|
telemetry;
|
|
533
513
|
logger;
|
|
534
|
-
constructor(
|
|
535
|
-
super(telemetry, 'LibP2PService'), this.
|
|
514
|
+
constructor(config, node, peerDiscoveryService, reqresp, peerManager, mempools, archiver, epochCache, proofVerifier, worldStateSynchronizer, blockMinFeesProvider, telemetry, logger = createLogger('p2p:libp2p_service'), txValidationCache){
|
|
515
|
+
super(telemetry, 'LibP2PService'), this.config = config, this.node = node, this.peerDiscoveryService = peerDiscoveryService, this.reqresp = reqresp, this.peerManager = peerManager, this.mempools = mempools, this.archiver = archiver, this.epochCache = epochCache, this.proofVerifier = proofVerifier, this.worldStateSynchronizer = worldStateSynchronizer, this.blockMinFeesProvider = blockMinFeesProvider, this.txValidationCache = txValidationCache, this.msgIdSeenValidators = (_initProto(this), {}), this.protocolVersion = '', this.topicStrings = {};
|
|
536
516
|
this.telemetry = telemetry;
|
|
537
517
|
// Create child logger with fisherman prefix if in fisherman mode
|
|
538
518
|
this.logger = config.fishermanMode ? logger.createChild('[FISHERMAN]') : logger;
|
|
@@ -548,35 +528,51 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
548
528
|
this.topicStrings[TopicType.block_proposal] = createTopicString(TopicType.block_proposal, this.protocolVersion);
|
|
549
529
|
this.topicStrings[TopicType.checkpoint_proposal] = createTopicString(TopicType.checkpoint_proposal, this.protocolVersion);
|
|
550
530
|
this.topicStrings[TopicType.checkpoint_attestation] = createTopicString(TopicType.checkpoint_attestation, this.protocolVersion);
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
531
|
+
const p2pPropagationTime = config.attestationPropagationTime;
|
|
532
|
+
const proposalValidatorOpts = {
|
|
533
|
+
txsPermitted: !config.disableTransactions,
|
|
534
|
+
maxTxsPerBlock: config.validateMaxTxsPerBlock ?? config.validateMaxTxsPerCheckpoint,
|
|
535
|
+
maxBlocksPerCheckpoint: config.maxBlocksPerCheckpoint,
|
|
536
|
+
p2pPropagationTime,
|
|
537
|
+
skipSlotValidation: config.skipProposalSlotValidation,
|
|
538
|
+
signatureContext: {
|
|
539
|
+
chainId: config.l1ChainId,
|
|
540
|
+
rollupAddress: config.rollupAddress
|
|
541
|
+
}
|
|
542
|
+
};
|
|
543
|
+
this.blockProposalValidator = new BlockProposalValidator(epochCache, proposalValidatorOpts);
|
|
544
|
+
this.checkpointProposalValidator = new CheckpointProposalValidator(epochCache, proposalValidatorOpts);
|
|
545
|
+
const attestationValidatorOpts = {
|
|
546
|
+
l1PublishingTime: config.l1PublishingTime,
|
|
547
|
+
p2pPropagationTime,
|
|
548
|
+
signatureContext: proposalValidatorOpts.signatureContext
|
|
549
|
+
};
|
|
550
|
+
this.checkpointAttestationValidator = config.fishermanMode ? new FishermanAttestationValidator(epochCache, mempools.attestationPool, telemetry, attestationValidatorOpts) : new CheckpointAttestationValidator(epochCache, attestationValidatorOpts);
|
|
558
551
|
this.gossipSubEventHandler = this.handleGossipSubEvent.bind(this);
|
|
559
552
|
this.blockReceivedCallback = async (block)=>{
|
|
560
|
-
this.logger.
|
|
553
|
+
this.logger.warn(`Handler for block received not yet registered on P2P service. Received block ${block.blockNumber} for slot ${block.slotNumber} from peer.`, {
|
|
561
554
|
p2pMessageIdentifier: await block.p2pMessageLoggingIdentifier()
|
|
562
555
|
});
|
|
563
|
-
return
|
|
556
|
+
return true;
|
|
564
557
|
};
|
|
565
|
-
this.
|
|
566
|
-
|
|
558
|
+
this.allNodesCheckpointReceivedCallback = (_checkpoint)=>{
|
|
559
|
+
throw new CheckpointProposalReceivedCallbackNotRegisteredError();
|
|
560
|
+
};
|
|
561
|
+
this.validatorCheckpointReceivedCallback = (_checkpoint)=>{
|
|
567
562
|
return Promise.resolve(undefined);
|
|
568
563
|
};
|
|
569
564
|
}
|
|
570
565
|
updateConfig(config) {
|
|
571
566
|
this.reqresp.updateConfig(config);
|
|
567
|
+
this.config = merge(this.config, config);
|
|
572
568
|
}
|
|
573
569
|
/**
|
|
574
570
|
* Creates an instance of the LibP2P service.
|
|
575
571
|
* @param config - The configuration to use when creating the service.
|
|
576
572
|
* @param txPool - The transaction pool to be accessed by the service.
|
|
577
573
|
* @returns The new service.
|
|
578
|
-
*/ static async new(
|
|
579
|
-
const { worldStateSynchronizer, epochCache, l2BlockSource, mempools, proofVerifier, peerStore, telemetry, logger, packageVersion } = deps;
|
|
574
|
+
*/ static async new(config, peerId, deps) {
|
|
575
|
+
const { worldStateSynchronizer, epochCache, l2BlockSource, mempools, proofVerifier, peerStore, blockMinFeesProvider, telemetry, logger, packageVersion, txValidationCache } = deps;
|
|
580
576
|
const { p2pPort, maxPeerCount, listenAddress } = config;
|
|
581
577
|
const bindAddrTcp = convertToMultiaddr(listenAddress, p2pPort, 'tcp');
|
|
582
578
|
const datastore = new AztecDatastore(peerStore);
|
|
@@ -595,10 +591,6 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
595
591
|
}
|
|
596
592
|
const versions = getVersions(config);
|
|
597
593
|
const protocolVersion = compressComponentVersions(versions);
|
|
598
|
-
const txTopic = createTopicString(TopicType.tx, protocolVersion);
|
|
599
|
-
const blockProposalTopic = createTopicString(TopicType.block_proposal, protocolVersion);
|
|
600
|
-
const checkpointProposalTopic = createTopicString(TopicType.checkpoint_proposal, protocolVersion);
|
|
601
|
-
const checkpointAttestationTopic = createTopicString(TopicType.checkpoint_attestation, protocolVersion);
|
|
602
594
|
const preferredPeersEnrs = config.preferredPeers.map((enr)=>ENR.decodeTxt(enr));
|
|
603
595
|
const directPeers = (await Promise.all(preferredPeersEnrs.map(async (enr)=>{
|
|
604
596
|
const peerId = await enr.peerId();
|
|
@@ -616,6 +608,18 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
616
608
|
const announceTcpMultiaddr = config.p2pIp ? [
|
|
617
609
|
convertToMultiaddr(config.p2pIp, p2pPort, 'tcp')
|
|
618
610
|
] : [];
|
|
611
|
+
// Create dynamic topic score params based on network configuration
|
|
612
|
+
const l1Constants = epochCache.getL1Constants();
|
|
613
|
+
const topicScoreParams = createAllTopicScoreParams(protocolVersion, {
|
|
614
|
+
slotDurationMs: l1Constants.slotDuration * 1000,
|
|
615
|
+
ethereumSlotDuration: l1Constants.ethereumSlotDuration,
|
|
616
|
+
heartbeatIntervalMs: config.gossipsubInterval,
|
|
617
|
+
targetCommitteeSize: l1Constants.targetCommitteeSize,
|
|
618
|
+
blockDurationMs: config.blockDurationMs,
|
|
619
|
+
l1PublishingTime: config.l1PublishingTime,
|
|
620
|
+
p2pPropagationTime: config.attestationPropagationTime,
|
|
621
|
+
expectedBlockProposalsPerSlot: config.expectedBlockProposalsPerSlot
|
|
622
|
+
});
|
|
619
623
|
const node = await createLibp2p({
|
|
620
624
|
start: false,
|
|
621
625
|
peerId,
|
|
@@ -716,32 +720,12 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
716
720
|
scoreParams: createPeerScoreParams({
|
|
717
721
|
// IPColocation factor can be disabled for local testing - default to -5
|
|
718
722
|
IPColocationFactorWeight: config.debugDisableColocationPenalty ? 0 : -5.0,
|
|
719
|
-
topics:
|
|
720
|
-
[txTopic]: createTopicScoreParams({
|
|
721
|
-
topicWeight: 1,
|
|
722
|
-
invalidMessageDeliveriesWeight: -20,
|
|
723
|
-
invalidMessageDeliveriesDecay: 0.5
|
|
724
|
-
}),
|
|
725
|
-
[blockProposalTopic]: createTopicScoreParams({
|
|
726
|
-
topicWeight: 1,
|
|
727
|
-
invalidMessageDeliveriesWeight: -20,
|
|
728
|
-
invalidMessageDeliveriesDecay: 0.5
|
|
729
|
-
}),
|
|
730
|
-
[checkpointProposalTopic]: createTopicScoreParams({
|
|
731
|
-
topicWeight: 1,
|
|
732
|
-
invalidMessageDeliveriesWeight: -20,
|
|
733
|
-
invalidMessageDeliveriesDecay: 0.5
|
|
734
|
-
}),
|
|
735
|
-
[checkpointAttestationTopic]: createTopicScoreParams({
|
|
736
|
-
topicWeight: 1,
|
|
737
|
-
invalidMessageDeliveriesWeight: -20,
|
|
738
|
-
invalidMessageDeliveriesDecay: 0.5
|
|
739
|
-
})
|
|
740
|
-
}
|
|
723
|
+
topics: topicScoreParams
|
|
741
724
|
})
|
|
742
725
|
}),
|
|
743
726
|
components: (components)=>({
|
|
744
|
-
connectionManager: components.connectionManager
|
|
727
|
+
connectionManager: components.connectionManager,
|
|
728
|
+
addressManager: components.addressManager
|
|
745
729
|
})
|
|
746
730
|
},
|
|
747
731
|
logger: createLibp2pComponentLogger(logger.module, logger.getBindings())
|
|
@@ -749,10 +733,16 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
749
733
|
const peerScoring = new PeerScoring(config, telemetry);
|
|
750
734
|
const reqresp = new ReqResp(config, node, peerScoring, createLogger(`${logger.module}:reqresp`));
|
|
751
735
|
const peerManager = new PeerManager(node, peerDiscoveryService, config, telemetry, createLogger(`${logger.module}:peer_manager`), peerScoring, reqresp, worldStateSynchronizer, protocolVersion, epochCache);
|
|
752
|
-
//
|
|
753
|
-
|
|
736
|
+
// Gate req/resp data protocols for unauthenticated peers when p2pAllowOnlyValidators is enabled
|
|
737
|
+
reqresp.setShouldRejectPeer((peerId)=>peerManager.shouldDisableP2PGossip(peerId));
|
|
738
|
+
// Configure application-specific scoring for gossipsub.
|
|
739
|
+
// The weight scales app score to align with gossipsub thresholds:
|
|
740
|
+
// - Disconnect (-50) × 10 = -500 = gossipThreshold (stops receiving gossip)
|
|
741
|
+
// - Ban (-100) × 10 = -1000 = publishThreshold (cannot publish)
|
|
742
|
+
// Note: positive topic scores can offset penalties, so alignment is best-effort.
|
|
743
|
+
node.services.pubsub.score.params.appSpecificWeight = APP_SPECIFIC_WEIGHT;
|
|
754
744
|
node.services.pubsub.score.params.appSpecificScore = (peerId)=>peerManager.shouldDisableP2PGossip(peerId) ? -Infinity : peerManager.getPeerScore(peerId);
|
|
755
|
-
return new LibP2PService(
|
|
745
|
+
return new LibP2PService(config, node, peerDiscoveryService, reqresp, peerManager, mempools, l2BlockSource, epochCache, proofVerifier, worldStateSynchronizer, blockMinFeesProvider, telemetry, logger, txValidationCache);
|
|
756
746
|
}
|
|
757
747
|
/**
|
|
758
748
|
* Starts the LibP2P service.
|
|
@@ -762,22 +752,19 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
762
752
|
if (this.node.status === 'started') {
|
|
763
753
|
throw new Error('P2P service already started');
|
|
764
754
|
}
|
|
765
|
-
// Get listen & announce addresses for logging
|
|
766
755
|
const { p2pIp, p2pPort } = this.config;
|
|
767
|
-
if (!p2pIp) {
|
|
768
|
-
throw new Error('Announce address not provided.');
|
|
756
|
+
if (!p2pIp && !this.config.queryForIp) {
|
|
757
|
+
throw new Error('Announce address not provided and queryForIp is not enabled.');
|
|
769
758
|
}
|
|
770
|
-
const announceTcpMultiaddr = convertToMultiaddr(p2pIp, p2pPort, 'tcp');
|
|
759
|
+
const announceTcpMultiaddr = p2pIp ? convertToMultiaddr(p2pIp, p2pPort, 'tcp') : undefined;
|
|
771
760
|
// Create request response protocol handlers
|
|
772
761
|
const txHandler = reqRespTxHandler(this.mempools);
|
|
773
762
|
const goodbyeHandler = reqGoodbyeHandler(this.peerManager);
|
|
774
|
-
const blockHandler = reqRespBlockHandler(this.archiver);
|
|
775
763
|
const statusHandler = reqRespStatusHandler(this.protocolVersion, this.worldStateSynchronizer, this.logger);
|
|
776
764
|
const requestResponseHandlers = {
|
|
777
765
|
[ReqRespSubProtocol.PING]: pingHandler,
|
|
778
766
|
[ReqRespSubProtocol.STATUS]: statusHandler.bind(this),
|
|
779
|
-
[ReqRespSubProtocol.GOODBYE]: goodbyeHandler.bind(this)
|
|
780
|
-
[ReqRespSubProtocol.BLOCK]: blockHandler.bind(this)
|
|
767
|
+
[ReqRespSubProtocol.GOODBYE]: goodbyeHandler.bind(this)
|
|
781
768
|
};
|
|
782
769
|
if (!this.config.disableTransactions) {
|
|
783
770
|
const blockTxsHandler = reqRespBlockTxsHandler(this.mempools.attestationPool, this.archiver, this.mempools.txPool);
|
|
@@ -786,18 +773,11 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
786
773
|
if (!this.config.disableTransactions) {
|
|
787
774
|
requestResponseHandlers[ReqRespSubProtocol.TX] = txHandler.bind(this);
|
|
788
775
|
}
|
|
789
|
-
// Define the sub protocol validators - This is done within this start() method to gain a callback to the existing validateTx function
|
|
790
|
-
const reqrespSubProtocolValidators = {
|
|
791
|
-
...DEFAULT_SUB_PROTOCOL_VALIDATORS,
|
|
792
|
-
[ReqRespSubProtocol.TX]: this.validateRequestedTxs.bind(this),
|
|
793
|
-
[ReqRespSubProtocol.BLOCK_TXS]: this.validateRequestedBlockTxs.bind(this),
|
|
794
|
-
[ReqRespSubProtocol.BLOCK]: this.validateRequestedBlock.bind(this)
|
|
795
|
-
};
|
|
796
776
|
await this.peerManager.initializePeers();
|
|
797
|
-
await this.reqresp.start(requestResponseHandlers
|
|
777
|
+
await this.reqresp.start(requestResponseHandlers);
|
|
798
778
|
await this.node.start();
|
|
799
779
|
// Subscribe to standard GossipSub topics by default
|
|
800
|
-
for (const topic of
|
|
780
|
+
for (const topic of getTopicsForConfig(this.config.disableTransactions)){
|
|
801
781
|
this.subscribeToTopic(this.topicStrings[topic]);
|
|
802
782
|
}
|
|
803
783
|
// add GossipSub listener
|
|
@@ -806,6 +786,34 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
806
786
|
if (!this.config.p2pDiscoveryDisabled) {
|
|
807
787
|
await this.peerDiscoveryService.start();
|
|
808
788
|
}
|
|
789
|
+
// Bridge discv5 IP changes to libp2p's AddressManager so peers see the updated address
|
|
790
|
+
if (this.config.queryForIp) {
|
|
791
|
+
this.discoveredP2pIp = this.config.p2pIp;
|
|
792
|
+
this.logger.info('IP change tracking enabled, bridging discv5 IP updates to libp2p AddressManager');
|
|
793
|
+
this.ipChangedHandler = (ip)=>{
|
|
794
|
+
const addressManager = this.node.services.components.addressManager;
|
|
795
|
+
const newAddr = multiaddr(convertToMultiaddr(ip, this.config.p2pPort, 'tcp'));
|
|
796
|
+
const previousIp = this.discoveredP2pIp;
|
|
797
|
+
if (previousIp) {
|
|
798
|
+
const oldAddr = multiaddr(convertToMultiaddr(previousIp, this.config.p2pPort, 'tcp'));
|
|
799
|
+
addressManager.removeObservedAddr(oldAddr);
|
|
800
|
+
this.logger.info('Libp2p announce address updated due to IP change', {
|
|
801
|
+
previousIp,
|
|
802
|
+
newIp: ip,
|
|
803
|
+
newMultiaddr: newAddr.toString()
|
|
804
|
+
});
|
|
805
|
+
} else {
|
|
806
|
+
this.logger.info('Libp2p announce address set from initial discv5 IP discovery', {
|
|
807
|
+
ip,
|
|
808
|
+
multiaddr: newAddr.toString()
|
|
809
|
+
});
|
|
810
|
+
}
|
|
811
|
+
addressManager.addObservedAddr(newAddr);
|
|
812
|
+
addressManager.confirmObservedAddr(newAddr);
|
|
813
|
+
this.discoveredP2pIp = ip;
|
|
814
|
+
};
|
|
815
|
+
this.peerDiscoveryService.on('ip:changed', this.ipChangedHandler);
|
|
816
|
+
}
|
|
809
817
|
this.discoveryRunningPromise = new RunningPromise(async ()=>{
|
|
810
818
|
await this.peerManager.heartbeat();
|
|
811
819
|
}, this.logger, this.config.peerCheckIntervalMS);
|
|
@@ -823,6 +831,10 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
823
831
|
*/ async stop() {
|
|
824
832
|
// Remove gossip sub listener
|
|
825
833
|
this.node.services.pubsub.removeEventListener(GossipSubEvent.MESSAGE, this.gossipSubEventHandler);
|
|
834
|
+
if (this.ipChangedHandler) {
|
|
835
|
+
this.peerDiscoveryService.removeListener('ip:changed', this.ipChangedHandler);
|
|
836
|
+
this.ipChangedHandler = undefined;
|
|
837
|
+
}
|
|
826
838
|
// Stop peer manager
|
|
827
839
|
this.logger.debug('Stopping peer manager...');
|
|
828
840
|
await this.peerManager.stop();
|
|
@@ -836,8 +848,8 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
836
848
|
await this.stopLibP2P();
|
|
837
849
|
this.logger.info('LibP2P service stopped');
|
|
838
850
|
}
|
|
839
|
-
addReqRespSubProtocol(subProtocol, handler
|
|
840
|
-
return this.reqresp.addSubProtocol(subProtocol, handler
|
|
851
|
+
addReqRespSubProtocol(subProtocol, handler) {
|
|
852
|
+
return this.reqresp.addSubProtocol(subProtocol, handler);
|
|
841
853
|
}
|
|
842
854
|
registerThisValidatorAddresses(address) {
|
|
843
855
|
this.peerManager.registerThisValidatorAddresses(address);
|
|
@@ -845,6 +857,9 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
845
857
|
getPeers(includePending) {
|
|
846
858
|
return this.peerManager.getPeers(includePending);
|
|
847
859
|
}
|
|
860
|
+
getGossipMeshPeerCount(topicType) {
|
|
861
|
+
return this.node.services.pubsub.getMeshPeers(this.topicStrings[topicType]).length;
|
|
862
|
+
}
|
|
848
863
|
handleGossipSubEvent(e) {
|
|
849
864
|
this.logger.trace(`Received PUBSUB message.`);
|
|
850
865
|
const safeJob = async ()=>{
|
|
@@ -856,14 +871,6 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
856
871
|
};
|
|
857
872
|
setImmediate(()=>void safeJob());
|
|
858
873
|
}
|
|
859
|
-
/**
|
|
860
|
-
* Send a batch of requests to peers, and return the responses
|
|
861
|
-
* @param protocol - The request response protocol to use
|
|
862
|
-
* @param requests - The requests to send to the peers
|
|
863
|
-
* @returns The responses to the requests
|
|
864
|
-
*/ sendBatchRequest(protocol, requests, pinnedPeerId) {
|
|
865
|
-
return this.reqresp.sendBatchRequest(protocol, requests, pinnedPeerId);
|
|
866
|
-
}
|
|
867
874
|
sendRequestToPeer(peerId, subProtocol, payload, dialTimeout) {
|
|
868
875
|
return this.reqresp.sendRequestToPeer(peerId, subProtocol, payload, dialTimeout);
|
|
869
876
|
}
|
|
@@ -876,8 +883,11 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
876
883
|
registerBlockReceivedCallback(callback) {
|
|
877
884
|
this.blockReceivedCallback = callback;
|
|
878
885
|
}
|
|
879
|
-
|
|
880
|
-
this.
|
|
886
|
+
registerValidatorCheckpointReceivedCallback(callback) {
|
|
887
|
+
this.validatorCheckpointReceivedCallback = callback;
|
|
888
|
+
}
|
|
889
|
+
registerAllNodesCheckpointReceivedCallback(callback) {
|
|
890
|
+
this.allNodesCheckpointReceivedCallback = callback;
|
|
881
891
|
}
|
|
882
892
|
/**
|
|
883
893
|
* Registers a callback to be invoked when a duplicate proposal is detected.
|
|
@@ -886,6 +896,16 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
886
896
|
this.duplicateProposalCallback = callback;
|
|
887
897
|
}
|
|
888
898
|
/**
|
|
899
|
+
* Registers a callback to be invoked when a duplicate attestation is detected.
|
|
900
|
+
* A validator signing attestations for different proposals at the same slot.
|
|
901
|
+
* This callback is triggered on the first duplicate (when count goes from 1 to 2).
|
|
902
|
+
*/ registerDuplicateAttestationCallback(callback) {
|
|
903
|
+
this.duplicateAttestationCallback = callback;
|
|
904
|
+
}
|
|
905
|
+
registerCheckpointAttestationCallback(callback) {
|
|
906
|
+
this.checkpointAttestationCallback = callback;
|
|
907
|
+
}
|
|
908
|
+
/**
|
|
889
909
|
* Subscribes to a topic.
|
|
890
910
|
* @param topic - The topic to subscribe to.
|
|
891
911
|
*/ subscribeToTopic(topic) {
|
|
@@ -936,6 +956,12 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
936
956
|
if (!validator || !validator.addMessage(msgId)) {
|
|
937
957
|
this.instrumentation.incMessagePrevalidationStatus(false, topicType);
|
|
938
958
|
this.node.services.pubsub.reportMessageValidationResult(msgId, source.toString(), TopicValidatorResult.Ignore);
|
|
959
|
+
if (topicType === TopicType.tx) {
|
|
960
|
+
this.logger.verbose(`Ignoring already-seen tx gossip message`, {
|
|
961
|
+
msgId,
|
|
962
|
+
source: source.toString()
|
|
963
|
+
});
|
|
964
|
+
}
|
|
939
965
|
return {
|
|
940
966
|
result: false,
|
|
941
967
|
topicType
|
|
@@ -993,12 +1019,17 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
993
1019
|
}
|
|
994
1020
|
// Process the message, optionally within a linked span for trace propagation
|
|
995
1021
|
const processMessage = async ()=>{
|
|
1022
|
+
if (this.config.skipIncomingProposals && (msg.topic === this.topicStrings[TopicType.block_proposal] || msg.topic === this.topicStrings[TopicType.checkpoint_proposal])) {
|
|
1023
|
+
this.logger.warn(`Ignoring incoming proposal (skipIncomingProposals is set)`, {
|
|
1024
|
+
topic: msg.topic
|
|
1025
|
+
});
|
|
1026
|
+
this.node.services.pubsub.reportMessageValidationResult(msgId, source.toString(), TopicValidatorResult.Ignore);
|
|
1027
|
+
return;
|
|
1028
|
+
}
|
|
996
1029
|
if (msg.topic === this.topicStrings[TopicType.tx]) {
|
|
997
1030
|
await this.handleGossipedTx(p2pMessage.payload, msgId, source);
|
|
998
1031
|
} else if (msg.topic === this.topicStrings[TopicType.checkpoint_attestation]) {
|
|
999
|
-
|
|
1000
|
-
await this.processCheckpointAttestationFromPeer(p2pMessage.payload, msgId, source);
|
|
1001
|
-
}
|
|
1032
|
+
await this.processCheckpointAttestationFromPeer(p2pMessage.payload, msgId, source);
|
|
1002
1033
|
} else if (msg.topic === this.topicStrings[TopicType.block_proposal]) {
|
|
1003
1034
|
await this.processBlockFromPeer(p2pMessage.payload, msgId, source);
|
|
1004
1035
|
} else if (msg.topic === this.topicStrings[TopicType.checkpoint_proposal]) {
|
|
@@ -1043,49 +1074,162 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1043
1074
|
return;
|
|
1044
1075
|
}
|
|
1045
1076
|
async validateReceivedMessage(validationFunc, msgId, source, topicType) {
|
|
1077
|
+
// Default to reject result with a penalty if validation function throws an error
|
|
1046
1078
|
let resultAndObj = {
|
|
1047
|
-
result: TopicValidatorResult.Reject
|
|
1079
|
+
result: TopicValidatorResult.Reject,
|
|
1080
|
+
severity: PeerErrorSeverity.MidToleranceError
|
|
1048
1081
|
};
|
|
1049
1082
|
const timer = new Timer();
|
|
1050
1083
|
try {
|
|
1051
1084
|
resultAndObj = await validationFunc();
|
|
1052
1085
|
} catch (err) {
|
|
1053
|
-
this.
|
|
1054
|
-
this.logger.error(`Error deserializing and validating gossipsub message`, err, {
|
|
1086
|
+
this.logger.error(`Error validating gossipsub message`, err, {
|
|
1055
1087
|
msgId,
|
|
1056
1088
|
source: source.toString(),
|
|
1057
1089
|
topicType
|
|
1058
1090
|
});
|
|
1059
1091
|
}
|
|
1092
|
+
const validationTimeMs = timer.ms();
|
|
1093
|
+
const mcacheWindowMs = this.config.gossipsubMcacheLength * this.config.gossipsubInterval;
|
|
1094
|
+
if (validationTimeMs > mcacheWindowMs * 0.75) {
|
|
1095
|
+
this.instrumentation.incSlowValidation(topicType);
|
|
1096
|
+
this.logger.warn(`Gossip validation for ${topicType} took ${validationTimeMs}ms, approaching mcache eviction window of ${mcacheWindowMs}ms. ` + `Message forwarding may be skipped if validation exceeds the window.`, {
|
|
1097
|
+
msgId,
|
|
1098
|
+
source: source.toString(),
|
|
1099
|
+
topicType,
|
|
1100
|
+
validationTimeMs,
|
|
1101
|
+
mcacheWindowMs
|
|
1102
|
+
});
|
|
1103
|
+
}
|
|
1060
1104
|
if (resultAndObj.result === TopicValidatorResult.Accept) {
|
|
1105
|
+
this.logger.debug(`Message ${topicType} accepted by validator`, {
|
|
1106
|
+
msgId,
|
|
1107
|
+
source: source.toString(),
|
|
1108
|
+
topicType
|
|
1109
|
+
});
|
|
1061
1110
|
this.instrumentation.recordMessageValidation(topicType, timer);
|
|
1111
|
+
} else if (resultAndObj.result === TopicValidatorResult.Reject) {
|
|
1112
|
+
this.logger.warn(`Message ${topicType} rejected by validator with severity ${resultAndObj.severity}`, {
|
|
1113
|
+
msgId,
|
|
1114
|
+
source: source.toString(),
|
|
1115
|
+
topicType,
|
|
1116
|
+
severity: resultAndObj.severity
|
|
1117
|
+
});
|
|
1118
|
+
this.peerManager.penalizePeer(source, resultAndObj.severity);
|
|
1119
|
+
} else {
|
|
1120
|
+
this.logger.trace(`Message ${topicType} ignored by validator`, {
|
|
1121
|
+
msgId,
|
|
1122
|
+
source: source.toString(),
|
|
1123
|
+
topicType
|
|
1124
|
+
});
|
|
1062
1125
|
}
|
|
1063
1126
|
this.node.services.pubsub.reportMessageValidationResult(msgId, source.toString(), resultAndObj.result);
|
|
1064
1127
|
return resultAndObj;
|
|
1065
1128
|
}
|
|
1129
|
+
tryDeserialize(deserializeFunc, msgId, source) {
|
|
1130
|
+
try {
|
|
1131
|
+
return deserializeFunc();
|
|
1132
|
+
} catch (err) {
|
|
1133
|
+
this.logger.warn(`Failed to deserialize gossipsub message from buffer`, {
|
|
1134
|
+
err,
|
|
1135
|
+
msgId,
|
|
1136
|
+
source: source.toString()
|
|
1137
|
+
});
|
|
1138
|
+
return undefined;
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1066
1141
|
async handleGossipedTx(payloadData, msgId, source) {
|
|
1067
1142
|
const validationFunc = async ()=>{
|
|
1068
|
-
const tx = Tx.fromBuffer(payloadData);
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1143
|
+
const tx = this.tryDeserialize(()=>Tx.fromBuffer(payloadData), msgId, source);
|
|
1144
|
+
if (!tx) {
|
|
1145
|
+
return {
|
|
1146
|
+
result: TopicValidatorResult.Reject,
|
|
1147
|
+
severity: PeerErrorSeverity.LowToleranceError
|
|
1148
|
+
};
|
|
1149
|
+
}
|
|
1150
|
+
const currentBlockNumber = await this.archiver.getBlockNumber();
|
|
1151
|
+
const { ts: nextSlotTimestamp } = this.epochCache.getEpochAndSlotInNextL1Slot();
|
|
1152
|
+
// Stage 1: fast validators (metadata, data, timestamps, double-spend, gas, phases, block header)
|
|
1153
|
+
const firstStageValidators = await this.createFirstStageMessageValidators(currentBlockNumber, nextSlotTimestamp);
|
|
1154
|
+
const firstStageOutcome = await this.runValidations(tx, firstStageValidators);
|
|
1155
|
+
if (!firstStageOutcome.allPassed) {
|
|
1156
|
+
const { name } = firstStageOutcome.failure;
|
|
1157
|
+
let { severity } = firstStageOutcome.failure;
|
|
1158
|
+
// Double spend validator has a special case handler. We perform more detailed examination
|
|
1159
|
+
// as to how recently the nullifier was entered into the tree and if the transaction should
|
|
1160
|
+
// have 'known' the nullifier existed. This determines the severity of the penalty applied to the peer.
|
|
1161
|
+
if (name === 'doubleSpendValidator') {
|
|
1162
|
+
const txBlockNumber = BlockNumber(currentBlockNumber + 1);
|
|
1163
|
+
severity = await this.handleDoubleSpendFailure(tx, txBlockNumber);
|
|
1164
|
+
}
|
|
1165
|
+
this.logger.verbose(`Rejecting gossiped tx ${tx.getTxHash().toString()}: stage 1 validation failed`, {
|
|
1166
|
+
validator: name,
|
|
1167
|
+
severity,
|
|
1168
|
+
source: source.toString()
|
|
1169
|
+
});
|
|
1170
|
+
return {
|
|
1171
|
+
result: TopicValidatorResult.Reject,
|
|
1172
|
+
severity
|
|
1173
|
+
};
|
|
1174
|
+
}
|
|
1175
|
+
// Pool pre-check: see if the pool would accept this tx before doing expensive proof verification
|
|
1176
|
+
const canAdd = await this.mempools.txPool.canAddPendingTx(tx);
|
|
1177
|
+
if (canAdd === 'ignored') {
|
|
1178
|
+
this.logger.verbose(`Ignoring gossiped tx ${tx.getTxHash().toString()}: pool pre-check returned ignored`, {
|
|
1179
|
+
source: source.toString()
|
|
1180
|
+
});
|
|
1181
|
+
return {
|
|
1182
|
+
result: TopicValidatorResult.Ignore,
|
|
1183
|
+
obj: tx
|
|
1184
|
+
};
|
|
1185
|
+
}
|
|
1186
|
+
// Stage 2: expensive proof verification
|
|
1187
|
+
const secondStageValidators = this.createSecondStageMessageValidators();
|
|
1188
|
+
const secondStageOutcome = await this.runValidations(tx, secondStageValidators);
|
|
1189
|
+
if (!secondStageOutcome.allPassed) {
|
|
1190
|
+
const { severity, name } = secondStageOutcome.failure;
|
|
1191
|
+
this.logger.verbose(`Rejecting gossiped tx ${tx.getTxHash().toString()}: stage 2 validation failed`, {
|
|
1192
|
+
validator: name,
|
|
1193
|
+
severity,
|
|
1194
|
+
source: source.toString()
|
|
1195
|
+
});
|
|
1196
|
+
return {
|
|
1197
|
+
result: TopicValidatorResult.Reject,
|
|
1198
|
+
severity
|
|
1199
|
+
};
|
|
1200
|
+
}
|
|
1201
|
+
// Pool add: persist the tx
|
|
1202
|
+
const txHash = tx.getTxHash();
|
|
1203
|
+
const addResult = await this.mempools.txPool.addPendingTxs([
|
|
1204
|
+
tx
|
|
1205
|
+
], {
|
|
1206
|
+
source: 'gossip'
|
|
1207
|
+
});
|
|
1208
|
+
const wasAccepted = addResult.accepted.some((h)=>h.equals(txHash));
|
|
1209
|
+
const wasIgnored = addResult.ignored.some((h)=>h.equals(txHash));
|
|
1210
|
+
this.logger.verbose(`Validate propagated tx ${txHash.toString()}`, {
|
|
1211
|
+
wasAccepted,
|
|
1212
|
+
wasIgnored,
|
|
1074
1213
|
[Attributes.P2P_ID]: source.toString()
|
|
1075
1214
|
});
|
|
1076
|
-
if (
|
|
1215
|
+
if (wasAccepted) {
|
|
1077
1216
|
return {
|
|
1078
|
-
result: TopicValidatorResult.
|
|
1217
|
+
result: TopicValidatorResult.Accept,
|
|
1218
|
+
obj: tx
|
|
1079
1219
|
};
|
|
1080
|
-
} else if (
|
|
1220
|
+
} else if (wasIgnored) {
|
|
1081
1221
|
return {
|
|
1082
1222
|
result: TopicValidatorResult.Ignore,
|
|
1083
1223
|
obj: tx
|
|
1084
1224
|
};
|
|
1085
1225
|
} else {
|
|
1226
|
+
this.logger.warn(`Gossiped tx ${txHash.toString()} unexpectedly rejected by pool`, {
|
|
1227
|
+
source: source.toString(),
|
|
1228
|
+
txHash: txHash.toString()
|
|
1229
|
+
});
|
|
1086
1230
|
return {
|
|
1087
|
-
result: TopicValidatorResult.
|
|
1088
|
-
|
|
1231
|
+
result: TopicValidatorResult.Reject,
|
|
1232
|
+
severity: PeerErrorSeverity.HighToleranceError
|
|
1089
1233
|
};
|
|
1090
1234
|
}
|
|
1091
1235
|
};
|
|
@@ -1093,26 +1237,29 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1093
1237
|
if (result !== TopicValidatorResult.Accept || !tx) {
|
|
1094
1238
|
return;
|
|
1095
1239
|
}
|
|
1240
|
+
// Tx was accepted into pool and will be propagated - just log and record metrics
|
|
1096
1241
|
const txHash = tx.getTxHash();
|
|
1097
1242
|
const txHashString = txHash.toString();
|
|
1098
1243
|
this.logger.verbose(`Received tx ${txHashString} from external peer ${source.toString()} via gossip`, {
|
|
1099
1244
|
source: source.toString(),
|
|
1100
1245
|
txHash: txHashString
|
|
1101
1246
|
});
|
|
1102
|
-
if (this.config.dropTransactions && randomInt(1000) < this.config.dropTransactionsProbability * 1000) {
|
|
1103
|
-
this.logger.warn(`Intentionally dropping tx ${txHashString} (probability rule)`);
|
|
1104
|
-
return;
|
|
1105
|
-
}
|
|
1106
1247
|
this.instrumentation.incrementTxReceived(1);
|
|
1107
|
-
await this.mempools.txPool.addTxs([
|
|
1108
|
-
tx
|
|
1109
|
-
]);
|
|
1110
1248
|
}
|
|
1111
1249
|
/**
|
|
1112
1250
|
* Process a checkpoint attestation from a peer.
|
|
1113
1251
|
* Validates the attestation and adds it to the pool.
|
|
1114
1252
|
*/ async processCheckpointAttestationFromPeer(payloadData, msgId, source) {
|
|
1115
|
-
const { result, obj: attestation } = await this.validateReceivedMessage(()=>
|
|
1253
|
+
const { result, obj: attestation } = await this.validateReceivedMessage(()=>{
|
|
1254
|
+
const attestation = this.tryDeserialize(()=>CheckpointAttestation.fromBuffer(payloadData), msgId, source);
|
|
1255
|
+
if (!attestation) {
|
|
1256
|
+
return Promise.resolve({
|
|
1257
|
+
result: TopicValidatorResult.Reject,
|
|
1258
|
+
severity: PeerErrorSeverity.LowToleranceError
|
|
1259
|
+
});
|
|
1260
|
+
}
|
|
1261
|
+
return this.validateAndStoreCheckpointAttestation(source, attestation);
|
|
1262
|
+
}, msgId, source, TopicType.checkpoint_attestation);
|
|
1116
1263
|
if (result !== TopicValidatorResult.Accept || !attestation) {
|
|
1117
1264
|
return;
|
|
1118
1265
|
}
|
|
@@ -1127,9 +1274,9 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1127
1274
|
const validationResult = await this.checkpointAttestationValidator.validate(attestation);
|
|
1128
1275
|
if (validationResult.result === 'reject') {
|
|
1129
1276
|
this.logger.warn(`Penalizing peer ${peerId} for checkpoint attestation validation failure`);
|
|
1130
|
-
this.peerManager.penalizePeer(peerId, validationResult.severity);
|
|
1131
1277
|
return {
|
|
1132
|
-
result: TopicValidatorResult.Reject
|
|
1278
|
+
result: TopicValidatorResult.Reject,
|
|
1279
|
+
severity: validationResult.severity
|
|
1133
1280
|
};
|
|
1134
1281
|
}
|
|
1135
1282
|
if (validationResult.result === 'ignore') {
|
|
@@ -1138,38 +1285,57 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1138
1285
|
obj: attestation
|
|
1139
1286
|
};
|
|
1140
1287
|
}
|
|
1141
|
-
// Get committee size for the attestation's slot
|
|
1142
|
-
const slot = attestation.payload.header.slotNumber;
|
|
1143
|
-
const { committee } = await this.epochCache.getCommittee(slot);
|
|
1144
|
-
const committeeSize = committee?.length ?? 0;
|
|
1145
1288
|
// Try to add the attestation: this handles existence check, cap check, and adding in one call
|
|
1146
|
-
|
|
1289
|
+
// count is the number of attestations by this signer for this slot (for duplicate detection)
|
|
1290
|
+
const slot = attestation.payload.header.slotNumber;
|
|
1291
|
+
const { added, alreadyExists, count } = await this.mempools.attestationPool.tryAddCheckpointAttestation(attestation);
|
|
1147
1292
|
this.logger.trace(`Validate propagated checkpoint attestation`, {
|
|
1148
1293
|
added,
|
|
1149
1294
|
alreadyExists,
|
|
1295
|
+
count,
|
|
1150
1296
|
[Attributes.SLOT_NUMBER]: slot.toString(),
|
|
1151
1297
|
[Attributes.P2P_ID]: peerId.toString()
|
|
1152
1298
|
});
|
|
1153
|
-
//
|
|
1299
|
+
// Exact same attestation received, no need to re-broadcast
|
|
1154
1300
|
if (alreadyExists) {
|
|
1155
1301
|
return {
|
|
1156
1302
|
result: TopicValidatorResult.Ignore,
|
|
1157
1303
|
obj: attestation
|
|
1158
1304
|
};
|
|
1159
1305
|
}
|
|
1160
|
-
// Could not add (cap reached),
|
|
1306
|
+
// Could not add (cap reached for signer), penalize and do not re-broadcast
|
|
1161
1307
|
if (!added) {
|
|
1162
|
-
this.logger.warn(`
|
|
1308
|
+
this.logger.warn(`Rejecting checkpoint attestation due to cap`, {
|
|
1163
1309
|
slot: slot.toString(),
|
|
1164
1310
|
archive: attestation.archive.toString(),
|
|
1165
|
-
source: peerId.toString()
|
|
1311
|
+
source: peerId.toString(),
|
|
1312
|
+
attester: attestation.getSender()?.toString(),
|
|
1313
|
+
count
|
|
1166
1314
|
});
|
|
1167
1315
|
return {
|
|
1168
|
-
result: TopicValidatorResult.
|
|
1169
|
-
|
|
1316
|
+
result: TopicValidatorResult.Reject,
|
|
1317
|
+
severity: PeerErrorSeverity.HighToleranceError
|
|
1170
1318
|
};
|
|
1171
1319
|
}
|
|
1172
|
-
//
|
|
1320
|
+
// Check if this is a duplicate attestation (signer attested to a different proposal at the same slot)
|
|
1321
|
+
// count is the number of attestations by this signer for this slot
|
|
1322
|
+
if (count === 2) {
|
|
1323
|
+
const attester = attestation.getSender();
|
|
1324
|
+
if (attester) {
|
|
1325
|
+
this.logger.warn(`Detected duplicate attestation (equivocation) at slot ${slot}`, {
|
|
1326
|
+
slot: slot.toString(),
|
|
1327
|
+
archive: attestation.archive.toString(),
|
|
1328
|
+
source: peerId.toString(),
|
|
1329
|
+
attester: attester.toString()
|
|
1330
|
+
});
|
|
1331
|
+
this.duplicateAttestationCallback?.({
|
|
1332
|
+
slot,
|
|
1333
|
+
attester
|
|
1334
|
+
});
|
|
1335
|
+
}
|
|
1336
|
+
}
|
|
1337
|
+
// Attestation was added successfully - accept it so other nodes can also detect the equivocation
|
|
1338
|
+
this.checkpointAttestationCallback?.(attestation);
|
|
1173
1339
|
return {
|
|
1174
1340
|
result: TopicValidatorResult.Accept,
|
|
1175
1341
|
obj: attestation
|
|
@@ -1187,9 +1353,9 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1187
1353
|
const validationResult = await this.blockProposalValidator.validate(block);
|
|
1188
1354
|
if (validationResult.result === 'reject') {
|
|
1189
1355
|
this.logger.warn(`Penalizing peer ${peerId} for block proposal validation failure`);
|
|
1190
|
-
this.peerManager.penalizePeer(peerId, validationResult.severity);
|
|
1191
1356
|
return {
|
|
1192
|
-
result: TopicValidatorResult.Reject
|
|
1357
|
+
result: TopicValidatorResult.Reject,
|
|
1358
|
+
severity: validationResult.severity
|
|
1193
1359
|
};
|
|
1194
1360
|
}
|
|
1195
1361
|
if (validationResult.result === 'ignore') {
|
|
@@ -1199,8 +1365,8 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1199
1365
|
};
|
|
1200
1366
|
}
|
|
1201
1367
|
// Try to add the proposal: this handles existence check, cap check, and adding in one call
|
|
1202
|
-
const { added, alreadyExists,
|
|
1203
|
-
const isEquivocated =
|
|
1368
|
+
const { added, alreadyExists, count } = await this.mempools.attestationPool.tryAddBlockProposal(block);
|
|
1369
|
+
const isEquivocated = count !== undefined && count > 1;
|
|
1204
1370
|
// Duplicate proposal received, no need to re-broadcast
|
|
1205
1371
|
if (alreadyExists) {
|
|
1206
1372
|
this.logger.debug(`Ignoring duplicate block proposal received`, {
|
|
@@ -1219,11 +1385,10 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1219
1385
|
}
|
|
1220
1386
|
// Too many blocks received for this slot and index, penalize peer and do not re-broadcast
|
|
1221
1387
|
if (!added) {
|
|
1222
|
-
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.HighToleranceError);
|
|
1223
1388
|
this.logger.warn(`Penalizing peer for block proposal exceeding per-position cap`, {
|
|
1224
1389
|
...block.toBlockInfo(),
|
|
1225
1390
|
indexWithinCheckpoint: block.indexWithinCheckpoint,
|
|
1226
|
-
|
|
1391
|
+
count,
|
|
1227
1392
|
proposer: block.getSender()?.toString(),
|
|
1228
1393
|
source: peerId.toString()
|
|
1229
1394
|
});
|
|
@@ -1231,7 +1396,8 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1231
1396
|
result: TopicValidatorResult.Reject,
|
|
1232
1397
|
metadata: {
|
|
1233
1398
|
isEquivocated
|
|
1234
|
-
}
|
|
1399
|
+
},
|
|
1400
|
+
severity: PeerErrorSeverity.HighToleranceError
|
|
1235
1401
|
};
|
|
1236
1402
|
}
|
|
1237
1403
|
// If this was a duplicate proposal, do not process it, but do invoke the duplicate callback,
|
|
@@ -1244,7 +1410,7 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1244
1410
|
proposer: proposer?.toString()
|
|
1245
1411
|
});
|
|
1246
1412
|
// Invoke the duplicate callback on the first duplicate spotted only
|
|
1247
|
-
if (proposer &&
|
|
1413
|
+
if (proposer && count === 2) {
|
|
1248
1414
|
this.duplicateProposalCallback?.({
|
|
1249
1415
|
slot: block.slotNumber,
|
|
1250
1416
|
proposer,
|
|
@@ -1274,13 +1440,13 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1274
1440
|
source: sender.toString(),
|
|
1275
1441
|
...block.toBlockInfo()
|
|
1276
1442
|
});
|
|
1277
|
-
// Mark the txs in this proposal as
|
|
1278
|
-
await this.mempools.txPool.
|
|
1443
|
+
// Mark the txs in this proposal as protected
|
|
1444
|
+
await this.mempools.txPool.protectTxs(block.txHashes, block.blockHeader);
|
|
1279
1445
|
// Call the block received callback to validate the proposal.
|
|
1280
1446
|
// Note: Validators do NOT attest to individual blocks, only to checkpoint proposals.
|
|
1281
1447
|
const isValid = await this.blockReceivedCallback(block, sender);
|
|
1282
1448
|
if (!isValid) {
|
|
1283
|
-
this.logger.
|
|
1449
|
+
this.logger.info(`Block proposal validation failed for block ${block.blockNumber}`, block.toBlockInfo());
|
|
1284
1450
|
}
|
|
1285
1451
|
}
|
|
1286
1452
|
/**
|
|
@@ -1288,15 +1454,24 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1288
1454
|
* Validates and processes the checkpoint proposal, then triggers the callback for attestation.
|
|
1289
1455
|
*/ async handleGossipedCheckpointProposal(payloadData, msgId, source) {
|
|
1290
1456
|
const { result, obj: checkpoint, metadata: { isEquivocated, processBlock } = {} } = await this.validateReceivedMessage(()=>this.validateAndStoreCheckpointProposal(source, CheckpointProposal.fromBuffer(payloadData)), msgId, source, TopicType.checkpoint_proposal);
|
|
1457
|
+
// Process checkpoint proposal if valid and not equivocated.
|
|
1458
|
+
const processCheckpointFn = ()=>result === TopicValidatorResult.Accept && checkpoint && !isEquivocated ? this.processValidCheckpointProposal(checkpoint.toCore(), source) : Promise.resolve();
|
|
1291
1459
|
// If the checkpoint contained a valid last block, we process it even if the checkpoint itself is to be rejected
|
|
1292
1460
|
// TODO(palla/mbps): Is this ok? Should we be considering a block from a checkpoint that was equivocated?
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1461
|
+
const processBlockFn = ()=>processBlock && checkpoint && checkpoint.getBlockProposal() ? this.processValidBlockProposal(checkpoint.getBlockProposal(), source) : Promise.resolve();
|
|
1462
|
+
// A node that skips checkpoint validation attests without re-executing the embedded last block, so run
|
|
1463
|
+
// the checkpoint callback first: this creates and broadcasts the attestation before the block is
|
|
1464
|
+
// processed. Otherwise the block's re-execution — which can stall until the re-execution deadline
|
|
1465
|
+
// waiting for a parent that may never arrive — would delay the attestation past the slot's attestation
|
|
1466
|
+
// window, after which peers reject it as stale.
|
|
1467
|
+
if (this.config.skipCheckpointProposalValidation) {
|
|
1468
|
+
await processCheckpointFn();
|
|
1469
|
+
await processBlockFn();
|
|
1297
1470
|
return;
|
|
1298
1471
|
}
|
|
1299
|
-
|
|
1472
|
+
// Process the block first, since it's required for the checkpoint proposal validation.
|
|
1473
|
+
await processBlockFn();
|
|
1474
|
+
await processCheckpointFn();
|
|
1300
1475
|
}
|
|
1301
1476
|
/**
|
|
1302
1477
|
* Validates a checkpoint proposal. Penalizes peer if validation fails. Adds the checkpoint and
|
|
@@ -1305,9 +1480,9 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1305
1480
|
const validationResult = await this.checkpointProposalValidator.validate(checkpoint);
|
|
1306
1481
|
if (validationResult.result === 'reject') {
|
|
1307
1482
|
this.logger.warn(`Penalizing peer ${peerId} for checkpoint proposal validation failure`);
|
|
1308
|
-
this.peerManager.penalizePeer(peerId, validationResult.severity);
|
|
1309
1483
|
return {
|
|
1310
|
-
result: TopicValidatorResult.Reject
|
|
1484
|
+
result: TopicValidatorResult.Reject,
|
|
1485
|
+
severity: validationResult.severity
|
|
1311
1486
|
};
|
|
1312
1487
|
}
|
|
1313
1488
|
if (validationResult.result === 'ignore') {
|
|
@@ -1324,26 +1499,28 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1324
1499
|
[Attributes.SLOT_NUMBER]: checkpoint.slotNumber.toString(),
|
|
1325
1500
|
[Attributes.P2P_ID]: peerId.toString()
|
|
1326
1501
|
});
|
|
1327
|
-
const
|
|
1328
|
-
|
|
1502
|
+
const blockProposalResult = await this.validateAndStoreBlockProposal(peerId, blockProposal);
|
|
1503
|
+
const { obj, metadata: { isEquivocated } = {} } = blockProposalResult;
|
|
1504
|
+
if (blockProposalResult.result === TopicValidatorResult.Reject || !obj || isEquivocated) {
|
|
1329
1505
|
this.logger.debug(`Rejecting checkpoint due to invalid last block proposal`, {
|
|
1330
1506
|
[Attributes.SLOT_NUMBER]: checkpoint.slotNumber.toString(),
|
|
1331
1507
|
[Attributes.P2P_ID]: peerId.toString(),
|
|
1332
1508
|
isEquivocated,
|
|
1333
|
-
result
|
|
1509
|
+
result: blockProposalResult.result
|
|
1334
1510
|
});
|
|
1335
1511
|
return {
|
|
1336
|
-
result: TopicValidatorResult.Reject
|
|
1512
|
+
result: TopicValidatorResult.Reject,
|
|
1513
|
+
severity: 'severity' in blockProposalResult ? blockProposalResult.severity : PeerErrorSeverity.MidToleranceError
|
|
1337
1514
|
};
|
|
1338
|
-
} else if (result === TopicValidatorResult.Accept && obj && !isEquivocated) {
|
|
1515
|
+
} else if (blockProposalResult.result === TopicValidatorResult.Accept && obj && !isEquivocated) {
|
|
1339
1516
|
processBlock = true;
|
|
1340
1517
|
}
|
|
1341
1518
|
}
|
|
1342
1519
|
// Try to add the checkpoint proposal core: this handles existence check, cap check, and adding in one call
|
|
1343
1520
|
const checkpointCore = checkpoint.toCore();
|
|
1344
1521
|
const tryAddResult = await this.mempools.attestationPool.tryAddCheckpointProposal(checkpointCore);
|
|
1345
|
-
const { added, alreadyExists,
|
|
1346
|
-
const isEquivocated =
|
|
1522
|
+
const { added, alreadyExists, count } = tryAddResult;
|
|
1523
|
+
const isEquivocated = count !== undefined && count > 1;
|
|
1347
1524
|
// Duplicate proposal received, do not re-broadcast
|
|
1348
1525
|
if (alreadyExists) {
|
|
1349
1526
|
this.logger.debug(`Ignoring duplicate checkpoint proposal received`, {
|
|
@@ -1362,10 +1539,9 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1362
1539
|
// Too many checkpoint proposals received for this slot, penalize peer and do not re-broadcast
|
|
1363
1540
|
// Note: We still return the checkpoint obj so the lastBlock can be processed if valid
|
|
1364
1541
|
if (!added) {
|
|
1365
|
-
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.HighToleranceError);
|
|
1366
1542
|
this.logger.warn(`Penalizing peer for checkpoint proposal exceeding per-slot cap`, {
|
|
1367
1543
|
...checkpoint.toCheckpointInfo(),
|
|
1368
|
-
|
|
1544
|
+
count,
|
|
1369
1545
|
source: peerId.toString()
|
|
1370
1546
|
});
|
|
1371
1547
|
return {
|
|
@@ -1374,7 +1550,8 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1374
1550
|
metadata: {
|
|
1375
1551
|
isEquivocated,
|
|
1376
1552
|
processBlock
|
|
1377
|
-
}
|
|
1553
|
+
},
|
|
1554
|
+
severity: PeerErrorSeverity.HighToleranceError
|
|
1378
1555
|
};
|
|
1379
1556
|
}
|
|
1380
1557
|
// If this was a duplicate proposal, do not process it, but do invoke the duplicate callback,
|
|
@@ -1387,7 +1564,7 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1387
1564
|
proposer: proposer?.toString()
|
|
1388
1565
|
});
|
|
1389
1566
|
// Invoke the duplicate callback on the first duplicate spotted only
|
|
1390
|
-
if (proposer &&
|
|
1567
|
+
if (proposer && count === 2) {
|
|
1391
1568
|
this.duplicateProposalCallback?.({
|
|
1392
1569
|
slot: checkpoint.slotNumber,
|
|
1393
1570
|
proposer,
|
|
@@ -1424,9 +1601,10 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1424
1601
|
archive: checkpoint.archive.toString(),
|
|
1425
1602
|
source: sender.toString()
|
|
1426
1603
|
});
|
|
1604
|
+
await this.allNodesCheckpointReceivedCallback(checkpoint, sender);
|
|
1427
1605
|
// Call the checkpoint received callback with the core version (without lastBlock)
|
|
1428
1606
|
// to validate and potentially generate attestations
|
|
1429
|
-
const attestations = await this.
|
|
1607
|
+
const attestations = await this.validatorCheckpointReceivedCallback(checkpoint, sender);
|
|
1430
1608
|
if (attestations && attestations.length > 0) {
|
|
1431
1609
|
// If the callback returned attestations, add them to the pool and propagate them
|
|
1432
1610
|
await this.mempools.attestationPool.addOwnCheckpointAttestations(attestations);
|
|
@@ -1450,192 +1628,78 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1450
1628
|
});
|
|
1451
1629
|
}
|
|
1452
1630
|
/**
|
|
1453
|
-
* Validate the requested block transactions
|
|
1631
|
+
* Validate the requested block transactions request-response consistency.
|
|
1632
|
+
* It does NOT validate the transactions themselves.
|
|
1454
1633
|
* @param request - The block transactions request.
|
|
1455
1634
|
* @param response - The block transactions response.
|
|
1456
1635
|
* @param peerId - The ID of the peer that made the request.
|
|
1457
|
-
* @returns True if the
|
|
1458
|
-
*/ async
|
|
1459
|
-
const requestedTxValidator = this.createRequestedTxValidator();
|
|
1636
|
+
* @returns True if the request-response is consistent, false otherwise.
|
|
1637
|
+
*/ async validateRequestedBlockTxsConsistency(request, response, peerId) {
|
|
1460
1638
|
try {
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
throw new ValidationError(`Received block txs for unexpected archive root: expected ${request.archiveRoot.toString()}, got ${response.archiveRoot.toString()}`);
|
|
1464
|
-
}
|
|
1465
|
-
if (response.txIndices.getLength() !== request.txIndices.getLength()) {
|
|
1466
|
-
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
1467
|
-
throw new ValidationError(`Received block txs with mismatched bitvector length: expected ${request.txIndices.getLength()}, got ${response.txIndices.getLength()}`);
|
|
1468
|
-
}
|
|
1469
|
-
// Check no duplicates and not exceeding returnable count
|
|
1470
|
-
const requestedIndices = new Set(request.txIndices.getTrueIndices());
|
|
1471
|
-
const availableIndices = new Set(response.txIndices.getTrueIndices());
|
|
1472
|
-
const maxReturnable = [
|
|
1473
|
-
...requestedIndices
|
|
1474
|
-
].filter((i)=>availableIndices.has(i)).length;
|
|
1475
|
-
const returnedHashes = await Promise.all(response.txs.map((tx)=>tx.getTxHash().toString()));
|
|
1639
|
+
// Check for duplicates txs (or hashes) in the response.
|
|
1640
|
+
const returnedHashes = response.txs.map((tx)=>tx.getTxHash().toString());
|
|
1476
1641
|
const uniqueReturned = new Set(returnedHashes.map((h)=>h.toString()));
|
|
1477
1642
|
if (uniqueReturned.size !== returnedHashes.length) {
|
|
1478
1643
|
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
1479
1644
|
throw new ValidationError(`Received duplicate txs in block txs response`);
|
|
1480
1645
|
}
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
if (
|
|
1488
|
-
//
|
|
1489
|
-
|
|
1490
|
-
//
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
i
|
|
1494
|
-
]));
|
|
1495
|
-
const allowedIndexSet = new Set(intersectIdx);
|
|
1496
|
-
const indices = returnedHashes.map((h)=>hashToIndexInProposal.get(h));
|
|
1497
|
-
const allAllowed = indices.every((idx)=>idx !== undefined && allowedIndexSet.has(idx));
|
|
1498
|
-
const strictlyIncreasing = indices.every((idx, i)=>i === 0 ? idx !== undefined : idx > indices[i - 1]);
|
|
1499
|
-
if (!allAllowed || !strictlyIncreasing) {
|
|
1500
|
-
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
|
|
1501
|
-
throw new ValidationError('Returned txs do not match expected subset/order for requested indices');
|
|
1502
|
-
}
|
|
1503
|
-
} else {
|
|
1504
|
-
// No local proposal, cannot check the membership/order of the returned txs
|
|
1505
|
-
this.logger.warn(`Block proposal not found for archive root ${request.archiveRoot.toString()}; cannot validate membership/order of returned txs`);
|
|
1646
|
+
// We get the block tx hashes from the proposal or the archiver.
|
|
1647
|
+
const proposal = await this.mempools.attestationPool.getBlockProposalByArchive(request.archiveRoot.toString());
|
|
1648
|
+
const blockTxHashes = proposal?.txHashes ?? (await this.archiver.getBlock({
|
|
1649
|
+
archive: request.archiveRoot
|
|
1650
|
+
}))?.body.txEffects.map((e)=>e.txHash);
|
|
1651
|
+
// If we don't have the block, we can't verify membership/order of the returned txs.
|
|
1652
|
+
if (!blockTxHashes) {
|
|
1653
|
+
// This shouldn't happen, since we asked for the block (proposal).
|
|
1654
|
+
// Neither a local proposal nor an archived block: we cannot verify membership/order of the
|
|
1655
|
+
// returned txs. This is a local-state gap, not a peer fault, so we do not penalize.
|
|
1656
|
+
this.logger.warn(`Block ${request.archiveRoot.toString()} not found in attestation pool or archiver; cannot validate membership/order of returned txs`);
|
|
1657
|
+
// NOTE: We mark the response as invalid, given the limitations of a true/false return value.
|
|
1506
1658
|
return false;
|
|
1507
1659
|
}
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
return false;
|
|
1517
|
-
}
|
|
1518
|
-
}
|
|
1519
|
-
/**
|
|
1520
|
-
* Validate a collection of txs that has been requested from a peer.
|
|
1521
|
-
*
|
|
1522
|
-
* The core component of this validator is that each tx hash MUST match the requested tx hash,
|
|
1523
|
-
* In order to perform this check, the tx proof must be verified.
|
|
1524
|
-
*
|
|
1525
|
-
* Note: This function is called from within `ReqResp.sendRequest` as part of the
|
|
1526
|
-
* ReqRespSubProtocol.TX subprotocol validation.
|
|
1527
|
-
*
|
|
1528
|
-
* @param requestedTxHash - The collection of the txs that was requested.
|
|
1529
|
-
* @param responseTx - The collection of txs that was received as a response to the request.
|
|
1530
|
-
* @param peerId - The peer ID of the peer that sent the tx.
|
|
1531
|
-
* @returns True if the whole collection of txs is valid, false otherwise.
|
|
1532
|
-
*/ async validateRequestedTxs(requestedTxHash, responseTx, peerId) {
|
|
1533
|
-
const requested = new Set(requestedTxHash.map((h)=>h.toString()));
|
|
1534
|
-
const requestedTxValidator = this.createRequestedTxValidator();
|
|
1535
|
-
//TODO: (mralj) - this is somewhat naive implementation, if single tx is invalid we consider the whole response invalid.
|
|
1536
|
-
// I think we should still extract the valid txs and return them, so that we can still use the response.
|
|
1537
|
-
try {
|
|
1538
|
-
await Promise.all(responseTx.map((tx)=>this.validateRequestedTx(tx, peerId, requestedTxValidator, requested)));
|
|
1539
|
-
return true;
|
|
1540
|
-
} catch (e) {
|
|
1541
|
-
if (e instanceof ValidationError) {
|
|
1542
|
-
this.logger.warn(`Failed to validate requested txs from peer ${peerId.toString()}, reason ${e.message}`);
|
|
1543
|
-
} else {
|
|
1544
|
-
this.logger.error(`Error during validation of requested txs`, e);
|
|
1545
|
-
}
|
|
1546
|
-
return false;
|
|
1547
|
-
}
|
|
1548
|
-
}
|
|
1549
|
-
/**
|
|
1550
|
-
* Validates a BLOCK response.
|
|
1551
|
-
*
|
|
1552
|
-
* If a local copy exists, enforces hash equality. If missing, rejects (no penalty) since the hash cannot be verified.
|
|
1553
|
-
* Penalizes on block number mismatch or hash mismatch.
|
|
1554
|
-
*
|
|
1555
|
-
* @param requestedBlockNumber - The requested block number.
|
|
1556
|
-
* @param responseBlock - The block returned by the peer.
|
|
1557
|
-
* @param peerId - The peer that returned the block.
|
|
1558
|
-
* @returns True if the response is valid, false otherwise.
|
|
1559
|
-
*/ async validateRequestedBlock(requestedBlockNumber, responseBlock, peerId) {
|
|
1560
|
-
try {
|
|
1561
|
-
const reqNum = Number(requestedBlockNumber.toString());
|
|
1562
|
-
if (responseBlock.number !== reqNum) {
|
|
1660
|
+
// Verify that the returned tx hashes are a subset of (tx hashes by index) U (explicitly requested tx hashes).
|
|
1661
|
+
const uniqueRequestedHashes = new Set([
|
|
1662
|
+
// tx hashes requested by index.
|
|
1663
|
+
...request.txIndices.getTrueIndices().map((i)=>blockTxHashes[i].toString()),
|
|
1664
|
+
// explicitly requested tx hashes.
|
|
1665
|
+
...request.txHashes.map((h)=>h.toString())
|
|
1666
|
+
]);
|
|
1667
|
+
if (!returnedHashes.every((h)=>uniqueRequestedHashes.has(h))) {
|
|
1563
1668
|
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
|
|
1564
|
-
|
|
1669
|
+
throw new ValidationError('Returned txs should be a subset of (tx hashes by index) U (explicitly requested tx hashes)');
|
|
1565
1670
|
}
|
|
1566
|
-
|
|
1567
|
-
if (!
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
// performing quorum-based checks when using P2P syncing prior to L1 sync.
|
|
1571
|
-
this.logger.warn(`Local block ${reqNum} not found; rejecting BLOCK response without hash verification`);
|
|
1572
|
-
return false;
|
|
1671
|
+
// Tx indices information is optional, but if present, we need to verify a few things.
|
|
1672
|
+
if (!response.peerHasBlock()) {
|
|
1673
|
+
this.logger.debug(`Peer ${peerId.toString()} signalled missing block`);
|
|
1674
|
+
return true;
|
|
1573
1675
|
}
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
responseBlock.hash()
|
|
1577
|
-
]);
|
|
1578
|
-
if (!localHash.equals(respHash)) {
|
|
1676
|
+
// If the response has a non-empty bitvector, it needs to be consistent with the number of txs in the block.
|
|
1677
|
+
if (response.txIndices.getLength() !== blockTxHashes.length) {
|
|
1579
1678
|
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
1580
|
-
|
|
1679
|
+
throw new ValidationError(`Received block txs with mismatched bitvector length: expected ${blockTxHashes.length}, got ${response.txIndices.getLength()}`);
|
|
1680
|
+
}
|
|
1681
|
+
// For every index we requested that the peer claims to have (per its bitvector), the
|
|
1682
|
+
// corresponding tx must be present in the response. A peer advertising availability but
|
|
1683
|
+
// withholding the tx is inconsistent.
|
|
1684
|
+
const returnedHashSet = new Set(returnedHashes);
|
|
1685
|
+
const expectedIndices = request.txIndices.getTrueIndices().filter((i)=>response.txIndices.isSet(i));
|
|
1686
|
+
const missingExpected = expectedIndices.some((i)=>!returnedHashSet.has(blockTxHashes[i].toString()));
|
|
1687
|
+
if (missingExpected) {
|
|
1688
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
|
|
1689
|
+
throw new ValidationError('Peer advertised requested txs via indices but did not return them');
|
|
1581
1690
|
}
|
|
1582
1691
|
return true;
|
|
1583
1692
|
} catch (e) {
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
async validateRequestedTx(tx, peerId, txValidator, requested) {
|
|
1589
|
-
const penalize = (severity)=>this.peerManager.penalizePeer(peerId, severity);
|
|
1590
|
-
if (requested && !requested.has(tx.getTxHash().toString())) {
|
|
1591
|
-
penalize(PeerErrorSeverity.MidToleranceError);
|
|
1592
|
-
throw new ValidationError(`Received tx with hash ${tx.getTxHash().toString()} that was not requested.`);
|
|
1593
|
-
}
|
|
1594
|
-
const { result } = await txValidator.validateTx(tx);
|
|
1595
|
-
if (result === 'invalid') {
|
|
1596
|
-
penalize(PeerErrorSeverity.LowToleranceError);
|
|
1597
|
-
throw new ValidationError(`Received tx with hash ${tx.getTxHash().toString()} that is invalid.`);
|
|
1598
|
-
}
|
|
1599
|
-
}
|
|
1600
|
-
createRequestedTxValidator() {
|
|
1601
|
-
return createTxReqRespValidator(this.proofVerifier, {
|
|
1602
|
-
l1ChainId: this.config.l1ChainId,
|
|
1603
|
-
rollupVersion: this.config.rollupVersion
|
|
1604
|
-
});
|
|
1605
|
-
}
|
|
1606
|
-
async validatePropagatedTx(tx, peerId) {
|
|
1607
|
-
const currentBlockNumber = await this.archiver.getBlockNumber();
|
|
1608
|
-
// We accept transactions if they are not expired by the next slot (checked based on the IncludeByTimestamp field)
|
|
1609
|
-
const { ts: nextSlotTimestamp } = this.epochCache.getEpochAndSlotInNextL1Slot();
|
|
1610
|
-
const messageValidators = await this.createMessageValidators(currentBlockNumber, nextSlotTimestamp);
|
|
1611
|
-
for (const validator of messageValidators){
|
|
1612
|
-
const outcome = await this.runValidations(tx, validator);
|
|
1613
|
-
if (outcome.allPassed) {
|
|
1614
|
-
continue;
|
|
1615
|
-
}
|
|
1616
|
-
const { name } = outcome.failure;
|
|
1617
|
-
let { severity } = outcome.failure;
|
|
1618
|
-
// Double spend validator has a special case handler
|
|
1619
|
-
if (name === 'doubleSpendValidator') {
|
|
1620
|
-
const txBlockNumber = BlockNumber(currentBlockNumber + 1); // tx is expected to be in the next block
|
|
1621
|
-
severity = await this.handleDoubleSpendFailure(tx, txBlockNumber);
|
|
1693
|
+
if (e instanceof ValidationError) {
|
|
1694
|
+
this.logger.warn(`Failed validation for requested block txs from peer ${peerId.toString()}`);
|
|
1695
|
+
} else {
|
|
1696
|
+
this.logger.error(`Error during validation of requested block txs`, e);
|
|
1622
1697
|
}
|
|
1623
|
-
this.peerManager.penalizePeer(peerId, severity);
|
|
1624
1698
|
return false;
|
|
1625
1699
|
}
|
|
1626
|
-
return true;
|
|
1627
1700
|
}
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
return this.feesCache.gasFees;
|
|
1631
|
-
}
|
|
1632
|
-
const header = await this.archiver.getBlockHeader(blockNumber);
|
|
1633
|
-
const gasFees = header?.globalVariables.gasFees ?? GasFees.empty();
|
|
1634
|
-
this.feesCache = {
|
|
1635
|
-
blockNumber,
|
|
1636
|
-
gasFees
|
|
1637
|
-
};
|
|
1638
|
-
return gasFees;
|
|
1701
|
+
getGasFees() {
|
|
1702
|
+
return this.blockMinFeesProvider.getCurrentMinFees();
|
|
1639
1703
|
}
|
|
1640
1704
|
/**
|
|
1641
1705
|
* Get the BatchTxRequesterLibP2PService dependencies for creating BatchTxRequester instances
|
|
@@ -1646,43 +1710,42 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1646
1710
|
txValidatorConfig: {
|
|
1647
1711
|
l1ChainId: this.config.l1ChainId,
|
|
1648
1712
|
rollupVersion: this.config.rollupVersion,
|
|
1649
|
-
proofVerifier: this.proofVerifier
|
|
1713
|
+
proofVerifier: this.proofVerifier,
|
|
1714
|
+
txValidationCache: this.txValidationCache
|
|
1650
1715
|
},
|
|
1651
|
-
peerScoring: this.peerManager
|
|
1716
|
+
peerScoring: this.peerManager,
|
|
1717
|
+
validateRequestedBlockTxsConsistency: this.validateRequestedBlockTxsConsistency.bind(this)
|
|
1652
1718
|
};
|
|
1653
1719
|
}
|
|
1654
|
-
async
|
|
1655
|
-
const
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
await Promise.all(txs.map(async (tx)=>{
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
if (!outcome.allPassed) {
|
|
1663
|
-
throw new Error('Invalid tx detected', {
|
|
1664
|
-
cause: {
|
|
1665
|
-
outcome
|
|
1666
|
-
}
|
|
1667
|
-
});
|
|
1668
|
-
}
|
|
1669
|
-
}
|
|
1720
|
+
async validateTxsReceivedInBlockProposal(txs) {
|
|
1721
|
+
const validator = createTxValidatorForBlockProposalReceivedTxs(this.proofVerifier, {
|
|
1722
|
+
l1ChainId: this.config.l1ChainId,
|
|
1723
|
+
rollupVersion: this.config.rollupVersion
|
|
1724
|
+
}, this.logger.getBindings(), this.txValidationCache);
|
|
1725
|
+
const results = await Promise.all(txs.map(async (tx)=>{
|
|
1726
|
+
const result = await validator.validateTx(tx);
|
|
1727
|
+
return result.result !== 'invalid';
|
|
1670
1728
|
}));
|
|
1729
|
+
if (results.some((value)=>value === false)) {
|
|
1730
|
+
throw new Error('Invalid tx detected');
|
|
1731
|
+
}
|
|
1671
1732
|
}
|
|
1672
|
-
/**
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1733
|
+
/** Creates the first stage (fast) validators for gossiped transactions. */ async createFirstStageMessageValidators(currentBlockNumber, nextSlotTimestamp) {
|
|
1734
|
+
const gasFees = await this.getGasFees();
|
|
1735
|
+
const allowedInSetup = [
|
|
1736
|
+
...await getDefaultAllowedSetupFunctions(),
|
|
1737
|
+
...this.config.txPublicSetupAllowListExtend ?? []
|
|
1738
|
+
];
|
|
1739
|
+
const blockNumber = BlockNumber(currentBlockNumber + 1);
|
|
1740
|
+
const l1Constants = await this.archiver.getL1Constants();
|
|
1741
|
+
return createFirstStageTxValidationsForGossipedTransactions(nextSlotTimestamp, blockNumber, this.worldStateSynchronizer, gasFees, this.config.l1ChainId, this.config.rollupVersion, protocolContractsHash, this.archiver, !this.config.disableTransactions, allowedInSetup, this.logger.getBindings(), {
|
|
1742
|
+
rollupManaLimit: l1Constants.rollupManaLimit,
|
|
1743
|
+
maxBlockL2Gas: this.config.validateMaxL2BlockGas,
|
|
1744
|
+
maxBlockDAGas: this.config.validateMaxDABlockGas
|
|
1745
|
+
});
|
|
1746
|
+
}
|
|
1747
|
+
/** Creates the second stage (expensive proof verification) validators for gossiped transactions. */ createSecondStageMessageValidators() {
|
|
1748
|
+
return createSecondStageTxValidationsForGossipedTransactions(this.proofVerifier, this.logger.getBindings());
|
|
1686
1749
|
}
|
|
1687
1750
|
/**
|
|
1688
1751
|
* Run validations on a tx.
|
|
@@ -1700,8 +1763,10 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1700
1763
|
});
|
|
1701
1764
|
// A promise that resolves when all validations have been run
|
|
1702
1765
|
const allValidations = await Promise.all(validationPromises);
|
|
1703
|
-
const
|
|
1704
|
-
if (
|
|
1766
|
+
const failures = allValidations.filter((x)=>!x.isValid);
|
|
1767
|
+
if (failures.length > 0) {
|
|
1768
|
+
// Pick the most severe failure (lowest tolerance = harshest penalty)
|
|
1769
|
+
const failed = maxBy(failures, (f)=>PeerErrorSeverityByHarshness.indexOf(f.severity));
|
|
1705
1770
|
return {
|
|
1706
1771
|
allPassed: false,
|
|
1707
1772
|
failure: {
|
|
@@ -1748,19 +1813,6 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
|
|
|
1748
1813
|
}
|
|
1749
1814
|
return PeerErrorSeverity.HighToleranceError;
|
|
1750
1815
|
}
|
|
1751
|
-
/**
|
|
1752
|
-
* Validate a checkpoint attestation.
|
|
1753
|
-
*
|
|
1754
|
-
* @param attestation - The checkpoint attestation to validate.
|
|
1755
|
-
* @returns True if the checkpoint attestation is valid, false otherwise.
|
|
1756
|
-
*/ async validateCheckpointAttestation(peerId, attestation) {
|
|
1757
|
-
const result = await this.checkpointAttestationValidator.validate(attestation);
|
|
1758
|
-
if (result.result === 'reject') {
|
|
1759
|
-
this.logger.warn(`Penalizing peer ${peerId} for checkpoint attestation validation failure`);
|
|
1760
|
-
this.peerManager.penalizePeer(peerId, result.severity);
|
|
1761
|
-
}
|
|
1762
|
-
return result;
|
|
1763
|
-
}
|
|
1764
1816
|
getPeerScore(peerId) {
|
|
1765
1817
|
return this.node.services.pubsub.score.score(peerId.toString());
|
|
1766
1818
|
}
|