@aztec/p2p 0.66.0 → 0.67.1-devnet
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 +4 -1
- package/dest/bootstrap/bootstrap.d.ts.map +1 -1
- package/dest/bootstrap/bootstrap.js +21 -9
- package/dest/client/index.d.ts +5 -4
- package/dest/client/index.d.ts.map +1 -1
- package/dest/client/index.js +18 -12
- package/dest/client/p2p_client.d.ts +13 -20
- package/dest/client/p2p_client.d.ts.map +1 -1
- package/dest/client/p2p_client.js +32 -15
- package/dest/config.d.ts +1 -1
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +2 -2
- package/dest/errors/reqresp.error.d.ts +12 -1
- package/dest/errors/reqresp.error.d.ts.map +1 -1
- package/dest/errors/reqresp.error.js +15 -2
- package/dest/index.d.ts +1 -1
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +2 -2
- package/dest/mem_pools/attestation_pool/attestation_pool.d.ts +9 -0
- package/dest/mem_pools/attestation_pool/attestation_pool.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.d.ts +3 -0
- package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.d.ts.map +1 -0
- package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.js +171 -0
- package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts +29 -0
- package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts.map +1 -0
- package/dest/mem_pools/attestation_pool/kv_attestation_pool.js +114 -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 +3 -3
- package/dest/mem_pools/instrumentation.d.ts.map +1 -1
- package/dest/mem_pools/instrumentation.js +2 -20
- package/dest/mem_pools/interface.d.ts +4 -3
- package/dest/mem_pools/interface.d.ts.map +1 -1
- 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 +4 -4
- package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/memory_tx_pool.js +4 -4
- package/dest/mocks/index.d.ts +6 -6
- package/dest/mocks/index.d.ts.map +1 -1
- package/dest/mocks/index.js +9 -9
- package/dest/services/data_store.d.ts.map +1 -0
- package/dest/services/data_store.js +188 -0
- package/dest/{service → services/discv5}/discV5_service.d.ts +4 -2
- package/dest/services/discv5/discV5_service.d.ts.map +1 -0
- package/dest/services/discv5/discV5_service.js +144 -0
- package/dest/{service → services}/dummy_service.d.ts +3 -1
- package/dest/services/dummy_service.d.ts.map +1 -0
- package/dest/{service → services}/dummy_service.js +5 -1
- package/dest/{service → services}/encoding.d.ts +5 -0
- package/dest/services/encoding.d.ts.map +1 -0
- package/dest/services/encoding.js +65 -0
- package/dest/services/index.d.ts +3 -0
- package/dest/services/index.d.ts.map +1 -0
- package/dest/services/index.js +3 -0
- package/dest/{service → services/libp2p}/libp2p_service.d.ts +50 -11
- package/dest/services/libp2p/libp2p_service.d.ts.map +1 -0
- package/dest/services/libp2p/libp2p_service.js +573 -0
- package/dest/{service → services/peer-scoring}/peer_scoring.d.ts +5 -2
- package/dest/services/peer-scoring/peer_scoring.d.ts.map +1 -0
- package/dest/services/peer-scoring/peer_scoring.js +72 -0
- package/dest/{service → services}/peer_manager.d.ts +8 -3
- package/dest/services/peer_manager.d.ts.map +1 -0
- package/dest/services/peer_manager.js +230 -0
- package/dest/services/reqresp/config.d.ts.map +1 -0
- package/dest/{service → services}/reqresp/config.js +1 -1
- package/dest/services/reqresp/handlers.d.ts.map +1 -0
- package/dest/{service → services}/reqresp/handlers.js +1 -1
- package/dest/services/reqresp/index.d.ts.map +1 -0
- package/dest/{service → services}/reqresp/index.js +1 -1
- package/dest/services/reqresp/interface.d.ts.map +1 -0
- package/dest/{service → services}/reqresp/interface.js +1 -1
- package/dest/services/reqresp/rate_limiter/index.d.ts.map +1 -0
- package/dest/{service → services}/reqresp/rate_limiter/index.js +1 -1
- package/dest/services/reqresp/rate_limiter/rate_limiter.d.ts.map +1 -0
- package/dest/{service → services}/reqresp/rate_limiter/rate_limiter.js +2 -2
- package/dest/services/reqresp/rate_limiter/rate_limits.d.ts.map +1 -0
- package/dest/{service → services}/reqresp/rate_limiter/rate_limits.js +1 -1
- package/dest/{service → services}/reqresp/reqresp.d.ts +16 -0
- package/dest/services/reqresp/reqresp.d.ts.map +1 -0
- package/dest/{service → services}/reqresp/reqresp.js +69 -20
- package/dest/{service → services}/service.d.ts +2 -1
- package/dest/services/service.d.ts.map +1 -0
- package/dest/{service → services}/service.js +1 -1
- package/dest/tx_validator/aggregate_tx_validator.d.ts +1 -1
- package/dest/tx_validator/aggregate_tx_validator.d.ts.map +1 -1
- package/dest/tx_validator/aggregate_tx_validator.js +5 -3
- package/dest/tx_validator/data_validator.js +3 -3
- package/dest/tx_validator/double_spend_validator.d.ts +3 -2
- package/dest/tx_validator/double_spend_validator.d.ts.map +1 -1
- package/dest/tx_validator/double_spend_validator.js +8 -8
- package/dest/tx_validator/metadata_validator.js +3 -3
- package/dest/tx_validator/tx_proof_validator.js +3 -3
- package/package.json +12 -8
- package/src/bootstrap/bootstrap.ts +24 -10
- package/src/client/index.ts +44 -19
- package/src/client/p2p_client.ts +58 -36
- package/src/config.ts +1 -1
- package/src/errors/reqresp.error.ts +15 -1
- package/src/index.ts +1 -1
- package/src/mem_pools/attestation_pool/attestation_pool.ts +10 -0
- package/src/mem_pools/attestation_pool/attestation_pool_test_suite.ts +237 -0
- package/src/mem_pools/attestation_pool/kv_attestation_pool.ts +153 -0
- package/src/mem_pools/attestation_pool/memory_attestation_pool.ts +2 -2
- package/src/mem_pools/instrumentation.ts +1 -21
- package/src/mem_pools/interface.ts +5 -3
- package/src/mem_pools/tx_pool/aztec_kv_tx_pool.ts +3 -3
- package/src/mem_pools/tx_pool/memory_tx_pool.ts +3 -3
- package/src/mocks/index.ts +14 -11
- package/src/{service → services/discv5}/discV5_service.ts +20 -15
- package/src/{service → services}/dummy_service.ts +6 -1
- package/src/{service → services}/encoding.ts +21 -3
- package/src/services/index.ts +2 -0
- package/src/{service → services/libp2p}/libp2p_service.ts +208 -96
- package/src/{service → services/peer-scoring}/peer_scoring.ts +9 -2
- package/src/{service → services}/peer_manager.ts +73 -24
- package/src/{service → services}/reqresp/rate_limiter/rate_limiter.ts +1 -1
- package/src/{service → services}/reqresp/reqresp.ts +87 -21
- package/src/{service → services}/service.ts +3 -1
- package/src/tx_validator/aggregate_tx_validator.ts +5 -3
- package/src/tx_validator/data_validator.ts +2 -2
- package/src/tx_validator/double_spend_validator.ts +8 -10
- package/src/tx_validator/metadata_validator.ts +2 -2
- package/src/tx_validator/tx_proof_validator.ts +2 -2
- package/dest/service/data_store.d.ts.map +0 -1
- package/dest/service/data_store.js +0 -188
- package/dest/service/discV5_service.d.ts.map +0 -1
- package/dest/service/discV5_service.js +0 -141
- package/dest/service/dummy_service.d.ts.map +0 -1
- package/dest/service/encoding.d.ts.map +0 -1
- package/dest/service/encoding.js +0 -49
- package/dest/service/index.d.ts +0 -3
- package/dest/service/index.d.ts.map +0 -1
- package/dest/service/index.js +0 -3
- package/dest/service/libp2p_service.d.ts.map +0 -1
- package/dest/service/libp2p_service.js +0 -496
- package/dest/service/peer_manager.d.ts.map +0 -1
- package/dest/service/peer_manager.js +0 -176
- package/dest/service/peer_scoring.d.ts.map +0 -1
- package/dest/service/peer_scoring.js +0 -67
- package/dest/service/reqresp/config.d.ts.map +0 -1
- package/dest/service/reqresp/handlers.d.ts.map +0 -1
- package/dest/service/reqresp/index.d.ts.map +0 -1
- package/dest/service/reqresp/interface.d.ts.map +0 -1
- package/dest/service/reqresp/rate_limiter/index.d.ts.map +0 -1
- package/dest/service/reqresp/rate_limiter/rate_limiter.d.ts.map +0 -1
- package/dest/service/reqresp/rate_limiter/rate_limits.d.ts.map +0 -1
- package/dest/service/reqresp/reqresp.d.ts.map +0 -1
- package/dest/service/service.d.ts.map +0 -1
- package/src/service/index.ts +0 -2
- /package/dest/{service → services}/data_store.d.ts +0 -0
- /package/dest/{service → services}/reqresp/config.d.ts +0 -0
- /package/dest/{service → services}/reqresp/handlers.d.ts +0 -0
- /package/dest/{service → services}/reqresp/index.d.ts +0 -0
- /package/dest/{service → services}/reqresp/interface.d.ts +0 -0
- /package/dest/{service → services}/reqresp/rate_limiter/index.d.ts +0 -0
- /package/dest/{service → services}/reqresp/rate_limiter/rate_limiter.d.ts +0 -0
- /package/dest/{service → services}/reqresp/rate_limiter/rate_limits.d.ts +0 -0
- /package/src/{service → services}/data_store.ts +0 -0
- /package/src/{service → services}/reqresp/config.ts +0 -0
- /package/src/{service → services}/reqresp/handlers.ts +0 -0
- /package/src/{service → services}/reqresp/index.ts +0 -0
- /package/src/{service → services}/reqresp/interface.ts +0 -0
- /package/src/{service → services}/reqresp/rate_limiter/index.ts +0 -0
- /package/src/{service → services}/reqresp/rate_limiter/rate_limits.ts +0 -0
|
@@ -6,16 +6,18 @@ import {
|
|
|
6
6
|
type Gossipable,
|
|
7
7
|
type L2BlockSource,
|
|
8
8
|
MerkleTreeId,
|
|
9
|
+
type PeerInfo,
|
|
9
10
|
type RawGossipMessage,
|
|
10
|
-
TopicType,
|
|
11
11
|
TopicTypeMap,
|
|
12
12
|
Tx,
|
|
13
13
|
TxHash,
|
|
14
14
|
type WorldStateSynchronizer,
|
|
15
|
+
getTopicTypeForClientType,
|
|
15
16
|
metricsTopicStrToLabels,
|
|
16
17
|
} from '@aztec/circuit-types';
|
|
18
|
+
import { P2PClientType } from '@aztec/circuit-types';
|
|
17
19
|
import { Fr } from '@aztec/circuits.js';
|
|
18
|
-
import {
|
|
20
|
+
import { createLogger } from '@aztec/foundation/log';
|
|
19
21
|
import { SerialQueue } from '@aztec/foundation/queue';
|
|
20
22
|
import { RunningPromise } from '@aztec/foundation/running-promise';
|
|
21
23
|
import type { AztecKVStore } from '@aztec/kv-store';
|
|
@@ -27,26 +29,26 @@ import { createPeerScoreParams, createTopicScoreParams } from '@chainsafe/libp2p
|
|
|
27
29
|
import { noise } from '@chainsafe/libp2p-noise';
|
|
28
30
|
import { yamux } from '@chainsafe/libp2p-yamux';
|
|
29
31
|
import { identify } from '@libp2p/identify';
|
|
30
|
-
import type
|
|
32
|
+
import { type Message, type PeerId, TopicValidatorResult } from '@libp2p/interface';
|
|
31
33
|
import '@libp2p/kad-dht';
|
|
32
34
|
import { mplex } from '@libp2p/mplex';
|
|
33
35
|
import { tcp } from '@libp2p/tcp';
|
|
34
36
|
import { createLibp2p } from 'libp2p';
|
|
35
37
|
|
|
36
|
-
import { type P2PConfig } from '
|
|
37
|
-
import { type MemPools } from '
|
|
38
|
+
import { type P2PConfig } from '../../config.js';
|
|
39
|
+
import { type MemPools } from '../../mem_pools/interface.js';
|
|
38
40
|
import {
|
|
39
41
|
DataTxValidator,
|
|
40
42
|
DoubleSpendTxValidator,
|
|
41
43
|
MetadataTxValidator,
|
|
42
44
|
TxProofValidator,
|
|
43
|
-
} from '
|
|
44
|
-
import { type PubSubLibp2p, convertToMultiaddr } from '
|
|
45
|
-
import { AztecDatastore } from '
|
|
46
|
-
import { SnappyTransform, fastMsgIdFn, getMsgIdFn, msgIdToStrFn } from '
|
|
47
|
-
import {
|
|
48
|
-
import {
|
|
49
|
-
import { pingHandler, statusHandler } from '
|
|
45
|
+
} from '../../tx_validator/index.js';
|
|
46
|
+
import { type PubSubLibp2p, convertToMultiaddr } from '../../util.js';
|
|
47
|
+
import { AztecDatastore } from '../data_store.js';
|
|
48
|
+
import { SnappyTransform, fastMsgIdFn, getMsgIdFn, msgIdToStrFn } from '../encoding.js';
|
|
49
|
+
import { PeerErrorSeverity } from '../peer-scoring/peer_scoring.js';
|
|
50
|
+
import { PeerManager } from '../peer_manager.js';
|
|
51
|
+
import { pingHandler, statusHandler } from '../reqresp/handlers.js';
|
|
50
52
|
import {
|
|
51
53
|
DEFAULT_SUB_PROTOCOL_HANDLERS,
|
|
52
54
|
DEFAULT_SUB_PROTOCOL_VALIDATORS,
|
|
@@ -56,14 +58,29 @@ import {
|
|
|
56
58
|
STATUS_PROTOCOL,
|
|
57
59
|
type SubProtocolMap,
|
|
58
60
|
TX_REQ_PROTOCOL,
|
|
59
|
-
} from '
|
|
60
|
-
import { ReqResp } from '
|
|
61
|
-
import type { P2PService, PeerDiscoveryService } from '
|
|
61
|
+
} from '../reqresp/interface.js';
|
|
62
|
+
import { ReqResp } from '../reqresp/reqresp.js';
|
|
63
|
+
import type { P2PService, PeerDiscoveryService } from '../service.js';
|
|
64
|
+
|
|
65
|
+
interface MessageValidator {
|
|
66
|
+
validator: {
|
|
67
|
+
validateTx(tx: Tx): Promise<boolean>;
|
|
68
|
+
};
|
|
69
|
+
severity: PeerErrorSeverity;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
interface ValidationResult {
|
|
73
|
+
name: string;
|
|
74
|
+
isValid: boolean;
|
|
75
|
+
severity: PeerErrorSeverity;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
type ValidationOutcome = { allPassed: true } | { allPassed: false; failure: ValidationResult };
|
|
62
79
|
|
|
63
80
|
/**
|
|
64
81
|
* Lib P2P implementation of the P2PService interface.
|
|
65
82
|
*/
|
|
66
|
-
export class LibP2PService extends WithTracer implements P2PService {
|
|
83
|
+
export class LibP2PService<T extends P2PClientType> extends WithTracer implements P2PService {
|
|
67
84
|
private jobQueue: SerialQueue = new SerialQueue();
|
|
68
85
|
private peerManager: PeerManager;
|
|
69
86
|
private discoveryRunningPromise?: RunningPromise;
|
|
@@ -79,20 +96,21 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
79
96
|
private blockReceivedCallback: (block: BlockProposal) => Promise<BlockAttestation | undefined>;
|
|
80
97
|
|
|
81
98
|
constructor(
|
|
99
|
+
private clientType: T,
|
|
82
100
|
private config: P2PConfig,
|
|
83
101
|
private node: PubSubLibp2p,
|
|
84
102
|
private peerDiscoveryService: PeerDiscoveryService,
|
|
85
|
-
private mempools: MemPools
|
|
103
|
+
private mempools: MemPools<T>,
|
|
86
104
|
private l2BlockSource: L2BlockSource,
|
|
87
105
|
private proofVerifier: ClientProtocolCircuitVerifier,
|
|
88
106
|
private worldStateSynchronizer: WorldStateSynchronizer,
|
|
89
107
|
private telemetry: TelemetryClient,
|
|
90
108
|
private requestResponseHandlers: ReqRespSubProtocolHandlers = DEFAULT_SUB_PROTOCOL_HANDLERS,
|
|
91
|
-
private logger =
|
|
109
|
+
private logger = createLogger('p2p:libp2p_service'),
|
|
92
110
|
) {
|
|
93
111
|
super(telemetry, 'LibP2PService');
|
|
94
112
|
|
|
95
|
-
this.peerManager = new PeerManager(node, peerDiscoveryService, config, logger);
|
|
113
|
+
this.peerManager = new PeerManager(node, peerDiscoveryService, config, this.tracer, logger);
|
|
96
114
|
this.node.services.pubsub.score.params.appSpecificScore = (peerId: string) => {
|
|
97
115
|
return this.peerManager.getPeerScore(peerId);
|
|
98
116
|
};
|
|
@@ -117,38 +135,40 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
117
135
|
throw new Error('P2P service already started');
|
|
118
136
|
}
|
|
119
137
|
|
|
120
|
-
//
|
|
138
|
+
// Get listen & announce addresses for logging
|
|
121
139
|
const { tcpListenAddress, tcpAnnounceAddress } = this.config;
|
|
122
|
-
this.logger.info(`Starting P2P node on ${tcpListenAddress}`);
|
|
123
140
|
if (!tcpAnnounceAddress) {
|
|
124
141
|
throw new Error('Announce address not provided.');
|
|
125
142
|
}
|
|
126
143
|
const announceTcpMultiaddr = convertToMultiaddr(tcpAnnounceAddress, 'tcp');
|
|
127
|
-
this.logger.info(`Announcing at ${announceTcpMultiaddr}`);
|
|
128
144
|
|
|
129
145
|
// Start job queue, peer discovery service and libp2p node
|
|
130
146
|
this.jobQueue.start();
|
|
131
147
|
await this.peerDiscoveryService.start();
|
|
132
148
|
await this.node.start();
|
|
133
|
-
this.logger.info(`Started P2P client with Peer ID ${this.node.peerId.toString()}`);
|
|
134
149
|
|
|
135
150
|
// Subscribe to standard GossipSub topics by default
|
|
136
|
-
for (const topic
|
|
151
|
+
for (const topic of getTopicTypeForClientType(this.clientType)) {
|
|
137
152
|
this.subscribeToTopic(TopicTypeMap[topic].p2pTopic);
|
|
138
153
|
}
|
|
139
154
|
|
|
155
|
+
// Add p2p topic validators
|
|
156
|
+
this.node.services.pubsub.topicValidators.set(Tx.p2pTopic, this.validatePropagatedTxFromMessage.bind(this));
|
|
157
|
+
|
|
140
158
|
// add GossipSub listener
|
|
141
159
|
this.node.services.pubsub.addEventListener('gossipsub:message', async e => {
|
|
142
|
-
const { msg
|
|
160
|
+
const { msg } = e.detail;
|
|
143
161
|
this.logger.trace(`Received PUBSUB message.`);
|
|
144
162
|
|
|
145
|
-
await this.jobQueue.put(() => this.handleNewGossipMessage(msg
|
|
163
|
+
await this.jobQueue.put(() => this.handleNewGossipMessage(msg));
|
|
146
164
|
});
|
|
147
165
|
|
|
148
166
|
// Start running promise for peer discovery
|
|
149
|
-
this.discoveryRunningPromise = new RunningPromise(
|
|
150
|
-
this.peerManager.heartbeat()
|
|
151
|
-
|
|
167
|
+
this.discoveryRunningPromise = new RunningPromise(
|
|
168
|
+
() => this.peerManager.heartbeat(),
|
|
169
|
+
this.logger,
|
|
170
|
+
this.config.peerCheckIntervalMS,
|
|
171
|
+
);
|
|
152
172
|
this.discoveryRunningPromise.start();
|
|
153
173
|
|
|
154
174
|
// Define the sub protocol validators - This is done within this start() method to gain a callback to the existing validateTx function
|
|
@@ -157,6 +177,11 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
157
177
|
[TX_REQ_PROTOCOL]: this.validateRequestedTx.bind(this),
|
|
158
178
|
};
|
|
159
179
|
await this.reqresp.start(this.requestResponseHandlers, reqrespSubProtocolValidators);
|
|
180
|
+
this.logger.info(`Started P2P service`, {
|
|
181
|
+
listen: tcpListenAddress,
|
|
182
|
+
announce: announceTcpMultiaddr,
|
|
183
|
+
peerId: this.node.peerId.toString(),
|
|
184
|
+
});
|
|
160
185
|
}
|
|
161
186
|
|
|
162
187
|
/**
|
|
@@ -175,7 +200,6 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
175
200
|
this.logger.debug('Stopping LibP2P...');
|
|
176
201
|
await this.stopLibP2P();
|
|
177
202
|
this.logger.info('LibP2P service stopped');
|
|
178
|
-
this.logger.debug('Stopping request response service...');
|
|
179
203
|
}
|
|
180
204
|
|
|
181
205
|
/**
|
|
@@ -184,11 +208,12 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
184
208
|
* @param txPool - The transaction pool to be accessed by the service.
|
|
185
209
|
* @returns The new service.
|
|
186
210
|
*/
|
|
187
|
-
public static async new(
|
|
211
|
+
public static async new<T extends P2PClientType>(
|
|
212
|
+
clientType: T,
|
|
188
213
|
config: P2PConfig,
|
|
189
214
|
peerDiscoveryService: PeerDiscoveryService,
|
|
190
215
|
peerId: PeerId,
|
|
191
|
-
mempools: MemPools
|
|
216
|
+
mempools: MemPools<T>,
|
|
192
217
|
l2BlockSource: L2BlockSource,
|
|
193
218
|
proofVerifier: ClientProtocolCircuitVerifier,
|
|
194
219
|
worldStateSynchronizer: WorldStateSynchronizer,
|
|
@@ -249,6 +274,7 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
249
274
|
dataTransform: new SnappyTransform(),
|
|
250
275
|
metricsRegister: otelMetricsAdapter,
|
|
251
276
|
metricsTopicStrToLabel: metricsTopicStrToLabels(),
|
|
277
|
+
asyncValidation: true,
|
|
252
278
|
scoreParams: createPeerScoreParams({
|
|
253
279
|
topics: {
|
|
254
280
|
[Tx.p2pTopic]: createTopicScoreParams({
|
|
@@ -297,6 +323,7 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
297
323
|
};
|
|
298
324
|
|
|
299
325
|
return new LibP2PService(
|
|
326
|
+
clientType,
|
|
300
327
|
config,
|
|
301
328
|
node,
|
|
302
329
|
peerDiscoveryService,
|
|
@@ -309,6 +336,10 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
309
336
|
);
|
|
310
337
|
}
|
|
311
338
|
|
|
339
|
+
public getPeers(includePending?: boolean): PeerInfo[] {
|
|
340
|
+
return this.peerManager.getPeers(includePending);
|
|
341
|
+
}
|
|
342
|
+
|
|
312
343
|
/**
|
|
313
344
|
* Send Request via the ReqResp service
|
|
314
345
|
* The subprotocol defined will determine the request and response types
|
|
@@ -370,12 +401,12 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
370
401
|
* @param topic - The message's topic.
|
|
371
402
|
* @param data - The message data
|
|
372
403
|
*/
|
|
373
|
-
private async handleNewGossipMessage(message: RawGossipMessage
|
|
404
|
+
private async handleNewGossipMessage(message: RawGossipMessage) {
|
|
374
405
|
if (message.topic === Tx.p2pTopic) {
|
|
375
406
|
const tx = Tx.fromBuffer(Buffer.from(message.data));
|
|
376
|
-
await this.processTxFromPeer(tx
|
|
407
|
+
await this.processTxFromPeer(tx);
|
|
377
408
|
}
|
|
378
|
-
if (message.topic === BlockAttestation.p2pTopic) {
|
|
409
|
+
if (message.topic === BlockAttestation.p2pTopic && this.clientType === P2PClientType.Full) {
|
|
379
410
|
const attestation = BlockAttestation.fromBuffer(Buffer.from(message.data));
|
|
380
411
|
await this.processAttestationFromPeer(attestation);
|
|
381
412
|
}
|
|
@@ -404,7 +435,7 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
404
435
|
}))
|
|
405
436
|
private async processAttestationFromPeer(attestation: BlockAttestation): Promise<void> {
|
|
406
437
|
this.logger.debug(`Received attestation ${attestation.p2pMessageIdentifier()} from external peer.`);
|
|
407
|
-
await this.mempools.attestationPool
|
|
438
|
+
await this.mempools.attestationPool!.addAttestations([attestation]);
|
|
408
439
|
}
|
|
409
440
|
|
|
410
441
|
/**Process block from peer
|
|
@@ -462,16 +493,11 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
462
493
|
});
|
|
463
494
|
}
|
|
464
495
|
|
|
465
|
-
private async processTxFromPeer(tx: Tx
|
|
496
|
+
private async processTxFromPeer(tx: Tx): Promise<void> {
|
|
466
497
|
const txHash = tx.getTxHash();
|
|
467
498
|
const txHashString = txHash.toString();
|
|
468
499
|
this.logger.verbose(`Received tx ${txHashString} from external peer.`);
|
|
469
|
-
|
|
470
|
-
const isValidTx = await this.validatePropagatedTx(tx, peerId);
|
|
471
|
-
|
|
472
|
-
if (isValidTx) {
|
|
473
|
-
await this.mempools.txPool.addTxs([tx]);
|
|
474
|
-
}
|
|
500
|
+
await this.mempools.txPool.addTxs([tx]);
|
|
475
501
|
}
|
|
476
502
|
|
|
477
503
|
/**
|
|
@@ -488,6 +514,9 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
488
514
|
* @param peerId - The peer ID of the peer that sent the tx.
|
|
489
515
|
* @returns True if the tx is valid, false otherwise.
|
|
490
516
|
*/
|
|
517
|
+
@trackSpan('Libp2pService.validateRequestedTx', (requestedTxHash, _responseTx) => ({
|
|
518
|
+
[Attributes.TX_HASH]: requestedTxHash.toString(),
|
|
519
|
+
}))
|
|
491
520
|
private async validateRequestedTx(requestedTxHash: TxHash, responseTx: Tx, peerId: PeerId): Promise<boolean> {
|
|
492
521
|
const proofValidator = new TxProofValidator(this.proofVerifier);
|
|
493
522
|
const validProof = await proofValidator.validateTx(responseTx);
|
|
@@ -508,67 +537,150 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
508
537
|
return true;
|
|
509
538
|
}
|
|
510
539
|
|
|
540
|
+
private async validatePropagatedTxFromMessage(
|
|
541
|
+
propagationSource: PeerId,
|
|
542
|
+
msg: Message,
|
|
543
|
+
): Promise<TopicValidatorResult> {
|
|
544
|
+
const tx = Tx.fromBuffer(Buffer.from(msg.data));
|
|
545
|
+
const isValid = await this.validatePropagatedTx(tx, propagationSource);
|
|
546
|
+
this.logger.trace(`validatePropagatedTx: ${isValid}`, {
|
|
547
|
+
[Attributes.TX_HASH]: tx.getTxHash().toString(),
|
|
548
|
+
[Attributes.P2P_ID]: propagationSource.toString(),
|
|
549
|
+
});
|
|
550
|
+
return isValid ? TopicValidatorResult.Accept : TopicValidatorResult.Reject;
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
/**
|
|
554
|
+
* Validate a tx that has been propagated from a peer.
|
|
555
|
+
* @param tx - The tx to validate.
|
|
556
|
+
* @param peerId - The peer ID of the peer that sent the tx.
|
|
557
|
+
* @returns True if the tx is valid, false otherwise.
|
|
558
|
+
*/
|
|
559
|
+
@trackSpan('Libp2pService.validatePropagatedTx', tx => ({
|
|
560
|
+
[Attributes.TX_HASH]: tx.getTxHash().toString(),
|
|
561
|
+
}))
|
|
511
562
|
private async validatePropagatedTx(tx: Tx, peerId: PeerId): Promise<boolean> {
|
|
512
563
|
const blockNumber = (await this.l2BlockSource.getBlockNumber()) + 1;
|
|
513
|
-
|
|
514
|
-
const
|
|
515
|
-
|
|
516
|
-
if (
|
|
517
|
-
|
|
518
|
-
this.node.services.pubsub.score.markInvalidMessageDelivery(peerId.toString(), Tx.p2pTopic);
|
|
519
|
-
return false;
|
|
564
|
+
const messageValidators = this.createMessageValidators(blockNumber);
|
|
565
|
+
const outcome = await this.runValidations(tx, messageValidators);
|
|
566
|
+
|
|
567
|
+
if (outcome.allPassed) {
|
|
568
|
+
return true;
|
|
520
569
|
}
|
|
521
570
|
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
if (
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
571
|
+
const { name, severity } = outcome.failure;
|
|
572
|
+
|
|
573
|
+
// Double spend validator has a special case handler
|
|
574
|
+
if (name === 'doubleSpendValidator') {
|
|
575
|
+
const isValid = await this.handleDoubleSpendFailure(tx, blockNumber, peerId);
|
|
576
|
+
if (isValid) {
|
|
577
|
+
return true;
|
|
578
|
+
}
|
|
529
579
|
}
|
|
530
580
|
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
581
|
+
this.peerManager.penalizePeer(peerId, severity);
|
|
582
|
+
return false;
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
/**
|
|
586
|
+
* Create message validators for the given block number.
|
|
587
|
+
*
|
|
588
|
+
* Each validator is a pair of a validator and a severity.
|
|
589
|
+
* If a validator fails, the peer is penalized with the severity of the validator.
|
|
590
|
+
*
|
|
591
|
+
* @param blockNumber - The block number to create validators for.
|
|
592
|
+
* @returns The message validators.
|
|
593
|
+
*/
|
|
594
|
+
private createMessageValidators(blockNumber: number): Record<string, MessageValidator> {
|
|
595
|
+
return {
|
|
596
|
+
dataValidator: {
|
|
597
|
+
validator: new DataTxValidator(),
|
|
598
|
+
severity: PeerErrorSeverity.HighToleranceError,
|
|
537
599
|
},
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
600
|
+
metadataValidator: {
|
|
601
|
+
validator: new MetadataTxValidator(new Fr(this.config.l1ChainId), new Fr(blockNumber)),
|
|
602
|
+
severity: PeerErrorSeverity.HighToleranceError,
|
|
603
|
+
},
|
|
604
|
+
proofValidator: {
|
|
605
|
+
validator: new TxProofValidator(this.proofVerifier),
|
|
606
|
+
severity: PeerErrorSeverity.MidToleranceError,
|
|
607
|
+
},
|
|
608
|
+
doubleSpendValidator: {
|
|
609
|
+
validator: new DoubleSpendTxValidator({
|
|
610
|
+
getNullifierIndices: (nullifiers: Buffer[]) => {
|
|
611
|
+
const merkleTree = this.worldStateSynchronizer.getCommitted();
|
|
612
|
+
return merkleTree.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, nullifiers);
|
|
550
613
|
},
|
|
551
|
-
})
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
614
|
+
}),
|
|
615
|
+
severity: PeerErrorSeverity.HighToleranceError,
|
|
616
|
+
},
|
|
617
|
+
};
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
/**
|
|
621
|
+
* Run validations on a tx.
|
|
622
|
+
* @param tx - The tx to validate.
|
|
623
|
+
* @param messageValidators - The message validators to run.
|
|
624
|
+
* @returns The validation outcome.
|
|
625
|
+
*/
|
|
626
|
+
private async runValidations(
|
|
627
|
+
tx: Tx,
|
|
628
|
+
messageValidators: Record<string, MessageValidator>,
|
|
629
|
+
): Promise<ValidationOutcome> {
|
|
630
|
+
const validationPromises = Object.entries(messageValidators).map(async ([name, { validator, severity }]) => {
|
|
631
|
+
const isValid = await validator.validateTx(tx);
|
|
632
|
+
return { name, isValid, severity };
|
|
633
|
+
});
|
|
634
|
+
|
|
635
|
+
// A promise that resolves when all validations have been run
|
|
636
|
+
const allValidations = Promise.all(validationPromises);
|
|
637
|
+
|
|
638
|
+
// A promise that resolves when the first validation fails
|
|
639
|
+
const firstFailure = Promise.race(
|
|
640
|
+
validationPromises.map(async promise => {
|
|
641
|
+
const result = await promise;
|
|
642
|
+
return result.isValid ? new Promise(() => {}) : result;
|
|
643
|
+
}),
|
|
644
|
+
);
|
|
645
|
+
|
|
646
|
+
// Wait for the first validation to fail or all validations to pass
|
|
647
|
+
const result = await Promise.race([
|
|
648
|
+
allValidations.then(() => ({ allPassed: true as const })),
|
|
649
|
+
firstFailure.then(failure => ({ allPassed: false as const, failure: failure as ValidationResult })),
|
|
650
|
+
]);
|
|
651
|
+
|
|
652
|
+
// If all validations pass, allPassed will be true, if failed, then the failure will be the first validation to fail
|
|
653
|
+
return result;
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
/**
|
|
657
|
+
* Handle a double spend failure.
|
|
658
|
+
*
|
|
659
|
+
* Double spend failures are managed on their own because they are a special case.
|
|
660
|
+
* We must check if the double spend is recent or old, if it is past a threshold, then we heavily penalize the peer.
|
|
661
|
+
*
|
|
662
|
+
* @param tx - The tx that failed the double spend validator.
|
|
663
|
+
* @param blockNumber - The block number of the tx.
|
|
664
|
+
* @param peerId - The peer ID of the peer that sent the tx.
|
|
665
|
+
* @returns True if the tx is valid, false otherwise.
|
|
666
|
+
*/
|
|
667
|
+
private async handleDoubleSpendFailure(tx: Tx, blockNumber: number, peerId: PeerId): Promise<boolean> {
|
|
668
|
+
if (blockNumber <= this.config.severePeerPenaltyBlockLength) {
|
|
563
669
|
return false;
|
|
564
670
|
}
|
|
565
671
|
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
672
|
+
const snapshotValidator = new DoubleSpendTxValidator({
|
|
673
|
+
getNullifierIndices: (nullifiers: Buffer[]) => {
|
|
674
|
+
const merkleTree = this.worldStateSynchronizer.getSnapshot(
|
|
675
|
+
blockNumber - this.config.severePeerPenaltyBlockLength,
|
|
676
|
+
);
|
|
677
|
+
return merkleTree.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, nullifiers);
|
|
678
|
+
},
|
|
679
|
+
});
|
|
680
|
+
|
|
681
|
+
const validSnapshot = await snapshotValidator.validateTx(tx);
|
|
682
|
+
if (!validSnapshot) {
|
|
683
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
|
|
572
684
|
return false;
|
|
573
685
|
}
|
|
574
686
|
|
|
@@ -583,10 +695,10 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
583
695
|
const parent = message.constructor as typeof Gossipable;
|
|
584
696
|
|
|
585
697
|
const identifier = message.p2pMessageIdentifier().toString();
|
|
586
|
-
this.logger.
|
|
698
|
+
this.logger.trace(`Sending message ${identifier}`);
|
|
587
699
|
|
|
588
700
|
const recipientsNum = await this.publishToTopic(parent.p2pTopic, message.toBuffer());
|
|
589
|
-
this.logger.
|
|
701
|
+
this.logger.debug(`Sent message ${identifier} to ${recipientsNum} peers`);
|
|
590
702
|
}
|
|
591
703
|
|
|
592
704
|
// Libp2p seems to hang sometimes if new peers are initiating connections.
|
|
@@ -597,7 +709,7 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
597
709
|
});
|
|
598
710
|
try {
|
|
599
711
|
await Promise.race([this.node.stop(), timeout]);
|
|
600
|
-
this.logger.debug('
|
|
712
|
+
this.logger.debug('LibP2P stopped');
|
|
601
713
|
} catch (error) {
|
|
602
714
|
this.logger.error('Error during stop or timeout:', error);
|
|
603
715
|
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { median } from '@aztec/foundation/collection';
|
|
2
|
+
|
|
3
|
+
import { type P2PConfig } from '../../config.js';
|
|
2
4
|
|
|
3
5
|
export enum PeerErrorSeverity {
|
|
4
6
|
/**
|
|
@@ -43,7 +45,7 @@ export class PeerScoring {
|
|
|
43
45
|
};
|
|
44
46
|
}
|
|
45
47
|
|
|
46
|
-
updateScore(peerId: string, scoreDelta: number):
|
|
48
|
+
updateScore(peerId: string, scoreDelta: number): number {
|
|
47
49
|
const currentTime = Date.now();
|
|
48
50
|
const lastUpdate = this.lastUpdateTime.get(peerId) || currentTime;
|
|
49
51
|
const timePassed = currentTime - lastUpdate;
|
|
@@ -59,6 +61,7 @@ export class PeerScoring {
|
|
|
59
61
|
|
|
60
62
|
this.scores.set(peerId, currentScore);
|
|
61
63
|
this.lastUpdateTime.set(peerId, currentTime);
|
|
64
|
+
return currentScore;
|
|
62
65
|
}
|
|
63
66
|
|
|
64
67
|
decayAllScores(): void {
|
|
@@ -78,4 +81,8 @@ export class PeerScoring {
|
|
|
78
81
|
getScore(peerId: string): number {
|
|
79
82
|
return this.scores.get(peerId) || 0;
|
|
80
83
|
}
|
|
84
|
+
|
|
85
|
+
getStats(): { medianScore: number } {
|
|
86
|
+
return { medianScore: median(Array.from(this.scores.values())) ?? 0 };
|
|
87
|
+
}
|
|
81
88
|
}
|