@aztec/p2p 3.0.0-devnet.2 → 3.0.0-devnet.2-patch.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dest/bootstrap/bootstrap.d.ts +1 -1
- package/dest/bootstrap/bootstrap.d.ts.map +1 -1
- package/dest/client/factory.d.ts +1 -1
- package/dest/client/index.d.ts +1 -1
- package/dest/client/interface.d.ts +4 -2
- package/dest/client/interface.d.ts.map +1 -1
- package/dest/client/p2p_client.d.ts +8 -26
- package/dest/client/p2p_client.d.ts.map +1 -1
- package/dest/client/p2p_client.js +31 -24
- package/dest/config.d.ts +60 -54
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +12 -2
- package/dest/enr/generate-enr.d.ts +1 -1
- package/dest/enr/index.d.ts +1 -1
- package/dest/errors/attestation-pool.error.d.ts +7 -0
- package/dest/errors/attestation-pool.error.d.ts.map +1 -0
- package/dest/errors/attestation-pool.error.js +12 -0
- package/dest/errors/reqresp.error.d.ts +1 -1
- package/dest/errors/reqresp.error.d.ts.map +1 -1
- package/dest/index.d.ts +1 -1
- package/dest/mem_pools/attestation_pool/attestation_pool.d.ts +43 -6
- package/dest/mem_pools/attestation_pool/attestation_pool.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.d.ts +1 -1
- package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.js +67 -34
- package/dest/mem_pools/attestation_pool/index.d.ts +1 -1
- package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts +15 -6
- package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/kv_attestation_pool.js +57 -18
- package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts +13 -6
- package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/memory_attestation_pool.js +51 -7
- package/dest/mem_pools/attestation_pool/mocks.d.ts +226 -5
- package/dest/mem_pools/attestation_pool/mocks.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/mocks.js +2 -2
- package/dest/mem_pools/index.d.ts +1 -1
- package/dest/mem_pools/instrumentation.d.ts +3 -1
- package/dest/mem_pools/instrumentation.d.ts.map +1 -1
- package/dest/mem_pools/instrumentation.js +11 -2
- package/dest/mem_pools/interface.d.ts +1 -1
- package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts +5 -38
- package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.js +9 -3
- package/dest/mem_pools/tx_pool/index.d.ts +1 -1
- package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts +5 -3
- package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/memory_tx_pool.js +7 -0
- package/dest/mem_pools/tx_pool/priority.d.ts +1 -1
- package/dest/mem_pools/tx_pool/tx_pool.d.ts +10 -3
- package/dest/mem_pools/tx_pool/tx_pool.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts +1 -1
- package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/tx_pool_test_suite.js +5 -4
- package/dest/msg_validators/attestation_validator/attestation_validator.d.ts +4 -3
- package/dest/msg_validators/attestation_validator/attestation_validator.d.ts.map +1 -1
- package/dest/msg_validators/attestation_validator/attestation_validator.js +12 -12
- package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts +20 -0
- package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts.map +1 -0
- package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.js +67 -0
- package/dest/msg_validators/attestation_validator/index.d.ts +2 -1
- package/dest/msg_validators/attestation_validator/index.d.ts.map +1 -1
- package/dest/msg_validators/attestation_validator/index.js +1 -0
- package/dest/msg_validators/block_proposal_validator/block_proposal_validator.d.ts +1 -1
- package/dest/msg_validators/block_proposal_validator/block_proposal_validator.d.ts.map +1 -1
- package/dest/msg_validators/block_proposal_validator/block_proposal_validator.js +22 -10
- package/dest/msg_validators/block_proposal_validator/index.d.ts +1 -1
- package/dest/msg_validators/index.d.ts +1 -1
- package/dest/msg_validators/msg_seen_validator/msg_seen_validator.d.ts +1 -1
- package/dest/msg_validators/msg_seen_validator/msg_seen_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts +1 -1
- package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/allowed_public_setup.d.ts +1 -1
- package/dest/msg_validators/tx_validator/archive_cache.d.ts +2 -2
- package/dest/msg_validators/tx_validator/archive_cache.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/block_header_validator.d.ts +2 -2
- package/dest/msg_validators/tx_validator/block_header_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/data_validator.d.ts +1 -1
- package/dest/msg_validators/tx_validator/data_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/double_spend_validator.d.ts +1 -1
- package/dest/msg_validators/tx_validator/double_spend_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/factory.d.ts +4 -3
- package/dest/msg_validators/tx_validator/factory.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/factory.js +1 -1
- package/dest/msg_validators/tx_validator/gas_validator.d.ts +1 -1
- package/dest/msg_validators/tx_validator/gas_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/index.d.ts +1 -1
- package/dest/msg_validators/tx_validator/metadata_validator.d.ts +2 -2
- package/dest/msg_validators/tx_validator/metadata_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/phases_validator.d.ts +1 -1
- package/dest/msg_validators/tx_validator/phases_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/phases_validator.js +3 -1
- package/dest/msg_validators/tx_validator/test_utils.d.ts +2 -2
- package/dest/msg_validators/tx_validator/test_utils.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/timestamp_validator.d.ts +3 -2
- package/dest/msg_validators/tx_validator/timestamp_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/tx_permitted_validator.d.ts +1 -1
- package/dest/msg_validators/tx_validator/tx_permitted_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/tx_proof_validator.d.ts +1 -1
- package/dest/msg_validators/tx_validator/tx_proof_validator.d.ts.map +1 -1
- package/dest/services/data_store.d.ts +1 -1
- package/dest/services/data_store.d.ts.map +1 -1
- package/dest/services/discv5/discV5_service.d.ts +1 -1
- package/dest/services/discv5/discV5_service.d.ts.map +1 -1
- package/dest/services/dummy_service.d.ts +1 -1
- package/dest/services/dummy_service.d.ts.map +1 -1
- package/dest/services/encoding.d.ts +25 -4
- package/dest/services/encoding.d.ts.map +1 -1
- package/dest/services/encoding.js +74 -6
- package/dest/services/gossipsub/scoring.d.ts +1 -1
- package/dest/services/index.d.ts +1 -1
- package/dest/services/libp2p/instrumentation.d.ts +3 -1
- package/dest/services/libp2p/instrumentation.d.ts.map +1 -1
- package/dest/services/libp2p/instrumentation.js +9 -2
- package/dest/services/libp2p/libp2p_service.d.ts +25 -74
- package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
- package/dest/services/libp2p/libp2p_service.js +308 -84
- package/dest/services/peer-manager/interface.d.ts +1 -1
- 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 +11 -0
- package/dest/services/peer-manager/peer_manager.d.ts +1 -32
- package/dest/services/peer-manager/peer_manager.d.ts.map +1 -1
- package/dest/services/peer-manager/peer_manager.js +4 -2
- package/dest/services/peer-manager/peer_scoring.d.ts +7 -2
- package/dest/services/peer-manager/peer_scoring.d.ts.map +1 -1
- package/dest/services/peer-manager/peer_scoring.js +40 -2
- package/dest/services/reqresp/config.d.ts +1 -1
- package/dest/services/reqresp/connection-sampler/batch_connection_sampler.d.ts +1 -1
- package/dest/services/reqresp/connection-sampler/batch_connection_sampler.d.ts.map +1 -1
- package/dest/services/reqresp/connection-sampler/connection_sampler.d.ts +1 -4
- package/dest/services/reqresp/connection-sampler/connection_sampler.d.ts.map +1 -1
- package/dest/services/reqresp/index.d.ts +1 -1
- package/dest/services/reqresp/interface.d.ts +2 -2
- package/dest/services/reqresp/interface.d.ts.map +1 -1
- package/dest/services/reqresp/interface.js +1 -1
- package/dest/services/reqresp/metrics.d.ts +1 -1
- package/dest/services/reqresp/metrics.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/auth.d.ts +2 -2
- package/dest/services/reqresp/protocols/auth.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/auth.js +2 -2
- package/dest/services/reqresp/protocols/block.d.ts +1 -1
- package/dest/services/reqresp/protocols/block.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/block.js +3 -2
- package/dest/services/reqresp/protocols/block_txs/bitvector.d.ts +1 -1
- package/dest/services/reqresp/protocols/block_txs/bitvector.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/block_txs/block_txs_handler.d.ts +1 -1
- package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.d.ts +4 -6
- package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.js +1 -1
- package/dest/services/reqresp/protocols/block_txs/index.d.ts +1 -1
- package/dest/services/reqresp/protocols/goodbye.d.ts +1 -1
- package/dest/services/reqresp/protocols/goodbye.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/index.d.ts +1 -1
- package/dest/services/reqresp/protocols/ping.d.ts +1 -1
- package/dest/services/reqresp/protocols/status.d.ts +6 -5
- package/dest/services/reqresp/protocols/status.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/status.js +4 -3
- package/dest/services/reqresp/protocols/tx.d.ts +1 -1
- package/dest/services/reqresp/rate-limiter/index.d.ts +1 -1
- package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts +2 -2
- package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts.map +1 -1
- package/dest/services/reqresp/rate-limiter/rate_limits.d.ts +1 -1
- package/dest/services/reqresp/reqresp.d.ts +1 -41
- package/dest/services/reqresp/reqresp.d.ts.map +1 -1
- package/dest/services/reqresp/reqresp.js +2 -2
- package/dest/services/reqresp/status.d.ts +2 -2
- package/dest/services/reqresp/status.d.ts.map +1 -1
- package/dest/services/service.d.ts +1 -1
- package/dest/services/tx_collection/config.d.ts +1 -1
- package/dest/services/tx_collection/fast_tx_collection.d.ts +4 -9
- package/dest/services/tx_collection/fast_tx_collection.d.ts.map +1 -1
- package/dest/services/tx_collection/index.d.ts +1 -1
- package/dest/services/tx_collection/instrumentation.d.ts +1 -1
- package/dest/services/tx_collection/instrumentation.d.ts.map +1 -1
- package/dest/services/tx_collection/slow_tx_collection.d.ts +6 -7
- package/dest/services/tx_collection/slow_tx_collection.d.ts.map +1 -1
- package/dest/services/tx_collection/slow_tx_collection.js +2 -1
- package/dest/services/tx_collection/tx_collection.d.ts +11 -11
- package/dest/services/tx_collection/tx_collection.d.ts.map +1 -1
- package/dest/services/tx_collection/tx_collection_sink.d.ts +3 -3
- package/dest/services/tx_collection/tx_collection_sink.d.ts.map +1 -1
- package/dest/services/tx_collection/tx_source.d.ts +1 -1
- package/dest/services/tx_collection/tx_source.d.ts.map +1 -1
- package/dest/services/tx_provider.d.ts +5 -4
- package/dest/services/tx_provider.d.ts.map +1 -1
- package/dest/services/tx_provider_instrumentation.d.ts +1 -1
- package/dest/services/tx_provider_instrumentation.d.ts.map +1 -1
- package/dest/test-helpers/generate-peer-id-private-keys.d.ts +1 -1
- package/dest/test-helpers/get-ports.d.ts +1 -1
- package/dest/test-helpers/get-ports.d.ts.map +1 -1
- package/dest/test-helpers/index.d.ts +1 -1
- package/dest/test-helpers/make-enrs.d.ts +1 -1
- package/dest/test-helpers/make-test-p2p-clients.d.ts +2 -2
- package/dest/test-helpers/make-test-p2p-clients.d.ts.map +1 -1
- package/dest/test-helpers/mock-pubsub.d.ts +4 -4
- package/dest/test-helpers/mock-pubsub.d.ts.map +1 -1
- package/dest/test-helpers/mock-tx-helpers.d.ts +2 -2
- package/dest/test-helpers/mock-tx-helpers.d.ts.map +1 -1
- package/dest/test-helpers/mock-tx-helpers.js +1 -1
- package/dest/test-helpers/reqresp-nodes.d.ts +1 -1
- package/dest/test-helpers/reqresp-nodes.d.ts.map +1 -1
- package/dest/testbench/p2p_client_testbench_worker.d.ts +1 -1
- package/dest/testbench/p2p_client_testbench_worker.js +14 -8
- package/dest/testbench/parse_log_file.d.ts +1 -1
- package/dest/testbench/testbench.d.ts +1 -1
- package/dest/testbench/testbench.js +2 -2
- package/dest/testbench/worker_client_manager.d.ts +1 -1
- package/dest/testbench/worker_client_manager.d.ts.map +1 -1
- package/dest/types/index.d.ts +1 -1
- package/dest/util.d.ts +2 -1
- package/dest/util.d.ts.map +1 -1
- package/dest/util.js +11 -2
- package/dest/versioning.d.ts +1 -1
- package/package.json +19 -18
- package/src/client/interface.ts +4 -1
- package/src/client/p2p_client.ts +51 -43
- package/src/config.ts +19 -2
- package/src/errors/attestation-pool.error.ts +13 -0
- package/src/mem_pools/attestation_pool/attestation_pool.ts +46 -5
- package/src/mem_pools/attestation_pool/attestation_pool_test_suite.ts +84 -34
- package/src/mem_pools/attestation_pool/kv_attestation_pool.ts +87 -24
- package/src/mem_pools/attestation_pool/memory_attestation_pool.ts +77 -15
- package/src/mem_pools/attestation_pool/mocks.ts +3 -3
- package/src/mem_pools/instrumentation.ts +13 -0
- package/src/mem_pools/tx_pool/aztec_kv_tx_pool.ts +15 -9
- package/src/mem_pools/tx_pool/memory_tx_pool.ts +13 -6
- package/src/mem_pools/tx_pool/tx_pool.ts +10 -2
- package/src/mem_pools/tx_pool/tx_pool_test_suite.ts +5 -4
- package/src/msg_validators/attestation_validator/attestation_validator.ts +14 -16
- package/src/msg_validators/attestation_validator/fisherman_attestation_validator.ts +91 -0
- package/src/msg_validators/attestation_validator/index.ts +1 -0
- package/src/msg_validators/block_proposal_validator/block_proposal_validator.ts +26 -10
- package/src/msg_validators/tx_validator/archive_cache.ts +1 -1
- package/src/msg_validators/tx_validator/block_header_validator.ts +1 -1
- package/src/msg_validators/tx_validator/factory.ts +3 -2
- package/src/msg_validators/tx_validator/metadata_validator.ts +1 -1
- package/src/msg_validators/tx_validator/phases_validator.ts +3 -1
- package/src/msg_validators/tx_validator/test_utils.ts +1 -1
- package/src/msg_validators/tx_validator/timestamp_validator.ts +2 -1
- package/src/services/encoding.ts +81 -6
- package/src/services/libp2p/instrumentation.ts +10 -1
- package/src/services/libp2p/libp2p_service.ts +334 -91
- package/src/services/peer-manager/metrics.ts +10 -0
- package/src/services/peer-manager/peer_manager.ts +4 -2
- package/src/services/peer-manager/peer_scoring.ts +46 -3
- package/src/services/reqresp/interface.ts +1 -1
- package/src/services/reqresp/protocols/auth.ts +2 -2
- package/src/services/reqresp/protocols/block.ts +3 -2
- package/src/services/reqresp/protocols/block_txs/block_txs_reqresp.ts +1 -1
- package/src/services/reqresp/protocols/status.ts +9 -8
- package/src/services/reqresp/reqresp.ts +2 -2
- package/src/services/tx_collection/fast_tx_collection.ts +3 -2
- package/src/services/tx_collection/slow_tx_collection.ts +7 -6
- package/src/services/tx_collection/tx_collection.ts +10 -9
- package/src/services/tx_provider.ts +4 -3
- package/src/test-helpers/mock-tx-helpers.ts +1 -1
- package/src/testbench/p2p_client_testbench_worker.ts +11 -5
- package/src/testbench/testbench.ts +2 -2
- package/src/util.ts +12 -2
|
@@ -4,10 +4,10 @@ function _ts_decorate(decorators, target, key, desc) {
|
|
|
4
4
|
else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
}
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
7
|
+
import { BlockNumber, SlotNumber } from '@aztec/foundation/branded-types';
|
|
8
|
+
import { randomInt } from '@aztec/foundation/crypto/random';
|
|
9
|
+
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
9
10
|
import { createLibp2pComponentLogger, createLogger } from '@aztec/foundation/log';
|
|
10
|
-
import { SerialQueue } from '@aztec/foundation/queue';
|
|
11
11
|
import { RunningPromise } from '@aztec/foundation/running-promise';
|
|
12
12
|
import { Timer } from '@aztec/foundation/timer';
|
|
13
13
|
import { getVKTreeRoot } from '@aztec/noir-protocol-circuits-types/vk-tree';
|
|
@@ -30,7 +30,8 @@ import { mplex } from '@libp2p/mplex';
|
|
|
30
30
|
import { tcp } from '@libp2p/tcp';
|
|
31
31
|
import { ENR } from '@nethermindeth/enr';
|
|
32
32
|
import { createLibp2p } from 'libp2p';
|
|
33
|
-
import {
|
|
33
|
+
import { ProposalSlotCapExceededError } from '../../errors/attestation-pool.error.js';
|
|
34
|
+
import { AttestationValidator, BlockProposalValidator, FishermanAttestationValidator } from '../../msg_validators/index.js';
|
|
34
35
|
import { MessageSeenValidator } from '../../msg_validators/msg_seen_validator/msg_seen_validator.js';
|
|
35
36
|
import { getDefaultAllowedSetupFunctions } from '../../msg_validators/tx_validator/allowed_public_setup.js';
|
|
36
37
|
import { createTxMessageValidators } from '../../msg_validators/tx_validator/factory.js';
|
|
@@ -64,8 +65,6 @@ import { P2PInstrumentation } from './instrumentation.js';
|
|
|
64
65
|
epochCache;
|
|
65
66
|
proofVerifier;
|
|
66
67
|
worldStateSynchronizer;
|
|
67
|
-
logger;
|
|
68
|
-
jobQueue;
|
|
69
68
|
discoveryRunningPromise;
|
|
70
69
|
msgIdSeenValidators;
|
|
71
70
|
// Message validators
|
|
@@ -81,8 +80,11 @@ import { P2PInstrumentation } from './instrumentation.js';
|
|
|
81
80
|
*/ blockReceivedCallback;
|
|
82
81
|
gossipSubEventHandler;
|
|
83
82
|
instrumentation;
|
|
83
|
+
logger;
|
|
84
84
|
constructor(clientType, config, node, peerDiscoveryService, reqresp, peerManager, mempools, archiver, epochCache, proofVerifier, worldStateSynchronizer, telemetry, logger = createLogger('p2p:libp2p_service')){
|
|
85
|
-
super(telemetry, 'LibP2PService'), this.clientType = clientType, this.config = config, this.node = node, this.peerDiscoveryService = peerDiscoveryService, this.reqresp = reqresp, this.peerManager = peerManager, this.mempools = mempools, this.archiver = archiver, this.epochCache = epochCache, this.proofVerifier = proofVerifier, this.worldStateSynchronizer = worldStateSynchronizer, this.
|
|
85
|
+
super(telemetry, 'LibP2PService'), this.clientType = clientType, this.config = config, this.node = node, this.peerDiscoveryService = peerDiscoveryService, this.reqresp = reqresp, this.peerManager = peerManager, this.mempools = mempools, this.archiver = archiver, this.epochCache = epochCache, this.proofVerifier = proofVerifier, this.worldStateSynchronizer = worldStateSynchronizer, this.msgIdSeenValidators = {}, this.protocolVersion = '', this.topicStrings = {};
|
|
86
|
+
// Create child logger with fisherman prefix if in fisherman mode
|
|
87
|
+
this.logger = config.fishermanMode ? logger.createChild('[FISHERMAN]') : logger;
|
|
86
88
|
this.instrumentation = new P2PInstrumentation(telemetry, 'LibP2PService');
|
|
87
89
|
this.msgIdSeenValidators[TopicType.tx] = new MessageSeenValidator(config.seenMessageCacheSize);
|
|
88
90
|
this.msgIdSeenValidators[TopicType.block_proposal] = new MessageSeenValidator(config.seenMessageCacheSize);
|
|
@@ -93,14 +95,15 @@ import { P2PInstrumentation } from './instrumentation.js';
|
|
|
93
95
|
this.topicStrings[TopicType.tx] = createTopicString(TopicType.tx, this.protocolVersion);
|
|
94
96
|
this.topicStrings[TopicType.block_proposal] = createTopicString(TopicType.block_proposal, this.protocolVersion);
|
|
95
97
|
this.topicStrings[TopicType.block_attestation] = createTopicString(TopicType.block_attestation, this.protocolVersion);
|
|
96
|
-
|
|
98
|
+
// Use FishermanAttestationValidator in fisherman mode to validate attestation payloads against proposals
|
|
99
|
+
this.attestationValidator = config.fishermanMode ? new FishermanAttestationValidator(epochCache, mempools.attestationPool, telemetry) : new AttestationValidator(epochCache);
|
|
97
100
|
this.blockProposalValidator = new BlockProposalValidator(epochCache, {
|
|
98
101
|
txsPermitted: !config.disableTransactions
|
|
99
102
|
});
|
|
100
103
|
this.gossipSubEventHandler = this.handleGossipSubEvent.bind(this);
|
|
101
104
|
this.blockReceivedCallback = async (block)=>{
|
|
102
|
-
this.logger.debug(`Handler not yet registered: Block received callback not set. Received block for slot ${block.slotNumber
|
|
103
|
-
p2pMessageIdentifier: await block.
|
|
105
|
+
this.logger.debug(`Handler not yet registered: Block received callback not set. Received block for slot ${block.slotNumber} from peer.`, {
|
|
106
|
+
p2pMessageIdentifier: await block.p2pMessageLoggingIdentifier()
|
|
104
107
|
});
|
|
105
108
|
return undefined;
|
|
106
109
|
};
|
|
@@ -278,7 +281,7 @@ import { P2PInstrumentation } from './instrumentation.js';
|
|
|
278
281
|
},
|
|
279
282
|
logger: createLibp2pComponentLogger(logger.module)
|
|
280
283
|
});
|
|
281
|
-
const peerScoring = new PeerScoring(config);
|
|
284
|
+
const peerScoring = new PeerScoring(config, telemetry);
|
|
282
285
|
const reqresp = new ReqResp(config, node, peerScoring, createLogger(`${logger.module}:reqresp`));
|
|
283
286
|
const peerManager = new PeerManager(node, peerDiscoveryService, config, telemetry, createLogger(`${logger.module}:peer_manager`), peerScoring, reqresp, worldStateSynchronizer, protocolVersion, epochCache);
|
|
284
287
|
// Update gossipsub score params
|
|
@@ -300,8 +303,6 @@ import { P2PInstrumentation } from './instrumentation.js';
|
|
|
300
303
|
throw new Error('Announce address not provided.');
|
|
301
304
|
}
|
|
302
305
|
const announceTcpMultiaddr = convertToMultiaddr(p2pIp, p2pPort, 'tcp');
|
|
303
|
-
// Start job queue, peer discovery service and libp2p node
|
|
304
|
-
this.jobQueue.start();
|
|
305
306
|
await this.peerManager.initializePeers();
|
|
306
307
|
if (!this.config.p2pDiscoveryDisabled) {
|
|
307
308
|
await this.peerDiscoveryService.start();
|
|
@@ -323,7 +324,7 @@ import { P2PInstrumentation } from './instrumentation.js';
|
|
|
323
324
|
[ReqRespSubProtocol.BLOCK]: blockHandler.bind(this)
|
|
324
325
|
};
|
|
325
326
|
// Only handle block transactions request if attestation pool is available to the client
|
|
326
|
-
if (this.mempools.attestationPool) {
|
|
327
|
+
if (this.mempools.attestationPool && !this.config.disableTransactions) {
|
|
327
328
|
const blockTxsHandler = reqRespBlockTxsHandler(this.mempools.attestationPool, this.mempools.txPool);
|
|
328
329
|
requestResponseHandlers[ReqRespSubProtocol.BLOCK_TXS] = blockTxsHandler.bind(this);
|
|
329
330
|
}
|
|
@@ -332,15 +333,17 @@ import { P2PInstrumentation } from './instrumentation.js';
|
|
|
332
333
|
}
|
|
333
334
|
// add GossipSub listener
|
|
334
335
|
this.node.services.pubsub.addEventListener(GossipSubEvent.MESSAGE, this.gossipSubEventHandler);
|
|
335
|
-
// Start running promise for peer discovery
|
|
336
|
-
this.discoveryRunningPromise = new RunningPromise(()=>
|
|
336
|
+
// Start running promise for peer discovery and metrics collection
|
|
337
|
+
this.discoveryRunningPromise = new RunningPromise(async ()=>{
|
|
338
|
+
await this.peerManager.heartbeat();
|
|
339
|
+
}, this.logger, this.config.peerCheckIntervalMS);
|
|
337
340
|
this.discoveryRunningPromise.start();
|
|
338
341
|
// Define the sub protocol validators - This is done within this start() method to gain a callback to the existing validateTx function
|
|
339
342
|
const reqrespSubProtocolValidators = {
|
|
340
343
|
...DEFAULT_SUB_PROTOCOL_VALIDATORS,
|
|
341
|
-
// TODO(#11336): A request validator for blocks
|
|
342
344
|
[ReqRespSubProtocol.TX]: this.validateRequestedTxs.bind(this),
|
|
343
|
-
[ReqRespSubProtocol.BLOCK_TXS]: this.validateRequestedBlockTxs.bind(this)
|
|
345
|
+
[ReqRespSubProtocol.BLOCK_TXS]: this.validateRequestedBlockTxs.bind(this),
|
|
346
|
+
[ReqRespSubProtocol.BLOCK]: this.validateRequestedBlock.bind(this)
|
|
344
347
|
};
|
|
345
348
|
await this.reqresp.start(requestResponseHandlers, reqrespSubProtocolValidators);
|
|
346
349
|
this.logger.info(`Started P2P service`, {
|
|
@@ -359,8 +362,6 @@ import { P2PInstrumentation } from './instrumentation.js';
|
|
|
359
362
|
// Stop peer manager
|
|
360
363
|
this.logger.debug('Stopping peer manager...');
|
|
361
364
|
await this.peerManager.stop();
|
|
362
|
-
this.logger.debug('Stopping job queue...');
|
|
363
|
-
await this.jobQueue.end();
|
|
364
365
|
this.logger.debug('Stopping running promise...');
|
|
365
366
|
await this.discoveryRunningPromise?.stop();
|
|
366
367
|
this.logger.debug('Stopping peer discovery service...');
|
|
@@ -426,11 +427,15 @@ import { P2PInstrumentation } from './instrumentation.js';
|
|
|
426
427
|
if (!this.node.services.pubsub) {
|
|
427
428
|
throw new Error('Pubsub service not available.');
|
|
428
429
|
}
|
|
429
|
-
const p2pMessage = P2PMessage.fromGossipable(message);
|
|
430
|
+
const p2pMessage = P2PMessage.fromGossipable(message, this.config.debugP2PInstrumentMessages);
|
|
430
431
|
const result = await this.node.services.pubsub.publish(topic, p2pMessage.toMessageData());
|
|
431
432
|
return result.recipients.length;
|
|
432
433
|
}
|
|
433
|
-
|
|
434
|
+
/**
|
|
435
|
+
* Checks if this message has already been seen, based on its msgId computed from hashing the message data.
|
|
436
|
+
* Note that we do not rely on the seenCache from gossipsub since we want to keep a longer history of seen
|
|
437
|
+
* messages to avoid tx echoes across the network.
|
|
438
|
+
*/ preValidateReceivedMessage(msg, msgId, source) {
|
|
434
439
|
let topicType;
|
|
435
440
|
switch(msg.topic){
|
|
436
441
|
case this.topicStrings[TopicType.tx]:
|
|
@@ -462,54 +467,108 @@ import { P2PInstrumentation } from './instrumentation.js';
|
|
|
462
467
|
};
|
|
463
468
|
}
|
|
464
469
|
/**
|
|
470
|
+
* Safely deserializes a P2PMessage from raw message data.
|
|
471
|
+
* @param msgId - The message ID.
|
|
472
|
+
* @param source - The peer ID of the message source.
|
|
473
|
+
* @param data - The raw message data.
|
|
474
|
+
* @returns The deserialized P2PMessage or undefined if deserialization fails.
|
|
475
|
+
*/ safelyDeserializeP2PMessage(msgId, source, data) {
|
|
476
|
+
try {
|
|
477
|
+
return P2PMessage.fromMessageData(Buffer.from(data), this.config.debugP2PInstrumentMessages);
|
|
478
|
+
} catch (err) {
|
|
479
|
+
this.logger.error(`Error deserializing P2PMessage`, err, {
|
|
480
|
+
msgId,
|
|
481
|
+
source: source.toString()
|
|
482
|
+
});
|
|
483
|
+
this.node.services.pubsub.reportMessageValidationResult(msgId, source.toString(), TopicValidatorResult.Reject);
|
|
484
|
+
this.peerManager.penalizePeer(source, PeerErrorSeverity.LowToleranceError);
|
|
485
|
+
return undefined;
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
/**
|
|
465
489
|
* Handles a new gossip message that was received by the client.
|
|
466
490
|
* @param topic - The message's topic.
|
|
467
491
|
* @param data - The message data
|
|
468
492
|
*/ async handleNewGossipMessage(msg, msgId, source) {
|
|
469
|
-
const
|
|
493
|
+
const msgReceivedTime = Date.now();
|
|
494
|
+
let topicType;
|
|
495
|
+
const p2pMessage = this.safelyDeserializeP2PMessage(msgId, source, msg.data);
|
|
496
|
+
if (!p2pMessage) {
|
|
497
|
+
return;
|
|
498
|
+
}
|
|
470
499
|
const preValidationResult = this.preValidateReceivedMessage(msg, msgId, source);
|
|
471
500
|
if (!preValidationResult.result) {
|
|
472
501
|
return;
|
|
473
502
|
}
|
|
474
503
|
if (msg.topic === this.topicStrings[TopicType.tx]) {
|
|
504
|
+
topicType = TopicType.tx;
|
|
475
505
|
await this.handleGossipedTx(p2pMessage.payload, msgId, source);
|
|
476
506
|
}
|
|
477
|
-
if (msg.topic === this.topicStrings[TopicType.block_attestation]
|
|
478
|
-
|
|
507
|
+
if (msg.topic === this.topicStrings[TopicType.block_attestation]) {
|
|
508
|
+
topicType = TopicType.block_attestation;
|
|
509
|
+
if (this.clientType === P2PClientType.Full) {
|
|
510
|
+
await this.processAttestationFromPeer(p2pMessage.payload, msgId, source);
|
|
511
|
+
}
|
|
479
512
|
}
|
|
480
513
|
if (msg.topic === this.topicStrings[TopicType.block_proposal]) {
|
|
514
|
+
topicType = TopicType.block_proposal;
|
|
481
515
|
await this.processBlockFromPeer(p2pMessage.payload, msgId, source);
|
|
482
516
|
}
|
|
517
|
+
if (p2pMessage.timestamp !== undefined && topicType !== undefined) {
|
|
518
|
+
const latency = msgReceivedTime - p2pMessage.timestamp.getTime();
|
|
519
|
+
this.instrumentation.recordMessageLatency(topicType, latency);
|
|
520
|
+
}
|
|
483
521
|
return;
|
|
484
522
|
}
|
|
485
523
|
async validateReceivedMessage(validationFunc, msgId, source, topicType) {
|
|
486
524
|
let resultAndObj = {
|
|
487
|
-
result:
|
|
488
|
-
obj: undefined
|
|
525
|
+
result: TopicValidatorResult.Reject
|
|
489
526
|
};
|
|
490
527
|
const timer = new Timer();
|
|
491
528
|
try {
|
|
492
529
|
resultAndObj = await validationFunc();
|
|
493
530
|
} catch (err) {
|
|
494
|
-
this.
|
|
531
|
+
this.peerManager.penalizePeer(source, PeerErrorSeverity.LowToleranceError);
|
|
532
|
+
this.logger.error(`Error deserializing and validating gossipsub message`, err, {
|
|
533
|
+
msgId,
|
|
534
|
+
source: source.toString(),
|
|
535
|
+
topicType
|
|
536
|
+
});
|
|
495
537
|
}
|
|
496
|
-
if (resultAndObj.result) {
|
|
538
|
+
if (resultAndObj.result === TopicValidatorResult.Accept) {
|
|
497
539
|
this.instrumentation.recordMessageValidation(topicType, timer);
|
|
498
540
|
}
|
|
499
|
-
this.node.services.pubsub.reportMessageValidationResult(msgId, source.toString(), resultAndObj.result
|
|
541
|
+
this.node.services.pubsub.reportMessageValidationResult(msgId, source.toString(), resultAndObj.result);
|
|
500
542
|
return resultAndObj;
|
|
501
543
|
}
|
|
502
544
|
async handleGossipedTx(payloadData, msgId, source) {
|
|
503
545
|
const validationFunc = async ()=>{
|
|
504
546
|
const tx = Tx.fromBuffer(payloadData);
|
|
505
|
-
const
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
547
|
+
const isValid = await this.validatePropagatedTx(tx, source);
|
|
548
|
+
const exists = isValid && await this.mempools.txPool.hasTx(tx.getTxHash());
|
|
549
|
+
this.logger.trace(`Validate propagated tx`, {
|
|
550
|
+
isValid,
|
|
551
|
+
exists,
|
|
552
|
+
[Attributes.P2P_ID]: source.toString()
|
|
553
|
+
});
|
|
554
|
+
if (!isValid) {
|
|
555
|
+
return {
|
|
556
|
+
result: TopicValidatorResult.Reject
|
|
557
|
+
};
|
|
558
|
+
} else if (exists) {
|
|
559
|
+
return {
|
|
560
|
+
result: TopicValidatorResult.Ignore,
|
|
561
|
+
obj: tx
|
|
562
|
+
};
|
|
563
|
+
} else {
|
|
564
|
+
return {
|
|
565
|
+
result: TopicValidatorResult.Accept,
|
|
566
|
+
obj: tx
|
|
567
|
+
};
|
|
568
|
+
}
|
|
510
569
|
};
|
|
511
570
|
const { result, obj: tx } = await this.validateReceivedMessage(validationFunc, msgId, source, TopicType.tx);
|
|
512
|
-
if (
|
|
571
|
+
if (result !== TopicValidatorResult.Accept || !tx) {
|
|
513
572
|
return;
|
|
514
573
|
}
|
|
515
574
|
const txHash = tx.getTxHash();
|
|
@@ -519,9 +578,10 @@ import { P2PInstrumentation } from './instrumentation.js';
|
|
|
519
578
|
txHash: txHashString
|
|
520
579
|
});
|
|
521
580
|
if (this.config.dropTransactions && randomInt(1000) < this.config.dropTransactionsProbability * 1000) {
|
|
522
|
-
this.logger.
|
|
581
|
+
this.logger.warn(`Intentionally dropping tx ${txHashString} (probability rule)`);
|
|
523
582
|
return;
|
|
524
583
|
}
|
|
584
|
+
this.instrumentation.incrementTxReceived(1);
|
|
525
585
|
await this.mempools.txPool.addTxs([
|
|
526
586
|
tx
|
|
527
587
|
]);
|
|
@@ -534,23 +594,56 @@ import { P2PInstrumentation } from './instrumentation.js';
|
|
|
534
594
|
*/ async processAttestationFromPeer(payloadData, msgId, source) {
|
|
535
595
|
const validationFunc = async ()=>{
|
|
536
596
|
const attestation = BlockAttestation.fromBuffer(payloadData);
|
|
537
|
-
const
|
|
538
|
-
this.
|
|
597
|
+
const pool = this.mempools.attestationPool;
|
|
598
|
+
const isValid = await this.validateAttestation(source, attestation);
|
|
599
|
+
const exists = isValid && await pool.hasAttestation(attestation);
|
|
600
|
+
let canAdd = true;
|
|
601
|
+
if (isValid && !exists) {
|
|
602
|
+
const slot = attestation.payload.header.slotNumber;
|
|
603
|
+
const { committee } = await this.epochCache.getCommittee(slot);
|
|
604
|
+
const committeeSize = committee?.length ?? 0;
|
|
605
|
+
canAdd = await pool.canAddAttestation(attestation, committeeSize);
|
|
606
|
+
}
|
|
607
|
+
this.logger.trace(`Validate propagated block attestation`, {
|
|
608
|
+
isValid,
|
|
609
|
+
exists,
|
|
610
|
+
canAdd,
|
|
539
611
|
[Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber.toString(),
|
|
540
612
|
[Attributes.P2P_ID]: source.toString()
|
|
541
613
|
});
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
614
|
+
if (!isValid) {
|
|
615
|
+
return {
|
|
616
|
+
result: TopicValidatorResult.Reject
|
|
617
|
+
};
|
|
618
|
+
} else if (exists) {
|
|
619
|
+
return {
|
|
620
|
+
result: TopicValidatorResult.Ignore,
|
|
621
|
+
obj: attestation
|
|
622
|
+
};
|
|
623
|
+
} else if (!canAdd) {
|
|
624
|
+
this.logger.warn(`Dropping block attestation due to per-(slot, proposalId) attestation cap`, {
|
|
625
|
+
slot: attestation.payload.header.slotNumber.toString(),
|
|
626
|
+
archive: attestation.archive.toString(),
|
|
627
|
+
source: source.toString()
|
|
628
|
+
});
|
|
629
|
+
return {
|
|
630
|
+
result: TopicValidatorResult.Ignore,
|
|
631
|
+
obj: attestation
|
|
632
|
+
};
|
|
633
|
+
} else {
|
|
634
|
+
return {
|
|
635
|
+
result: TopicValidatorResult.Accept,
|
|
636
|
+
obj: attestation
|
|
637
|
+
};
|
|
638
|
+
}
|
|
546
639
|
};
|
|
547
640
|
const { result, obj: attestation } = await this.validateReceivedMessage(validationFunc, msgId, source, TopicType.block_attestation);
|
|
548
|
-
if (
|
|
641
|
+
if (result !== TopicValidatorResult.Accept || !attestation) {
|
|
549
642
|
return;
|
|
550
643
|
}
|
|
551
|
-
this.logger.debug(`Received attestation for slot ${attestation.slotNumber
|
|
552
|
-
p2pMessageIdentifier: await attestation.
|
|
553
|
-
slot: attestation.slotNumber
|
|
644
|
+
this.logger.debug(`Received attestation for slot ${attestation.slotNumber} from external peer ${source.toString()}`, {
|
|
645
|
+
p2pMessageIdentifier: await attestation.p2pMessageLoggingIdentifier(),
|
|
646
|
+
slot: attestation.slotNumber,
|
|
554
647
|
archive: attestation.archive.toString(),
|
|
555
648
|
source: source.toString()
|
|
556
649
|
});
|
|
@@ -561,15 +654,44 @@ import { P2PInstrumentation } from './instrumentation.js';
|
|
|
561
654
|
async processBlockFromPeer(payloadData, msgId, source) {
|
|
562
655
|
const validationFunc = async ()=>{
|
|
563
656
|
const block = BlockProposal.fromBuffer(payloadData);
|
|
564
|
-
const
|
|
565
|
-
this.
|
|
657
|
+
const isValid = await this.validateBlockProposal(source, block);
|
|
658
|
+
const pool = this.mempools.attestationPool;
|
|
659
|
+
// Note that we dont have an attestation pool if we're a prover node, but we still
|
|
660
|
+
// subscribe to block proposal topics in order to prevent their txs from being cleared.
|
|
661
|
+
const exists = isValid && await pool?.hasBlockProposal(block);
|
|
662
|
+
const canAdd = isValid && await pool?.canAddProposal(block);
|
|
663
|
+
this.logger.trace(`Validate propagated block proposal`, {
|
|
664
|
+
isValid,
|
|
665
|
+
exists,
|
|
666
|
+
canAdd,
|
|
566
667
|
[Attributes.SLOT_NUMBER]: block.payload.header.slotNumber.toString(),
|
|
567
668
|
[Attributes.P2P_ID]: source.toString()
|
|
568
669
|
});
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
670
|
+
if (!isValid) {
|
|
671
|
+
return {
|
|
672
|
+
result: TopicValidatorResult.Reject
|
|
673
|
+
};
|
|
674
|
+
} else if (exists) {
|
|
675
|
+
return {
|
|
676
|
+
result: TopicValidatorResult.Ignore,
|
|
677
|
+
obj: block
|
|
678
|
+
};
|
|
679
|
+
} else if (!canAdd) {
|
|
680
|
+
this.peerManager.penalizePeer(source, PeerErrorSeverity.MidToleranceError);
|
|
681
|
+
this.logger.warn(`Penalizing peer for block proposal exceeding per-slot cap`, {
|
|
682
|
+
slot: block.slotNumber.toString(),
|
|
683
|
+
archive: block.archive.toString(),
|
|
684
|
+
source: source.toString()
|
|
685
|
+
});
|
|
686
|
+
return {
|
|
687
|
+
result: TopicValidatorResult.Reject
|
|
688
|
+
};
|
|
689
|
+
} else {
|
|
690
|
+
return {
|
|
691
|
+
result: TopicValidatorResult.Accept,
|
|
692
|
+
obj: block
|
|
693
|
+
};
|
|
694
|
+
}
|
|
573
695
|
};
|
|
574
696
|
const { result, obj: block } = await this.validateReceivedMessage(validationFunc, msgId, source, TopicType.block_proposal);
|
|
575
697
|
if (!result || !block) {
|
|
@@ -579,11 +701,11 @@ import { P2PInstrumentation } from './instrumentation.js';
|
|
|
579
701
|
}
|
|
580
702
|
// REVIEW: callback pattern https://github.com/AztecProtocol/aztec-packages/issues/7963
|
|
581
703
|
async processValidBlockProposal(block, sender) {
|
|
582
|
-
const slot = block.slotNumber
|
|
583
|
-
const previousSlot = slot -
|
|
704
|
+
const slot = block.slotNumber;
|
|
705
|
+
const previousSlot = SlotNumber(slot - 1);
|
|
584
706
|
this.logger.verbose(`Received block proposal for slot ${slot} from external peer ${sender.toString()}.`, {
|
|
585
|
-
p2pMessageIdentifier: await block.
|
|
586
|
-
slot: block.slotNumber
|
|
707
|
+
p2pMessageIdentifier: await block.p2pMessageLoggingIdentifier(),
|
|
708
|
+
slot: block.slotNumber,
|
|
587
709
|
archive: block.archive.toString(),
|
|
588
710
|
source: sender.toString()
|
|
589
711
|
});
|
|
@@ -591,17 +713,30 @@ import { P2PInstrumentation } from './instrumentation.js';
|
|
|
591
713
|
if (attestationsForPreviousSlot !== undefined) {
|
|
592
714
|
this.logger.verbose(`Received ${attestationsForPreviousSlot.length} attestations for slot ${previousSlot}`);
|
|
593
715
|
}
|
|
594
|
-
//
|
|
716
|
+
// Attempt to add proposal, then mark the txs in this proposal as non-evictable
|
|
717
|
+
try {
|
|
718
|
+
await this.mempools.attestationPool?.addBlockProposal(block);
|
|
719
|
+
} catch (err) {
|
|
720
|
+
// Drop proposals if we hit per-slot cap in the attestation pool; rethrow unknown errors
|
|
721
|
+
if (err instanceof ProposalSlotCapExceededError) {
|
|
722
|
+
this.logger.warn(`Dropping block proposal due to per-slot proposal cap`, {
|
|
723
|
+
slot: String(slot),
|
|
724
|
+
archive: block.archive.toString(),
|
|
725
|
+
error: err.message
|
|
726
|
+
});
|
|
727
|
+
return;
|
|
728
|
+
}
|
|
729
|
+
throw err;
|
|
730
|
+
}
|
|
595
731
|
await this.mempools.txPool.markTxsAsNonEvictable(block.txHashes);
|
|
596
|
-
await this.mempools.attestationPool?.addBlockProposal(block);
|
|
597
732
|
const attestations = await this.blockReceivedCallback(block, sender);
|
|
598
733
|
// TODO: fix up this pattern - the abstraction is not nice
|
|
599
|
-
// The attestation can be undefined if no handler is registered / the validator deems the block invalid
|
|
734
|
+
// The attestation can be undefined if no handler is registered / the validator deems the block invalid / in fisherman mode
|
|
600
735
|
if (attestations?.length) {
|
|
601
736
|
for (const attestation of attestations){
|
|
602
|
-
this.logger.verbose(`Broadcasting attestation for slot ${attestation.slotNumber
|
|
603
|
-
p2pMessageIdentifier: await attestation.
|
|
604
|
-
slot: attestation.slotNumber
|
|
737
|
+
this.logger.verbose(`Broadcasting attestation for slot ${attestation.slotNumber}`, {
|
|
738
|
+
p2pMessageIdentifier: await attestation.p2pMessageLoggingIdentifier(),
|
|
739
|
+
slot: attestation.slotNumber,
|
|
605
740
|
archive: attestation.archive.toString()
|
|
606
741
|
});
|
|
607
742
|
await this.broadcastAttestation(attestation);
|
|
@@ -618,28 +753,72 @@ import { P2PInstrumentation } from './instrumentation.js';
|
|
|
618
753
|
* Propagates provided message to peers.
|
|
619
754
|
* @param message - The message to propagate.
|
|
620
755
|
*/ async propagate(message) {
|
|
621
|
-
const p2pMessageIdentifier = await message.
|
|
756
|
+
const p2pMessageIdentifier = await message.p2pMessageLoggingIdentifier();
|
|
622
757
|
this.logger.trace(`Message ${p2pMessageIdentifier} queued`, {
|
|
623
758
|
p2pMessageIdentifier
|
|
624
759
|
});
|
|
625
|
-
void this.
|
|
626
|
-
await this.sendToPeers(message);
|
|
627
|
-
}).catch((error)=>{
|
|
760
|
+
void this.sendToPeers(message).catch((error)=>{
|
|
628
761
|
this.logger.error(`Error propagating message ${p2pMessageIdentifier}`, {
|
|
629
762
|
error
|
|
630
763
|
});
|
|
631
764
|
});
|
|
632
765
|
}
|
|
633
766
|
/**
|
|
634
|
-
* Validate the requested block transactions.
|
|
767
|
+
* Validate the requested block transactions. Allow partial returns.
|
|
635
768
|
* @param request - The block transactions request.
|
|
636
769
|
* @param response - The block transactions response.
|
|
637
770
|
* @param peerId - The ID of the peer that made the request.
|
|
638
771
|
* @returns True if the requested block transactions are valid, false otherwise.
|
|
639
|
-
*/ async validateRequestedBlockTxs(
|
|
772
|
+
*/ async validateRequestedBlockTxs(request, response, peerId) {
|
|
640
773
|
const requestedTxValidator = this.createRequestedTxValidator();
|
|
641
774
|
try {
|
|
642
|
-
|
|
775
|
+
if (!response.blockHash.equals(request.blockHash)) {
|
|
776
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
777
|
+
throw new ValidationError(`Received block txs for unexpected block: expected ${request.blockHash.toString()}, got ${response.blockHash.toString()}`);
|
|
778
|
+
}
|
|
779
|
+
if (response.txIndices.getLength() !== request.txIndices.getLength()) {
|
|
780
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
781
|
+
throw new ValidationError(`Received block txs with mismatched bitvector length: expected ${request.txIndices.getLength()}, got ${response.txIndices.getLength()}`);
|
|
782
|
+
}
|
|
783
|
+
// Check no duplicates and not exceeding returnable count
|
|
784
|
+
const requestedIndices = new Set(request.txIndices.getTrueIndices());
|
|
785
|
+
const availableIndices = new Set(response.txIndices.getTrueIndices());
|
|
786
|
+
const maxReturnable = [
|
|
787
|
+
...requestedIndices
|
|
788
|
+
].filter((i)=>availableIndices.has(i)).length;
|
|
789
|
+
const returnedHashes = await Promise.all(response.txs.map((tx)=>tx.getTxHash().toString()));
|
|
790
|
+
const uniqueReturned = new Set(returnedHashes.map((h)=>h.toString()));
|
|
791
|
+
if (uniqueReturned.size !== returnedHashes.length) {
|
|
792
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
793
|
+
throw new ValidationError(`Received duplicate txs in block txs response`);
|
|
794
|
+
}
|
|
795
|
+
if (response.txs.length > maxReturnable) {
|
|
796
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
797
|
+
throw new ValidationError(`Received more txs (${response.txs.length}) than requested-and-available (${maxReturnable})`);
|
|
798
|
+
}
|
|
799
|
+
// Given proposal (should have locally), ensure returned txs are valid subset and match request indices
|
|
800
|
+
const proposal = await this.mempools.attestationPool?.getBlockProposal(request.blockHash.toString());
|
|
801
|
+
if (proposal) {
|
|
802
|
+
// Build intersected indices
|
|
803
|
+
const intersectIdx = request.txIndices.getTrueIndices().filter((i)=>response.txIndices.isSet(i));
|
|
804
|
+
// Enforce subset membership and preserve increasing order by index.
|
|
805
|
+
const hashToIndexInProposal = new Map(proposal.txHashes.map((h, i)=>[
|
|
806
|
+
h.toString(),
|
|
807
|
+
i
|
|
808
|
+
]));
|
|
809
|
+
const allowedIndexSet = new Set(intersectIdx);
|
|
810
|
+
const indices = returnedHashes.map((h)=>hashToIndexInProposal.get(h));
|
|
811
|
+
const allAllowed = indices.every((idx)=>idx !== undefined && allowedIndexSet.has(idx));
|
|
812
|
+
const strictlyIncreasing = indices.every((idx, i)=>i === 0 ? idx !== undefined : idx > indices[i - 1]);
|
|
813
|
+
if (!allAllowed || !strictlyIncreasing) {
|
|
814
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
|
|
815
|
+
throw new ValidationError('Returned txs do not match expected subset/order for requested indices');
|
|
816
|
+
}
|
|
817
|
+
} else {
|
|
818
|
+
// No local proposal, cannot check the membership/order of the returned txs
|
|
819
|
+
this.logger.warn(`Block proposal not found for block hash ${request.blockHash.toString()}; cannot validate membership/order of returned txs`);
|
|
820
|
+
return false;
|
|
821
|
+
}
|
|
643
822
|
await Promise.all(response.txs.map((tx)=>this.validateRequestedTx(tx, peerId, requestedTxValidator)));
|
|
644
823
|
return true;
|
|
645
824
|
} catch (e) {
|
|
@@ -661,7 +840,7 @@ import { P2PInstrumentation } from './instrumentation.js';
|
|
|
661
840
|
* ReqRespSubProtocol.TX subprotocol validation.
|
|
662
841
|
*
|
|
663
842
|
* @param requestedTxHash - The collection of the txs that was requested.
|
|
664
|
-
* @param responseTx - The
|
|
843
|
+
* @param responseTx - The collection of txs that was received as a response to the request.
|
|
665
844
|
* @param peerId - The peer ID of the peer that sent the tx.
|
|
666
845
|
* @returns True if the whole collection of txs is valid, false otherwise.
|
|
667
846
|
*/ async validateRequestedTxs(requestedTxHash, responseTx, peerId) {
|
|
@@ -681,6 +860,45 @@ import { P2PInstrumentation } from './instrumentation.js';
|
|
|
681
860
|
return false;
|
|
682
861
|
}
|
|
683
862
|
}
|
|
863
|
+
/**
|
|
864
|
+
* Validates a BLOCK response.
|
|
865
|
+
*
|
|
866
|
+
* If a local copy exists, enforces hash equality. If missing, rejects (no penalty) since the hash cannot be verified.
|
|
867
|
+
* Penalizes on block number mismatch or hash mismatch.
|
|
868
|
+
*
|
|
869
|
+
* @param requestedBlockNumber - The requested block number.
|
|
870
|
+
* @param responseBlock - The block returned by the peer.
|
|
871
|
+
* @param peerId - The peer that returned the block.
|
|
872
|
+
* @returns True if the response is valid, false otherwise.
|
|
873
|
+
*/ async validateRequestedBlock(requestedBlockNumber, responseBlock, peerId) {
|
|
874
|
+
try {
|
|
875
|
+
const reqNum = Number(requestedBlockNumber.toString());
|
|
876
|
+
if (responseBlock.number !== reqNum) {
|
|
877
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
|
|
878
|
+
return false;
|
|
879
|
+
}
|
|
880
|
+
const local = await this.archiver.getBlock(BlockNumber(reqNum));
|
|
881
|
+
if (!local) {
|
|
882
|
+
// We are missing the local block; we cannot verify the hash yet. Reject without penalizing.
|
|
883
|
+
// TODO: Consider extending this validator to accept an expected hash or
|
|
884
|
+
// performing quorum-based checks when using P2P syncing prior to L1 sync.
|
|
885
|
+
this.logger.warn(`Local block ${reqNum} not found; rejecting BLOCK response without hash verification`);
|
|
886
|
+
return false;
|
|
887
|
+
}
|
|
888
|
+
const [localHash, respHash] = await Promise.all([
|
|
889
|
+
local.hash(),
|
|
890
|
+
responseBlock.hash()
|
|
891
|
+
]);
|
|
892
|
+
if (!localHash.equals(respHash)) {
|
|
893
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
894
|
+
return false;
|
|
895
|
+
}
|
|
896
|
+
return true;
|
|
897
|
+
} catch (e) {
|
|
898
|
+
this.logger.warn(`Error validating requested block`, e);
|
|
899
|
+
return false;
|
|
900
|
+
}
|
|
901
|
+
}
|
|
684
902
|
createRequestedTxValidator() {
|
|
685
903
|
return new AggregateTxValidator(new DataTxValidator(), new MetadataTxValidator({
|
|
686
904
|
l1ChainId: new Fr(this.config.l1ChainId),
|
|
@@ -690,17 +908,18 @@ import { P2PInstrumentation } from './instrumentation.js';
|
|
|
690
908
|
}), new TxProofValidator(this.proofVerifier));
|
|
691
909
|
}
|
|
692
910
|
async validateRequestedTx(tx, peerId, txValidator, requested) {
|
|
911
|
+
const penalize = (severity)=>this.peerManager.penalizePeer(peerId, severity);
|
|
693
912
|
if (!await tx.validateTxHash()) {
|
|
694
|
-
|
|
913
|
+
penalize(PeerErrorSeverity.MidToleranceError);
|
|
695
914
|
throw new ValidationError(`Received tx with invalid hash ${tx.getTxHash().toString()}.`);
|
|
696
915
|
}
|
|
697
916
|
if (requested && !requested.has(tx.getTxHash().toString())) {
|
|
698
|
-
|
|
917
|
+
penalize(PeerErrorSeverity.MidToleranceError);
|
|
699
918
|
throw new ValidationError(`Received tx with hash ${tx.getTxHash().toString()} that was not requested.`);
|
|
700
919
|
}
|
|
701
920
|
const { result } = await txValidator.validateTx(tx);
|
|
702
921
|
if (result === 'invalid') {
|
|
703
|
-
|
|
922
|
+
penalize(PeerErrorSeverity.LowToleranceError);
|
|
704
923
|
throw new ValidationError(`Received tx with hash ${tx.getTxHash().toString()} that is invalid.`);
|
|
705
924
|
}
|
|
706
925
|
}
|
|
@@ -718,7 +937,7 @@ import { P2PInstrumentation } from './instrumentation.js';
|
|
|
718
937
|
let { severity } = outcome.failure;
|
|
719
938
|
// Double spend validator has a special case handler
|
|
720
939
|
if (name === 'doubleSpendValidator') {
|
|
721
|
-
const txBlockNumber = currentBlockNumber + 1; // tx is expected to be in the next block
|
|
940
|
+
const txBlockNumber = BlockNumber(currentBlockNumber + 1); // tx is expected to be in the next block
|
|
722
941
|
severity = await this.handleDoubleSpendFailure(tx, txBlockNumber);
|
|
723
942
|
}
|
|
724
943
|
this.peerManager.penalizePeer(peerId, severity);
|
|
@@ -768,7 +987,7 @@ import { P2PInstrumentation } from './instrumentation.js';
|
|
|
768
987
|
*/ async createMessageValidators(currentBlockNumber, nextSlotTimestamp) {
|
|
769
988
|
const gasFees = await this.getGasFees(currentBlockNumber);
|
|
770
989
|
const allowedInSetup = this.config.txPublicSetupAllowList ?? await getDefaultAllowedSetupFunctions();
|
|
771
|
-
const blockNumberInWhichTheTxIsConsideredToBeIncluded = currentBlockNumber + 1;
|
|
990
|
+
const blockNumberInWhichTheTxIsConsideredToBeIncluded = BlockNumber(currentBlockNumber + 1);
|
|
772
991
|
return createTxMessageValidators(nextSlotTimestamp, blockNumberInWhichTheTxIsConsideredToBeIncluded, this.worldStateSynchronizer, gasFees, this.config.l1ChainId, this.config.rollupVersion, protocolContractsHash, this.archiver, this.proofVerifier, !this.config.disableTransactions, allowedInSetup);
|
|
773
992
|
}
|
|
774
993
|
/**
|
|
@@ -824,7 +1043,7 @@ import { P2PInstrumentation } from './instrumentation.js';
|
|
|
824
1043
|
}
|
|
825
1044
|
const snapshotValidator = new DoubleSpendTxValidator({
|
|
826
1045
|
nullifiersExist: async (nullifiers)=>{
|
|
827
|
-
const merkleTree = this.worldStateSynchronizer.getSnapshot(blockNumber - this.config.doubleSpendSeverePeerPenaltyWindow);
|
|
1046
|
+
const merkleTree = this.worldStateSynchronizer.getSnapshot(BlockNumber(blockNumber - this.config.doubleSpendSeverePeerPenaltyWindow));
|
|
828
1047
|
const indices = await merkleTree.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, nullifiers);
|
|
829
1048
|
return indices.map((index)=>index !== undefined);
|
|
830
1049
|
}
|
|
@@ -870,7 +1089,7 @@ import { P2PInstrumentation } from './instrumentation.js';
|
|
|
870
1089
|
}
|
|
871
1090
|
async sendToPeers(message) {
|
|
872
1091
|
const parent = message.constructor;
|
|
873
|
-
const identifier = await message.
|
|
1092
|
+
const identifier = await message.p2pMessageLoggingIdentifier().then((i)=>i.toString());
|
|
874
1093
|
this.logger.trace(`Sending message ${identifier}`, {
|
|
875
1094
|
p2pMessageIdentifier: identifier
|
|
876
1095
|
});
|
|
@@ -899,16 +1118,16 @@ import { P2PInstrumentation } from './instrumentation.js';
|
|
|
899
1118
|
}
|
|
900
1119
|
_ts_decorate([
|
|
901
1120
|
trackSpan('Libp2pService.processValidBlockProposal', async (block)=>({
|
|
902
|
-
[Attributes.SLOT_NUMBER]: block.slotNumber
|
|
1121
|
+
[Attributes.SLOT_NUMBER]: block.slotNumber,
|
|
903
1122
|
[Attributes.BLOCK_ARCHIVE]: block.archive.toString(),
|
|
904
|
-
[Attributes.P2P_ID]: await block.
|
|
1123
|
+
[Attributes.P2P_ID]: await block.p2pMessageLoggingIdentifier().then((i)=>i.toString())
|
|
905
1124
|
}))
|
|
906
1125
|
], LibP2PService.prototype, "processValidBlockProposal", null);
|
|
907
1126
|
_ts_decorate([
|
|
908
1127
|
trackSpan('Libp2pService.broadcastAttestation', async (attestation)=>({
|
|
909
|
-
[Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber
|
|
1128
|
+
[Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber,
|
|
910
1129
|
[Attributes.BLOCK_ARCHIVE]: attestation.archive.toString(),
|
|
911
|
-
[Attributes.P2P_ID]: await attestation.
|
|
1130
|
+
[Attributes.P2P_ID]: await attestation.p2pMessageLoggingIdentifier().then((i)=>i.toString())
|
|
912
1131
|
}))
|
|
913
1132
|
], LibP2PService.prototype, "broadcastAttestation", null);
|
|
914
1133
|
_ts_decorate([
|
|
@@ -921,6 +1140,11 @@ _ts_decorate([
|
|
|
921
1140
|
[Attributes.TX_HASH]: requestedTxHash.toString()
|
|
922
1141
|
}))
|
|
923
1142
|
], LibP2PService.prototype, "validateRequestedTxs", null);
|
|
1143
|
+
_ts_decorate([
|
|
1144
|
+
trackSpan('Libp2pService.validateRequestedBlock', (requestedBlockNumber, _responseBlock)=>({
|
|
1145
|
+
[Attributes.BLOCK_NUMBER]: requestedBlockNumber.toString()
|
|
1146
|
+
}))
|
|
1147
|
+
], LibP2PService.prototype, "validateRequestedBlock", null);
|
|
924
1148
|
_ts_decorate([
|
|
925
1149
|
trackSpan('Libp2pService.validatePropagatedTx', (tx)=>({
|
|
926
1150
|
[Attributes.TX_HASH]: tx.getTxHash().toString()
|
|
@@ -928,9 +1152,9 @@ _ts_decorate([
|
|
|
928
1152
|
], LibP2PService.prototype, "validatePropagatedTx", null);
|
|
929
1153
|
_ts_decorate([
|
|
930
1154
|
trackSpan('Libp2pService.validateAttestation', async (_, attestation)=>({
|
|
931
|
-
[Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber
|
|
1155
|
+
[Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber,
|
|
932
1156
|
[Attributes.BLOCK_ARCHIVE]: attestation.archive.toString(),
|
|
933
|
-
[Attributes.P2P_ID]: await attestation.
|
|
1157
|
+
[Attributes.P2P_ID]: await attestation.p2pMessageLoggingIdentifier().then((i)=>i.toString())
|
|
934
1158
|
}))
|
|
935
1159
|
], LibP2PService.prototype, "validateAttestation", null);
|
|
936
1160
|
_ts_decorate([
|