@aztec/p2p 0.0.1-commit.6d63667d → 0.0.1-commit.7b97ef96e
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dest/client/factory.d.ts +7 -6
- package/dest/client/factory.d.ts.map +1 -1
- package/dest/client/factory.js +46 -11
- package/dest/client/interface.d.ts +43 -23
- package/dest/client/interface.d.ts.map +1 -1
- package/dest/client/p2p_client.d.ts +38 -42
- package/dest/client/p2p_client.d.ts.map +1 -1
- package/dest/client/p2p_client.js +145 -145
- package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.js +6 -6
- package/dest/config.d.ts +23 -4
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +16 -1
- 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 -1
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +1 -0
- package/dest/mem_pools/attestation_pool/attestation_pool.d.ts +104 -88
- package/dest/mem_pools/attestation_pool/attestation_pool.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/attestation_pool.js +441 -3
- package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.d.ts +2 -2
- 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 +353 -87
- package/dest/mem_pools/attestation_pool/index.d.ts +2 -3
- package/dest/mem_pools/attestation_pool/index.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/index.js +1 -2
- 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 +2 -2
- package/dest/mem_pools/index.d.ts +3 -2
- package/dest/mem_pools/index.d.ts.map +1 -1
- package/dest/mem_pools/index.js +1 -1
- package/dest/mem_pools/interface.d.ts +5 -5
- package/dest/mem_pools/interface.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.js +3 -3
- 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 +4 -1
- 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 +10 -4
- package/dest/mem_pools/tx_pool_v2/eviction/index.d.ts +2 -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 +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/interfaces.d.ts +48 -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 +5 -3
- package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.d.ts +1 -1
- 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 +8 -4
- 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 +14 -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 +2 -2
- package/dest/mem_pools/tx_pool_v2/index.d.ts +2 -1
- package/dest/mem_pools/tx_pool_v2/index.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/index.js +1 -0
- 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 +16 -4
- package/dest/mem_pools/tx_pool_v2/interfaces.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/interfaces.js +3 -1
- package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts +31 -5
- package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/tx_metadata.js +62 -5
- 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 +27 -4
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts +8 -3
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2.js +11 -6
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts +12 -4
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.js +239 -109
- package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts +3 -3
- package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts +3 -3
- package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts.map +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/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/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/services/dummy_service.d.ts +12 -3
- package/dest/services/dummy_service.d.ts.map +1 -1
- package/dest/services/dummy_service.js +9 -0
- package/dest/services/encoding.d.ts +2 -2
- package/dest/services/encoding.d.ts.map +1 -1
- package/dest/services/encoding.js +4 -3
- 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 +173 -0
- package/dest/services/gossipsub/topic_score_params.d.ts.map +1 -0
- package/dest/services/gossipsub/topic_score_params.js +346 -0
- package/dest/services/libp2p/libp2p_service.d.ts +85 -35
- package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
- package/dest/services/libp2p/libp2p_service.js +370 -267
- package/dest/services/peer-manager/peer_scoring.d.ts +1 -1
- package/dest/services/peer-manager/peer_scoring.d.ts.map +1 -1
- package/dest/services/peer-manager/peer_scoring.js +25 -2
- package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts +4 -3
- 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 +5 -9
- package/dest/services/reqresp/batch-tx-requester/interface.d.ts +2 -6
- package/dest/services/reqresp/batch-tx-requester/interface.d.ts.map +1 -1
- package/dest/services/reqresp/batch-tx-requester/missing_txs.d.ts +10 -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 +25 -46
- package/dest/services/reqresp/interface.d.ts +10 -1
- package/dest/services/reqresp/interface.d.ts.map +1 -1
- package/dest/services/reqresp/interface.js +15 -1
- package/dest/services/reqresp/protocols/block_txs/block_txs_handler.d.ts +4 -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_reqresp.d.ts +7 -1
- 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 +15 -0
- 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 +20 -0
- package/dest/services/reqresp/reqresp.d.ts +1 -1
- package/dest/services/reqresp/reqresp.d.ts.map +1 -1
- package/dest/services/reqresp/reqresp.js +11 -4
- package/dest/services/service.d.ts +38 -2
- package/dest/services/service.d.ts.map +1 -1
- package/dest/services/tx_collection/config.d.ts +19 -1
- package/dest/services/tx_collection/config.d.ts.map +1 -1
- package/dest/services/tx_collection/config.js +46 -0
- package/dest/services/tx_collection/fast_tx_collection.d.ts +3 -1
- package/dest/services/tx_collection/fast_tx_collection.d.ts.map +1 -1
- package/dest/services/tx_collection/fast_tx_collection.js +56 -36
- package/dest/services/tx_collection/file_store_tx_collection.d.ts +53 -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 +167 -0
- package/dest/services/tx_collection/file_store_tx_source.d.ts +37 -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 +90 -0
- package/dest/services/tx_collection/index.d.ts +2 -1
- package/dest/services/tx_collection/index.d.ts.map +1 -1
- package/dest/services/tx_collection/index.js +1 -0
- package/dest/services/tx_collection/instrumentation.d.ts +1 -1
- package/dest/services/tx_collection/instrumentation.d.ts.map +1 -1
- package/dest/services/tx_collection/instrumentation.js +2 -1
- package/dest/services/tx_collection/missing_txs_tracker.d.ts +32 -0
- package/dest/services/tx_collection/missing_txs_tracker.d.ts.map +1 -0
- package/dest/services/tx_collection/missing_txs_tracker.js +27 -0
- package/dest/services/tx_collection/proposal_tx_collector.d.ts +7 -6
- package/dest/services/tx_collection/proposal_tx_collector.d.ts.map +1 -1
- package/dest/services/tx_collection/proposal_tx_collector.js +5 -4
- package/dest/services/tx_collection/slow_tx_collection.d.ts +7 -3
- package/dest/services/tx_collection/slow_tx_collection.d.ts.map +1 -1
- package/dest/services/tx_collection/slow_tx_collection.js +60 -26
- package/dest/services/tx_collection/tx_collection.d.ts +23 -10
- package/dest/services/tx_collection/tx_collection.d.ts.map +1 -1
- package/dest/services/tx_collection/tx_collection.js +75 -3
- package/dest/services/tx_collection/tx_collection_sink.d.ts +18 -8
- package/dest/services/tx_collection/tx_collection_sink.d.ts.map +1 -1
- package/dest/services/tx_collection/tx_collection_sink.js +26 -29
- package/dest/services/tx_collection/tx_source.d.ts +8 -3
- package/dest/services/tx_collection/tx_source.d.ts.map +1 -1
- package/dest/services/tx_collection/tx_source.js +19 -2
- 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 -3
- package/dest/services/tx_file_store/tx_file_store.d.ts.map +1 -1
- package/dest/services/tx_file_store/tx_file_store.js +9 -6
- package/dest/services/tx_provider.d.ts +3 -3
- package/dest/services/tx_provider.d.ts.map +1 -1
- package/dest/services/tx_provider.js +5 -4
- package/dest/test-helpers/make-test-p2p-clients.d.ts +3 -3
- package/dest/test-helpers/make-test-p2p-clients.d.ts.map +1 -1
- package/dest/test-helpers/mock-pubsub.d.ts +29 -2
- package/dest/test-helpers/mock-pubsub.d.ts.map +1 -1
- package/dest/test-helpers/mock-pubsub.js +103 -2
- package/dest/test-helpers/reqresp-nodes.d.ts +1 -1
- package/dest/test-helpers/reqresp-nodes.d.ts.map +1 -1
- package/dest/test-helpers/reqresp-nodes.js +2 -1
- package/dest/test-helpers/testbench-utils.d.ts +43 -38
- package/dest/test-helpers/testbench-utils.d.ts.map +1 -1
- package/dest/test-helpers/testbench-utils.js +128 -59
- package/dest/testbench/p2p_client_testbench_worker.d.ts +2 -2
- package/dest/testbench/p2p_client_testbench_worker.d.ts.map +1 -1
- package/dest/testbench/p2p_client_testbench_worker.js +10 -10
- package/dest/util.d.ts +2 -2
- package/dest/util.d.ts.map +1 -1
- package/package.json +14 -14
- package/src/client/factory.ts +86 -15
- package/src/client/interface.ts +59 -23
- package/src/client/p2p_client.ts +184 -167
- package/src/client/test/tx_proposal_collector/proposal_tx_collector_worker.ts +19 -9
- package/src/config.ts +34 -2
- package/src/errors/tx-pool.error.ts +12 -0
- package/src/index.ts +1 -0
- package/src/mem_pools/attestation_pool/attestation_pool.ts +496 -91
- package/src/mem_pools/attestation_pool/attestation_pool_test_suite.ts +442 -102
- package/src/mem_pools/attestation_pool/index.ts +9 -2
- package/src/mem_pools/attestation_pool/mocks.ts +2 -1
- package/src/mem_pools/index.ts +4 -1
- package/src/mem_pools/interface.ts +4 -4
- package/src/mem_pools/tx_pool/README.md +1 -1
- package/src/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.ts +3 -3
- package/src/mem_pools/tx_pool_v2/README.md +76 -10
- 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 +4 -1
- package/src/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.ts +15 -4
- package/src/mem_pools/tx_pool_v2/eviction/index.ts +4 -0
- package/src/mem_pools/tx_pool_v2/eviction/interfaces.ts +49 -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 +3 -3
- package/src/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.ts +8 -7
- package/src/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.ts +24 -6
- package/src/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.ts +3 -3
- package/src/mem_pools/tx_pool_v2/index.ts +1 -0
- package/src/mem_pools/tx_pool_v2/instrumentation.ts +69 -0
- package/src/mem_pools/tx_pool_v2/interfaces.ts +16 -4
- package/src/mem_pools/tx_pool_v2/tx_metadata.ts +90 -9
- package/src/mem_pools/tx_pool_v2/tx_pool_indices.ts +32 -5
- package/src/mem_pools/tx_pool_v2/tx_pool_v2.ts +17 -6
- package/src/mem_pools/tx_pool_v2/tx_pool_v2_impl.ts +274 -104
- package/src/msg_validators/attestation_validator/fisherman_attestation_validator.ts +2 -2
- package/src/msg_validators/tx_validator/aggregate_tx_validator.ts +2 -2
- package/src/msg_validators/tx_validator/block_header_validator.ts +15 -3
- package/src/msg_validators/tx_validator/double_spend_validator.ts +11 -6
- package/src/msg_validators/tx_validator/timestamp_validator.ts +23 -18
- package/src/services/dummy_service.ts +17 -1
- package/src/services/encoding.ts +4 -3
- 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 +487 -0
- package/src/services/libp2p/libp2p_service.ts +367 -271
- package/src/services/peer-manager/peer_scoring.ts +25 -0
- package/src/services/reqresp/batch-tx-requester/batch_tx_requester.ts +6 -6
- package/src/services/reqresp/batch-tx-requester/interface.ts +1 -5
- package/src/services/reqresp/batch-tx-requester/missing_txs.ts +23 -71
- package/src/services/reqresp/interface.ts +26 -1
- package/src/services/reqresp/protocols/block_txs/block_txs_handler.ts +4 -3
- package/src/services/reqresp/protocols/block_txs/block_txs_reqresp.ts +17 -0
- package/src/services/reqresp/protocols/tx.ts +22 -0
- package/src/services/reqresp/reqresp.ts +13 -3
- package/src/services/service.ts +50 -1
- package/src/services/tx_collection/config.ts +68 -0
- package/src/services/tx_collection/fast_tx_collection.ts +65 -32
- package/src/services/tx_collection/file_store_tx_collection.ts +202 -0
- package/src/services/tx_collection/file_store_tx_source.ts +117 -0
- package/src/services/tx_collection/index.ts +1 -0
- package/src/services/tx_collection/instrumentation.ts +7 -1
- package/src/services/tx_collection/missing_txs_tracker.ts +52 -0
- package/src/services/tx_collection/proposal_tx_collector.ts +8 -7
- package/src/services/tx_collection/slow_tx_collection.ts +66 -33
- package/src/services/tx_collection/tx_collection.ts +113 -16
- package/src/services/tx_collection/tx_collection_sink.ts +30 -34
- package/src/services/tx_collection/tx_source.ts +22 -3
- package/src/services/tx_file_store/config.ts +0 -6
- package/src/services/tx_file_store/tx_file_store.ts +10 -8
- package/src/services/tx_provider.ts +8 -7
- package/src/test-helpers/make-test-p2p-clients.ts +3 -3
- package/src/test-helpers/mock-pubsub.ts +143 -3
- package/src/test-helpers/reqresp-nodes.ts +2 -1
- package/src/test-helpers/testbench-utils.ts +127 -71
- package/src/testbench/p2p_client_testbench_worker.ts +22 -15
- package/src/util.ts +7 -1
- package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts +0 -40
- package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts.map +0 -1
- package/dest/mem_pools/attestation_pool/kv_attestation_pool.js +0 -218
- package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts +0 -31
- package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts.map +0 -1
- package/dest/mem_pools/attestation_pool/memory_attestation_pool.js +0 -180
- package/src/mem_pools/attestation_pool/kv_attestation_pool.ts +0 -320
- package/src/mem_pools/attestation_pool/memory_attestation_pool.ts +0 -264
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { EpochCacheInterface } from '@aztec/epoch-cache';
|
|
2
|
-
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
3
|
-
import { randomInt } from '@aztec/foundation/crypto/random';
|
|
2
|
+
import { BlockNumber, type SlotNumber } from '@aztec/foundation/branded-types';
|
|
4
3
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
5
4
|
import { type Logger, createLibp2pComponentLogger, createLogger } from '@aztec/foundation/log';
|
|
6
5
|
import { RunningPromise } from '@aztec/foundation/running-promise';
|
|
@@ -45,7 +44,7 @@ import {
|
|
|
45
44
|
type GossipsubMessage,
|
|
46
45
|
gossipsub,
|
|
47
46
|
} from '@chainsafe/libp2p-gossipsub';
|
|
48
|
-
import { createPeerScoreParams
|
|
47
|
+
import { createPeerScoreParams } from '@chainsafe/libp2p-gossipsub/score';
|
|
49
48
|
import { SignaturePolicy } from '@chainsafe/libp2p-gossipsub/types';
|
|
50
49
|
import { noise } from '@chainsafe/libp2p-noise';
|
|
51
50
|
import { yamux } from '@chainsafe/libp2p-yamux';
|
|
@@ -59,8 +58,7 @@ import { ENR } from '@nethermindeth/enr';
|
|
|
59
58
|
import { createLibp2p } from 'libp2p';
|
|
60
59
|
|
|
61
60
|
import type { P2PConfig } from '../../config.js';
|
|
62
|
-
import {
|
|
63
|
-
import type { MemPools } from '../../mem_pools/index.js';
|
|
61
|
+
import type { MemPools } from '../../mem_pools/interface.js';
|
|
64
62
|
import {
|
|
65
63
|
BlockProposalValidator,
|
|
66
64
|
CheckpointAttestationValidator,
|
|
@@ -81,7 +79,8 @@ import { getVersions } from '../../versioning.js';
|
|
|
81
79
|
import { AztecDatastore } from '../data_store.js';
|
|
82
80
|
import { DiscV5Service } from '../discv5/discV5_service.js';
|
|
83
81
|
import { SnappyTransform, fastMsgIdFn, getMsgIdFn, msgIdToStrFn } from '../encoding.js';
|
|
84
|
-
import { gossipScoreThresholds } from '../gossipsub/scoring.js';
|
|
82
|
+
import { APP_SPECIFIC_WEIGHT, gossipScoreThresholds } from '../gossipsub/scoring.js';
|
|
83
|
+
import { createAllTopicScoreParams } from '../gossipsub/topic_score_params.js';
|
|
85
84
|
import type { PeerManagerInterface } from '../peer-manager/interface.js';
|
|
86
85
|
import { PeerManager } from '../peer-manager/peer_manager.js';
|
|
87
86
|
import { PeerScoring } from '../peer-manager/peer_scoring.js';
|
|
@@ -114,6 +113,7 @@ import { ReqResp } from '../reqresp/reqresp.js';
|
|
|
114
113
|
import type {
|
|
115
114
|
P2PBlockReceivedCallback,
|
|
116
115
|
P2PCheckpointReceivedCallback,
|
|
116
|
+
P2PDuplicateAttestationCallback,
|
|
117
117
|
P2PService,
|
|
118
118
|
PeerDiscoveryService,
|
|
119
119
|
} from '../service.js';
|
|
@@ -128,9 +128,9 @@ interface ValidationResult {
|
|
|
128
128
|
type ValidationOutcome = { allPassed: true } | { allPassed: false; failure: ValidationResult };
|
|
129
129
|
|
|
130
130
|
// REFACTOR: Unify with the type above
|
|
131
|
-
type ReceivedMessageValidationResult<T> =
|
|
132
|
-
| { obj: T; result: Exclude<TopicValidatorResult, TopicValidatorResult.Reject
|
|
133
|
-
| { obj?:
|
|
131
|
+
type ReceivedMessageValidationResult<T, M = undefined> =
|
|
132
|
+
| { obj: T; result: Exclude<TopicValidatorResult, TopicValidatorResult.Reject>; metadata?: M }
|
|
133
|
+
| { obj?: T; result: TopicValidatorResult.Reject; metadata?: M };
|
|
134
134
|
|
|
135
135
|
/**
|
|
136
136
|
* Lib P2P implementation of the P2PService interface.
|
|
@@ -149,6 +149,16 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
149
149
|
|
|
150
150
|
private feesCache: { blockNumber: BlockNumber; gasFees: GasFees } | undefined;
|
|
151
151
|
|
|
152
|
+
/** Callback invoked when a duplicate proposal is detected (triggers slashing). */
|
|
153
|
+
private duplicateProposalCallback?: (info: {
|
|
154
|
+
slot: SlotNumber;
|
|
155
|
+
proposer: EthAddress;
|
|
156
|
+
type: 'checkpoint' | 'block';
|
|
157
|
+
}) => void;
|
|
158
|
+
|
|
159
|
+
/** Callback invoked when a duplicate attestation is detected (triggers slashing). */
|
|
160
|
+
private duplicateAttestationCallback?: P2PDuplicateAttestationCallback;
|
|
161
|
+
|
|
152
162
|
/**
|
|
153
163
|
* Callback for when a block is received from a peer.
|
|
154
164
|
* @param block - The block received from the peer.
|
|
@@ -177,9 +187,9 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
177
187
|
protected node: PubSubLibp2p,
|
|
178
188
|
private peerDiscoveryService: PeerDiscoveryService,
|
|
179
189
|
private reqresp: ReqRespInterface,
|
|
180
|
-
|
|
190
|
+
protected peerManager: PeerManagerInterface,
|
|
181
191
|
protected mempools: MemPools,
|
|
182
|
-
|
|
192
|
+
protected archiver: L2BlockSource & ContractDataSource,
|
|
183
193
|
private epochCache: EpochCacheInterface,
|
|
184
194
|
private proofVerifier: ClientProtocolCircuitVerifier,
|
|
185
195
|
private worldStateSynchronizer: WorldStateSynchronizer,
|
|
@@ -305,11 +315,6 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
305
315
|
const versions = getVersions(config);
|
|
306
316
|
const protocolVersion = compressComponentVersions(versions);
|
|
307
317
|
|
|
308
|
-
const txTopic = createTopicString(TopicType.tx, protocolVersion);
|
|
309
|
-
const blockProposalTopic = createTopicString(TopicType.block_proposal, protocolVersion);
|
|
310
|
-
const checkpointProposalTopic = createTopicString(TopicType.checkpoint_proposal, protocolVersion);
|
|
311
|
-
const checkpointAttestationTopic = createTopicString(TopicType.checkpoint_attestation, protocolVersion);
|
|
312
|
-
|
|
313
318
|
const preferredPeersEnrs: ENR[] = config.preferredPeers.map(enr => ENR.decodeTxt(enr));
|
|
314
319
|
const directPeers = (
|
|
315
320
|
await Promise.all(
|
|
@@ -329,6 +334,16 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
329
334
|
|
|
330
335
|
const announceTcpMultiaddr = config.p2pIp ? [convertToMultiaddr(config.p2pIp, p2pPort, 'tcp')] : [];
|
|
331
336
|
|
|
337
|
+
// Create dynamic topic score params based on network configuration
|
|
338
|
+
const l1Constants = epochCache.getL1Constants();
|
|
339
|
+
const topicScoreParams = createAllTopicScoreParams(protocolVersion, {
|
|
340
|
+
slotDurationMs: l1Constants.slotDuration * 1000,
|
|
341
|
+
heartbeatIntervalMs: config.gossipsubInterval,
|
|
342
|
+
targetCommitteeSize: l1Constants.targetCommitteeSize,
|
|
343
|
+
blockDurationMs: config.blockDurationMs,
|
|
344
|
+
expectedBlockProposalsPerSlot: config.expectedBlockProposalsPerSlot,
|
|
345
|
+
});
|
|
346
|
+
|
|
332
347
|
const node = await createLibp2p({
|
|
333
348
|
start: false,
|
|
334
349
|
peerId,
|
|
@@ -424,28 +439,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
424
439
|
scoreParams: createPeerScoreParams({
|
|
425
440
|
// IPColocation factor can be disabled for local testing - default to -5
|
|
426
441
|
IPColocationFactorWeight: config.debugDisableColocationPenalty ? 0 : -5.0,
|
|
427
|
-
topics:
|
|
428
|
-
[txTopic]: createTopicScoreParams({
|
|
429
|
-
topicWeight: 1,
|
|
430
|
-
invalidMessageDeliveriesWeight: -20,
|
|
431
|
-
invalidMessageDeliveriesDecay: 0.5,
|
|
432
|
-
}),
|
|
433
|
-
[blockProposalTopic]: createTopicScoreParams({
|
|
434
|
-
topicWeight: 1,
|
|
435
|
-
invalidMessageDeliveriesWeight: -20,
|
|
436
|
-
invalidMessageDeliveriesDecay: 0.5,
|
|
437
|
-
}),
|
|
438
|
-
[checkpointProposalTopic]: createTopicScoreParams({
|
|
439
|
-
topicWeight: 1,
|
|
440
|
-
invalidMessageDeliveriesWeight: -20,
|
|
441
|
-
invalidMessageDeliveriesDecay: 0.5,
|
|
442
|
-
}),
|
|
443
|
-
[checkpointAttestationTopic]: createTopicScoreParams({
|
|
444
|
-
topicWeight: 1,
|
|
445
|
-
invalidMessageDeliveriesWeight: -20,
|
|
446
|
-
invalidMessageDeliveriesDecay: 0.5,
|
|
447
|
-
}),
|
|
448
|
-
},
|
|
442
|
+
topics: topicScoreParams,
|
|
449
443
|
}),
|
|
450
444
|
}) as (components: GossipSubComponents) => GossipSub,
|
|
451
445
|
components: (components: { connectionManager: ConnectionManager }) => ({
|
|
@@ -471,8 +465,12 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
471
465
|
epochCache,
|
|
472
466
|
);
|
|
473
467
|
|
|
474
|
-
//
|
|
475
|
-
|
|
468
|
+
// Configure application-specific scoring for gossipsub.
|
|
469
|
+
// The weight scales app score to align with gossipsub thresholds:
|
|
470
|
+
// - Disconnect (-50) × 10 = -500 = gossipThreshold (stops receiving gossip)
|
|
471
|
+
// - Ban (-100) × 10 = -1000 = publishThreshold (cannot publish)
|
|
472
|
+
// Note: positive topic scores can offset penalties, so alignment is best-effort.
|
|
473
|
+
node.services.pubsub.score.params.appSpecificWeight = APP_SPECIFIC_WEIGHT;
|
|
476
474
|
node.services.pubsub.score.params.appSpecificScore = (peerId: string) =>
|
|
477
475
|
peerManager.shouldDisableP2PGossip(peerId) ? -Infinity : peerManager.getPeerScore(peerId);
|
|
478
476
|
|
|
@@ -617,6 +615,10 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
617
615
|
return this.peerManager.getPeers(includePending);
|
|
618
616
|
}
|
|
619
617
|
|
|
618
|
+
public getGossipMeshPeerCount(topicType: TopicType): number {
|
|
619
|
+
return this.node.services.pubsub.getMeshPeers(this.topicStrings[topicType]).length;
|
|
620
|
+
}
|
|
621
|
+
|
|
620
622
|
private handleGossipSubEvent(e: CustomEvent<GossipsubMessage>) {
|
|
621
623
|
this.logger.trace(`Received PUBSUB message.`);
|
|
622
624
|
|
|
@@ -669,6 +671,25 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
669
671
|
this.checkpointReceivedCallback = callback;
|
|
670
672
|
}
|
|
671
673
|
|
|
674
|
+
/**
|
|
675
|
+
* Registers a callback to be invoked when a duplicate proposal is detected.
|
|
676
|
+
* This callback is triggered on the first duplicate (when count goes from 1 to 2).
|
|
677
|
+
*/
|
|
678
|
+
public registerDuplicateProposalCallback(
|
|
679
|
+
callback: (info: { slot: SlotNumber; proposer: EthAddress; type: 'checkpoint' | 'block' }) => void,
|
|
680
|
+
): void {
|
|
681
|
+
this.duplicateProposalCallback = callback;
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
/**
|
|
685
|
+
* Registers a callback to be invoked when a duplicate attestation is detected.
|
|
686
|
+
* A validator signing attestations for different proposals at the same slot.
|
|
687
|
+
* This callback is triggered on the first duplicate (when count goes from 1 to 2).
|
|
688
|
+
*/
|
|
689
|
+
public registerDuplicateAttestationCallback(callback: P2PDuplicateAttestationCallback): void {
|
|
690
|
+
this.duplicateAttestationCallback = callback;
|
|
691
|
+
}
|
|
692
|
+
|
|
672
693
|
/**
|
|
673
694
|
* Subscribes to a topic.
|
|
674
695
|
* @param topic - The topic to subscribe to.
|
|
@@ -855,13 +876,13 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
855
876
|
return;
|
|
856
877
|
}
|
|
857
878
|
|
|
858
|
-
protected async validateReceivedMessage<T>(
|
|
859
|
-
validationFunc: () => Promise<ReceivedMessageValidationResult<T>>,
|
|
879
|
+
protected async validateReceivedMessage<T, M = undefined>(
|
|
880
|
+
validationFunc: () => Promise<ReceivedMessageValidationResult<T, M>>,
|
|
860
881
|
msgId: string,
|
|
861
882
|
source: PeerId,
|
|
862
883
|
topicType: TopicType,
|
|
863
|
-
): Promise<ReceivedMessageValidationResult<T>> {
|
|
864
|
-
let resultAndObj: ReceivedMessageValidationResult<T> = { result: TopicValidatorResult.Reject };
|
|
884
|
+
): Promise<ReceivedMessageValidationResult<T, M>> {
|
|
885
|
+
let resultAndObj: ReceivedMessageValidationResult<T, M> = { result: TopicValidatorResult.Reject };
|
|
865
886
|
const timer = new Timer();
|
|
866
887
|
try {
|
|
867
888
|
resultAndObj = await validationFunc();
|
|
@@ -886,20 +907,33 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
886
907
|
const validationFunc: () => Promise<ReceivedMessageValidationResult<Tx>> = async () => {
|
|
887
908
|
const tx = Tx.fromBuffer(payloadData);
|
|
888
909
|
const isValid = await this.validatePropagatedTx(tx, source);
|
|
889
|
-
|
|
910
|
+
if (!isValid) {
|
|
911
|
+
this.logger.trace(`Rejecting invalid propagated tx`, {
|
|
912
|
+
[Attributes.P2P_ID]: source.toString(),
|
|
913
|
+
});
|
|
914
|
+
return { result: TopicValidatorResult.Reject };
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
// Propagate only on pool acceptance
|
|
918
|
+
const txHash = tx.getTxHash();
|
|
919
|
+
const addResult = await this.mempools.txPool.addPendingTxs([tx], { source: 'gossip' });
|
|
920
|
+
|
|
921
|
+
const wasAccepted = addResult.accepted.some(h => h.equals(txHash));
|
|
922
|
+
const wasIgnored = addResult.ignored.some(h => h.equals(txHash));
|
|
890
923
|
|
|
891
924
|
this.logger.trace(`Validate propagated tx`, {
|
|
892
925
|
isValid,
|
|
893
|
-
|
|
926
|
+
wasAccepted,
|
|
927
|
+
wasIgnored,
|
|
894
928
|
[Attributes.P2P_ID]: source.toString(),
|
|
895
929
|
});
|
|
896
930
|
|
|
897
|
-
if (
|
|
898
|
-
return { result: TopicValidatorResult.
|
|
899
|
-
} else if (
|
|
931
|
+
if (wasAccepted) {
|
|
932
|
+
return { result: TopicValidatorResult.Accept, obj: tx };
|
|
933
|
+
} else if (wasIgnored) {
|
|
900
934
|
return { result: TopicValidatorResult.Ignore, obj: tx };
|
|
901
935
|
} else {
|
|
902
|
-
return { result: TopicValidatorResult.
|
|
936
|
+
return { result: TopicValidatorResult.Reject };
|
|
903
937
|
}
|
|
904
938
|
};
|
|
905
939
|
|
|
@@ -908,6 +942,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
908
942
|
return;
|
|
909
943
|
}
|
|
910
944
|
|
|
945
|
+
// Tx was accepted into pool and will be propagated - just log and record metrics
|
|
911
946
|
const txHash = tx.getTxHash();
|
|
912
947
|
const txHashString = txHash.toString();
|
|
913
948
|
this.logger.verbose(`Received tx ${txHashString} from external peer ${source.toString()} via gossip`, {
|
|
@@ -915,13 +950,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
915
950
|
txHash: txHashString,
|
|
916
951
|
});
|
|
917
952
|
|
|
918
|
-
if (this.config.dropTransactions && randomInt(1000) < this.config.dropTransactionsProbability * 1000) {
|
|
919
|
-
this.logger.warn(`Intentionally dropping tx ${txHashString} (probability rule)`);
|
|
920
|
-
return;
|
|
921
|
-
}
|
|
922
|
-
|
|
923
953
|
this.instrumentation.incrementTxReceived(1);
|
|
924
|
-
await this.mempools.txPool.addTxs([tx]);
|
|
925
954
|
}
|
|
926
955
|
|
|
927
956
|
/**
|
|
@@ -933,47 +962,8 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
933
962
|
msgId: string,
|
|
934
963
|
source: PeerId,
|
|
935
964
|
): Promise<void> {
|
|
936
|
-
const validationFunc: () => Promise<ReceivedMessageValidationResult<CheckpointAttestation>> = async () => {
|
|
937
|
-
const attestation = CheckpointAttestation.fromBuffer(payloadData);
|
|
938
|
-
const pool = this.mempools.attestationPool;
|
|
939
|
-
const validationResult = await this.validateCheckpointAttestation(source, attestation);
|
|
940
|
-
const isValid = validationResult.result === 'accept';
|
|
941
|
-
const exists = isValid && (await pool.hasCheckpointAttestation(attestation));
|
|
942
|
-
|
|
943
|
-
let canAdd = true;
|
|
944
|
-
if (isValid && !exists) {
|
|
945
|
-
const slot = attestation.payload.header.slotNumber;
|
|
946
|
-
const { committee } = await this.epochCache.getCommittee(slot);
|
|
947
|
-
const committeeSize = committee?.length ?? 0;
|
|
948
|
-
canAdd = await pool.canAddCheckpointAttestation(attestation, committeeSize);
|
|
949
|
-
}
|
|
950
|
-
|
|
951
|
-
this.logger.trace(`Validate propagated checkpoint attestation`, {
|
|
952
|
-
isValid,
|
|
953
|
-
exists,
|
|
954
|
-
canAdd,
|
|
955
|
-
[Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber.toString(),
|
|
956
|
-
[Attributes.P2P_ID]: source.toString(),
|
|
957
|
-
});
|
|
958
|
-
|
|
959
|
-
if (validationResult.result === 'reject') {
|
|
960
|
-
return { result: TopicValidatorResult.Reject };
|
|
961
|
-
} else if (validationResult.result === 'ignore' || exists) {
|
|
962
|
-
return { result: TopicValidatorResult.Ignore, obj: attestation };
|
|
963
|
-
} else if (!canAdd) {
|
|
964
|
-
this.logger.warn(`Dropping checkpoint attestation due to per-(slot, proposalId) attestation cap`, {
|
|
965
|
-
slot: attestation.payload.header.slotNumber.toString(),
|
|
966
|
-
archive: attestation.archive.toString(),
|
|
967
|
-
source: source.toString(),
|
|
968
|
-
});
|
|
969
|
-
return { result: TopicValidatorResult.Ignore, obj: attestation };
|
|
970
|
-
} else {
|
|
971
|
-
return { result: TopicValidatorResult.Accept, obj: attestation };
|
|
972
|
-
}
|
|
973
|
-
};
|
|
974
|
-
|
|
975
965
|
const { result, obj: attestation } = await this.validateReceivedMessage<CheckpointAttestation>(
|
|
976
|
-
|
|
966
|
+
() => this.validateAndStoreCheckpointAttestation(source, CheckpointAttestation.fromBuffer(payloadData)),
|
|
977
967
|
msgId,
|
|
978
968
|
source,
|
|
979
969
|
TopicType.checkpoint_attestation,
|
|
@@ -983,8 +973,8 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
983
973
|
return;
|
|
984
974
|
}
|
|
985
975
|
|
|
986
|
-
this.logger.
|
|
987
|
-
`Received checkpoint attestation for slot ${attestation.slotNumber} from external peer ${source.toString()}`,
|
|
976
|
+
this.logger.verbose(
|
|
977
|
+
`Received valid checkpoint attestation for slot ${attestation.slotNumber} from external peer ${source.toString()}`,
|
|
988
978
|
{
|
|
989
979
|
p2pMessageIdentifier: await attestation.p2pMessageLoggingIdentifier(),
|
|
990
980
|
slot: attestation.slotNumber,
|
|
@@ -992,60 +982,167 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
992
982
|
source: source.toString(),
|
|
993
983
|
},
|
|
994
984
|
);
|
|
995
|
-
|
|
996
|
-
await this.mempools.attestationPool.addCheckpointAttestations([attestation]);
|
|
997
985
|
}
|
|
998
986
|
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
987
|
+
/** Validates a checkpoint attestation and adds it to the pool. Penalizes the peer if validation fails. */
|
|
988
|
+
@trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId, attestation) => ({
|
|
989
|
+
[Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber.toString(),
|
|
990
|
+
}))
|
|
991
|
+
protected async validateAndStoreCheckpointAttestation(
|
|
992
|
+
peerId: PeerId,
|
|
993
|
+
attestation: CheckpointAttestation,
|
|
994
|
+
): Promise<ReceivedMessageValidationResult<CheckpointAttestation>> {
|
|
995
|
+
const validationResult = await this.checkpointAttestationValidator.validate(attestation);
|
|
996
|
+
|
|
997
|
+
if (validationResult.result === 'reject') {
|
|
998
|
+
this.logger.warn(`Penalizing peer ${peerId} for checkpoint attestation validation failure`);
|
|
999
|
+
this.peerManager.penalizePeer(peerId, validationResult.severity);
|
|
1000
|
+
return { result: TopicValidatorResult.Reject };
|
|
1001
|
+
}
|
|
1005
1002
|
|
|
1006
|
-
|
|
1007
|
-
|
|
1003
|
+
if (validationResult.result === 'ignore') {
|
|
1004
|
+
return { result: TopicValidatorResult.Ignore, obj: attestation };
|
|
1005
|
+
}
|
|
1008
1006
|
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1007
|
+
// Try to add the attestation: this handles existence check, cap check, and adding in one call
|
|
1008
|
+
// count is the number of attestations by this signer for this slot (for duplicate detection)
|
|
1009
|
+
const slot = attestation.payload.header.slotNumber;
|
|
1010
|
+
const { added, alreadyExists, count } =
|
|
1011
|
+
await this.mempools.attestationPool.tryAddCheckpointAttestation(attestation);
|
|
1012
|
+
|
|
1013
|
+
this.logger.trace(`Validate propagated checkpoint attestation`, {
|
|
1014
|
+
added,
|
|
1015
|
+
alreadyExists,
|
|
1016
|
+
count,
|
|
1017
|
+
[Attributes.SLOT_NUMBER]: slot.toString(),
|
|
1018
|
+
[Attributes.P2P_ID]: peerId.toString(),
|
|
1019
|
+
});
|
|
1020
|
+
|
|
1021
|
+
// Exact same attestation received, no need to re-broadcast
|
|
1022
|
+
if (alreadyExists) {
|
|
1023
|
+
return { result: TopicValidatorResult.Ignore, obj: attestation };
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
// Could not add (cap reached for signer), no need to re-broadcast
|
|
1027
|
+
if (!added) {
|
|
1028
|
+
this.logger.warn(`Dropping checkpoint attestation due to cap`, {
|
|
1029
|
+
slot: slot.toString(),
|
|
1030
|
+
archive: attestation.archive.toString(),
|
|
1031
|
+
source: peerId.toString(),
|
|
1032
|
+
attester: attestation.getSender()?.toString(),
|
|
1033
|
+
count,
|
|
1015
1034
|
});
|
|
1035
|
+
return { result: TopicValidatorResult.Ignore, obj: attestation };
|
|
1036
|
+
}
|
|
1016
1037
|
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
this.
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1038
|
+
// Check if this is a duplicate attestation (signer attested to a different proposal at the same slot)
|
|
1039
|
+
// count is the number of attestations by this signer for this slot
|
|
1040
|
+
if (count === 2) {
|
|
1041
|
+
const attester = attestation.getSender();
|
|
1042
|
+
if (attester) {
|
|
1043
|
+
this.logger.warn(`Detected duplicate attestation (equivocation) at slot ${slot}`, {
|
|
1044
|
+
slot: slot.toString(),
|
|
1045
|
+
archive: attestation.archive.toString(),
|
|
1046
|
+
source: peerId.toString(),
|
|
1047
|
+
attester: attester.toString(),
|
|
1027
1048
|
});
|
|
1028
|
-
|
|
1029
|
-
} else {
|
|
1030
|
-
return { result: TopicValidatorResult.Accept, obj: block };
|
|
1049
|
+
this.duplicateAttestationCallback?.({ slot, attester });
|
|
1031
1050
|
}
|
|
1032
|
-
}
|
|
1051
|
+
}
|
|
1033
1052
|
|
|
1034
|
-
|
|
1035
|
-
|
|
1053
|
+
// Attestation was added successfully - accept it so other nodes can also detect the equivocation
|
|
1054
|
+
return { result: TopicValidatorResult.Accept, obj: attestation };
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
protected async processBlockFromPeer(payloadData: Buffer, msgId: string, source: PeerId): Promise<void> {
|
|
1058
|
+
const {
|
|
1059
|
+
result,
|
|
1060
|
+
obj: block,
|
|
1061
|
+
metadata: { isEquivocated } = {},
|
|
1062
|
+
} = await this.validateReceivedMessage<BlockProposal, { isEquivocated: boolean }>(
|
|
1063
|
+
() => this.validateAndStoreBlockProposal(source, BlockProposal.fromBuffer(payloadData)),
|
|
1036
1064
|
msgId,
|
|
1037
1065
|
source,
|
|
1038
1066
|
TopicType.block_proposal,
|
|
1039
1067
|
);
|
|
1040
1068
|
|
|
1041
|
-
|
|
1069
|
+
// If not accepted or equivocated, return
|
|
1070
|
+
if (result !== TopicValidatorResult.Accept || !block || isEquivocated) {
|
|
1042
1071
|
return;
|
|
1043
1072
|
}
|
|
1044
1073
|
|
|
1045
1074
|
await this.processValidBlockProposal(block, source);
|
|
1046
1075
|
}
|
|
1047
1076
|
|
|
1048
|
-
|
|
1077
|
+
/** Validates a block proposal. Triggers a penalization to the peer that sent it if invalid. Adds to the mempool if valid. */
|
|
1078
|
+
@trackSpan('Libp2pService.validateAndStoreBlockProposal', (_peerId, block) => ({
|
|
1079
|
+
[Attributes.BLOCK_NUMBER]: block.blockNumber.toString(),
|
|
1080
|
+
[Attributes.SLOT_NUMBER]: block.slotNumber.toString(),
|
|
1081
|
+
}))
|
|
1082
|
+
protected async validateAndStoreBlockProposal(
|
|
1083
|
+
peerId: PeerId,
|
|
1084
|
+
block: BlockProposal,
|
|
1085
|
+
): Promise<ReceivedMessageValidationResult<BlockProposal, { isEquivocated: boolean }>> {
|
|
1086
|
+
const validationResult = await this.blockProposalValidator.validate(block);
|
|
1087
|
+
|
|
1088
|
+
if (validationResult.result === 'reject') {
|
|
1089
|
+
this.logger.warn(`Penalizing peer ${peerId} for block proposal validation failure`);
|
|
1090
|
+
this.peerManager.penalizePeer(peerId, validationResult.severity);
|
|
1091
|
+
return { result: TopicValidatorResult.Reject };
|
|
1092
|
+
}
|
|
1093
|
+
|
|
1094
|
+
if (validationResult.result === 'ignore') {
|
|
1095
|
+
return { result: TopicValidatorResult.Ignore, obj: block };
|
|
1096
|
+
}
|
|
1097
|
+
|
|
1098
|
+
// Try to add the proposal: this handles existence check, cap check, and adding in one call
|
|
1099
|
+
const { added, alreadyExists, count } = await this.mempools.attestationPool.tryAddBlockProposal(block);
|
|
1100
|
+
const isEquivocated = count !== undefined && count > 1;
|
|
1101
|
+
|
|
1102
|
+
// Duplicate proposal received, no need to re-broadcast
|
|
1103
|
+
if (alreadyExists) {
|
|
1104
|
+
this.logger.debug(`Ignoring duplicate block proposal received`, {
|
|
1105
|
+
...block.toBlockInfo(),
|
|
1106
|
+
indexWithinCheckpoint: block.indexWithinCheckpoint,
|
|
1107
|
+
proposer: block.getSender()?.toString(),
|
|
1108
|
+
source: peerId.toString(),
|
|
1109
|
+
});
|
|
1110
|
+
return { result: TopicValidatorResult.Ignore, obj: block, metadata: { isEquivocated } };
|
|
1111
|
+
}
|
|
1112
|
+
|
|
1113
|
+
// Too many blocks received for this slot and index, penalize peer and do not re-broadcast
|
|
1114
|
+
if (!added) {
|
|
1115
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.HighToleranceError);
|
|
1116
|
+
this.logger.warn(`Penalizing peer for block proposal exceeding per-position cap`, {
|
|
1117
|
+
...block.toBlockInfo(),
|
|
1118
|
+
indexWithinCheckpoint: block.indexWithinCheckpoint,
|
|
1119
|
+
count,
|
|
1120
|
+
proposer: block.getSender()?.toString(),
|
|
1121
|
+
source: peerId.toString(),
|
|
1122
|
+
});
|
|
1123
|
+
return { result: TopicValidatorResult.Reject, metadata: { isEquivocated } };
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
// If this was a duplicate proposal, do not process it, but do invoke the duplicate callback,
|
|
1127
|
+
// and do re-broadcast it so other nodes in the network know to slash the proposer
|
|
1128
|
+
if (isEquivocated) {
|
|
1129
|
+
const proposer = block.getSender();
|
|
1130
|
+
this.logger.warn(`Detected duplicate block proposal (equivocation) at slot ${block.slotNumber}`, {
|
|
1131
|
+
...block.toBlockInfo(),
|
|
1132
|
+
source: peerId.toString(),
|
|
1133
|
+
proposer: proposer?.toString(),
|
|
1134
|
+
});
|
|
1135
|
+
// Invoke the duplicate callback on the first duplicate spotted only
|
|
1136
|
+
if (proposer && count === 2) {
|
|
1137
|
+
this.duplicateProposalCallback?.({ slot: block.slotNumber, proposer, type: 'block' });
|
|
1138
|
+
}
|
|
1139
|
+
return { result: TopicValidatorResult.Accept, obj: block, metadata: { isEquivocated } };
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
// Otherwise, we're good to go!
|
|
1143
|
+
return { result: TopicValidatorResult.Accept, obj: block };
|
|
1144
|
+
}
|
|
1145
|
+
|
|
1049
1146
|
// REFACTOR(palla): This method should be moved to the p2p_client or to a separate component,
|
|
1050
1147
|
// should not be here as it does not deal with p2p networking.
|
|
1051
1148
|
@trackSpan('Libp2pService.processValidBlockProposal', async block => ({
|
|
@@ -1053,7 +1150,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1053
1150
|
[Attributes.BLOCK_ARCHIVE]: block.archive.toString(),
|
|
1054
1151
|
[Attributes.P2P_ID]: await block.p2pMessageLoggingIdentifier().then(i => i.toString()),
|
|
1055
1152
|
}))
|
|
1056
|
-
|
|
1153
|
+
protected async processValidBlockProposal(block: BlockProposal, sender: PeerId) {
|
|
1057
1154
|
const slot = block.slotNumber;
|
|
1058
1155
|
this.logger.verbose(`Received block proposal for slot ${slot} from external peer ${sender.toString()}.`, {
|
|
1059
1156
|
p2pMessageIdentifier: await block.p2pMessageLoggingIdentifier(),
|
|
@@ -1061,24 +1158,8 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1061
1158
|
...block.toBlockInfo(),
|
|
1062
1159
|
});
|
|
1063
1160
|
|
|
1064
|
-
//
|
|
1065
|
-
|
|
1066
|
-
await this.mempools.attestationPool.addBlockProposal(block);
|
|
1067
|
-
} catch (err: unknown) {
|
|
1068
|
-
// Drop proposals if we hit per-slot cap in the attestation pool; rethrow unknown errors
|
|
1069
|
-
if (err instanceof ProposalSlotCapExceededError) {
|
|
1070
|
-
this.logger.warn(`Dropping block proposal due to per-slot proposal cap`, {
|
|
1071
|
-
slot: String(slot),
|
|
1072
|
-
archive: block.archive.toString(),
|
|
1073
|
-
error: (err as Error).message,
|
|
1074
|
-
});
|
|
1075
|
-
return;
|
|
1076
|
-
}
|
|
1077
|
-
throw err;
|
|
1078
|
-
}
|
|
1079
|
-
|
|
1080
|
-
// Mark the txs in this proposal as non-evictable
|
|
1081
|
-
await this.mempools.txPool.markTxsAsNonEvictable(block.txHashes);
|
|
1161
|
+
// Mark the txs in this proposal as protected
|
|
1162
|
+
await this.mempools.txPool.protectTxs(block.txHashes, block.blockHeader);
|
|
1082
1163
|
|
|
1083
1164
|
// Call the block received callback to validate the proposal.
|
|
1084
1165
|
// Note: Validators do NOT attest to individual blocks, only to checkpoint proposals.
|
|
@@ -1092,67 +1173,145 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1092
1173
|
* Handle a gossiped checkpoint proposal.
|
|
1093
1174
|
* Validates and processes the checkpoint proposal, then triggers the callback for attestation.
|
|
1094
1175
|
*/
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1176
|
+
protected async handleGossipedCheckpointProposal(payloadData: Buffer, msgId: string, source: PeerId): Promise<void> {
|
|
1177
|
+
const {
|
|
1178
|
+
result,
|
|
1179
|
+
obj: checkpoint,
|
|
1180
|
+
metadata: { isEquivocated, processBlock } = {},
|
|
1181
|
+
} = await this.validateReceivedMessage<CheckpointProposal, { isEquivocated: boolean; processBlock: boolean }>(
|
|
1182
|
+
() => this.validateAndStoreCheckpointProposal(source, CheckpointProposal.fromBuffer(payloadData)),
|
|
1183
|
+
msgId,
|
|
1184
|
+
source,
|
|
1185
|
+
TopicType.checkpoint_proposal,
|
|
1186
|
+
);
|
|
1187
|
+
|
|
1188
|
+
// If the checkpoint contained a valid last block, we process it even if the checkpoint itself is to be rejected
|
|
1189
|
+
// TODO(palla/mbps): Is this ok? Should we be considering a block from a checkpoint that was equivocated?
|
|
1190
|
+
if (processBlock && checkpoint?.getBlockProposal()) {
|
|
1191
|
+
await this.processValidBlockProposal(checkpoint.getBlockProposal()!, source);
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1194
|
+
if (result !== TopicValidatorResult.Accept || !checkpoint || isEquivocated) {
|
|
1195
|
+
return;
|
|
1196
|
+
}
|
|
1197
|
+
|
|
1198
|
+
await this.processValidCheckpointProposal(checkpoint.toCore(), source);
|
|
1199
|
+
}
|
|
1200
|
+
|
|
1201
|
+
/**
|
|
1202
|
+
* Validates a checkpoint proposal. Penalizes peer if validation fails. Adds the checkpoint and
|
|
1203
|
+
* its last block (if present) to the mempool if valid. Triggers equivocation detection on both.
|
|
1204
|
+
*/
|
|
1205
|
+
@trackSpan('Libp2pService.validateAndStoreCheckpointProposal', (_peerId, checkpoint) => ({
|
|
1206
|
+
[Attributes.SLOT_NUMBER]: checkpoint.slotNumber.toString(),
|
|
1207
|
+
}))
|
|
1208
|
+
protected async validateAndStoreCheckpointProposal(
|
|
1209
|
+
peerId: PeerId,
|
|
1210
|
+
checkpoint: CheckpointProposal,
|
|
1211
|
+
): Promise<ReceivedMessageValidationResult<CheckpointProposal, { isEquivocated: boolean; processBlock: boolean }>> {
|
|
1212
|
+
const validationResult = await this.checkpointProposalValidator.validate(checkpoint);
|
|
1213
|
+
|
|
1214
|
+
if (validationResult.result === 'reject') {
|
|
1215
|
+
this.logger.warn(`Penalizing peer ${peerId} for checkpoint proposal validation failure`);
|
|
1216
|
+
this.peerManager.penalizePeer(peerId, validationResult.severity);
|
|
1217
|
+
return { result: TopicValidatorResult.Reject };
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1220
|
+
if (validationResult.result === 'ignore') {
|
|
1221
|
+
return { result: TopicValidatorResult.Ignore, obj: checkpoint };
|
|
1222
|
+
}
|
|
1223
|
+
|
|
1224
|
+
// Extract and try to add the block proposal first if present
|
|
1225
|
+
const blockProposal = checkpoint.getBlockProposal();
|
|
1226
|
+
let processBlock = false;
|
|
1227
|
+
if (blockProposal) {
|
|
1228
|
+
this.logger.debug(`Validating block proposal from propagated checkpoint`, {
|
|
1110
1229
|
[Attributes.SLOT_NUMBER]: checkpoint.slotNumber.toString(),
|
|
1111
|
-
[Attributes.P2P_ID]:
|
|
1230
|
+
[Attributes.P2P_ID]: peerId.toString(),
|
|
1112
1231
|
});
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
this.
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1232
|
+
const {
|
|
1233
|
+
result,
|
|
1234
|
+
obj,
|
|
1235
|
+
metadata: { isEquivocated } = {},
|
|
1236
|
+
} = await this.validateAndStoreBlockProposal(peerId, blockProposal);
|
|
1237
|
+
if (result === TopicValidatorResult.Reject || !obj || isEquivocated) {
|
|
1238
|
+
this.logger.debug(`Rejecting checkpoint due to invalid last block proposal`, {
|
|
1239
|
+
[Attributes.SLOT_NUMBER]: checkpoint.slotNumber.toString(),
|
|
1240
|
+
[Attributes.P2P_ID]: peerId.toString(),
|
|
1241
|
+
isEquivocated,
|
|
1242
|
+
result,
|
|
1124
1243
|
});
|
|
1125
1244
|
return { result: TopicValidatorResult.Reject };
|
|
1126
|
-
} else {
|
|
1127
|
-
|
|
1245
|
+
} else if (result === TopicValidatorResult.Accept && obj && !isEquivocated) {
|
|
1246
|
+
processBlock = true;
|
|
1128
1247
|
}
|
|
1129
|
-
}
|
|
1248
|
+
}
|
|
1130
1249
|
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1250
|
+
// Try to add the checkpoint proposal core: this handles existence check, cap check, and adding in one call
|
|
1251
|
+
const checkpointCore = checkpoint.toCore();
|
|
1252
|
+
const tryAddResult = await this.mempools.attestationPool.tryAddCheckpointProposal(checkpointCore);
|
|
1253
|
+
const { added, alreadyExists, count } = tryAddResult;
|
|
1254
|
+
const isEquivocated = count !== undefined && count > 1;
|
|
1255
|
+
|
|
1256
|
+
// Duplicate proposal received, do not re-broadcast
|
|
1257
|
+
if (alreadyExists) {
|
|
1258
|
+
this.logger.debug(`Ignoring duplicate checkpoint proposal received`, {
|
|
1259
|
+
...checkpoint.toCheckpointInfo(),
|
|
1260
|
+
source: peerId.toString(),
|
|
1261
|
+
});
|
|
1262
|
+
return {
|
|
1263
|
+
result: TopicValidatorResult.Ignore,
|
|
1264
|
+
obj: checkpoint,
|
|
1265
|
+
metadata: { isEquivocated, processBlock },
|
|
1266
|
+
};
|
|
1267
|
+
}
|
|
1137
1268
|
|
|
1138
|
-
|
|
1139
|
-
|
|
1269
|
+
// Too many checkpoint proposals received for this slot, penalize peer and do not re-broadcast
|
|
1270
|
+
// Note: We still return the checkpoint obj so the lastBlock can be processed if valid
|
|
1271
|
+
if (!added) {
|
|
1272
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.HighToleranceError);
|
|
1273
|
+
this.logger.warn(`Penalizing peer for checkpoint proposal exceeding per-slot cap`, {
|
|
1274
|
+
...checkpoint.toCheckpointInfo(),
|
|
1275
|
+
count,
|
|
1276
|
+
source: peerId.toString(),
|
|
1277
|
+
});
|
|
1278
|
+
return { result: TopicValidatorResult.Reject, obj: checkpoint, metadata: { isEquivocated, processBlock } };
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
// If this was a duplicate proposal, do not process it, but do invoke the duplicate callback,
|
|
1282
|
+
// and do re-broadcast it so other nodes in the network know to slash the proposer
|
|
1283
|
+
if (isEquivocated) {
|
|
1284
|
+
const proposer = checkpoint.getSender();
|
|
1285
|
+
this.logger.warn(`Detected duplicate checkpoint proposal (equivocation) at slot ${checkpoint.slotNumber}`, {
|
|
1286
|
+
...checkpoint.toCheckpointInfo(),
|
|
1287
|
+
source: peerId.toString(),
|
|
1288
|
+
proposer: proposer?.toString(),
|
|
1289
|
+
});
|
|
1290
|
+
// Invoke the duplicate callback on the first duplicate spotted only
|
|
1291
|
+
if (proposer && count === 2) {
|
|
1292
|
+
this.duplicateProposalCallback?.({ slot: checkpoint.slotNumber, proposer, type: 'checkpoint' });
|
|
1293
|
+
}
|
|
1294
|
+
return {
|
|
1295
|
+
result: TopicValidatorResult.Accept,
|
|
1296
|
+
obj: checkpoint,
|
|
1297
|
+
metadata: { isEquivocated, processBlock },
|
|
1298
|
+
};
|
|
1140
1299
|
}
|
|
1141
1300
|
|
|
1142
|
-
|
|
1301
|
+
// Otherwise, we're good to go!
|
|
1302
|
+
return { result: TopicValidatorResult.Accept, obj: checkpoint, metadata: { processBlock, isEquivocated } };
|
|
1143
1303
|
}
|
|
1144
1304
|
|
|
1145
1305
|
/**
|
|
1146
1306
|
* Process a validated checkpoint proposal.
|
|
1147
|
-
*
|
|
1148
|
-
* The block callback is invoked before the checkpoint callback.
|
|
1307
|
+
* Note: The proposal was already added to the pool by tryAddCheckpointProposal in handleGossipedCheckpointProposal.
|
|
1149
1308
|
*/
|
|
1150
1309
|
@trackSpan('Libp2pService.processValidCheckpointProposal', async checkpoint => ({
|
|
1151
1310
|
[Attributes.SLOT_NUMBER]: checkpoint.slotNumber,
|
|
1152
1311
|
[Attributes.BLOCK_ARCHIVE]: checkpoint.archive.toString(),
|
|
1153
1312
|
[Attributes.P2P_ID]: await checkpoint.p2pMessageLoggingIdentifier().then(i => i.toString()),
|
|
1154
1313
|
}))
|
|
1155
|
-
|
|
1314
|
+
protected async processValidCheckpointProposal(checkpoint: CheckpointProposalCore, sender: PeerId) {
|
|
1156
1315
|
const slot = checkpoint.slotNumber;
|
|
1157
1316
|
this.logger.verbose(`Received checkpoint proposal for slot ${slot} from external peer ${sender.toString()}.`, {
|
|
1158
1317
|
p2pMessageIdentifier: await checkpoint.p2pMessageLoggingIdentifier(),
|
|
@@ -1161,37 +1320,12 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1161
1320
|
source: sender.toString(),
|
|
1162
1321
|
});
|
|
1163
1322
|
|
|
1164
|
-
// Extract block proposal before adding to pool (pool stores them separately)
|
|
1165
|
-
const blockProposal = checkpoint.getBlockProposal();
|
|
1166
|
-
|
|
1167
|
-
// Add proposal to the pool (this extracts and stores block proposal separately)
|
|
1168
|
-
await this.mempools.attestationPool.addCheckpointProposal(checkpoint);
|
|
1169
|
-
|
|
1170
|
-
// Mark txs as non-evictable if present (from the last block)
|
|
1171
|
-
if (checkpoint.txHashes.length > 0) {
|
|
1172
|
-
await this.mempools.txPool.markTxsAsNonEvictable(checkpoint.txHashes);
|
|
1173
|
-
}
|
|
1174
|
-
|
|
1175
|
-
// If there was a last block proposal, invoke the block callback first for validation.
|
|
1176
|
-
// Note: The block proposal is already stored in the pool by addCheckpointProposal.
|
|
1177
|
-
if (blockProposal) {
|
|
1178
|
-
const isValid = await this.blockReceivedCallback(blockProposal, sender);
|
|
1179
|
-
if (!isValid) {
|
|
1180
|
-
this.logger.warn(`Block proposal from checkpoint failed validation`, {
|
|
1181
|
-
slot: slot.toString(),
|
|
1182
|
-
archive: checkpoint.archive.toString(),
|
|
1183
|
-
blockNumber: blockProposal.blockNumber.toString(),
|
|
1184
|
-
});
|
|
1185
|
-
return;
|
|
1186
|
-
}
|
|
1187
|
-
}
|
|
1188
|
-
|
|
1189
1323
|
// Call the checkpoint received callback with the core version (without lastBlock)
|
|
1190
1324
|
// to validate and potentially generate attestations
|
|
1191
|
-
const attestations = await this.checkpointReceivedCallback(checkpoint
|
|
1325
|
+
const attestations = await this.checkpointReceivedCallback(checkpoint, sender);
|
|
1192
1326
|
if (attestations && attestations.length > 0) {
|
|
1193
1327
|
// If the callback returned attestations, add them to the pool and propagate them
|
|
1194
|
-
await this.mempools.attestationPool.
|
|
1328
|
+
await this.mempools.attestationPool.addOwnCheckpointAttestations(attestations);
|
|
1195
1329
|
for (const attestation of attestations) {
|
|
1196
1330
|
await this.propagate(attestation);
|
|
1197
1331
|
}
|
|
@@ -1220,7 +1354,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1220
1354
|
@trackSpan('Libp2pService.validateRequestedBlockTxs', request => ({
|
|
1221
1355
|
[Attributes.BLOCK_ARCHIVE]: request.archiveRoot.toString(),
|
|
1222
1356
|
}))
|
|
1223
|
-
|
|
1357
|
+
protected async validateRequestedBlockTxs(
|
|
1224
1358
|
request: BlockTxsRequest,
|
|
1225
1359
|
response: BlockTxsResponse,
|
|
1226
1360
|
peerId: PeerId,
|
|
@@ -1350,7 +1484,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1350
1484
|
@trackSpan('Libp2pService.validateRequestedBlock', (requestedBlockNumber, _responseBlock) => ({
|
|
1351
1485
|
[Attributes.BLOCK_NUMBER]: requestedBlockNumber.toString(),
|
|
1352
1486
|
}))
|
|
1353
|
-
|
|
1487
|
+
protected async validateRequestedBlock(
|
|
1354
1488
|
requestedBlockNumber: Fr,
|
|
1355
1489
|
responseBlock: L2Block,
|
|
1356
1490
|
peerId: PeerId,
|
|
@@ -1383,7 +1517,12 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1383
1517
|
}
|
|
1384
1518
|
}
|
|
1385
1519
|
|
|
1386
|
-
|
|
1520
|
+
protected async validateRequestedTx(
|
|
1521
|
+
tx: Tx,
|
|
1522
|
+
peerId: PeerId,
|
|
1523
|
+
txValidator: TxValidator,
|
|
1524
|
+
requested?: Set<`0x${string}`>,
|
|
1525
|
+
) {
|
|
1387
1526
|
const penalize = (severity: PeerErrorSeverity) => this.peerManager.penalizePeer(peerId, severity);
|
|
1388
1527
|
if (requested && !requested.has(tx.getTxHash().toString())) {
|
|
1389
1528
|
penalize(PeerErrorSeverity.MidToleranceError);
|
|
@@ -1397,7 +1536,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1397
1536
|
}
|
|
1398
1537
|
}
|
|
1399
1538
|
|
|
1400
|
-
|
|
1539
|
+
protected createRequestedTxValidator(): TxValidator {
|
|
1401
1540
|
return createTxReqRespValidator(this.proofVerifier, {
|
|
1402
1541
|
l1ChainId: this.config.l1ChainId,
|
|
1403
1542
|
rollupVersion: this.config.rollupVersion,
|
|
@@ -1407,10 +1546,10 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1407
1546
|
@trackSpan('Libp2pService.validatePropagatedTx', tx => ({
|
|
1408
1547
|
[Attributes.TX_HASH]: tx.getTxHash().toString(),
|
|
1409
1548
|
}))
|
|
1410
|
-
|
|
1549
|
+
protected async validatePropagatedTx(tx: Tx, peerId: PeerId): Promise<boolean> {
|
|
1411
1550
|
const currentBlockNumber = await this.archiver.getBlockNumber();
|
|
1412
1551
|
|
|
1413
|
-
// We accept transactions if they are not expired by the next slot (checked based on the
|
|
1552
|
+
// We accept transactions if they are not expired by the next slot (checked based on the ExpirationTimestamp field)
|
|
1414
1553
|
const { ts: nextSlotTimestamp } = this.epochCache.getEpochAndSlotInNextL1Slot();
|
|
1415
1554
|
const messageValidators = await this.createMessageValidators(currentBlockNumber, nextSlotTimestamp);
|
|
1416
1555
|
|
|
@@ -1465,7 +1604,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1465
1604
|
public async validate(txs: Tx[]): Promise<void> {
|
|
1466
1605
|
const currentBlockNumber = await this.archiver.getBlockNumber();
|
|
1467
1606
|
|
|
1468
|
-
// We accept transactions if they are not expired by the next slot (checked based on the
|
|
1607
|
+
// We accept transactions if they are not expired by the next slot (checked based on the ExpirationTimestamp field)
|
|
1469
1608
|
const { ts: nextSlotTimestamp } = this.epochCache.getEpochAndSlotInNextL1Slot();
|
|
1470
1609
|
const messageValidators = await this.createMessageValidators(currentBlockNumber, nextSlotTimestamp);
|
|
1471
1610
|
|
|
@@ -1605,50 +1744,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1605
1744
|
const result = await this.checkpointAttestationValidator.validate(attestation);
|
|
1606
1745
|
|
|
1607
1746
|
if (result.result === 'reject') {
|
|
1608
|
-
this.logger.
|
|
1609
|
-
this.peerManager.penalizePeer(peerId, result.severity);
|
|
1610
|
-
}
|
|
1611
|
-
|
|
1612
|
-
return result;
|
|
1613
|
-
}
|
|
1614
|
-
|
|
1615
|
-
/**
|
|
1616
|
-
* Validate a block proposal.
|
|
1617
|
-
*
|
|
1618
|
-
* @param block - The block proposal to validate.
|
|
1619
|
-
* @returns True if the block proposal is valid, false otherwise.
|
|
1620
|
-
*/
|
|
1621
|
-
@trackSpan('Libp2pService.validateBlockProposal', (_peerId, block) => ({
|
|
1622
|
-
[Attributes.SLOT_NUMBER]: block.slotNumber.toString(),
|
|
1623
|
-
}))
|
|
1624
|
-
public async validateBlockProposal(peerId: PeerId, block: BlockProposal): Promise<P2PValidationResult> {
|
|
1625
|
-
const result = await this.blockProposalValidator.validate(block);
|
|
1626
|
-
|
|
1627
|
-
if (result.result === 'reject') {
|
|
1628
|
-
this.logger.debug(`Penalizing peer ${peerId} for block proposal validation failure`);
|
|
1629
|
-
this.peerManager.penalizePeer(peerId, result.severity);
|
|
1630
|
-
}
|
|
1631
|
-
|
|
1632
|
-
return result;
|
|
1633
|
-
}
|
|
1634
|
-
|
|
1635
|
-
/**
|
|
1636
|
-
* Validate a checkpoint proposal.
|
|
1637
|
-
*
|
|
1638
|
-
* @param checkpoint - The checkpoint proposal to validate.
|
|
1639
|
-
* @returns True if the checkpoint proposal is valid, false otherwise.
|
|
1640
|
-
*/
|
|
1641
|
-
@trackSpan('Libp2pService.validateCheckpointProposal', (_peerId, checkpoint) => ({
|
|
1642
|
-
[Attributes.SLOT_NUMBER]: checkpoint.slotNumber.toString(),
|
|
1643
|
-
}))
|
|
1644
|
-
public async validateCheckpointProposal(
|
|
1645
|
-
peerId: PeerId,
|
|
1646
|
-
checkpoint: CheckpointProposal,
|
|
1647
|
-
): Promise<P2PValidationResult> {
|
|
1648
|
-
const result = await this.checkpointProposalValidator.validate(checkpoint);
|
|
1649
|
-
|
|
1650
|
-
if (result.result === 'reject') {
|
|
1651
|
-
this.logger.debug(`Penalizing peer ${peerId} for checkpoint proposal validation failure`);
|
|
1747
|
+
this.logger.warn(`Penalizing peer ${peerId} for checkpoint attestation validation failure`);
|
|
1652
1748
|
this.peerManager.penalizePeer(peerId, result.severity);
|
|
1653
1749
|
}
|
|
1654
1750
|
|