@aztec/p2p 0.0.1-commit.b2a5d0dd1 → 0.0.1-commit.b3d3157a
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dest/bootstrap/bootstrap.d.ts +1 -1
- package/dest/bootstrap/bootstrap.d.ts.map +1 -1
- package/dest/bootstrap/bootstrap.js +9 -1
- package/dest/client/factory.d.ts +3 -3
- package/dest/client/factory.d.ts.map +1 -1
- package/dest/client/factory.js +12 -9
- package/dest/client/interface.d.ts +6 -4
- package/dest/client/interface.d.ts.map +1 -1
- package/dest/client/p2p_client.d.ts +11 -8
- package/dest/client/p2p_client.d.ts.map +1 -1
- package/dest/client/p2p_client.js +53 -17
- package/dest/config.d.ts +43 -17
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +48 -8
- package/dest/errors/reqresp.error.d.ts +1 -20
- package/dest/errors/reqresp.error.d.ts.map +1 -1
- package/dest/errors/reqresp.error.js +0 -21
- package/dest/mem_pools/attestation_pool/attestation_pool.d.ts +93 -55
- package/dest/mem_pools/attestation_pool/attestation_pool.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/attestation_pool.js +258 -195
- package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.d.ts +1 -1
- package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.js +175 -59
- package/dest/mem_pools/attestation_pool/mocks.d.ts +1 -1
- package/dest/mem_pools/attestation_pool/mocks.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/mocks.js +6 -4
- package/dest/mem_pools/instrumentation.d.ts +1 -1
- package/dest/mem_pools/instrumentation.d.ts.map +1 -1
- package/dest/mem_pools/instrumentation.js +17 -1
- package/dest/mem_pools/tx_pool_v2/archive/tx_archive.d.ts +1 -5
- package/dest/mem_pools/tx_pool_v2/archive/tx_archive.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/archive/tx_archive.js +1 -7
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts +1 -1
- 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 +73 -83
- package/dest/msg_validators/attestation_validator/attestation_validator.d.ts +5 -2
- package/dest/msg_validators/attestation_validator/attestation_validator.d.ts.map +1 -1
- package/dest/msg_validators/attestation_validator/attestation_validator.js +18 -2
- package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts +5 -3
- package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts.map +1 -1
- package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.js +3 -4
- package/dest/msg_validators/clock_tolerance.d.ts +1 -1
- package/dest/msg_validators/clock_tolerance.d.ts.map +1 -1
- package/dest/msg_validators/clock_tolerance.js +13 -11
- package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts +5 -2
- package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts.map +1 -1
- package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts +5 -2
- package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts.map +1 -1
- package/dest/msg_validators/proposal_validator/proposal_validator.d.ts +8 -2
- package/dest/msg_validators/proposal_validator/proposal_validator.d.ts.map +1 -1
- package/dest/msg_validators/proposal_validator/proposal_validator.js +28 -2
- 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/aggregate_tx_validator.js +8 -15
- package/dest/msg_validators/tx_validator/allowed_public_setup.js +3 -3
- package/dest/msg_validators/tx_validator/cached_tx_validator.d.ts +15 -0
- package/dest/msg_validators/tx_validator/cached_tx_validator.d.ts.map +1 -0
- package/dest/msg_validators/tx_validator/cached_tx_validator.js +19 -0
- package/dest/msg_validators/tx_validator/data_validator.d.ts +2 -1
- package/dest/msg_validators/tx_validator/data_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/data_validator.js +1 -0
- package/dest/msg_validators/tx_validator/factory.d.ts +5 -4
- package/dest/msg_validators/tx_validator/factory.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/factory.js +11 -7
- package/dest/msg_validators/tx_validator/index.d.ts +3 -1
- package/dest/msg_validators/tx_validator/index.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/index.js +2 -0
- package/dest/msg_validators/tx_validator/tx_proof_validator.d.ts +2 -1
- package/dest/msg_validators/tx_validator/tx_proof_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/tx_proof_validator.js +2 -0
- package/dest/msg_validators/tx_validator/tx_validation_cache.d.ts +48 -0
- package/dest/msg_validators/tx_validator/tx_validation_cache.d.ts.map +1 -0
- package/dest/msg_validators/tx_validator/tx_validation_cache.js +68 -0
- package/dest/services/discv5/discV5_service.d.ts +2 -1
- package/dest/services/discv5/discV5_service.d.ts.map +1 -1
- package/dest/services/discv5/discV5_service.js +35 -8
- package/dest/services/dummy_service.d.ts +10 -17
- package/dest/services/dummy_service.d.ts.map +1 -1
- package/dest/services/dummy_service.js +9 -18
- package/dest/services/libp2p/libp2p_service.d.ts +19 -21
- package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
- package/dest/services/libp2p/libp2p_service.js +147 -148
- package/dest/services/peer-manager/peer_manager.d.ts +1 -1
- package/dest/services/peer-manager/peer_manager.d.ts.map +1 -1
- package/dest/services/peer-manager/peer_manager.js +1 -0
- package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts +1 -8
- package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts.map +1 -1
- package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.js +35 -44
- package/dest/services/reqresp/batch-tx-requester/interface.d.ts +8 -5
- package/dest/services/reqresp/batch-tx-requester/interface.d.ts.map +1 -1
- package/dest/services/reqresp/batch-tx-requester/tx_validator.d.ts +5 -14
- package/dest/services/reqresp/batch-tx-requester/tx_validator.d.ts.map +1 -1
- package/dest/services/reqresp/batch-tx-requester/tx_validator.js +6 -20
- package/dest/services/reqresp/interface.d.ts +3 -10
- package/dest/services/reqresp/interface.d.ts.map +1 -1
- package/dest/services/reqresp/interface.js +0 -9
- package/dest/services/reqresp/protocols/block_txs/bitvector.d.ts +4 -3
- package/dest/services/reqresp/protocols/block_txs/bitvector.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/block_txs/bitvector.js +3 -2
- package/dest/services/reqresp/protocols/block_txs/block_txs_handler.d.ts +1 -1
- package/dest/services/reqresp/protocols/block_txs/block_txs_handler.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/block_txs/block_txs_handler.js +31 -28
- package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.d.ts +12 -7
- package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.js +42 -24
- package/dest/services/reqresp/reqresp.d.ts +5 -29
- package/dest/services/reqresp/reqresp.d.ts.map +1 -1
- package/dest/services/reqresp/reqresp.js +16 -206
- package/dest/services/service.d.ts +7 -13
- package/dest/services/service.d.ts.map +1 -1
- package/dest/services/tx_collection/config.d.ts +2 -23
- package/dest/services/tx_collection/config.d.ts.map +1 -1
- package/dest/services/tx_collection/config.js +2 -55
- package/dest/services/tx_collection/file_store_tx_collection.d.ts +12 -28
- package/dest/services/tx_collection/file_store_tx_collection.d.ts.map +1 -1
- package/dest/services/tx_collection/file_store_tx_collection.js +43 -83
- package/dest/services/tx_collection/index.d.ts +2 -3
- package/dest/services/tx_collection/index.d.ts.map +1 -1
- package/dest/services/tx_collection/index.js +0 -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/instrumentation.js +0 -2
- package/dest/services/tx_collection/tx_collection.d.ts +35 -51
- package/dest/services/tx_collection/tx_collection.d.ts.map +1 -1
- package/dest/services/tx_collection/tx_collection.js +275 -119
- package/dest/services/tx_collection/tx_collection_sink.d.ts +1 -1
- package/dest/services/tx_collection/tx_collection_sink.js +2 -2
- package/dest/services/tx_file_store/tx_file_store.d.ts +1 -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 +4 -14
- package/dest/services/tx_provider.d.ts +3 -1
- package/dest/services/tx_provider.d.ts.map +1 -1
- package/dest/services/tx_provider.js +3 -0
- package/dest/test-helpers/make-test-p2p-clients.d.ts +1 -1
- package/dest/test-helpers/make-test-p2p-clients.d.ts.map +1 -1
- package/dest/test-helpers/make-test-p2p-clients.js +1 -1
- package/dest/test-helpers/mock-pubsub.d.ts +13 -7
- package/dest/test-helpers/mock-pubsub.d.ts.map +1 -1
- package/dest/test-helpers/mock-pubsub.js +12 -37
- package/dest/test-helpers/reqresp-nodes.d.ts +4 -5
- package/dest/test-helpers/reqresp-nodes.d.ts.map +1 -1
- package/dest/test-helpers/reqresp-nodes.js +11 -15
- package/dest/test-helpers/test_tx_provider.d.ts +3 -1
- package/dest/test-helpers/test_tx_provider.d.ts.map +1 -1
- package/dest/test-helpers/test_tx_provider.js +3 -0
- package/dest/test-helpers/testbench-utils.d.ts +12 -14
- package/dest/test-helpers/testbench-utils.d.ts.map +1 -1
- package/dest/test-helpers/testbench-utils.js +19 -14
- package/dest/testbench/p2p_client_testbench_worker.d.ts +3 -5
- package/dest/testbench/p2p_client_testbench_worker.d.ts.map +1 -1
- package/dest/testbench/p2p_client_testbench_worker.js +13 -24
- package/dest/testbench/worker_client_manager.d.ts +3 -6
- package/dest/testbench/worker_client_manager.d.ts.map +1 -1
- package/dest/testbench/worker_client_manager.js +2 -8
- package/dest/util.d.ts +11 -6
- package/dest/util.d.ts.map +1 -1
- package/dest/util.js +35 -14
- package/dest/versioning.d.ts +3 -6
- package/dest/versioning.d.ts.map +1 -1
- package/dest/versioning.js +3 -24
- package/package.json +15 -14
- package/src/bootstrap/bootstrap.ts +9 -1
- package/src/client/factory.ts +20 -5
- package/src/client/interface.ts +6 -10
- package/src/client/p2p_client.ts +61 -36
- package/src/client/test/{tx_proposal_collector/README.md → p2p_client.batch_tx_requester.bench.README.md} +23 -53
- package/src/config.ts +94 -6
- package/src/errors/reqresp.error.ts +0 -25
- package/src/mem_pools/attestation_pool/attestation_pool.ts +309 -238
- package/src/mem_pools/attestation_pool/attestation_pool_test_suite.ts +198 -62
- package/src/mem_pools/attestation_pool/mocks.ts +13 -8
- package/src/mem_pools/instrumentation.ts +5 -1
- package/src/mem_pools/tx_pool_v2/archive/tx_archive.ts +1 -9
- package/src/mem_pools/tx_pool_v2/tx_pool_v2_impl.ts +73 -90
- package/src/msg_validators/attestation_validator/attestation_validator.ts +21 -1
- package/src/msg_validators/attestation_validator/fisherman_attestation_validator.ts +11 -7
- package/src/msg_validators/clock_tolerance.ts +13 -12
- package/src/msg_validators/proposal_validator/block_proposal_validator.ts +9 -2
- package/src/msg_validators/proposal_validator/checkpoint_proposal_validator.ts +14 -2
- package/src/msg_validators/proposal_validator/proposal_validator.ts +39 -2
- package/src/msg_validators/tx_validator/aggregate_tx_validator.ts +3 -12
- package/src/msg_validators/tx_validator/allowed_public_setup.ts +3 -3
- package/src/msg_validators/tx_validator/cached_tx_validator.ts +31 -0
- package/src/msg_validators/tx_validator/data_validator.ts +2 -0
- package/src/msg_validators/tx_validator/factory.ts +15 -6
- package/src/msg_validators/tx_validator/index.ts +2 -0
- package/src/msg_validators/tx_validator/tx_proof_validator.ts +2 -0
- package/src/msg_validators/tx_validator/tx_validation_cache.ts +101 -0
- package/src/services/discv5/discV5_service.ts +38 -5
- package/src/services/dummy_service.ts +12 -43
- package/src/services/libp2p/libp2p_service.ts +169 -167
- package/src/services/peer-manager/peer_manager.ts +1 -0
- package/src/services/reqresp/README.md +0 -14
- package/src/services/reqresp/batch-tx-requester/batch_tx_requester.ts +39 -52
- package/src/services/reqresp/batch-tx-requester/interface.ts +11 -4
- package/src/services/reqresp/batch-tx-requester/tx_validator.ts +12 -25
- package/src/services/reqresp/interface.ts +2 -38
- package/src/services/reqresp/protocols/block_txs/bitvector.ts +3 -2
- package/src/services/reqresp/protocols/block_txs/block_txs_handler.ts +34 -30
- package/src/services/reqresp/protocols/block_txs/block_txs_reqresp.ts +47 -20
- package/src/services/reqresp/reqresp.ts +11 -251
- package/src/services/service.ts +9 -30
- package/src/services/tx_collection/config.ts +3 -80
- package/src/services/tx_collection/file_store_tx_collection.ts +54 -103
- package/src/services/tx_collection/index.ts +1 -6
- package/src/services/tx_collection/instrumentation.ts +1 -7
- package/src/services/tx_collection/tx_collection.ts +330 -173
- package/src/services/tx_collection/tx_collection_sink.ts +2 -2
- package/src/services/tx_file_store/tx_file_store.ts +5 -17
- package/src/services/tx_provider.ts +5 -0
- package/src/test-helpers/make-test-p2p-clients.ts +1 -0
- package/src/test-helpers/mock-pubsub.ts +17 -60
- package/src/test-helpers/reqresp-nodes.ts +8 -20
- package/src/test-helpers/test_tx_provider.ts +5 -0
- package/src/test-helpers/testbench-utils.ts +23 -27
- package/src/testbench/p2p_client_testbench_worker.ts +16 -42
- package/src/testbench/worker_client_manager.ts +4 -19
- package/src/util.ts +32 -17
- package/src/versioning.ts +3 -33
- package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.d.ts +0 -2
- package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.d.ts.map +0 -1
- package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.js +0 -318
- package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker_protocol.d.ts +0 -73
- package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker_protocol.d.ts.map +0 -1
- package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker_protocol.js +0 -8
- package/dest/services/reqresp/connection-sampler/batch_connection_sampler.d.ts +0 -64
- package/dest/services/reqresp/connection-sampler/batch_connection_sampler.d.ts.map +0 -1
- package/dest/services/reqresp/connection-sampler/batch_connection_sampler.js +0 -151
- package/dest/services/tx_collection/fast_tx_collection.d.ts +0 -51
- package/dest/services/tx_collection/fast_tx_collection.d.ts.map +0 -1
- package/dest/services/tx_collection/fast_tx_collection.js +0 -311
- package/dest/services/tx_collection/proposal_tx_collector.d.ts +0 -48
- package/dest/services/tx_collection/proposal_tx_collector.d.ts.map +0 -1
- package/dest/services/tx_collection/proposal_tx_collector.js +0 -50
- package/dest/services/tx_collection/slow_tx_collection.d.ts +0 -57
- package/dest/services/tx_collection/slow_tx_collection.d.ts.map +0 -1
- package/dest/services/tx_collection/slow_tx_collection.js +0 -211
- package/src/client/test/tx_proposal_collector/proposal_tx_collector_worker.ts +0 -357
- package/src/client/test/tx_proposal_collector/proposal_tx_collector_worker_protocol.ts +0 -43
- package/src/services/reqresp/connection-sampler/batch_connection_sampler.ts +0 -161
- package/src/services/tx_collection/fast_tx_collection.ts +0 -361
- package/src/services/tx_collection/proposal_tx_collector.ts +0 -108
- package/src/services/tx_collection/slow_tx_collection.ts +0 -266
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { EpochCacheInterface } from '@aztec/epoch-cache';
|
|
2
2
|
import { BlockNumber, type SlotNumber } from '@aztec/foundation/branded-types';
|
|
3
|
-
import { maxBy } from '@aztec/foundation/collection';
|
|
3
|
+
import { maxBy, merge } from '@aztec/foundation/collection';
|
|
4
4
|
import { type Logger, createLibp2pComponentLogger, createLogger } from '@aztec/foundation/log';
|
|
5
5
|
import { RunningPromise } from '@aztec/foundation/running-promise';
|
|
6
6
|
import { Timer } from '@aztec/foundation/timer';
|
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
metricsTopicStrToLabels,
|
|
26
26
|
} from '@aztec/stdlib/p2p';
|
|
27
27
|
import { MerkleTreeId } from '@aztec/stdlib/trees';
|
|
28
|
-
import { Tx, type
|
|
28
|
+
import { Tx, type TxValidationResult } from '@aztec/stdlib/tx';
|
|
29
29
|
import type { UInt64 } from '@aztec/stdlib/types';
|
|
30
30
|
import { compressComponentVersions } from '@aztec/stdlib/versioning';
|
|
31
31
|
import {
|
|
@@ -50,9 +50,10 @@ import { yamux } from '@chainsafe/libp2p-yamux';
|
|
|
50
50
|
import { bootstrap } from '@libp2p/bootstrap';
|
|
51
51
|
import { identify } from '@libp2p/identify';
|
|
52
52
|
import { type Message, type MultiaddrConnection, type PeerId, TopicValidatorResult } from '@libp2p/interface';
|
|
53
|
-
import type { ConnectionManager } from '@libp2p/interface-internal';
|
|
53
|
+
import type { AddressManager, ConnectionManager } from '@libp2p/interface-internal';
|
|
54
54
|
import { mplex } from '@libp2p/mplex';
|
|
55
55
|
import { tcp } from '@libp2p/tcp';
|
|
56
|
+
import { multiaddr } from '@multiformats/multiaddr';
|
|
56
57
|
import { ENR } from '@nethermindeth/enr';
|
|
57
58
|
import { createLibp2p } from 'libp2p';
|
|
58
59
|
|
|
@@ -73,8 +74,8 @@ import {
|
|
|
73
74
|
createFirstStageTxValidationsForGossipedTransactions,
|
|
74
75
|
createSecondStageTxValidationsForGossipedTransactions,
|
|
75
76
|
createTxValidatorForBlockProposalReceivedTxs,
|
|
76
|
-
createTxValidatorForReqResponseReceivedTxs,
|
|
77
77
|
} from '../../msg_validators/tx_validator/factory.js';
|
|
78
|
+
import { TxValidationCache } from '../../msg_validators/tx_validator/tx_validation_cache.js';
|
|
78
79
|
import { GossipSubEvent } from '../../types/index.js';
|
|
79
80
|
import { type PubSubLibp2p, convertToMultiaddr } from '../../util.js';
|
|
80
81
|
import { getVersions } from '../../versioning.js';
|
|
@@ -92,15 +93,12 @@ import {
|
|
|
92
93
|
AuthRequest,
|
|
93
94
|
BlockTxsRequest,
|
|
94
95
|
BlockTxsResponse,
|
|
95
|
-
DEFAULT_SUB_PROTOCOL_VALIDATORS,
|
|
96
96
|
type ReqRespInterface,
|
|
97
97
|
type ReqRespResponse,
|
|
98
98
|
ReqRespSubProtocol,
|
|
99
99
|
type ReqRespSubProtocolHandler,
|
|
100
100
|
type ReqRespSubProtocolHandlers,
|
|
101
|
-
type ReqRespSubProtocolValidators,
|
|
102
101
|
StatusMessage,
|
|
103
|
-
type SubProtocolMap,
|
|
104
102
|
ValidationError,
|
|
105
103
|
pingHandler,
|
|
106
104
|
reqGoodbyeHandler,
|
|
@@ -111,6 +109,7 @@ import {
|
|
|
111
109
|
import { ReqResp } from '../reqresp/reqresp.js';
|
|
112
110
|
import type {
|
|
113
111
|
P2PBlockReceivedCallback,
|
|
112
|
+
P2PCheckpointAttestationCallback,
|
|
114
113
|
P2PCheckpointReceivedCallback,
|
|
115
114
|
P2PDuplicateAttestationCallback,
|
|
116
115
|
P2PService,
|
|
@@ -156,6 +155,9 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
156
155
|
/** Callback invoked when a duplicate attestation is detected (triggers slashing). */
|
|
157
156
|
private duplicateAttestationCallback?: P2PDuplicateAttestationCallback;
|
|
158
157
|
|
|
158
|
+
/** Callback invoked when a valid checkpoint attestation is accepted into the pool. */
|
|
159
|
+
private checkpointAttestationCallback?: P2PCheckpointAttestationCallback;
|
|
160
|
+
|
|
159
161
|
/**
|
|
160
162
|
* Callback for when a block is received from a peer.
|
|
161
163
|
* @param block - The block received from the peer.
|
|
@@ -178,6 +180,9 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
178
180
|
|
|
179
181
|
private gossipSubEventHandler: (e: CustomEvent<GossipsubMessage>) => void;
|
|
180
182
|
|
|
183
|
+
private ipChangedHandler?: (ip: string) => void;
|
|
184
|
+
private discoveredP2pIp?: string;
|
|
185
|
+
|
|
181
186
|
private instrumentation: P2PInstrumentation;
|
|
182
187
|
|
|
183
188
|
private telemetry: TelemetryClient;
|
|
@@ -198,6 +203,7 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
198
203
|
private blockMinFeesProvider: BlockMinFeesProvider,
|
|
199
204
|
telemetry: TelemetryClient,
|
|
200
205
|
logger: Logger = createLogger('p2p:libp2p_service'),
|
|
206
|
+
private txValidationCache?: TxValidationCache,
|
|
201
207
|
) {
|
|
202
208
|
super(telemetry, 'LibP2PService');
|
|
203
209
|
this.telemetry = telemetry;
|
|
@@ -231,15 +237,24 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
231
237
|
const proposalValidatorOpts = {
|
|
232
238
|
txsPermitted: !config.disableTransactions,
|
|
233
239
|
maxTxsPerBlock: config.validateMaxTxsPerBlock ?? config.validateMaxTxsPerCheckpoint,
|
|
240
|
+
maxBlocksPerCheckpoint: config.maxBlocksPerCheckpoint,
|
|
234
241
|
p2pPropagationTime,
|
|
242
|
+
skipSlotValidation: config.skipProposalSlotValidation,
|
|
243
|
+
signatureContext: {
|
|
244
|
+
chainId: config.l1ChainId,
|
|
245
|
+
rollupAddress: config.rollupAddress,
|
|
246
|
+
},
|
|
235
247
|
};
|
|
236
248
|
this.blockProposalValidator = new BlockProposalValidator(epochCache, proposalValidatorOpts);
|
|
237
249
|
this.checkpointProposalValidator = new CheckpointProposalValidator(epochCache, proposalValidatorOpts);
|
|
250
|
+
const attestationValidatorOpts = {
|
|
251
|
+
l1PublishingTime: config.l1PublishingTime,
|
|
252
|
+
p2pPropagationTime,
|
|
253
|
+
signatureContext: proposalValidatorOpts.signatureContext,
|
|
254
|
+
};
|
|
238
255
|
this.checkpointAttestationValidator = config.fishermanMode
|
|
239
|
-
? new FishermanAttestationValidator(epochCache, mempools.attestationPool, telemetry,
|
|
240
|
-
|
|
241
|
-
})
|
|
242
|
-
: new CheckpointAttestationValidator(epochCache, { l1PublishingTime: config.l1PublishingTime });
|
|
256
|
+
? new FishermanAttestationValidator(epochCache, mempools.attestationPool, telemetry, attestationValidatorOpts)
|
|
257
|
+
: new CheckpointAttestationValidator(epochCache, attestationValidatorOpts);
|
|
243
258
|
|
|
244
259
|
this.gossipSubEventHandler = this.handleGossipSubEvent.bind(this);
|
|
245
260
|
|
|
@@ -264,8 +279,9 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
264
279
|
};
|
|
265
280
|
}
|
|
266
281
|
|
|
267
|
-
public updateConfig(config: Partial<P2PReqRespConfig
|
|
282
|
+
public updateConfig(config: Partial<P2PReqRespConfig & Pick<P2PConfig, 'skipIncomingProposals'>>) {
|
|
268
283
|
this.reqresp.updateConfig(config);
|
|
284
|
+
this.config = merge(this.config, config);
|
|
269
285
|
}
|
|
270
286
|
|
|
271
287
|
/**
|
|
@@ -288,6 +304,7 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
288
304
|
telemetry: TelemetryClient;
|
|
289
305
|
logger: Logger;
|
|
290
306
|
packageVersion: string;
|
|
307
|
+
txValidationCache?: TxValidationCache;
|
|
291
308
|
},
|
|
292
309
|
) {
|
|
293
310
|
const {
|
|
@@ -301,6 +318,7 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
301
318
|
telemetry,
|
|
302
319
|
logger,
|
|
303
320
|
packageVersion,
|
|
321
|
+
txValidationCache,
|
|
304
322
|
} = deps;
|
|
305
323
|
const { p2pPort, maxPeerCount, listenAddress } = config;
|
|
306
324
|
const bindAddrTcp = convertToMultiaddr(listenAddress, p2pPort, 'tcp');
|
|
@@ -458,8 +476,9 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
458
476
|
topics: topicScoreParams,
|
|
459
477
|
}),
|
|
460
478
|
}) as (components: GossipSubComponents) => GossipSub,
|
|
461
|
-
components: (components: { connectionManager: ConnectionManager }) => ({
|
|
479
|
+
components: (components: { connectionManager: ConnectionManager; addressManager: AddressManager }) => ({
|
|
462
480
|
connectionManager: components.connectionManager,
|
|
481
|
+
addressManager: components.addressManager,
|
|
463
482
|
}),
|
|
464
483
|
},
|
|
465
484
|
logger: createLibp2pComponentLogger(logger.module, logger.getBindings()),
|
|
@@ -507,6 +526,7 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
507
526
|
blockMinFeesProvider,
|
|
508
527
|
telemetry,
|
|
509
528
|
logger,
|
|
529
|
+
txValidationCache,
|
|
510
530
|
);
|
|
511
531
|
}
|
|
512
532
|
|
|
@@ -520,12 +540,11 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
520
540
|
throw new Error('P2P service already started');
|
|
521
541
|
}
|
|
522
542
|
|
|
523
|
-
// Get listen & announce addresses for logging
|
|
524
543
|
const { p2pIp, p2pPort } = this.config;
|
|
525
|
-
if (!p2pIp) {
|
|
526
|
-
throw new Error('Announce address not provided.');
|
|
544
|
+
if (!p2pIp && !this.config.queryForIp) {
|
|
545
|
+
throw new Error('Announce address not provided and queryForIp is not enabled.');
|
|
527
546
|
}
|
|
528
|
-
const announceTcpMultiaddr = convertToMultiaddr(p2pIp, p2pPort, 'tcp');
|
|
547
|
+
const announceTcpMultiaddr = p2pIp ? convertToMultiaddr(p2pIp, p2pPort, 'tcp') : undefined;
|
|
529
548
|
|
|
530
549
|
// Create request response protocol handlers
|
|
531
550
|
const txHandler = reqRespTxHandler(this.mempools);
|
|
@@ -551,16 +570,9 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
551
570
|
requestResponseHandlers[ReqRespSubProtocol.TX] = txHandler.bind(this);
|
|
552
571
|
}
|
|
553
572
|
|
|
554
|
-
// Define the sub protocol validators - This is done within this start() method to gain a callback to the existing validateTx function
|
|
555
|
-
const reqrespSubProtocolValidators = {
|
|
556
|
-
...DEFAULT_SUB_PROTOCOL_VALIDATORS,
|
|
557
|
-
[ReqRespSubProtocol.TX]: this.validateRequestedTxs.bind(this),
|
|
558
|
-
[ReqRespSubProtocol.BLOCK_TXS]: this.validateRequestedBlockTxs.bind(this),
|
|
559
|
-
};
|
|
560
|
-
|
|
561
573
|
await this.peerManager.initializePeers();
|
|
562
574
|
|
|
563
|
-
await this.reqresp.start(requestResponseHandlers
|
|
575
|
+
await this.reqresp.start(requestResponseHandlers);
|
|
564
576
|
|
|
565
577
|
await this.node.start();
|
|
566
578
|
|
|
@@ -576,6 +588,38 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
576
588
|
if (!this.config.p2pDiscoveryDisabled) {
|
|
577
589
|
await this.peerDiscoveryService.start();
|
|
578
590
|
}
|
|
591
|
+
|
|
592
|
+
// Bridge discv5 IP changes to libp2p's AddressManager so peers see the updated address
|
|
593
|
+
if (this.config.queryForIp) {
|
|
594
|
+
this.discoveredP2pIp = this.config.p2pIp;
|
|
595
|
+
this.logger.info('IP change tracking enabled, bridging discv5 IP updates to libp2p AddressManager');
|
|
596
|
+
this.ipChangedHandler = (ip: string) => {
|
|
597
|
+
const addressManager = this.node.services.components.addressManager;
|
|
598
|
+
const newAddr = multiaddr(convertToMultiaddr(ip, this.config.p2pPort, 'tcp'));
|
|
599
|
+
const previousIp = this.discoveredP2pIp;
|
|
600
|
+
|
|
601
|
+
if (previousIp) {
|
|
602
|
+
const oldAddr = multiaddr(convertToMultiaddr(previousIp, this.config.p2pPort, 'tcp'));
|
|
603
|
+
addressManager.removeObservedAddr(oldAddr);
|
|
604
|
+
this.logger.info('Libp2p announce address updated due to IP change', {
|
|
605
|
+
previousIp,
|
|
606
|
+
newIp: ip,
|
|
607
|
+
newMultiaddr: newAddr.toString(),
|
|
608
|
+
});
|
|
609
|
+
} else {
|
|
610
|
+
this.logger.info('Libp2p announce address set from initial discv5 IP discovery', {
|
|
611
|
+
ip,
|
|
612
|
+
multiaddr: newAddr.toString(),
|
|
613
|
+
});
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
addressManager.addObservedAddr(newAddr);
|
|
617
|
+
addressManager.confirmObservedAddr(newAddr);
|
|
618
|
+
this.discoveredP2pIp = ip;
|
|
619
|
+
};
|
|
620
|
+
this.peerDiscoveryService.on('ip:changed', this.ipChangedHandler);
|
|
621
|
+
}
|
|
622
|
+
|
|
579
623
|
this.discoveryRunningPromise = new RunningPromise(
|
|
580
624
|
async () => {
|
|
581
625
|
await this.peerManager.heartbeat();
|
|
@@ -601,6 +645,11 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
601
645
|
// Remove gossip sub listener
|
|
602
646
|
this.node.services.pubsub.removeEventListener(GossipSubEvent.MESSAGE, this.gossipSubEventHandler);
|
|
603
647
|
|
|
648
|
+
if (this.ipChangedHandler) {
|
|
649
|
+
this.peerDiscoveryService.removeListener('ip:changed', this.ipChangedHandler);
|
|
650
|
+
this.ipChangedHandler = undefined;
|
|
651
|
+
}
|
|
652
|
+
|
|
604
653
|
// Stop peer manager
|
|
605
654
|
this.logger.debug('Stopping peer manager...');
|
|
606
655
|
await this.peerManager.stop();
|
|
@@ -615,12 +664,8 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
615
664
|
this.logger.info('LibP2P service stopped');
|
|
616
665
|
}
|
|
617
666
|
|
|
618
|
-
addReqRespSubProtocol(
|
|
619
|
-
subProtocol
|
|
620
|
-
handler: ReqRespSubProtocolHandler,
|
|
621
|
-
validator?: ReqRespSubProtocolValidators[ReqRespSubProtocol],
|
|
622
|
-
): Promise<void> {
|
|
623
|
-
return this.reqresp.addSubProtocol(subProtocol, handler, validator);
|
|
667
|
+
addReqRespSubProtocol(subProtocol: ReqRespSubProtocol, handler: ReqRespSubProtocolHandler): Promise<void> {
|
|
668
|
+
return this.reqresp.addSubProtocol(subProtocol, handler);
|
|
624
669
|
}
|
|
625
670
|
|
|
626
671
|
public registerThisValidatorAddresses(address: EthAddress[]): void {
|
|
@@ -648,20 +693,6 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
648
693
|
setImmediate(() => void safeJob());
|
|
649
694
|
}
|
|
650
695
|
|
|
651
|
-
/**
|
|
652
|
-
* Send a batch of requests to peers, and return the responses
|
|
653
|
-
* @param protocol - The request response protocol to use
|
|
654
|
-
* @param requests - The requests to send to the peers
|
|
655
|
-
* @returns The responses to the requests
|
|
656
|
-
*/
|
|
657
|
-
sendBatchRequest<SubProtocol extends ReqRespSubProtocol>(
|
|
658
|
-
protocol: SubProtocol,
|
|
659
|
-
requests: InstanceType<SubProtocolMap[SubProtocol]['request']>[],
|
|
660
|
-
pinnedPeerId: PeerId | undefined,
|
|
661
|
-
): Promise<InstanceType<SubProtocolMap[SubProtocol]['response']>[]> {
|
|
662
|
-
return this.reqresp.sendBatchRequest(protocol, requests, pinnedPeerId);
|
|
663
|
-
}
|
|
664
|
-
|
|
665
696
|
public sendRequestToPeer(
|
|
666
697
|
peerId: PeerId,
|
|
667
698
|
subProtocol: ReqRespSubProtocol,
|
|
@@ -691,10 +722,6 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
691
722
|
this.allNodesCheckpointReceivedCallback = callback;
|
|
692
723
|
}
|
|
693
724
|
|
|
694
|
-
public async notifyOwnCheckpointProposal(checkpoint: CheckpointProposalCore): Promise<void> {
|
|
695
|
-
await this.allNodesCheckpointReceivedCallback(checkpoint, this.node.peerId);
|
|
696
|
-
}
|
|
697
|
-
|
|
698
725
|
/**
|
|
699
726
|
* Registers a callback to be invoked when a duplicate proposal is detected.
|
|
700
727
|
* This callback is triggered on the first duplicate (when count goes from 1 to 2).
|
|
@@ -714,6 +741,10 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
714
741
|
this.duplicateAttestationCallback = callback;
|
|
715
742
|
}
|
|
716
743
|
|
|
744
|
+
public registerCheckpointAttestationCallback(callback: P2PCheckpointAttestationCallback): void {
|
|
745
|
+
this.checkpointAttestationCallback = callback;
|
|
746
|
+
}
|
|
747
|
+
|
|
717
748
|
/**
|
|
718
749
|
* Subscribes to a topic.
|
|
719
750
|
* @param topic - The topic to subscribe to.
|
|
@@ -842,6 +873,15 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
842
873
|
|
|
843
874
|
// Process the message, optionally within a linked span for trace propagation
|
|
844
875
|
const processMessage = async () => {
|
|
876
|
+
if (
|
|
877
|
+
this.config.skipIncomingProposals &&
|
|
878
|
+
(msg.topic === this.topicStrings[TopicType.block_proposal] ||
|
|
879
|
+
msg.topic === this.topicStrings[TopicType.checkpoint_proposal])
|
|
880
|
+
) {
|
|
881
|
+
this.logger.warn(`Ignoring incoming proposal (skipIncomingProposals is set)`, { topic: msg.topic });
|
|
882
|
+
this.node.services.pubsub.reportMessageValidationResult(msgId, source.toString(), TopicValidatorResult.Ignore);
|
|
883
|
+
return;
|
|
884
|
+
}
|
|
845
885
|
if (msg.topic === this.topicStrings[TopicType.tx]) {
|
|
846
886
|
await this.handleGossipedTx(p2pMessage.payload, msgId, source);
|
|
847
887
|
} else if (msg.topic === this.topicStrings[TopicType.checkpoint_attestation]) {
|
|
@@ -1165,6 +1205,7 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1165
1205
|
}
|
|
1166
1206
|
|
|
1167
1207
|
// Attestation was added successfully - accept it so other nodes can also detect the equivocation
|
|
1208
|
+
this.checkpointAttestationCallback?.(attestation);
|
|
1168
1209
|
return { result: TopicValidatorResult.Accept, obj: attestation };
|
|
1169
1210
|
}
|
|
1170
1211
|
|
|
@@ -1301,17 +1342,33 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1301
1342
|
TopicType.checkpoint_proposal,
|
|
1302
1343
|
);
|
|
1303
1344
|
|
|
1345
|
+
// Process checkpoint proposal if valid and not equivocated.
|
|
1346
|
+
const processCheckpointFn = () =>
|
|
1347
|
+
result === TopicValidatorResult.Accept && checkpoint && !isEquivocated
|
|
1348
|
+
? this.processValidCheckpointProposal(checkpoint.toCore(), source)
|
|
1349
|
+
: Promise.resolve();
|
|
1350
|
+
|
|
1304
1351
|
// If the checkpoint contained a valid last block, we process it even if the checkpoint itself is to be rejected
|
|
1305
1352
|
// TODO(palla/mbps): Is this ok? Should we be considering a block from a checkpoint that was equivocated?
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1353
|
+
const processBlockFn = () =>
|
|
1354
|
+
processBlock && checkpoint && checkpoint.getBlockProposal()
|
|
1355
|
+
? this.processValidBlockProposal(checkpoint.getBlockProposal()!, source)
|
|
1356
|
+
: Promise.resolve();
|
|
1357
|
+
|
|
1358
|
+
// A node that skips checkpoint validation attests without re-executing the embedded last block, so run
|
|
1359
|
+
// the checkpoint callback first: this creates and broadcasts the attestation before the block is
|
|
1360
|
+
// processed. Otherwise the block's re-execution — which can stall until the re-execution deadline
|
|
1361
|
+
// waiting for a parent that may never arrive — would delay the attestation past the slot's attestation
|
|
1362
|
+
// window, after which peers reject it as stale.
|
|
1363
|
+
if (this.config.skipCheckpointProposalValidation) {
|
|
1364
|
+
await processCheckpointFn();
|
|
1365
|
+
await processBlockFn();
|
|
1311
1366
|
return;
|
|
1312
1367
|
}
|
|
1313
1368
|
|
|
1314
|
-
|
|
1369
|
+
// Process the block first, since it's required for the checkpoint proposal validation.
|
|
1370
|
+
await processBlockFn();
|
|
1371
|
+
await processCheckpointFn();
|
|
1315
1372
|
}
|
|
1316
1373
|
|
|
1317
1374
|
/**
|
|
@@ -1467,82 +1524,87 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1467
1524
|
}
|
|
1468
1525
|
|
|
1469
1526
|
/**
|
|
1470
|
-
* Validate the requested block transactions
|
|
1527
|
+
* Validate the requested block transactions request-response consistency.
|
|
1528
|
+
* It does NOT validate the transactions themselves.
|
|
1471
1529
|
* @param request - The block transactions request.
|
|
1472
1530
|
* @param response - The block transactions response.
|
|
1473
1531
|
* @param peerId - The ID of the peer that made the request.
|
|
1474
|
-
* @returns True if the
|
|
1532
|
+
* @returns True if the request-response is consistent, false otherwise.
|
|
1475
1533
|
*/
|
|
1476
|
-
@trackSpan('Libp2pService.
|
|
1534
|
+
@trackSpan('Libp2pService.validateRequestedBlockTxsConsistency', request => ({
|
|
1477
1535
|
[Attributes.BLOCK_ARCHIVE]: request.archiveRoot.toString(),
|
|
1478
1536
|
}))
|
|
1479
|
-
protected async
|
|
1537
|
+
protected async validateRequestedBlockTxsConsistency(
|
|
1480
1538
|
request: BlockTxsRequest,
|
|
1481
1539
|
response: BlockTxsResponse,
|
|
1482
1540
|
peerId: PeerId,
|
|
1483
1541
|
): Promise<boolean> {
|
|
1484
|
-
const requestedTxValidator = this.createRequestedTxValidator();
|
|
1485
|
-
|
|
1486
1542
|
try {
|
|
1487
|
-
|
|
1543
|
+
// Check for duplicates txs (or hashes) in the response.
|
|
1544
|
+
const returnedHashes = response.txs.map(tx => tx.getTxHash().toString());
|
|
1545
|
+
const uniqueReturned = new Set(returnedHashes.map(h => h.toString()));
|
|
1546
|
+
if (uniqueReturned.size !== returnedHashes.length) {
|
|
1488
1547
|
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
1489
|
-
throw new ValidationError(
|
|
1490
|
-
|
|
1548
|
+
throw new ValidationError(`Received duplicate txs in block txs response`);
|
|
1549
|
+
}
|
|
1550
|
+
|
|
1551
|
+
// We get the block tx hashes from the proposal or the archiver.
|
|
1552
|
+
const proposal = await this.mempools.attestationPool.getBlockProposalByArchive(request.archiveRoot.toString());
|
|
1553
|
+
const blockTxHashes =
|
|
1554
|
+
proposal?.txHashes ??
|
|
1555
|
+
(await this.archiver.getBlock({ archive: request.archiveRoot }))?.body.txEffects.map(e => e.txHash);
|
|
1556
|
+
|
|
1557
|
+
// If we don't have the block, we can't verify membership/order of the returned txs.
|
|
1558
|
+
if (!blockTxHashes) {
|
|
1559
|
+
// This shouldn't happen, since we asked for the block (proposal).
|
|
1560
|
+
// Neither a local proposal nor an archived block: we cannot verify membership/order of the
|
|
1561
|
+
// returned txs. This is a local-state gap, not a peer fault, so we do not penalize.
|
|
1562
|
+
this.logger.warn(
|
|
1563
|
+
`Block ${request.archiveRoot.toString()} not found in attestation pool or archiver; cannot validate membership/order of returned txs`,
|
|
1491
1564
|
);
|
|
1565
|
+
// NOTE: We mark the response as invalid, given the limitations of a true/false return value.
|
|
1566
|
+
return false;
|
|
1492
1567
|
}
|
|
1493
1568
|
|
|
1494
|
-
|
|
1495
|
-
|
|
1569
|
+
// Verify that the returned tx hashes are a subset of (tx hashes by index) U (explicitly requested tx hashes).
|
|
1570
|
+
const uniqueRequestedHashes = new Set([
|
|
1571
|
+
// tx hashes requested by index.
|
|
1572
|
+
...request.txIndices.getTrueIndices().map(i => blockTxHashes[i].toString()),
|
|
1573
|
+
// explicitly requested tx hashes.
|
|
1574
|
+
...request.txHashes.map(h => h.toString()),
|
|
1575
|
+
]);
|
|
1576
|
+
if (!returnedHashes.every(h => uniqueRequestedHashes.has(h))) {
|
|
1577
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
|
|
1496
1578
|
throw new ValidationError(
|
|
1497
|
-
|
|
1579
|
+
'Returned txs should be a subset of (tx hashes by index) U (explicitly requested tx hashes)',
|
|
1498
1580
|
);
|
|
1499
1581
|
}
|
|
1500
1582
|
|
|
1501
|
-
//
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
const returnedHashes = await Promise.all(response.txs.map(tx => tx.getTxHash().toString()));
|
|
1507
|
-
const uniqueReturned = new Set(returnedHashes.map(h => h.toString()));
|
|
1508
|
-
if (uniqueReturned.size !== returnedHashes.length) {
|
|
1509
|
-
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
1510
|
-
throw new ValidationError(`Received duplicate txs in block txs response`);
|
|
1583
|
+
// Tx indices information is optional, but if present, we need to verify a few things.
|
|
1584
|
+
if (!response.peerHasBlock()) {
|
|
1585
|
+
this.logger.debug(`Peer ${peerId.toString()} signalled missing block`);
|
|
1586
|
+
return true;
|
|
1511
1587
|
}
|
|
1512
|
-
|
|
1588
|
+
|
|
1589
|
+
// If the response has a non-empty bitvector, it needs to be consistent with the number of txs in the block.
|
|
1590
|
+
if (response.txIndices.getLength() !== blockTxHashes.length) {
|
|
1513
1591
|
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
1514
1592
|
throw new ValidationError(
|
|
1515
|
-
`Received
|
|
1593
|
+
`Received block txs with mismatched bitvector length: expected ${blockTxHashes.length}, got ${response.txIndices.getLength()}`,
|
|
1516
1594
|
);
|
|
1517
1595
|
}
|
|
1518
1596
|
|
|
1519
|
-
//
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
);
|
|
1529
|
-
const allowedIndexSet = new Set(intersectIdx);
|
|
1530
|
-
const indices = returnedHashes.map(h => hashToIndexInProposal.get(h));
|
|
1531
|
-
const allAllowed = indices.every(idx => idx !== undefined && allowedIndexSet.has(idx));
|
|
1532
|
-
const strictlyIncreasing = indices.every((idx, i) => (i === 0 ? idx !== undefined : idx! > indices[i - 1]!));
|
|
1533
|
-
if (!allAllowed || !strictlyIncreasing) {
|
|
1534
|
-
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
|
|
1535
|
-
throw new ValidationError('Returned txs do not match expected subset/order for requested indices');
|
|
1536
|
-
}
|
|
1537
|
-
} else {
|
|
1538
|
-
// No local proposal, cannot check the membership/order of the returned txs
|
|
1539
|
-
this.logger.warn(
|
|
1540
|
-
`Block proposal not found for archive root ${request.archiveRoot.toString()}; cannot validate membership/order of returned txs`,
|
|
1541
|
-
);
|
|
1542
|
-
return false;
|
|
1597
|
+
// For every index we requested that the peer claims to have (per its bitvector), the
|
|
1598
|
+
// corresponding tx must be present in the response. A peer advertising availability but
|
|
1599
|
+
// withholding the tx is inconsistent.
|
|
1600
|
+
const returnedHashSet = new Set(returnedHashes);
|
|
1601
|
+
const expectedIndices = request.txIndices.getTrueIndices().filter(i => response.txIndices.isSet(i));
|
|
1602
|
+
const missingExpected = expectedIndices.some(i => !returnedHashSet.has(blockTxHashes[i].toString()));
|
|
1603
|
+
if (missingExpected) {
|
|
1604
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
|
|
1605
|
+
throw new ValidationError('Peer advertised requested txs via indices but did not return them');
|
|
1543
1606
|
}
|
|
1544
1607
|
|
|
1545
|
-
await Promise.all(response.txs.map(tx => this.validateRequestedTx(tx, peerId, requestedTxValidator)));
|
|
1546
1608
|
return true;
|
|
1547
1609
|
} catch (e: any) {
|
|
1548
1610
|
if (e instanceof ValidationError) {
|
|
@@ -1555,69 +1617,6 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1555
1617
|
}
|
|
1556
1618
|
}
|
|
1557
1619
|
|
|
1558
|
-
/**
|
|
1559
|
-
* Validate a collection of txs that has been requested from a peer.
|
|
1560
|
-
*
|
|
1561
|
-
* The core component of this validator is that each tx hash MUST match the requested tx hash,
|
|
1562
|
-
* In order to perform this check, the tx proof must be verified.
|
|
1563
|
-
*
|
|
1564
|
-
* Note: This function is called from within `ReqResp.sendRequest` as part of the
|
|
1565
|
-
* ReqRespSubProtocol.TX subprotocol validation.
|
|
1566
|
-
*
|
|
1567
|
-
* @param requestedTxHash - The collection of the txs that was requested.
|
|
1568
|
-
* @param responseTx - The collection of txs that was received as a response to the request.
|
|
1569
|
-
* @param peerId - The peer ID of the peer that sent the tx.
|
|
1570
|
-
* @returns True if the whole collection of txs is valid, false otherwise.
|
|
1571
|
-
*/
|
|
1572
|
-
@trackSpan('Libp2pService.validateRequestedTx', (requestedTxHash, _responseTx) => ({
|
|
1573
|
-
[Attributes.TX_HASH]: requestedTxHash.toString(),
|
|
1574
|
-
}))
|
|
1575
|
-
private async validateRequestedTxs(requestedTxHash: TxHash[], responseTx: Tx[], peerId: PeerId): Promise<boolean> {
|
|
1576
|
-
const requested = new Set(requestedTxHash.map(h => h.toString()));
|
|
1577
|
-
const requestedTxValidator = this.createRequestedTxValidator();
|
|
1578
|
-
|
|
1579
|
-
//TODO: (mralj) - this is somewhat naive implementation, if single tx is invalid we consider the whole response invalid.
|
|
1580
|
-
// I think we should still extract the valid txs and return them, so that we can still use the response.
|
|
1581
|
-
try {
|
|
1582
|
-
await Promise.all(responseTx.map(tx => this.validateRequestedTx(tx, peerId, requestedTxValidator, requested)));
|
|
1583
|
-
return true;
|
|
1584
|
-
} catch (e: any) {
|
|
1585
|
-
if (e instanceof ValidationError) {
|
|
1586
|
-
this.logger.warn(`Failed to validate requested txs from peer ${peerId.toString()}, reason ${e.message}`);
|
|
1587
|
-
} else {
|
|
1588
|
-
this.logger.error(`Error during validation of requested txs`, e);
|
|
1589
|
-
}
|
|
1590
|
-
|
|
1591
|
-
return false;
|
|
1592
|
-
}
|
|
1593
|
-
}
|
|
1594
|
-
|
|
1595
|
-
protected async validateRequestedTx(
|
|
1596
|
-
tx: Tx,
|
|
1597
|
-
peerId: PeerId,
|
|
1598
|
-
txValidator: TxValidator,
|
|
1599
|
-
requested?: Set<`0x${string}`>,
|
|
1600
|
-
) {
|
|
1601
|
-
const penalize = (severity: PeerErrorSeverity) => this.peerManager.penalizePeer(peerId, severity);
|
|
1602
|
-
if (requested && !requested.has(tx.getTxHash().toString())) {
|
|
1603
|
-
penalize(PeerErrorSeverity.MidToleranceError);
|
|
1604
|
-
throw new ValidationError(`Received tx with hash ${tx.getTxHash().toString()} that was not requested.`);
|
|
1605
|
-
}
|
|
1606
|
-
|
|
1607
|
-
const { result } = await txValidator.validateTx(tx);
|
|
1608
|
-
if (result === 'invalid') {
|
|
1609
|
-
penalize(PeerErrorSeverity.LowToleranceError);
|
|
1610
|
-
throw new ValidationError(`Received tx with hash ${tx.getTxHash().toString()} that is invalid.`);
|
|
1611
|
-
}
|
|
1612
|
-
}
|
|
1613
|
-
|
|
1614
|
-
protected createRequestedTxValidator(): TxValidator {
|
|
1615
|
-
return createTxValidatorForReqResponseReceivedTxs(this.proofVerifier, {
|
|
1616
|
-
l1ChainId: this.config.l1ChainId,
|
|
1617
|
-
rollupVersion: this.config.rollupVersion,
|
|
1618
|
-
});
|
|
1619
|
-
}
|
|
1620
|
-
|
|
1621
1620
|
private getGasFees(): Promise<GasFees> {
|
|
1622
1621
|
return this.blockMinFeesProvider.getCurrentMinFees();
|
|
1623
1622
|
}
|
|
@@ -1633,8 +1632,10 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1633
1632
|
l1ChainId: this.config.l1ChainId,
|
|
1634
1633
|
rollupVersion: this.config.rollupVersion,
|
|
1635
1634
|
proofVerifier: this.proofVerifier,
|
|
1635
|
+
txValidationCache: this.txValidationCache,
|
|
1636
1636
|
},
|
|
1637
1637
|
peerScoring: this.peerManager,
|
|
1638
|
+
validateRequestedBlockTxsConsistency: this.validateRequestedBlockTxsConsistency.bind(this),
|
|
1638
1639
|
};
|
|
1639
1640
|
}
|
|
1640
1641
|
|
|
@@ -1643,6 +1644,7 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1643
1644
|
this.proofVerifier,
|
|
1644
1645
|
{ l1ChainId: this.config.l1ChainId, rollupVersion: this.config.rollupVersion },
|
|
1645
1646
|
this.logger.getBindings(),
|
|
1647
|
+
this.txValidationCache,
|
|
1646
1648
|
);
|
|
1647
1649
|
|
|
1648
1650
|
const results = await Promise.all(
|
|
@@ -527,6 +527,7 @@ export class PeerManager implements PeerManagerInterface {
|
|
|
527
527
|
protectedConnections: protectedPeerCount,
|
|
528
528
|
maxPeerCount: this.config.maxPeerCount,
|
|
529
529
|
cachedPeers: this.cachedPeers.size,
|
|
530
|
+
discv5KadPeers: this.peerDiscoveryService.getKadValues().length,
|
|
530
531
|
...this.peerScoring.getStats(),
|
|
531
532
|
});
|
|
532
533
|
|
|
@@ -46,7 +46,6 @@ Per-protocol size limits checked via preamble before decompression.
|
|
|
46
46
|
| Error Type | Severity |
|
|
47
47
|
|------------|----------|
|
|
48
48
|
| GOODBYE subprotocol errors | None |
|
|
49
|
-
| `CollectiveReqRespTimeoutError` / `InvalidResponseError` | None |
|
|
50
49
|
| `AbortError` / connection close / muxer closed | None |
|
|
51
50
|
| `ECONNRESET` / `EPIPE` / `ECONNREFUSED` / `ERR_UNEXPECTED_EOF` | HighToleranceError |
|
|
52
51
|
| `ERR_UNSUPPORTED_PROTOCOL` | HighToleranceError |
|
|
@@ -183,19 +182,6 @@ Protected peers (private/trusted/preferred) are always considered "authenticated
|
|
|
183
182
|
|
|
184
183
|
Conditional registration: BLOCK_TXS handler only registered when `config.disableTransactions` is false. Otherwise peers get `ERR_UNSUPPORTED_PROTOCOL`.
|
|
185
184
|
|
|
186
|
-
**Requester side via `sendBatchRequest`** (Snappy limit: `max(N, 1) * 512 + 1` KB):
|
|
187
|
-
|
|
188
|
-
| Rule | Consequence | File |
|
|
189
|
-
|------|-------------|------|
|
|
190
|
-
| Archive root must match request | MidToleranceError | `libp2p_service.ts` (`validateRequestedBlockTxs`) |
|
|
191
|
-
| BitVector length must match request | MidToleranceError | same |
|
|
192
|
-
| No duplicate tx hashes | MidToleranceError | same |
|
|
193
|
-
| Tx count within bounds | MidToleranceError | same |
|
|
194
|
-
| Local block proposal must exist for archive root | Rejected (no penalty) | same |
|
|
195
|
-
| All tx hashes must be in proposal's tx list at allowed indices | LowToleranceError | same |
|
|
196
|
-
| Txs in strictly increasing index order | LowToleranceError | same |
|
|
197
|
-
| Each tx passes well-formedness (Metadata [4 fields], Size, Data, Proof) | LowToleranceError | same |
|
|
198
|
-
|
|
199
185
|
**Requester side via `BatchTxRequester`** (separate validation path):
|
|
200
186
|
|
|
201
187
|
| Rule | Consequence | File |
|