@aztec/p2p 0.86.0-starknet.1 → 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 +1 -1
- package/dest/client/factory.d.ts.map +1 -1
- package/dest/client/factory.js +11 -13
- package/dest/client/interface.d.ts +10 -1
- package/dest/client/interface.d.ts.map +1 -1
- package/dest/client/p2p_client.d.ts +18 -6
- package/dest/client/p2p_client.d.ts.map +1 -1
- package/dest/client/p2p_client.js +103 -53
- 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 +7 -0
- package/dest/enr/generate-enr.d.ts.map +1 -1
- package/dest/enr/generate-enr.js +23 -2
- package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/mocks.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts +3 -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 +44 -14
- package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts +2 -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 +6 -0
- package/dest/mem_pools/tx_pool/tx_pool.d.ts +7 -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/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.js +5 -5
- 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 +87 -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 +2 -2
- package/dest/services/service.d.ts +3 -2
- 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 +9 -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 +33 -32
- package/src/client/interface.ts +13 -1
- package/src/client/p2p_client.ts +129 -55
- package/src/config.ts +11 -18
- package/src/enr/generate-enr.ts +33 -3
- package/src/mem_pools/attestation_pool/kv_attestation_pool.ts +2 -2
- package/src/mem_pools/attestation_pool/memory_attestation_pool.ts +4 -1
- package/src/mem_pools/tx_pool/aztec_kv_tx_pool.ts +72 -34
- package/src/mem_pools/tx_pool/memory_tx_pool.ts +12 -1
- package/src/mem_pools/tx_pool/tx_pool.ts +9 -0
- package/src/mem_pools/tx_pool/tx_pool_test_suite.ts +9 -3
- 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 +5 -5
- 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 +95 -107
- 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 +2 -1
- package/src/services/service.ts +4 -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 +8 -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
|
@@ -10,9 +10,9 @@ import { type Multiaddr, multiaddr } from '@multiformats/multiaddr';
|
|
|
10
10
|
import EventEmitter from 'events';
|
|
11
11
|
|
|
12
12
|
import type { P2PConfig } from '../../config.js';
|
|
13
|
+
import { createNodeENR } from '../../enr/generate-enr.js';
|
|
13
14
|
import { AZTEC_ENR_KEY, Discv5Event, PeerEvent } from '../../types/index.js';
|
|
14
15
|
import { convertToMultiaddr } from '../../util.js';
|
|
15
|
-
import { setAztecEnrKey } from '../../versioning.js';
|
|
16
16
|
import { type PeerDiscoveryService, PeerDiscoveryState } from '../service.js';
|
|
17
17
|
|
|
18
18
|
const delayBeforeStart = 2000; // 2sec
|
|
@@ -22,7 +22,7 @@ const delayBeforeStart = 2000; // 2sec
|
|
|
22
22
|
*/
|
|
23
23
|
export class DiscV5Service extends EventEmitter implements PeerDiscoveryService {
|
|
24
24
|
/** The Discv5 instance */
|
|
25
|
-
private discv5:
|
|
25
|
+
private discv5: Discv5EventEmitter;
|
|
26
26
|
|
|
27
27
|
/** This instance's ENR */
|
|
28
28
|
private enr: SignableENR;
|
|
@@ -47,6 +47,7 @@ export class DiscV5Service extends EventEmitter implements PeerDiscoveryService
|
|
|
47
47
|
constructor(
|
|
48
48
|
private peerId: PeerId,
|
|
49
49
|
private config: P2PConfig,
|
|
50
|
+
private readonly packageVersion: string,
|
|
50
51
|
telemetry: TelemetryClient = getTelemetryClient(),
|
|
51
52
|
private logger = createLogger('p2p:discv5_service'),
|
|
52
53
|
configOverrides: Partial<IDiscv5CreateOptions> = {},
|
|
@@ -57,10 +58,6 @@ export class DiscV5Service extends EventEmitter implements PeerDiscoveryService
|
|
|
57
58
|
this.bootstrapNodeEnrs = bootstrapNodes.map(x => ENR.decodeTxt(x));
|
|
58
59
|
const privatePeerEnrs = new Set(privatePeers);
|
|
59
60
|
this.trustedPeerEnrs = trustedPeers.filter(x => !privatePeerEnrs.has(x)).map(x => ENR.decodeTxt(x));
|
|
60
|
-
// create ENR from PeerId
|
|
61
|
-
this.enr = SignableENR.createFromPeerId(peerId);
|
|
62
|
-
// Add aztec identification to ENR
|
|
63
|
-
this.versions = setAztecEnrKey(this.enr, config);
|
|
64
61
|
|
|
65
62
|
// If no overridden broadcast port is provided, use the p2p port as the broadcast port
|
|
66
63
|
if (!p2pBroadcastPort) {
|
|
@@ -72,19 +69,24 @@ export class DiscV5Service extends EventEmitter implements PeerDiscoveryService
|
|
|
72
69
|
ip4: multiaddr(convertToMultiaddr(config.listenAddress, p2pPort, 'udp')),
|
|
73
70
|
};
|
|
74
71
|
|
|
72
|
+
let multiAddrUdp, multiAddrTcp;
|
|
75
73
|
if (p2pIp) {
|
|
76
|
-
|
|
74
|
+
multiAddrTcp = multiaddr(
|
|
77
75
|
`${convertToMultiaddr(p2pIp!, config.p2pBroadcastPort!, 'tcp')}/p2p/${peerId.toString()}`,
|
|
78
76
|
);
|
|
79
|
-
|
|
77
|
+
multiAddrUdp = multiaddr(
|
|
80
78
|
`${convertToMultiaddr(p2pIp!, config.p2pBroadcastPort!, 'udp')}/p2p/${peerId.toString()}`,
|
|
81
79
|
);
|
|
82
|
-
|
|
83
|
-
// set location multiaddr in ENR record
|
|
84
|
-
this.enr.setLocationMultiaddr(multiAddrUdp);
|
|
85
|
-
this.enr.setLocationMultiaddr(multiAddrTcp);
|
|
86
80
|
}
|
|
87
81
|
|
|
82
|
+
({ enr: this.enr, versions: this.versions } = createNodeENR(
|
|
83
|
+
peerId,
|
|
84
|
+
multiAddrUdp,
|
|
85
|
+
multiAddrTcp,
|
|
86
|
+
config,
|
|
87
|
+
this.packageVersion,
|
|
88
|
+
));
|
|
89
|
+
|
|
88
90
|
const metricsRegistry = new OtelMetricsAdapter(telemetry);
|
|
89
91
|
this.discv5 = Discv5.create({
|
|
90
92
|
enr: this.enr,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { PeerInfo } from '@aztec/stdlib/interfaces/server';
|
|
2
2
|
import type { BlockAttestation, BlockProposal, Gossipable } from '@aztec/stdlib/p2p';
|
|
3
|
-
import { TxHash } from '@aztec/stdlib/tx';
|
|
3
|
+
import { Tx, TxHash } from '@aztec/stdlib/tx';
|
|
4
4
|
|
|
5
5
|
import type { ENR } from '@chainsafe/enr';
|
|
6
6
|
import type { PeerId } from '@libp2p/interface';
|
|
@@ -38,7 +38,9 @@ export class DummyP2PService implements P2PService {
|
|
|
38
38
|
* Called to have the given message propagated through the P2P network.
|
|
39
39
|
* @param _ - The message to be propagated.
|
|
40
40
|
*/
|
|
41
|
-
public propagate<T extends Gossipable>(_: T) {
|
|
41
|
+
public propagate<T extends Gossipable>(_: T) {
|
|
42
|
+
return Promise.resolve();
|
|
43
|
+
}
|
|
42
44
|
|
|
43
45
|
/**
|
|
44
46
|
* Called upon receipt of settled transactions.
|
|
@@ -84,6 +86,10 @@ export class DummyP2PService implements P2PService {
|
|
|
84
86
|
public getEnr(): undefined {
|
|
85
87
|
return undefined;
|
|
86
88
|
}
|
|
89
|
+
|
|
90
|
+
validate(_txs: Tx[]): Promise<void> {
|
|
91
|
+
return Promise.resolve();
|
|
92
|
+
}
|
|
87
93
|
}
|
|
88
94
|
|
|
89
95
|
/**
|
|
@@ -1,11 +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 {
|
|
8
|
-
import { ProtocolContractAddress, protocolContractTreeRoot } from '@aztec/protocol-contracts';
|
|
6
|
+
import { protocolContractTreeRoot } from '@aztec/protocol-contracts';
|
|
9
7
|
import type { L2BlockSource } from '@aztec/stdlib/block';
|
|
10
8
|
import type { ContractDataSource } from '@aztec/stdlib/contract';
|
|
11
9
|
import { GasFees } from '@aztec/stdlib/gas';
|
|
@@ -15,13 +13,14 @@ import {
|
|
|
15
13
|
BlockProposal,
|
|
16
14
|
type Gossipable,
|
|
17
15
|
P2PClientType,
|
|
16
|
+
P2PMessage,
|
|
18
17
|
PeerErrorSeverity,
|
|
19
18
|
TopicType,
|
|
20
19
|
createTopicString,
|
|
21
20
|
getTopicTypeForClientType,
|
|
22
21
|
metricsTopicStrToLabels,
|
|
23
22
|
} from '@aztec/stdlib/p2p';
|
|
24
|
-
import {
|
|
23
|
+
import { MerkleTreeId } from '@aztec/stdlib/trees';
|
|
25
24
|
import { Tx, type TxHash, type TxValidationResult } from '@aztec/stdlib/tx';
|
|
26
25
|
import { compressComponentVersions } from '@aztec/stdlib/versioning';
|
|
27
26
|
import { Attributes, OtelMetricsAdapter, type TelemetryClient, WithTracer, trackSpan } from '@aztec/telemetry-client';
|
|
@@ -50,14 +49,8 @@ import type { P2PConfig } from '../../config.js';
|
|
|
50
49
|
import type { MemPools } from '../../mem_pools/interface.js';
|
|
51
50
|
import { AttestationValidator, BlockProposalValidator } from '../../msg_validators/index.js';
|
|
52
51
|
import { getDefaultAllowedSetupFunctions } from '../../msg_validators/tx_validator/allowed_public_setup.js';
|
|
53
|
-
import {
|
|
54
|
-
|
|
55
|
-
DoubleSpendTxValidator,
|
|
56
|
-
GasTxValidator,
|
|
57
|
-
MetadataTxValidator,
|
|
58
|
-
PhasesTxValidator,
|
|
59
|
-
TxProofValidator,
|
|
60
|
-
} 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';
|
|
61
54
|
import { GossipSubEvent } from '../../types/index.js';
|
|
62
55
|
import { type PubSubLibp2p, convertToMultiaddr } from '../../util.js';
|
|
63
56
|
import { getVersions } from '../../versioning.js';
|
|
@@ -72,13 +65,6 @@ import { pingHandler, reqRespBlockHandler, reqRespTxHandler, statusHandler } fro
|
|
|
72
65
|
import { ReqResp } from '../reqresp/reqresp.js';
|
|
73
66
|
import type { P2PService, PeerDiscoveryService } from '../service.js';
|
|
74
67
|
|
|
75
|
-
interface MessageValidator {
|
|
76
|
-
validator: {
|
|
77
|
-
validateTx(tx: Tx): Promise<TxValidationResult>;
|
|
78
|
-
};
|
|
79
|
-
severity: PeerErrorSeverity;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
68
|
interface ValidationResult {
|
|
83
69
|
name: string;
|
|
84
70
|
isValid: TxValidationResult;
|
|
@@ -234,7 +220,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
234
220
|
tcp({
|
|
235
221
|
maxConnections: config.maxPeerCount,
|
|
236
222
|
// socket option: the maximum length of the queue of pending connections
|
|
237
|
-
// https://nodejs.org/dist/latest-
|
|
223
|
+
// https://nodejs.org/dist/latest-v22.x/docs/api/net.html#serverlisten
|
|
238
224
|
// it's not safe if we increase this number
|
|
239
225
|
backlog: 5,
|
|
240
226
|
closeServerOnMaxConnections: {
|
|
@@ -271,6 +257,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
271
257
|
heartbeatInterval: config.gossipsubInterval,
|
|
272
258
|
mcacheLength: config.gossipsubMcacheLength,
|
|
273
259
|
mcacheGossip: config.gossipsubMcacheGossip,
|
|
260
|
+
seenTTL: config.gossipsubSeenTTL,
|
|
274
261
|
msgIdFn: getMsgIdFn,
|
|
275
262
|
msgIdToStrFn: msgIdToStrFn,
|
|
276
263
|
fastMsgIdFn: fastMsgIdFn,
|
|
@@ -490,14 +477,19 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
490
477
|
/**
|
|
491
478
|
* Publishes data to a topic.
|
|
492
479
|
* @param topic - The topic to publish to.
|
|
493
|
-
* @param data - The
|
|
480
|
+
* @param data - The message to publish.
|
|
494
481
|
* @returns The number of recipients the data was sent to.
|
|
495
482
|
*/
|
|
496
|
-
private async publishToTopic(topic: string,
|
|
483
|
+
private async publishToTopic(topic: string, message: Gossipable) {
|
|
497
484
|
if (!this.node.services.pubsub) {
|
|
498
485
|
throw new Error('Pubsub service not available.');
|
|
499
486
|
}
|
|
500
|
-
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());
|
|
501
493
|
|
|
502
494
|
return result.recipients.length;
|
|
503
495
|
}
|
|
@@ -508,14 +500,22 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
508
500
|
* @param data - The message data
|
|
509
501
|
*/
|
|
510
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
|
+
});
|
|
511
511
|
if (msg.topic === this.topicStrings[TopicType.tx]) {
|
|
512
|
-
await this.handleGossipedTx(
|
|
512
|
+
await this.handleGossipedTx(p2pMessage.payload, msgId, source);
|
|
513
513
|
}
|
|
514
514
|
if (msg.topic === this.topicStrings[TopicType.block_attestation] && this.clientType === P2PClientType.Full) {
|
|
515
|
-
await this.processAttestationFromPeer(
|
|
515
|
+
await this.processAttestationFromPeer(p2pMessage.payload, msgId, source);
|
|
516
516
|
}
|
|
517
517
|
if (msg.topic === this.topicStrings[TopicType.block_proposal]) {
|
|
518
|
-
await this.processBlockFromPeer(
|
|
518
|
+
await this.processBlockFromPeer(p2pMessage.payload, msgId, source);
|
|
519
519
|
}
|
|
520
520
|
|
|
521
521
|
return;
|
|
@@ -541,9 +541,9 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
541
541
|
return resultAndObj;
|
|
542
542
|
}
|
|
543
543
|
|
|
544
|
-
protected async handleGossipedTx(
|
|
544
|
+
protected async handleGossipedTx(payloadData: Buffer, msgId: string, source: PeerId) {
|
|
545
545
|
const validationFunc = async () => {
|
|
546
|
-
const tx = Tx.fromBuffer(
|
|
546
|
+
const tx = Tx.fromBuffer(payloadData);
|
|
547
547
|
const result = await this.validatePropagatedTx(tx, source);
|
|
548
548
|
return { result, obj: tx };
|
|
549
549
|
};
|
|
@@ -564,9 +564,9 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
564
564
|
*
|
|
565
565
|
* @param attestation - The attestation to process.
|
|
566
566
|
*/
|
|
567
|
-
private async processAttestationFromPeer(
|
|
567
|
+
private async processAttestationFromPeer(payloadData: Buffer, msgId: string, source: PeerId): Promise<void> {
|
|
568
568
|
const validationFunc = async () => {
|
|
569
|
-
const attestation = BlockAttestation.fromBuffer(
|
|
569
|
+
const attestation = BlockAttestation.fromBuffer(payloadData);
|
|
570
570
|
const result = await this.validateAttestation(source, attestation);
|
|
571
571
|
this.logger.trace(`validatePropagatedAttestation: ${result}`, {
|
|
572
572
|
[Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber.toString(),
|
|
@@ -595,9 +595,9 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
595
595
|
await this.mempools.attestationPool!.addAttestations([attestation]);
|
|
596
596
|
}
|
|
597
597
|
|
|
598
|
-
private async processBlockFromPeer(
|
|
598
|
+
private async processBlockFromPeer(payloadData: Buffer, msgId: string, source: PeerId): Promise<void> {
|
|
599
599
|
const validationFunc = async () => {
|
|
600
|
-
const block = BlockProposal.fromBuffer(
|
|
600
|
+
const block = BlockProposal.fromBuffer(payloadData);
|
|
601
601
|
const result = await this.validateBlockProposal(source, block);
|
|
602
602
|
this.logger.trace(`validatePropagatedBlock: ${result}`, {
|
|
603
603
|
[Attributes.SLOT_NUMBER]: block.payload.header.slotNumber.toString(),
|
|
@@ -630,6 +630,8 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
630
630
|
block: block.blockNumber.toNumber(),
|
|
631
631
|
},
|
|
632
632
|
);
|
|
633
|
+
// Mark the txs in this proposal as non-evictable
|
|
634
|
+
await this.mempools.txPool.markTxsAsNonEvictable(block.payload.txHashes);
|
|
633
635
|
const attestation = await this.blockReceivedCallback(block);
|
|
634
636
|
|
|
635
637
|
// TODO: fix up this pattern - the abstraction is not nice
|
|
@@ -721,21 +723,25 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
721
723
|
private async validatePropagatedTx(tx: Tx, peerId: PeerId): Promise<boolean> {
|
|
722
724
|
const blockNumber = (await this.archiver.getBlockNumber()) + 1;
|
|
723
725
|
const messageValidators = await this.createMessageValidators(blockNumber);
|
|
724
|
-
const outcome = await this.runValidations(tx, messageValidators);
|
|
725
726
|
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
}
|
|
729
|
-
const { name } = outcome.failure;
|
|
730
|
-
let { severity } = outcome.failure;
|
|
727
|
+
for (const validator of messageValidators) {
|
|
728
|
+
const outcome = await this.runValidations(tx, validator);
|
|
731
729
|
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
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
|
+
}
|
|
736
740
|
|
|
737
|
-
|
|
738
|
-
|
|
741
|
+
this.peerManager.penalizePeer(peerId, severity);
|
|
742
|
+
return false;
|
|
743
|
+
}
|
|
744
|
+
return true;
|
|
739
745
|
}
|
|
740
746
|
|
|
741
747
|
private async getGasFees(blockNumber: number): Promise<GasFees> {
|
|
@@ -749,6 +755,22 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
749
755
|
return gasFees;
|
|
750
756
|
}
|
|
751
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
|
+
|
|
752
774
|
/**
|
|
753
775
|
* Create message validators for the given block number.
|
|
754
776
|
*
|
|
@@ -758,53 +780,21 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
758
780
|
* @param blockNumber - The block number to create validators for.
|
|
759
781
|
* @returns The message validators.
|
|
760
782
|
*/
|
|
761
|
-
private async createMessageValidators(blockNumber: number): Promise<Record<string, MessageValidator
|
|
762
|
-
const merkleTree = this.worldStateSynchronizer.getCommitted();
|
|
783
|
+
private async createMessageValidators(blockNumber: number): Promise<Record<string, MessageValidator>[]> {
|
|
763
784
|
const gasFees = await this.getGasFees(blockNumber - 1);
|
|
764
785
|
const allowedInSetup = this.config.txPublicSetupAllowList ?? (await getDefaultAllowedSetupFunctions());
|
|
765
786
|
|
|
766
|
-
return
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
vkTreeRoot: getVKTreeRoot(),
|
|
778
|
-
}),
|
|
779
|
-
severity: PeerErrorSeverity.HighToleranceError,
|
|
780
|
-
},
|
|
781
|
-
proofValidator: {
|
|
782
|
-
validator: new TxProofValidator(this.proofVerifier),
|
|
783
|
-
severity: PeerErrorSeverity.MidToleranceError,
|
|
784
|
-
},
|
|
785
|
-
doubleSpendValidator: {
|
|
786
|
-
validator: new DoubleSpendTxValidator({
|
|
787
|
-
nullifiersExist: async (nullifiers: Buffer[]) => {
|
|
788
|
-
const merkleTree = this.worldStateSynchronizer.getCommitted();
|
|
789
|
-
const indices = await merkleTree.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, nullifiers);
|
|
790
|
-
return indices.map(index => index !== undefined);
|
|
791
|
-
},
|
|
792
|
-
}),
|
|
793
|
-
severity: PeerErrorSeverity.HighToleranceError,
|
|
794
|
-
},
|
|
795
|
-
gasValidator: {
|
|
796
|
-
validator: new GasTxValidator(
|
|
797
|
-
new DatabasePublicStateSource(merkleTree),
|
|
798
|
-
ProtocolContractAddress.FeeJuice,
|
|
799
|
-
gasFees,
|
|
800
|
-
),
|
|
801
|
-
severity: PeerErrorSeverity.HighToleranceError,
|
|
802
|
-
},
|
|
803
|
-
phasesValidator: {
|
|
804
|
-
validator: new PhasesTxValidator(this.archiver, allowedInSetup, blockNumber),
|
|
805
|
-
severity: PeerErrorSeverity.MidToleranceError,
|
|
806
|
-
},
|
|
807
|
-
};
|
|
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
|
+
);
|
|
808
798
|
}
|
|
809
799
|
|
|
810
800
|
/**
|
|
@@ -823,24 +813,22 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
823
813
|
});
|
|
824
814
|
|
|
825
815
|
// A promise that resolves when all validations have been run
|
|
826
|
-
const allValidations = Promise.all(validationPromises);
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
// If all validations pass, allPassed will be true, if failed, then the failure will be the first validation to fail
|
|
843
|
-
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
|
+
}
|
|
844
832
|
}
|
|
845
833
|
|
|
846
834
|
/**
|
|
@@ -929,7 +917,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
929
917
|
const identifier = await message.p2pMessageIdentifier().then(i => i.toString());
|
|
930
918
|
this.logger.trace(`Sending message ${identifier}`, { p2pMessageIdentifier: identifier });
|
|
931
919
|
|
|
932
|
-
const recipientsNum = await this.publishToTopic(this.topicStrings[parent.p2pTopic], message
|
|
920
|
+
const recipientsNum = await this.publishToTopic(this.topicStrings[parent.p2pTopic], message);
|
|
933
921
|
this.logger.debug(`Sent message ${identifier} to ${recipientsNum} peers`, {
|
|
934
922
|
p2pMessageIdentifier: identifier,
|
|
935
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)) {
|
|
@@ -420,12 +420,13 @@ export class ReqResp {
|
|
|
420
420
|
peerId: PeerId,
|
|
421
421
|
subProtocol: ReqRespSubProtocol,
|
|
422
422
|
payload: Buffer,
|
|
423
|
+
dialTimeout?: number,
|
|
423
424
|
): Promise<ReqRespResponse> {
|
|
424
425
|
let stream: Stream | undefined;
|
|
425
426
|
try {
|
|
426
427
|
this.metrics.recordRequestSent(subProtocol);
|
|
427
428
|
|
|
428
|
-
stream = await this.connectionSampler.dialProtocol(peerId, subProtocol);
|
|
429
|
+
stream = await this.connectionSampler.dialProtocol(peerId, subProtocol, dialTimeout);
|
|
429
430
|
|
|
430
431
|
// Open the stream with a timeout
|
|
431
432
|
const result = await executeTimeout<ReqRespResponse>(
|