@aztec/p2p 0.86.0 → 0.87.0
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.map +1 -1
- package/dest/client/factory.d.ts +4 -1
- package/dest/client/factory.d.ts.map +1 -1
- package/dest/client/factory.js +16 -14
- package/dest/client/index.d.ts +1 -0
- package/dest/client/index.d.ts.map +1 -1
- package/dest/client/index.js +1 -0
- package/dest/client/interface.d.ts +155 -0
- package/dest/client/interface.d.ts.map +1 -0
- package/dest/client/interface.js +9 -0
- package/dest/client/p2p_client.d.ts +26 -164
- package/dest/client/p2p_client.d.ts.map +1 -1
- package/dest/client/p2p_client.js +185 -114
- package/dest/config.d.ts +5 -6
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +6 -11
- package/dest/enr/generate-enr.d.ts +9 -1
- package/dest/enr/generate-enr.d.ts.map +1 -1
- package/dest/enr/generate-enr.js +24 -2
- package/dest/index.d.ts +1 -0
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +1 -0
- package/dest/mem_pools/attestation_pool/attestation_pool.d.ts +2 -0
- package/dest/mem_pools/attestation_pool/attestation_pool.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.js +4 -4
- package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts +1 -0
- package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/kv_attestation_pool.js +8 -2
- package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts +1 -0
- package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/memory_attestation_pool.js +5 -2
- package/dest/mem_pools/attestation_pool/mocks.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/mocks.js +2 -2
- package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts +4 -0
- 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 +50 -14
- package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts +3 -0
- package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/memory_tx_pool.js +9 -0
- package/dest/mem_pools/tx_pool/tx_pool.d.ts +9 -0
- 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.map +1 -1
- package/dest/mem_pools/tx_pool/tx_pool_test_suite.js +13 -5
- package/dest/msg_validators/attestation_validator/attestation_validator.js +1 -1
- package/dest/msg_validators/block_proposal_validator/block_proposal_validator.js +1 -1
- package/dest/msg_validators/tx_validator/block_header_validator.js +1 -1
- package/dest/msg_validators/tx_validator/data_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/data_validator.js +15 -14
- package/dest/msg_validators/tx_validator/double_spend_validator.d.ts +0 -2
- package/dest/msg_validators/tx_validator/double_spend_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/double_spend_validator.js +2 -2
- package/dest/msg_validators/tx_validator/factory.d.ts +14 -0
- package/dest/msg_validators/tx_validator/factory.d.ts.map +1 -0
- package/dest/msg_validators/tx_validator/factory.js +62 -0
- package/dest/msg_validators/tx_validator/gas_validator.js +3 -3
- package/dest/msg_validators/tx_validator/metadata_validator.d.ts +8 -4
- package/dest/msg_validators/tx_validator/metadata_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/metadata_validator.js +35 -17
- package/dest/msg_validators/tx_validator/phases_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/phases_validator.js +1 -1
- package/dest/msg_validators/tx_validator/tx_proof_validator.js +1 -1
- package/dest/services/discv5/discV5_service.d.ts +2 -2
- package/dest/services/discv5/discV5_service.d.ts.map +1 -1
- package/dest/services/discv5/discV5_service.js +9 -13
- package/dest/services/dummy_service.d.ts +3 -3
- package/dest/services/dummy_service.d.ts.map +1 -1
- package/dest/services/dummy_service.js +6 -1
- package/dest/services/encoding.d.ts +1 -3
- package/dest/services/encoding.d.ts.map +1 -1
- package/dest/services/libp2p/libp2p_service.d.ts +4 -2
- package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
- package/dest/services/libp2p/libp2p_service.js +94 -88
- package/dest/services/peer-manager/metrics.d.ts.map +1 -1
- 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 +11 -2
- package/dest/services/reqresp/connection-sampler/batch_connection_sampler.d.ts.map +1 -1
- package/dest/services/reqresp/connection-sampler/connection_sampler.d.ts +2 -2
- package/dest/services/reqresp/connection-sampler/connection_sampler.d.ts.map +1 -1
- package/dest/services/reqresp/connection-sampler/connection_sampler.js +41 -21
- package/dest/services/reqresp/interface.d.ts +1 -3
- package/dest/services/reqresp/interface.d.ts.map +1 -1
- package/dest/services/reqresp/metrics.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/goodbye.d.ts +0 -2
- package/dest/services/reqresp/protocols/goodbye.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/goodbye.js +1 -1
- package/dest/services/reqresp/protocols/ping.d.ts +0 -2
- package/dest/services/reqresp/protocols/ping.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/status.d.ts +0 -2
- package/dest/services/reqresp/protocols/status.d.ts.map +1 -1
- package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts.map +1 -1
- package/dest/services/reqresp/reqresp.d.ts +1 -3
- package/dest/services/reqresp/reqresp.d.ts.map +1 -1
- package/dest/services/reqresp/reqresp.js +13 -10
- package/dest/services/service.d.ts +4 -3
- package/dest/services/service.d.ts.map +1 -1
- package/dest/test-helpers/get-ports.d.ts.map +1 -1
- package/dest/test-helpers/make-test-p2p-clients.d.ts.map +1 -1
- package/dest/test-helpers/make-test-p2p-clients.js +2 -2
- package/dest/test-helpers/reqresp-nodes.d.ts.map +1 -1
- package/dest/test-helpers/reqresp-nodes.js +1 -1
- package/dest/testbench/p2p_client_testbench_worker.js +11 -6
- package/dest/testbench/testbench.js +1 -1
- package/dest/testbench/worker_client_manager.d.ts +0 -1
- package/dest/testbench/worker_client_manager.d.ts.map +1 -1
- package/dest/testbench/worker_client_manager.js +2 -2
- package/dest/types/index.d.ts +1 -0
- package/dest/types/index.d.ts.map +1 -1
- package/dest/types/index.js +1 -0
- package/dest/versioning.d.ts +2 -2
- package/dest/versioning.d.ts.map +1 -1
- package/dest/versioning.js +6 -1
- package/package.json +15 -15
- package/src/bootstrap/bootstrap.ts +1 -1
- package/src/client/factory.ts +38 -33
- package/src/client/index.ts +1 -0
- package/src/client/interface.ts +186 -0
- package/src/client/p2p_client.ts +226 -287
- package/src/config.ts +11 -18
- package/src/enr/generate-enr.ts +35 -3
- package/src/index.ts +1 -0
- package/src/mem_pools/attestation_pool/attestation_pool.ts +3 -0
- package/src/mem_pools/attestation_pool/attestation_pool_test_suite.ts +4 -4
- package/src/mem_pools/attestation_pool/kv_attestation_pool.ts +11 -4
- package/src/mem_pools/attestation_pool/memory_attestation_pool.ts +10 -3
- package/src/mem_pools/attestation_pool/mocks.ts +2 -2
- package/src/mem_pools/tx_pool/aztec_kv_tx_pool.ts +79 -34
- package/src/mem_pools/tx_pool/memory_tx_pool.ts +16 -1
- package/src/mem_pools/tx_pool/tx_pool.ts +12 -0
- package/src/mem_pools/tx_pool/tx_pool_test_suite.ts +9 -3
- package/src/msg_validators/attestation_validator/attestation_validator.ts +1 -1
- package/src/msg_validators/block_proposal_validator/block_proposal_validator.ts +1 -1
- package/src/msg_validators/tx_validator/block_header_validator.ts +1 -1
- package/src/msg_validators/tx_validator/data_validator.ts +24 -18
- package/src/msg_validators/tx_validator/double_spend_validator.ts +2 -2
- package/src/msg_validators/tx_validator/factory.ts +94 -0
- package/src/msg_validators/tx_validator/gas_validator.ts +3 -3
- package/src/msg_validators/tx_validator/metadata_validator.ts +50 -14
- package/src/msg_validators/tx_validator/phases_validator.ts +6 -2
- package/src/msg_validators/tx_validator/tx_proof_validator.ts +1 -1
- package/src/services/discv5/discV5_service.ts +14 -12
- package/src/services/dummy_service.ts +8 -2
- package/src/services/libp2p/libp2p_service.ts +102 -111
- package/src/services/peer-manager/metrics.ts +4 -1
- package/src/services/peer-manager/peer_manager.ts +18 -1
- package/src/services/reqresp/connection-sampler/batch_connection_sampler.ts +5 -1
- package/src/services/reqresp/connection-sampler/connection_sampler.ts +42 -19
- package/src/services/reqresp/metrics.ts +4 -1
- package/src/services/reqresp/protocols/goodbye.ts +1 -1
- package/src/services/reqresp/rate-limiter/rate_limiter.ts +4 -1
- package/src/services/reqresp/reqresp.ts +12 -12
- package/src/services/service.ts +7 -1
- package/src/test-helpers/make-test-p2p-clients.ts +2 -1
- package/src/test-helpers/reqresp-nodes.ts +1 -1
- package/src/testbench/p2p_client_testbench_worker.ts +10 -4
- package/src/testbench/testbench.ts +1 -1
- package/src/testbench/worker_client_manager.ts +2 -2
- package/src/types/index.ts +1 -0
- package/src/versioning.ts +8 -1
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import type { EpochCacheInterface } from '@aztec/epoch-cache';
|
|
2
|
-
import { Fr } from '@aztec/foundation/fields';
|
|
3
2
|
import { createLibp2pComponentLogger, createLogger } from '@aztec/foundation/log';
|
|
4
3
|
import { SerialQueue } from '@aztec/foundation/queue';
|
|
5
4
|
import { RunningPromise } from '@aztec/foundation/running-promise';
|
|
6
5
|
import type { AztecAsyncKVStore } from '@aztec/kv-store';
|
|
7
|
-
import {
|
|
6
|
+
import { protocolContractTreeRoot } from '@aztec/protocol-contracts';
|
|
8
7
|
import type { L2BlockSource } from '@aztec/stdlib/block';
|
|
9
8
|
import type { ContractDataSource } from '@aztec/stdlib/contract';
|
|
10
9
|
import { GasFees } from '@aztec/stdlib/gas';
|
|
@@ -14,13 +13,14 @@ import {
|
|
|
14
13
|
BlockProposal,
|
|
15
14
|
type Gossipable,
|
|
16
15
|
P2PClientType,
|
|
16
|
+
P2PMessage,
|
|
17
17
|
PeerErrorSeverity,
|
|
18
18
|
TopicType,
|
|
19
19
|
createTopicString,
|
|
20
20
|
getTopicTypeForClientType,
|
|
21
21
|
metricsTopicStrToLabels,
|
|
22
22
|
} from '@aztec/stdlib/p2p';
|
|
23
|
-
import {
|
|
23
|
+
import { MerkleTreeId } from '@aztec/stdlib/trees';
|
|
24
24
|
import { Tx, type TxHash, type TxValidationResult } from '@aztec/stdlib/tx';
|
|
25
25
|
import { compressComponentVersions } from '@aztec/stdlib/versioning';
|
|
26
26
|
import { Attributes, OtelMetricsAdapter, type TelemetryClient, WithTracer, trackSpan } from '@aztec/telemetry-client';
|
|
@@ -49,14 +49,8 @@ import type { P2PConfig } from '../../config.js';
|
|
|
49
49
|
import type { MemPools } from '../../mem_pools/interface.js';
|
|
50
50
|
import { AttestationValidator, BlockProposalValidator } from '../../msg_validators/index.js';
|
|
51
51
|
import { getDefaultAllowedSetupFunctions } from '../../msg_validators/tx_validator/allowed_public_setup.js';
|
|
52
|
-
import {
|
|
53
|
-
|
|
54
|
-
DoubleSpendTxValidator,
|
|
55
|
-
GasTxValidator,
|
|
56
|
-
MetadataTxValidator,
|
|
57
|
-
PhasesTxValidator,
|
|
58
|
-
TxProofValidator,
|
|
59
|
-
} from '../../msg_validators/tx_validator/index.js';
|
|
52
|
+
import { type MessageValidator, createTxMessageValidators } from '../../msg_validators/tx_validator/factory.js';
|
|
53
|
+
import { DoubleSpendTxValidator, TxProofValidator } from '../../msg_validators/tx_validator/index.js';
|
|
60
54
|
import { GossipSubEvent } from '../../types/index.js';
|
|
61
55
|
import { type PubSubLibp2p, convertToMultiaddr } from '../../util.js';
|
|
62
56
|
import { getVersions } from '../../versioning.js';
|
|
@@ -71,13 +65,6 @@ import { pingHandler, reqRespBlockHandler, reqRespTxHandler, statusHandler } fro
|
|
|
71
65
|
import { ReqResp } from '../reqresp/reqresp.js';
|
|
72
66
|
import type { P2PService, PeerDiscoveryService } from '../service.js';
|
|
73
67
|
|
|
74
|
-
interface MessageValidator {
|
|
75
|
-
validator: {
|
|
76
|
-
validateTx(tx: Tx): Promise<TxValidationResult>;
|
|
77
|
-
};
|
|
78
|
-
severity: PeerErrorSeverity;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
68
|
interface ValidationResult {
|
|
82
69
|
name: string;
|
|
83
70
|
isValid: TxValidationResult;
|
|
@@ -233,7 +220,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
233
220
|
tcp({
|
|
234
221
|
maxConnections: config.maxPeerCount,
|
|
235
222
|
// socket option: the maximum length of the queue of pending connections
|
|
236
|
-
// https://nodejs.org/dist/latest-
|
|
223
|
+
// https://nodejs.org/dist/latest-v22.x/docs/api/net.html#serverlisten
|
|
237
224
|
// it's not safe if we increase this number
|
|
238
225
|
backlog: 5,
|
|
239
226
|
closeServerOnMaxConnections: {
|
|
@@ -270,6 +257,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
270
257
|
heartbeatInterval: config.gossipsubInterval,
|
|
271
258
|
mcacheLength: config.gossipsubMcacheLength,
|
|
272
259
|
mcacheGossip: config.gossipsubMcacheGossip,
|
|
260
|
+
seenTTL: config.gossipsubSeenTTL,
|
|
273
261
|
msgIdFn: getMsgIdFn,
|
|
274
262
|
msgIdToStrFn: msgIdToStrFn,
|
|
275
263
|
fastMsgIdFn: fastMsgIdFn,
|
|
@@ -489,14 +477,19 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
489
477
|
/**
|
|
490
478
|
* Publishes data to a topic.
|
|
491
479
|
* @param topic - The topic to publish to.
|
|
492
|
-
* @param data - The
|
|
480
|
+
* @param data - The message to publish.
|
|
493
481
|
* @returns The number of recipients the data was sent to.
|
|
494
482
|
*/
|
|
495
|
-
private async publishToTopic(topic: string,
|
|
483
|
+
private async publishToTopic(topic: string, message: Gossipable) {
|
|
496
484
|
if (!this.node.services.pubsub) {
|
|
497
485
|
throw new Error('Pubsub service not available.');
|
|
498
486
|
}
|
|
499
|
-
const
|
|
487
|
+
const p2pMessage = await P2PMessage.fromGossipable(message);
|
|
488
|
+
this.logger.debug(`Publishing message`, {
|
|
489
|
+
topic,
|
|
490
|
+
messageId: p2pMessage.id,
|
|
491
|
+
});
|
|
492
|
+
const result = await this.node.services.pubsub.publish(topic, p2pMessage.toMessageData());
|
|
500
493
|
|
|
501
494
|
return result.recipients.length;
|
|
502
495
|
}
|
|
@@ -507,14 +500,22 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
507
500
|
* @param data - The message data
|
|
508
501
|
*/
|
|
509
502
|
protected async handleNewGossipMessage(msg: Message, msgId: string, source: PeerId) {
|
|
503
|
+
const p2pMessage = P2PMessage.fromMessageData(Buffer.from(msg.data));
|
|
504
|
+
const currentTime = new Date();
|
|
505
|
+
const messageLatency = currentTime.getTime() - p2pMessage.publishTime.getTime();
|
|
506
|
+
this.logger.debug(`Received message`, {
|
|
507
|
+
topic: msg.topic,
|
|
508
|
+
messageId: p2pMessage.id,
|
|
509
|
+
messageLatency,
|
|
510
|
+
});
|
|
510
511
|
if (msg.topic === this.topicStrings[TopicType.tx]) {
|
|
511
|
-
await this.handleGossipedTx(
|
|
512
|
+
await this.handleGossipedTx(p2pMessage.payload, msgId, source);
|
|
512
513
|
}
|
|
513
514
|
if (msg.topic === this.topicStrings[TopicType.block_attestation] && this.clientType === P2PClientType.Full) {
|
|
514
|
-
await this.processAttestationFromPeer(
|
|
515
|
+
await this.processAttestationFromPeer(p2pMessage.payload, msgId, source);
|
|
515
516
|
}
|
|
516
517
|
if (msg.topic === this.topicStrings[TopicType.block_proposal]) {
|
|
517
|
-
await this.processBlockFromPeer(
|
|
518
|
+
await this.processBlockFromPeer(p2pMessage.payload, msgId, source);
|
|
518
519
|
}
|
|
519
520
|
|
|
520
521
|
return;
|
|
@@ -540,9 +541,9 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
540
541
|
return resultAndObj;
|
|
541
542
|
}
|
|
542
543
|
|
|
543
|
-
protected async handleGossipedTx(
|
|
544
|
+
protected async handleGossipedTx(payloadData: Buffer, msgId: string, source: PeerId) {
|
|
544
545
|
const validationFunc = async () => {
|
|
545
|
-
const tx = Tx.fromBuffer(
|
|
546
|
+
const tx = Tx.fromBuffer(payloadData);
|
|
546
547
|
const result = await this.validatePropagatedTx(tx, source);
|
|
547
548
|
return { result, obj: tx };
|
|
548
549
|
};
|
|
@@ -563,12 +564,12 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
563
564
|
*
|
|
564
565
|
* @param attestation - The attestation to process.
|
|
565
566
|
*/
|
|
566
|
-
private async processAttestationFromPeer(
|
|
567
|
+
private async processAttestationFromPeer(payloadData: Buffer, msgId: string, source: PeerId): Promise<void> {
|
|
567
568
|
const validationFunc = async () => {
|
|
568
|
-
const attestation = BlockAttestation.fromBuffer(
|
|
569
|
+
const attestation = BlockAttestation.fromBuffer(payloadData);
|
|
569
570
|
const result = await this.validateAttestation(source, attestation);
|
|
570
571
|
this.logger.trace(`validatePropagatedAttestation: ${result}`, {
|
|
571
|
-
[Attributes.SLOT_NUMBER]: attestation.payload.header.
|
|
572
|
+
[Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber.toString(),
|
|
572
573
|
[Attributes.P2P_ID]: source.toString(),
|
|
573
574
|
});
|
|
574
575
|
return { result, obj: attestation };
|
|
@@ -594,12 +595,12 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
594
595
|
await this.mempools.attestationPool!.addAttestations([attestation]);
|
|
595
596
|
}
|
|
596
597
|
|
|
597
|
-
private async processBlockFromPeer(
|
|
598
|
+
private async processBlockFromPeer(payloadData: Buffer, msgId: string, source: PeerId): Promise<void> {
|
|
598
599
|
const validationFunc = async () => {
|
|
599
|
-
const block = BlockProposal.fromBuffer(
|
|
600
|
+
const block = BlockProposal.fromBuffer(payloadData);
|
|
600
601
|
const result = await this.validateBlockProposal(source, block);
|
|
601
602
|
this.logger.trace(`validatePropagatedBlock: ${result}`, {
|
|
602
|
-
[Attributes.SLOT_NUMBER]: block.payload.header.
|
|
603
|
+
[Attributes.SLOT_NUMBER]: block.payload.header.slotNumber.toString(),
|
|
603
604
|
[Attributes.P2P_ID]: source.toString(),
|
|
604
605
|
});
|
|
605
606
|
return { result, obj: block };
|
|
@@ -629,6 +630,8 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
629
630
|
block: block.blockNumber.toNumber(),
|
|
630
631
|
},
|
|
631
632
|
);
|
|
633
|
+
// Mark the txs in this proposal as non-evictable
|
|
634
|
+
await this.mempools.txPool.markTxsAsNonEvictable(block.payload.txHashes);
|
|
632
635
|
const attestation = await this.blockReceivedCallback(block);
|
|
633
636
|
|
|
634
637
|
// TODO: fix up this pattern - the abstraction is not nice
|
|
@@ -652,8 +655,8 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
652
655
|
* @param attestation - The attestation to broadcast.
|
|
653
656
|
*/
|
|
654
657
|
@trackSpan('Libp2pService.broadcastAttestation', async attestation => ({
|
|
655
|
-
[Attributes.BLOCK_NUMBER]: attestation.
|
|
656
|
-
[Attributes.SLOT_NUMBER]: attestation.payload.header.
|
|
658
|
+
[Attributes.BLOCK_NUMBER]: attestation.blockNumber.toNumber(),
|
|
659
|
+
[Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber.toNumber(),
|
|
657
660
|
[Attributes.BLOCK_ARCHIVE]: attestation.archive.toString(),
|
|
658
661
|
[Attributes.P2P_ID]: await attestation.p2pMessageIdentifier().then(i => i.toString()),
|
|
659
662
|
}))
|
|
@@ -720,21 +723,25 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
720
723
|
private async validatePropagatedTx(tx: Tx, peerId: PeerId): Promise<boolean> {
|
|
721
724
|
const blockNumber = (await this.archiver.getBlockNumber()) + 1;
|
|
722
725
|
const messageValidators = await this.createMessageValidators(blockNumber);
|
|
723
|
-
const outcome = await this.runValidations(tx, messageValidators);
|
|
724
726
|
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
}
|
|
728
|
-
const { name } = outcome.failure;
|
|
729
|
-
let { severity } = outcome.failure;
|
|
727
|
+
for (const validator of messageValidators) {
|
|
728
|
+
const outcome = await this.runValidations(tx, validator);
|
|
730
729
|
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
730
|
+
if (outcome.allPassed) {
|
|
731
|
+
continue;
|
|
732
|
+
}
|
|
733
|
+
const { name } = outcome.failure;
|
|
734
|
+
let { severity } = outcome.failure;
|
|
735
|
+
|
|
736
|
+
// Double spend validator has a special case handler
|
|
737
|
+
if (name === 'doubleSpendValidator') {
|
|
738
|
+
severity = await this.handleDoubleSpendFailure(tx, blockNumber);
|
|
739
|
+
}
|
|
735
740
|
|
|
736
|
-
|
|
737
|
-
|
|
741
|
+
this.peerManager.penalizePeer(peerId, severity);
|
|
742
|
+
return false;
|
|
743
|
+
}
|
|
744
|
+
return true;
|
|
738
745
|
}
|
|
739
746
|
|
|
740
747
|
private async getGasFees(blockNumber: number): Promise<GasFees> {
|
|
@@ -748,6 +755,22 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
748
755
|
return gasFees;
|
|
749
756
|
}
|
|
750
757
|
|
|
758
|
+
public async validate(txs: Tx[]): Promise<void> {
|
|
759
|
+
const blockNumber = (await this.archiver.getBlockNumber()) + 1;
|
|
760
|
+
const messageValidators = await this.createMessageValidators(blockNumber);
|
|
761
|
+
|
|
762
|
+
await Promise.all(
|
|
763
|
+
txs.map(async tx => {
|
|
764
|
+
for (const validator of messageValidators) {
|
|
765
|
+
const outcome = await this.runValidations(tx, validator);
|
|
766
|
+
if (!outcome.allPassed) {
|
|
767
|
+
throw new Error('Invalid tx detected', { cause: { outcome } });
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
}),
|
|
771
|
+
);
|
|
772
|
+
}
|
|
773
|
+
|
|
751
774
|
/**
|
|
752
775
|
* Create message validators for the given block number.
|
|
753
776
|
*
|
|
@@ -757,51 +780,21 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
757
780
|
* @param blockNumber - The block number to create validators for.
|
|
758
781
|
* @returns The message validators.
|
|
759
782
|
*/
|
|
760
|
-
private async createMessageValidators(blockNumber: number): Promise<Record<string, MessageValidator
|
|
761
|
-
const merkleTree = this.worldStateSynchronizer.getCommitted();
|
|
783
|
+
private async createMessageValidators(blockNumber: number): Promise<Record<string, MessageValidator>[]> {
|
|
762
784
|
const gasFees = await this.getGasFees(blockNumber - 1);
|
|
763
785
|
const allowedInSetup = this.config.txPublicSetupAllowList ?? (await getDefaultAllowedSetupFunctions());
|
|
764
786
|
|
|
765
|
-
return
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
severity: PeerErrorSeverity.HighToleranceError,
|
|
777
|
-
},
|
|
778
|
-
proofValidator: {
|
|
779
|
-
validator: new TxProofValidator(this.proofVerifier),
|
|
780
|
-
severity: PeerErrorSeverity.MidToleranceError,
|
|
781
|
-
},
|
|
782
|
-
doubleSpendValidator: {
|
|
783
|
-
validator: new DoubleSpendTxValidator({
|
|
784
|
-
nullifiersExist: async (nullifiers: Buffer[]) => {
|
|
785
|
-
const merkleTree = this.worldStateSynchronizer.getCommitted();
|
|
786
|
-
const indices = await merkleTree.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, nullifiers);
|
|
787
|
-
return indices.map(index => index !== undefined);
|
|
788
|
-
},
|
|
789
|
-
}),
|
|
790
|
-
severity: PeerErrorSeverity.HighToleranceError,
|
|
791
|
-
},
|
|
792
|
-
gasValidator: {
|
|
793
|
-
validator: new GasTxValidator(
|
|
794
|
-
new DatabasePublicStateSource(merkleTree),
|
|
795
|
-
ProtocolContractAddress.FeeJuice,
|
|
796
|
-
gasFees,
|
|
797
|
-
),
|
|
798
|
-
severity: PeerErrorSeverity.HighToleranceError,
|
|
799
|
-
},
|
|
800
|
-
phasesValidator: {
|
|
801
|
-
validator: new PhasesTxValidator(this.archiver, allowedInSetup, blockNumber),
|
|
802
|
-
severity: PeerErrorSeverity.MidToleranceError,
|
|
803
|
-
},
|
|
804
|
-
};
|
|
787
|
+
return createTxMessageValidators(
|
|
788
|
+
blockNumber,
|
|
789
|
+
this.worldStateSynchronizer,
|
|
790
|
+
gasFees,
|
|
791
|
+
this.config.l1ChainId,
|
|
792
|
+
this.config.rollupVersion,
|
|
793
|
+
protocolContractTreeRoot,
|
|
794
|
+
this.archiver,
|
|
795
|
+
this.proofVerifier,
|
|
796
|
+
allowedInSetup,
|
|
797
|
+
);
|
|
805
798
|
}
|
|
806
799
|
|
|
807
800
|
/**
|
|
@@ -820,24 +813,22 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
820
813
|
});
|
|
821
814
|
|
|
822
815
|
// A promise that resolves when all validations have been run
|
|
823
|
-
const allValidations = Promise.all(validationPromises);
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
// If all validations pass, allPassed will be true, if failed, then the failure will be the first validation to fail
|
|
840
|
-
return result;
|
|
816
|
+
const allValidations = await Promise.all(validationPromises);
|
|
817
|
+
const failed = allValidations.find(x => !x.isValid);
|
|
818
|
+
if (failed) {
|
|
819
|
+
return {
|
|
820
|
+
allPassed: false,
|
|
821
|
+
failure: {
|
|
822
|
+
isValid: { result: 'invalid' as const, reason: ['Failed validation'] },
|
|
823
|
+
name: failed.name,
|
|
824
|
+
severity: failed.severity,
|
|
825
|
+
},
|
|
826
|
+
};
|
|
827
|
+
} else {
|
|
828
|
+
return {
|
|
829
|
+
allPassed: true,
|
|
830
|
+
};
|
|
831
|
+
}
|
|
841
832
|
}
|
|
842
833
|
|
|
843
834
|
/**
|
|
@@ -881,8 +872,8 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
881
872
|
* @returns True if the attestation is valid, false otherwise.
|
|
882
873
|
*/
|
|
883
874
|
@trackSpan('Libp2pService.validateAttestation', async (_, attestation) => ({
|
|
884
|
-
[Attributes.BLOCK_NUMBER]: attestation.
|
|
885
|
-
[Attributes.SLOT_NUMBER]: attestation.payload.header.
|
|
875
|
+
[Attributes.BLOCK_NUMBER]: attestation.blockNumber.toNumber(),
|
|
876
|
+
[Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber.toNumber(),
|
|
886
877
|
[Attributes.BLOCK_ARCHIVE]: attestation.archive.toString(),
|
|
887
878
|
[Attributes.P2P_ID]: await attestation.p2pMessageIdentifier().then(i => i.toString()),
|
|
888
879
|
}))
|
|
@@ -903,7 +894,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
903
894
|
* @returns True if the block proposal is valid, false otherwise.
|
|
904
895
|
*/
|
|
905
896
|
@trackSpan('Libp2pService.validateBlockProposal', (_peerId, block) => ({
|
|
906
|
-
[Attributes.SLOT_NUMBER]: block.payload.header.
|
|
897
|
+
[Attributes.SLOT_NUMBER]: block.payload.header.slotNumber.toString(),
|
|
907
898
|
}))
|
|
908
899
|
public async validateBlockProposal(peerId: PeerId, block: BlockProposal): Promise<boolean> {
|
|
909
900
|
const severity = await this.blockProposalValidator.validate(block);
|
|
@@ -926,7 +917,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
926
917
|
const identifier = await message.p2pMessageIdentifier().then(i => i.toString());
|
|
927
918
|
this.logger.trace(`Sending message ${identifier}`, { p2pMessageIdentifier: identifier });
|
|
928
919
|
|
|
929
|
-
const recipientsNum = await this.publishToTopic(this.topicStrings[parent.p2pTopic], message
|
|
920
|
+
const recipientsNum = await this.publishToTopic(this.topicStrings[parent.p2pTopic], message);
|
|
930
921
|
this.logger.debug(`Sent message ${identifier} to ${recipientsNum} peers`, {
|
|
931
922
|
p2pMessageIdentifier: identifier,
|
|
932
923
|
sourcePeer: this.node.peerId.toString(),
|
|
@@ -18,7 +18,10 @@ export class PeerManagerMetrics {
|
|
|
18
18
|
|
|
19
19
|
public readonly tracer: Tracer;
|
|
20
20
|
|
|
21
|
-
constructor(
|
|
21
|
+
constructor(
|
|
22
|
+
public readonly telemetryClient: TelemetryClient = getTelemetryClient(),
|
|
23
|
+
name = 'PeerManager',
|
|
24
|
+
) {
|
|
22
25
|
this.tracer = telemetryClient.getTracer(name);
|
|
23
26
|
|
|
24
27
|
const meter = telemetryClient.getMeter(name);
|
|
@@ -14,6 +14,7 @@ import type { PubSubLibp2p } from '../../util.js';
|
|
|
14
14
|
import { ReqRespSubProtocol } from '../reqresp/interface.js';
|
|
15
15
|
import { GoodByeReason, prettyGoodbyeReason } from '../reqresp/protocols/goodbye.js';
|
|
16
16
|
import type { ReqResp } from '../reqresp/reqresp.js';
|
|
17
|
+
import { ReqRespStatus } from '../reqresp/status.js';
|
|
17
18
|
import type { PeerDiscoveryService } from '../service.js';
|
|
18
19
|
import { PeerManagerMetrics } from './metrics.js';
|
|
19
20
|
import { PeerScoreState, type PeerScoring } from './peer_scoring.js';
|
|
@@ -22,6 +23,7 @@ const MAX_DIAL_ATTEMPTS = 3;
|
|
|
22
23
|
const MAX_CACHED_PEERS = 100;
|
|
23
24
|
const MAX_CACHED_PEER_AGE_MS = 5 * 60 * 1000; // 5 minutes
|
|
24
25
|
const FAILED_PEER_BAN_TIME_MS = 5 * 60 * 1000; // 5 minutes timeout after failing MAX_DIAL_ATTEMPTS
|
|
26
|
+
const GOODBYE_DIAL_TIMEOUT_MS = 1000;
|
|
25
27
|
|
|
26
28
|
type CachedPeer = {
|
|
27
29
|
peerId: PeerId;
|
|
@@ -455,7 +457,22 @@ export class PeerManager {
|
|
|
455
457
|
this.metrics.recordGoodbyeSent(reason);
|
|
456
458
|
|
|
457
459
|
try {
|
|
458
|
-
await this.reqresp.sendRequestToPeer(
|
|
460
|
+
const resp = await this.reqresp.sendRequestToPeer(
|
|
461
|
+
peer,
|
|
462
|
+
ReqRespSubProtocol.GOODBYE,
|
|
463
|
+
Buffer.from([reason]),
|
|
464
|
+
GOODBYE_DIAL_TIMEOUT_MS,
|
|
465
|
+
);
|
|
466
|
+
|
|
467
|
+
if (resp.status === ReqRespStatus.FAILURE) {
|
|
468
|
+
this.logger.debug(`Failed to send goodbye to peer ${peer.toString()}`);
|
|
469
|
+
} else if (resp.status === ReqRespStatus.SUCCESS) {
|
|
470
|
+
this.logger.verbose(`Sent goodbye to peer ${peer.toString()}`);
|
|
471
|
+
} else {
|
|
472
|
+
this.logger.debug(
|
|
473
|
+
`Unexpected status sending goodbye to peer ${peer.toString()}: ${ReqRespStatus[resp.status]}`,
|
|
474
|
+
);
|
|
475
|
+
}
|
|
459
476
|
} catch (error) {
|
|
460
477
|
this.logger.debug(`Failed to send goodbye to peer ${peer.toString()}: ${error}`);
|
|
461
478
|
} finally {
|
|
@@ -22,7 +22,11 @@ export class BatchConnectionSampler {
|
|
|
22
22
|
private readonly batch: PeerId[] = [];
|
|
23
23
|
private readonly requestsPerPeer: number;
|
|
24
24
|
|
|
25
|
-
constructor(
|
|
25
|
+
constructor(
|
|
26
|
+
private readonly connectionSampler: ConnectionSampler,
|
|
27
|
+
batchSize: number,
|
|
28
|
+
maxPeers: number,
|
|
29
|
+
) {
|
|
26
30
|
if (maxPeers <= 0) {
|
|
27
31
|
throw new Error('Max peers cannot be 0');
|
|
28
32
|
}
|
|
@@ -26,7 +26,7 @@ export class RandomSampler {
|
|
|
26
26
|
export class ConnectionSampler {
|
|
27
27
|
private readonly logger = createLogger('p2p:reqresp:connection-sampler');
|
|
28
28
|
private cleanupInterval: NodeJS.Timeout;
|
|
29
|
-
private
|
|
29
|
+
private dialAttempts: AbortController[] = [];
|
|
30
30
|
|
|
31
31
|
private readonly activeConnectionsCount: Map<PeerId, number> = new Map();
|
|
32
32
|
private readonly streams: Map<string, StreamAndPeerId> = new Map();
|
|
@@ -51,7 +51,10 @@ export class ConnectionSampler {
|
|
|
51
51
|
this.logger.info('Stopping connection sampler');
|
|
52
52
|
clearInterval(this.cleanupInterval);
|
|
53
53
|
|
|
54
|
-
this.
|
|
54
|
+
for (const attempt of this.dialAttempts) {
|
|
55
|
+
attempt.abort();
|
|
56
|
+
}
|
|
57
|
+
this.dialAttempts = [];
|
|
55
58
|
await this.dialQueue.end();
|
|
56
59
|
|
|
57
60
|
// Close all active streams
|
|
@@ -184,24 +187,44 @@ export class ConnectionSampler {
|
|
|
184
187
|
* @param protocol - The protocol
|
|
185
188
|
* @returns The stream
|
|
186
189
|
*/
|
|
187
|
-
async dialProtocol(peerId: PeerId, protocol: string): Promise<Stream> {
|
|
190
|
+
async dialProtocol(peerId: PeerId, protocol: string, timeout?: number): Promise<Stream> {
|
|
188
191
|
// Dialling at the same time can cause race conditions where two different streams
|
|
189
192
|
// end up with the same id, hence a serial queue
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
);
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
193
|
+
this.logger.debug(`Dial queue length: ${this.dialQueue.length()}`);
|
|
194
|
+
|
|
195
|
+
const abortController = new AbortController();
|
|
196
|
+
this.dialAttempts.push(abortController);
|
|
197
|
+
let timeoutHandle: NodeJS.Timeout | undefined;
|
|
198
|
+
if (timeout) {
|
|
199
|
+
timeoutHandle = setTimeout(() => abortController.abort(), timeout);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
try {
|
|
203
|
+
const stream = await this.dialQueue.put(() =>
|
|
204
|
+
this.libp2p.dialProtocol(peerId, protocol, { signal: abortController.signal }),
|
|
205
|
+
);
|
|
206
|
+
|
|
207
|
+
this.streams.set(stream.id, { stream, peerId });
|
|
208
|
+
const updatedActiveConnectionsCount = (this.activeConnectionsCount.get(peerId) ?? 0) + 1;
|
|
209
|
+
this.activeConnectionsCount.set(peerId, updatedActiveConnectionsCount);
|
|
210
|
+
|
|
211
|
+
this.logger.trace('Dialed protocol', {
|
|
212
|
+
streamId: stream.id,
|
|
213
|
+
protocol,
|
|
214
|
+
peerId: peerId.toString(),
|
|
215
|
+
activeConnectionsCount: updatedActiveConnectionsCount,
|
|
216
|
+
});
|
|
217
|
+
return stream;
|
|
218
|
+
} finally {
|
|
219
|
+
if (timeoutHandle) {
|
|
220
|
+
clearTimeout(timeoutHandle);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const idx = this.dialAttempts.indexOf(abortController);
|
|
224
|
+
if (idx > -1) {
|
|
225
|
+
this.dialAttempts.splice(idx, 1);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
205
228
|
}
|
|
206
229
|
|
|
207
230
|
/**
|
|
@@ -213,7 +236,7 @@ export class ConnectionSampler {
|
|
|
213
236
|
try {
|
|
214
237
|
const streamAndPeerId = this.streams.get(streamId);
|
|
215
238
|
if (!streamAndPeerId) {
|
|
216
|
-
this.logger.
|
|
239
|
+
this.logger.debug(`Stream ${streamId} not found`);
|
|
217
240
|
return;
|
|
218
241
|
}
|
|
219
242
|
|
|
@@ -11,7 +11,10 @@ export class ReqRespMetrics {
|
|
|
11
11
|
private readonly failedOutboundRequests: UpDownCounter;
|
|
12
12
|
private readonly failedInboundRequests: UpDownCounter;
|
|
13
13
|
|
|
14
|
-
constructor(
|
|
14
|
+
constructor(
|
|
15
|
+
readonly telemetryClient: TelemetryClient,
|
|
16
|
+
name = 'ReqResp',
|
|
17
|
+
) {
|
|
15
18
|
this.tracer = telemetryClient.getTracer(name);
|
|
16
19
|
|
|
17
20
|
const meter = telemetryClient.getMeter(name);
|
|
@@ -180,7 +180,10 @@ export class RequestResponseRateLimiter {
|
|
|
180
180
|
|
|
181
181
|
private cleanupInterval: NodeJS.Timeout | undefined = undefined;
|
|
182
182
|
|
|
183
|
-
constructor(
|
|
183
|
+
constructor(
|
|
184
|
+
private peerScoring: PeerScoring,
|
|
185
|
+
rateLimits: ReqRespSubProtocolRateLimits = DEFAULT_RATE_LIMITS,
|
|
186
|
+
) {
|
|
184
187
|
this.subProtocolRateLimiters = new Map();
|
|
185
188
|
|
|
186
189
|
for (const [subProtocol, protocolLimits] of Object.entries(rateLimits)) {
|
|
@@ -262,7 +262,7 @@ export class ReqResp {
|
|
|
262
262
|
subProtocol: SubProtocol,
|
|
263
263
|
requests: InstanceType<SubProtocolMap[SubProtocol]['request']>[],
|
|
264
264
|
timeoutMs = 10000,
|
|
265
|
-
maxPeers = Math.
|
|
265
|
+
maxPeers = Math.max(10, Math.ceil(requests.length / 3)),
|
|
266
266
|
maxRetryAttempts = 3,
|
|
267
267
|
): Promise<(InstanceType<SubProtocolMap[SubProtocol]['response']> | undefined)[]> {
|
|
268
268
|
const responseValidator = this.subProtocolValidators[subProtocol];
|
|
@@ -292,7 +292,8 @@ export class ReqResp {
|
|
|
292
292
|
let retryAttempts = 0;
|
|
293
293
|
while (pendingRequestIndices.size > 0 && batchSampler.activePeerCount > 0 && retryAttempts < maxRetryAttempts) {
|
|
294
294
|
// Process requests in parallel for each available peer
|
|
295
|
-
|
|
295
|
+
type BatchEntry = { peerId: PeerId; indices: number[] };
|
|
296
|
+
const requestBatches = new Map<string, BatchEntry>();
|
|
296
297
|
|
|
297
298
|
// Group requests by peer
|
|
298
299
|
for (const requestIndex of pendingRequestIndices) {
|
|
@@ -300,11 +301,11 @@ export class ReqResp {
|
|
|
300
301
|
if (!peer) {
|
|
301
302
|
break;
|
|
302
303
|
}
|
|
303
|
-
|
|
304
|
-
if (!requestBatches.has(
|
|
305
|
-
requestBatches.set(peer, []);
|
|
304
|
+
const peerAsString = peer.toString();
|
|
305
|
+
if (!requestBatches.has(peerAsString)) {
|
|
306
|
+
requestBatches.set(peerAsString, { peerId: peer, indices: [] });
|
|
306
307
|
}
|
|
307
|
-
requestBatches.get(
|
|
308
|
+
requestBatches.get(peerAsString)!.indices.push(requestIndex);
|
|
308
309
|
}
|
|
309
310
|
|
|
310
311
|
// Make parallel requests for each peer's batch
|
|
@@ -316,7 +317,7 @@ export class ReqResp {
|
|
|
316
317
|
// while simultaneously Peer Id 1 will send requests 4, 5, 6, 7 in serial
|
|
317
318
|
|
|
318
319
|
const batchResults = await Promise.all(
|
|
319
|
-
Array.from(requestBatches.entries()).map(async ([peer, indices]) => {
|
|
320
|
+
Array.from(requestBatches.entries()).map(async ([peerAsString, { peerId: peer, indices }]) => {
|
|
320
321
|
try {
|
|
321
322
|
// Requests all going to the same peer are sent synchronously
|
|
322
323
|
const peerResults: { index: number; response: InstanceType<SubProtocolMap[SubProtocol]['response']> }[] =
|
|
@@ -327,9 +328,7 @@ export class ReqResp {
|
|
|
327
328
|
// Check the status of the response buffer
|
|
328
329
|
if (response.status !== ReqRespStatus.SUCCESS) {
|
|
329
330
|
this.logger.debug(
|
|
330
|
-
`Request to peer ${
|
|
331
|
-
response.status,
|
|
332
|
-
)}`,
|
|
331
|
+
`Request to peer ${peerAsString} failed with status ${prettyPrintReqRespStatus(response.status)}`,
|
|
333
332
|
);
|
|
334
333
|
|
|
335
334
|
// If we hit a rate limit or some failure, we remove the peer and return the results,
|
|
@@ -350,7 +349,7 @@ export class ReqResp {
|
|
|
350
349
|
|
|
351
350
|
return { peer, results: peerResults };
|
|
352
351
|
} catch (error) {
|
|
353
|
-
this.logger.debug(`Failed batch request to peer ${
|
|
352
|
+
this.logger.debug(`Failed batch request to peer ${peerAsString}:`, error);
|
|
354
353
|
batchSampler.removePeerAndReplace(peer);
|
|
355
354
|
return { peer, results: [] };
|
|
356
355
|
}
|
|
@@ -421,12 +420,13 @@ export class ReqResp {
|
|
|
421
420
|
peerId: PeerId,
|
|
422
421
|
subProtocol: ReqRespSubProtocol,
|
|
423
422
|
payload: Buffer,
|
|
423
|
+
dialTimeout?: number,
|
|
424
424
|
): Promise<ReqRespResponse> {
|
|
425
425
|
let stream: Stream | undefined;
|
|
426
426
|
try {
|
|
427
427
|
this.metrics.recordRequestSent(subProtocol);
|
|
428
428
|
|
|
429
|
-
stream = await this.connectionSampler.dialProtocol(peerId, subProtocol);
|
|
429
|
+
stream = await this.connectionSampler.dialProtocol(peerId, subProtocol, dialTimeout);
|
|
430
430
|
|
|
431
431
|
// Open the stream with a timeout
|
|
432
432
|
const result = await executeTimeout<ReqRespResponse>(
|