@aztec/p2p 0.87.5 → 0.87.7
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/client/interface.d.ts +8 -4
- package/dest/client/interface.d.ts.map +1 -1
- package/dest/client/p2p_client.d.ts +4 -3
- package/dest/client/p2p_client.d.ts.map +1 -1
- package/dest/client/p2p_client.js +17 -10
- package/dest/config.d.ts +10 -0
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +12 -2
- package/dest/index.d.ts +1 -0
- package/dest/index.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts +5 -6
- 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 +37 -12
- package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts +2 -2
- package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/memory_tx_pool.js +1 -3
- package/dest/mem_pools/tx_pool/tx_pool.d.ts +6 -1
- package/dest/mem_pools/tx_pool/tx_pool.d.ts.map +1 -1
- package/dest/msg_validators/msg_seen_validator/msg_seen_validator.d.ts +10 -0
- package/dest/msg_validators/msg_seen_validator/msg_seen_validator.d.ts.map +1 -0
- package/dest/msg_validators/msg_seen_validator/msg_seen_validator.js +36 -0
- package/dest/services/dummy_service.d.ts +1 -1
- package/dest/services/dummy_service.d.ts.map +1 -1
- package/dest/services/dummy_service.js +1 -1
- package/dest/services/index.d.ts +1 -0
- package/dest/services/index.d.ts.map +1 -1
- package/dest/services/index.js +1 -0
- package/dest/services/libp2p/instrumentation.d.ts +11 -0
- package/dest/services/libp2p/instrumentation.d.ts.map +1 -0
- package/dest/services/libp2p/instrumentation.js +29 -0
- package/dest/services/libp2p/libp2p_service.d.ts +8 -5
- package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
- package/dest/services/libp2p/libp2p_service.js +59 -12
- package/dest/services/reqresp/connection-sampler/batch_connection_sampler.d.ts +1 -1
- package/dest/services/reqresp/connection-sampler/batch_connection_sampler.d.ts.map +1 -1
- package/dest/services/reqresp/connection-sampler/batch_connection_sampler.js +7 -3
- package/dest/services/reqresp/connection-sampler/connection_sampler.d.ts +2 -1
- package/dest/services/reqresp/connection-sampler/connection_sampler.d.ts.map +1 -1
- package/dest/services/reqresp/connection-sampler/connection_sampler.js +8 -3
- package/dest/services/reqresp/protocols/goodbye.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/goodbye.js +3 -1
- package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts +4 -2
- package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts.map +1 -1
- package/dest/services/reqresp/rate-limiter/rate_limiter.js +10 -2
- package/dest/services/reqresp/rate-limiter/rate_limits.js +1 -1
- package/dest/services/reqresp/reqresp.d.ts +3 -3
- package/dest/services/reqresp/reqresp.d.ts.map +1 -1
- package/dest/services/reqresp/reqresp.js +39 -13
- package/dest/services/service.d.ts +3 -2
- package/dest/services/service.d.ts.map +1 -1
- package/dest/services/tx_collector.d.ts +14 -0
- package/dest/services/tx_collector.d.ts.map +1 -0
- package/dest/services/tx_collector.js +76 -0
- package/dest/test-helpers/reqresp-nodes.d.ts +3 -3
- package/dest/test-helpers/reqresp-nodes.d.ts.map +1 -1
- package/dest/test-helpers/reqresp-nodes.js +4 -4
- package/dest/testbench/p2p_client_testbench_worker.js +1 -1
- package/package.json +12 -12
- package/src/client/interface.ts +8 -4
- package/src/client/p2p_client.ts +22 -10
- package/src/config.ts +22 -1
- package/src/index.ts +2 -0
- package/src/mem_pools/tx_pool/aztec_kv_tx_pool.ts +45 -18
- package/src/mem_pools/tx_pool/memory_tx_pool.ts +2 -4
- package/src/mem_pools/tx_pool/tx_pool.ts +7 -1
- package/src/msg_validators/msg_seen_validator/msg_seen_validator.ts +36 -0
- package/src/services/dummy_service.ts +3 -1
- package/src/services/index.ts +1 -0
- package/src/services/libp2p/instrumentation.ts +39 -0
- package/src/services/libp2p/libp2p_service.ts +79 -11
- package/src/services/reqresp/connection-sampler/batch_connection_sampler.ts +4 -2
- package/src/services/reqresp/connection-sampler/connection_sampler.ts +8 -3
- package/src/services/reqresp/protocols/goodbye.ts +3 -1
- package/src/services/reqresp/rate-limiter/rate_limiter.ts +9 -3
- package/src/services/reqresp/rate-limiter/rate_limits.ts +1 -1
- package/src/services/reqresp/reqresp.ts +44 -16
- package/src/services/service.ts +4 -1
- package/src/services/tx_collector.ts +103 -0
- package/src/test-helpers/reqresp-nodes.ts +13 -8
- package/src/testbench/p2p_client_testbench_worker.ts +1 -1
|
@@ -5,6 +5,7 @@ function _ts_decorate(decorators, target, key, desc) {
|
|
|
5
5
|
else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
6
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
7
|
}
|
|
8
|
+
import { compactArray } from '@aztec/foundation/collection';
|
|
8
9
|
import { createLogger } from '@aztec/foundation/log';
|
|
9
10
|
import { executeTimeout } from '@aztec/foundation/timer';
|
|
10
11
|
import { PeerErrorSeverity } from '@aztec/stdlib/p2p';
|
|
@@ -44,7 +45,7 @@ import { ReqRespStatus, ReqRespStatusError, parseStatusChunk, prettyPrintReqResp
|
|
|
44
45
|
rateLimiter;
|
|
45
46
|
snappyTransform;
|
|
46
47
|
metrics;
|
|
47
|
-
constructor(config, libp2p, peerScoring, telemetryClient = getTelemetryClient()){
|
|
48
|
+
constructor(config, libp2p, peerScoring, rateLimits = {}, telemetryClient = getTelemetryClient()){
|
|
48
49
|
this.libp2p = libp2p;
|
|
49
50
|
this.peerScoring = peerScoring;
|
|
50
51
|
this.subProtocolHandlers = DEFAULT_SUB_PROTOCOL_HANDLERS;
|
|
@@ -52,7 +53,7 @@ import { ReqRespStatus, ReqRespStatusError, parseStatusChunk, prettyPrintReqResp
|
|
|
52
53
|
this.logger = createLogger('p2p:reqresp');
|
|
53
54
|
this.overallRequestTimeoutMs = config.overallRequestTimeoutMs;
|
|
54
55
|
this.individualRequestTimeoutMs = config.individualRequestTimeoutMs;
|
|
55
|
-
this.rateLimiter = new RequestResponseRateLimiter(peerScoring);
|
|
56
|
+
this.rateLimiter = new RequestResponseRateLimiter(peerScoring, rateLimits);
|
|
56
57
|
// Connection sampler is used to sample our connected peers
|
|
57
58
|
this.connectionSampler = new ConnectionSampler(libp2p);
|
|
58
59
|
this.snappyTransform = new SnappyTransform();
|
|
@@ -185,7 +186,7 @@ import { ReqRespStatus, ReqRespStatusError, parseStatusChunk, prettyPrintReqResp
|
|
|
185
186
|
* @returns
|
|
186
187
|
*
|
|
187
188
|
* @throws {CollectiveReqRespTimeoutError} - If the request batch exceeds the specified timeout (`timeoutMs`).
|
|
188
|
-
*/ async sendBatchRequest(subProtocol, requests, timeoutMs = 10000, maxPeers = Math.max(10, Math.ceil(requests.length / 3)), maxRetryAttempts = 3) {
|
|
189
|
+
*/ async sendBatchRequest(subProtocol, requests, pinnedPeer, timeoutMs = 10000, maxPeers = Math.max(10, Math.ceil(requests.length / 3)), maxRetryAttempts = 3) {
|
|
189
190
|
const responseValidator = this.subProtocolValidators[subProtocol];
|
|
190
191
|
const responses = new Array(requests.length);
|
|
191
192
|
const requestBuffers = requests.map((req)=>req.toBuffer());
|
|
@@ -193,9 +194,11 @@ import { ReqRespStatus, ReqRespStatusError, parseStatusChunk, prettyPrintReqResp
|
|
|
193
194
|
// Track which requests still need to be processed
|
|
194
195
|
const pendingRequestIndices = new Set(requestBuffers.map((_, i)=>i));
|
|
195
196
|
// Create batch sampler with the total number of requests and max peers
|
|
196
|
-
const batchSampler = new BatchConnectionSampler(this.connectionSampler, requests.length, maxPeers
|
|
197
|
-
|
|
198
|
-
|
|
197
|
+
const batchSampler = new BatchConnectionSampler(this.connectionSampler, requests.length, maxPeers, compactArray([
|
|
198
|
+
pinnedPeer
|
|
199
|
+
]));
|
|
200
|
+
if (batchSampler.activePeerCount === 0 && !pinnedPeer) {
|
|
201
|
+
this.logger.warn('No active peers to send requests to');
|
|
199
202
|
return [];
|
|
200
203
|
}
|
|
201
204
|
// This is where it gets fun
|
|
@@ -222,6 +225,15 @@ import { ReqRespStatus, ReqRespStatusError, parseStatusChunk, prettyPrintReqResp
|
|
|
222
225
|
}
|
|
223
226
|
requestBatches.get(peerAsString).indices.push(requestIndex);
|
|
224
227
|
}
|
|
228
|
+
// If there is a pinned peer, we will always send every request to that peer
|
|
229
|
+
// We use the default limits for the subprotocol to avoid hitting the rate limiter
|
|
230
|
+
if (pinnedPeer) {
|
|
231
|
+
const limit = this.rateLimiter.getRateLimits(subProtocol).peerLimit.quotaCount;
|
|
232
|
+
requestBatches.set(pinnedPeer.toString(), {
|
|
233
|
+
peerId: pinnedPeer,
|
|
234
|
+
indices: Array.from(pendingRequestIndices.values()).slice(0, limit)
|
|
235
|
+
});
|
|
236
|
+
}
|
|
225
237
|
// Make parallel requests for each peer's batch
|
|
226
238
|
// A batch entry will look something like this:
|
|
227
239
|
// PeerId0: [0, 1, 2, 3]
|
|
@@ -233,6 +245,7 @@ import { ReqRespStatus, ReqRespStatusError, parseStatusChunk, prettyPrintReqResp
|
|
|
233
245
|
// Requests all going to the same peer are sent synchronously
|
|
234
246
|
const peerResults = [];
|
|
235
247
|
for (const index of indices){
|
|
248
|
+
this.logger.trace(`Sending request ${index} to peer ${peerAsString}`);
|
|
236
249
|
const response = await this.sendRequestToPeer(peer, subProtocol, requestBuffers[index]);
|
|
237
250
|
// Check the status of the response buffer
|
|
238
251
|
if (response.status !== ReqRespStatus.SUCCESS) {
|
|
@@ -468,8 +481,9 @@ import { ReqRespStatus, ReqRespStatusError, parseStatusChunk, prettyPrintReqResp
|
|
|
468
481
|
const msg = Buffer.from(chunkList.subarray());
|
|
469
482
|
const response = await handler(connection.remotePeer, msg);
|
|
470
483
|
if (protocol === ReqRespSubProtocol.GOODBYE) {
|
|
484
|
+
// NOTE: The stream was already closed by Goodbye handler
|
|
485
|
+
// peerManager.goodbyeReceived(peerId, reason); will call libp2p.hangUp closing all active streams and connections
|
|
471
486
|
// Don't respond
|
|
472
|
-
await stream.close();
|
|
473
487
|
return;
|
|
474
488
|
}
|
|
475
489
|
// Send success code first, then the response
|
|
@@ -488,13 +502,25 @@ import { ReqRespStatus, ReqRespStatusError, parseStatusChunk, prettyPrintReqResp
|
|
|
488
502
|
if (e instanceof ReqRespStatusError) {
|
|
489
503
|
errorStatus = e.status;
|
|
490
504
|
}
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
505
|
+
if (stream.status === 'open') {
|
|
506
|
+
const sendErrorChunk = this.sendErrorChunk(errorStatus);
|
|
507
|
+
// Return and yield the response chunk
|
|
508
|
+
await pipe(stream, async function*(_source) {
|
|
509
|
+
yield* sendErrorChunk;
|
|
510
|
+
}, stream);
|
|
511
|
+
} else {
|
|
512
|
+
this.logger.debug('Stream already closed, not sending error response', {
|
|
513
|
+
protocol,
|
|
514
|
+
err: e,
|
|
515
|
+
errorStatus
|
|
516
|
+
});
|
|
517
|
+
}
|
|
496
518
|
} finally{
|
|
497
|
-
|
|
519
|
+
//NOTE: All other status codes indicate closed stream.
|
|
520
|
+
//Either graceful close (closed/closing) or forced close (aborted/reset)
|
|
521
|
+
if (stream.status === 'open') {
|
|
522
|
+
await stream.close();
|
|
523
|
+
}
|
|
498
524
|
}
|
|
499
525
|
}
|
|
500
526
|
async *sendErrorChunk(error) {
|
|
@@ -9,6 +9,7 @@ export declare enum PeerDiscoveryState {
|
|
|
9
9
|
RUNNING = "running",
|
|
10
10
|
STOPPED = "stopped"
|
|
11
11
|
}
|
|
12
|
+
export type P2PBlockReceivedCallback = (block: BlockProposal, sender: PeerId) => Promise<BlockAttestation | undefined>;
|
|
12
13
|
/**
|
|
13
14
|
* The interface for a P2P service implementation.
|
|
14
15
|
*/
|
|
@@ -43,8 +44,8 @@ export interface P2PService {
|
|
|
43
44
|
* @param requests - The requests to send to the peers
|
|
44
45
|
* @returns The responses to the requests
|
|
45
46
|
*/
|
|
46
|
-
sendBatchRequest<Protocol extends ReqRespSubProtocol>(protocol: Protocol, requests: InstanceType<SubProtocolMap[Protocol]['request']>[], timeoutMs?: number, maxPeers?: number, maxRetryAttempts?: number): Promise<(InstanceType<SubProtocolMap[Protocol]['response']> | undefined)[]>;
|
|
47
|
-
registerBlockReceivedCallback(callback:
|
|
47
|
+
sendBatchRequest<Protocol extends ReqRespSubProtocol>(protocol: Protocol, requests: InstanceType<SubProtocolMap[Protocol]['request']>[], pinnedPeerId?: PeerId, timeoutMs?: number, maxPeers?: number, maxRetryAttempts?: number): Promise<(InstanceType<SubProtocolMap[Protocol]['response']> | undefined)[]>;
|
|
48
|
+
registerBlockReceivedCallback(callback: P2PBlockReceivedCallback): void;
|
|
48
49
|
getEnr(): ENR | undefined;
|
|
49
50
|
getPeers(includePending?: boolean): PeerInfo[];
|
|
50
51
|
validate(txs: Tx[]): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/services/service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iCAAiC,CAAC;AAChE,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACrF,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AAE3C,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,YAAY,MAAM,QAAQ,CAAC;AAEvC,OAAO,KAAK,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAEjF,oBAAY,kBAAkB;IAC5B,OAAO,YAAY;IACnB,OAAO,YAAY;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB;;;OAGG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvB;;;OAGG;IACH,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEtB;;;OAGG;IACH,SAAS,CAAC,CAAC,SAAS,UAAU,EAAE,OAAO,EAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE3D;;;;;;OAMG;IACH,WAAW,CAAC,QAAQ,SAAS,kBAAkB,EAC7C,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,YAAY,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC,GACzD,OAAO,CAAC,YAAY,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;IAE3E;;;;;;OAMG;IACH,gBAAgB,CAAC,QAAQ,SAAS,kBAAkB,EAClD,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,YAAY,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,EAC7D,SAAS,CAAC,EAAE,MAAM,EAClB,QAAQ,CAAC,EAAE,MAAM,EACjB,gBAAgB,CAAC,EAAE,MAAM,GACxB,OAAO,CAAC,CAAC,YAAY,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC,CAAC,GAAG,SAAS,CAAC,EAAE,CAAC,CAAC;IAG/E,6BAA6B,CAAC,QAAQ,EAAE,
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/services/service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type Logger } from '@aztec/foundation/log';
|
|
2
|
+
import type { BlockProposal } from '@aztec/stdlib/p2p';
|
|
3
|
+
import type { Tx, TxHash } from '@aztec/stdlib/tx';
|
|
4
|
+
import type { P2PClient } from '../client/p2p_client.js';
|
|
5
|
+
export declare class TxCollector {
|
|
6
|
+
private p2pClient;
|
|
7
|
+
private log;
|
|
8
|
+
constructor(p2pClient: Pick<P2PClient, 'getTxsByHashFromPool' | 'hasTxsInPool' | 'getTxsByHash' | 'validate' | 'requestTxsByHash'>, log?: Logger);
|
|
9
|
+
collectForBlockProposal(proposal: BlockProposal, peerWhoSentTheProposal: any): Promise<{
|
|
10
|
+
txs: Tx[];
|
|
11
|
+
missing?: TxHash[];
|
|
12
|
+
}>;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=tx_collector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tx_collector.d.ts","sourceRoot":"","sources":["../../src/services/tx_collector.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,MAAM,EAAgB,MAAM,uBAAuB,CAAC;AAClE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAEnD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAEzD,qBAAa,WAAW;IAEpB,OAAO,CAAC,SAAS;IAIjB,OAAO,CAAC,GAAG;gBAJH,SAAS,EAAE,IAAI,CACrB,SAAS,EACT,sBAAsB,GAAG,cAAc,GAAG,cAAc,GAAG,UAAU,GAAG,kBAAkB,CAC3F,EACO,GAAG,GAAE,MAAyC;IAGlD,uBAAuB,CAC3B,QAAQ,EAAE,aAAa,EACvB,sBAAsB,EAAE,GAAG,GAC1B,OAAO,CAAC;QAAE,GAAG,EAAE,EAAE,EAAE,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;CAmF9C"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { compactArray } from '@aztec/foundation/collection';
|
|
2
|
+
import { createLogger } from '@aztec/foundation/log';
|
|
3
|
+
export class TxCollector {
|
|
4
|
+
p2pClient;
|
|
5
|
+
log;
|
|
6
|
+
constructor(p2pClient, log = createLogger('p2p:tx-collector')){
|
|
7
|
+
this.p2pClient = p2pClient;
|
|
8
|
+
this.log = log;
|
|
9
|
+
}
|
|
10
|
+
async collectForBlockProposal(proposal, peerWhoSentTheProposal) {
|
|
11
|
+
if (proposal.payload.txHashes.length === 0) {
|
|
12
|
+
this.log.verbose(`Received block proposal with no transactions, skipping transaction availability check`);
|
|
13
|
+
return {
|
|
14
|
+
txs: []
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
// Is this a new style proposal?
|
|
18
|
+
if (proposal.txs && proposal.txs.length > 0 && proposal.txs.length === proposal.payload.txHashes.length) {
|
|
19
|
+
// Yes, any txs that we already have we should use
|
|
20
|
+
this.log.info(`Using new style proposal with ${proposal.txs.length} transactions`);
|
|
21
|
+
// Request from the pool based on the signed hashes in the payload
|
|
22
|
+
const hashesFromPayload = proposal.payload.txHashes;
|
|
23
|
+
const txsToUse = await this.p2pClient.getTxsByHashFromPool(hashesFromPayload);
|
|
24
|
+
const missingTxs = txsToUse.filter((tx)=>tx === undefined).length;
|
|
25
|
+
if (missingTxs > 0) {
|
|
26
|
+
this.log.verbose(`Missing ${missingTxs}/${hashesFromPayload.length} transactions in the tx pool, will attempt to take from the proposal`);
|
|
27
|
+
}
|
|
28
|
+
let usedFromProposal = 0;
|
|
29
|
+
// Fill any holes with txs in the proposal, provided their hash matches the hash in the payload
|
|
30
|
+
for(let i = 0; i < txsToUse.length; i++){
|
|
31
|
+
if (txsToUse[i] === undefined) {
|
|
32
|
+
// We don't have the transaction, take from the proposal, provided the hash is the same
|
|
33
|
+
const hashOfTxInProposal = await proposal.txs[i].getTxHash();
|
|
34
|
+
if (hashOfTxInProposal.equals(hashesFromPayload[i])) {
|
|
35
|
+
// Hash is equal, we can use the tx from the proposal
|
|
36
|
+
txsToUse[i] = proposal.txs[i];
|
|
37
|
+
usedFromProposal++;
|
|
38
|
+
} else {
|
|
39
|
+
this.log.warn(`Unable to take tx: ${hashOfTxInProposal.toString()} from the proposal, it does not match payload hash: ${hashesFromPayload[i].toString()}`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
// See if we still have any holes, if there are then we were not successful and will try the old method
|
|
44
|
+
if (txsToUse.some((tx)=>tx === undefined)) {
|
|
45
|
+
this.log.warn(`Failed to use transactions from proposal. Falling back to old proposal logic`);
|
|
46
|
+
} else {
|
|
47
|
+
this.log.info(`Successfully used ${usedFromProposal}/${hashesFromPayload.length} transactions from the proposal`);
|
|
48
|
+
await this.p2pClient.validate(txsToUse);
|
|
49
|
+
return {
|
|
50
|
+
txs: txsToUse
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
this.log.info(`Using old style proposal with ${proposal.payload.txHashes.length} transactions`);
|
|
55
|
+
// Old style proposal, we will perform a request by hash from pool
|
|
56
|
+
// This will request from network any txs that are missing
|
|
57
|
+
const txHashes = proposal.payload.txHashes;
|
|
58
|
+
// This part is just for logging that we are requesting from the network
|
|
59
|
+
const availability = await this.p2pClient.hasTxsInPool(txHashes);
|
|
60
|
+
const notAvailable = availability.filter((availability)=>availability === false);
|
|
61
|
+
if (notAvailable.length) {
|
|
62
|
+
this.log.verbose(`Missing ${notAvailable.length} transactions in the tx pool, will need to request from the network`);
|
|
63
|
+
}
|
|
64
|
+
// This will request from the network any txs that are missing
|
|
65
|
+
// NOTE: this could still return missing txs so we need to (1) be careful to handle undefined and (2) keep the txs in the correct order for re-execution
|
|
66
|
+
const maybeRetrievedTxs = await this.p2pClient.getTxsByHash(txHashes, peerWhoSentTheProposal);
|
|
67
|
+
const missingTxs = compactArray(maybeRetrievedTxs.map((tx, index)=>tx === undefined ? txHashes[index] : undefined));
|
|
68
|
+
// if we found all txs, this is a noop. If we didn't find all txs then validate the ones we did find and tell the validator to skip attestations because missingTxs.length > 0
|
|
69
|
+
const retrievedTxs = compactArray(maybeRetrievedTxs);
|
|
70
|
+
await this.p2pClient.validate(retrievedTxs);
|
|
71
|
+
return {
|
|
72
|
+
txs: retrievedTxs,
|
|
73
|
+
missing: missingTxs
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -14,7 +14,7 @@ import type { BootnodeConfig } from '../config.js';
|
|
|
14
14
|
import type { MemPools } from '../mem_pools/interface.js';
|
|
15
15
|
import { LibP2PService } from '../services/libp2p/libp2p_service.js';
|
|
16
16
|
import type { PeerScoring } from '../services/peer-manager/peer_scoring.js';
|
|
17
|
-
import { type ReqRespSubProtocolHandlers, type ReqRespSubProtocolValidators } from '../services/reqresp/interface.js';
|
|
17
|
+
import { type ReqRespSubProtocolHandlers, type ReqRespSubProtocolRateLimits, type ReqRespSubProtocolValidators } from '../services/reqresp/interface.js';
|
|
18
18
|
import { ReqResp } from '../services/reqresp/reqresp.js';
|
|
19
19
|
/**
|
|
20
20
|
* Creates a libp2p node, pre configured.
|
|
@@ -43,10 +43,10 @@ export declare const MOCK_SUB_PROTOCOL_VALIDATORS: ReqRespSubProtocolValidators;
|
|
|
43
43
|
* @param numberOfNodes - the number of nodes to create
|
|
44
44
|
* @returns An array of the created nodes
|
|
45
45
|
*/
|
|
46
|
-
export declare const createNodes: (peerScoring: PeerScoring, numberOfNodes: number) => Promise<ReqRespNode[]>;
|
|
46
|
+
export declare const createNodes: (peerScoring: PeerScoring, numberOfNodes: number, rateLimits?: Partial<ReqRespSubProtocolRateLimits>) => Promise<ReqRespNode[]>;
|
|
47
47
|
export declare const startNodes: (nodes: ReqRespNode[], subProtocolHandlers?: ReqRespSubProtocolHandlers, subProtocolValidators?: ReqRespSubProtocolValidators) => Promise<void>;
|
|
48
48
|
export declare const stopNodes: (nodes: ReqRespNode[]) => Promise<void>;
|
|
49
|
-
export declare const createReqResp: (peerScoring: PeerScoring) => Promise<ReqRespNode>;
|
|
49
|
+
export declare const createReqResp: (peerScoring: PeerScoring, rateLimits?: Partial<ReqRespSubProtocolRateLimits>) => Promise<ReqRespNode>;
|
|
50
50
|
export declare const connectToPeers: (nodes: ReqRespNode[]) => Promise<void>;
|
|
51
51
|
export declare class AlwaysTrueCircuitVerifier implements ClientProtocolCircuitVerifier {
|
|
52
52
|
verifyProof(_tx: Tx): Promise<boolean>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reqresp-nodes.d.ts","sourceRoot":"","sources":["../../src/test-helpers/reqresp-nodes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAIrD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,KAAK,WAAW,EAAoB,MAAM,sBAAsB,CAAC;AAC1E,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,KAAK,EAAE,6BAA6B,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AAC7G,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AAC3C,OAAO,EAAE,KAAK,eAAe,EAAsB,MAAM,yBAAyB,CAAC;AAEnF,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAM7C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAKhD,OAAO,EAAE,KAAK,MAAM,EAAoC,MAAM,QAAQ,CAAC;AAEvE,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,KAAK,EAAE,cAAc,EAAa,MAAM,cAAc,CAAC;AAC9D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAE1D,OAAO,EAAE,aAAa,EAAE,MAAM,sCAAsC,CAAC;AACrE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0CAA0C,CAAC;AAE5E,OAAO,EAEL,KAAK,0BAA0B,EAC/B,KAAK,4BAA4B,EAElC,MAAM,kCAAkC,CAAC;AAE1C,OAAO,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAC;AAGzD;;;;GAIG;AACH,wBAAsB,gBAAgB,CACpC,aAAa,GAAE,MAAM,EAAO,EAC5B,MAAM,CAAC,EAAE,MAAM,EACf,IAAI,CAAC,EAAE,MAAM,EACb,eAAe,GAAE,OAAe,EAChC,KAAK,GAAE,OAAc,GACpB,OAAO,CAAC,MAAM,CAAC,CAqCjB;AAED;;;;;GAKG;AACH,wBAAsB,uBAAuB,CAAC,CAAC,SAAS,aAAa,EACnE,UAAU,EAAE,CAAC,EACb,aAAa,EAAE,MAAM,EAAE,YAAK,EAC5B,QAAQ,EAAE,aAAa,GAAG,kBAAkB,EAC5C,sBAAsB,EAAE,sBAAsB,EAC9C,UAAU,EAAE,UAAU,EACtB,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,EACrB,SAAS,EAAE,eAAe,EAC1B,IAAI,GAAE,MAAU,EAChB,MAAM,CAAC,EAAE,MAAM,EACf,WAAW,GAAE,WAA8B,6BAgC5C;AAED;;;GAGG;AACH,MAAM,MAAM,WAAW,GAAG;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,OAAO,CAAC;CACd,CAAC;AAGF,eAAO,MAAM,0BAA0B,EAAE,0BAMxC,CAAC;AAIF,eAAO,MAAM,4BAA4B,EAAE,4BAM1C,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,WAAW,
|
|
1
|
+
{"version":3,"file":"reqresp-nodes.d.ts","sourceRoot":"","sources":["../../src/test-helpers/reqresp-nodes.ts"],"names":[],"mappings":"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"}
|
|
@@ -112,8 +112,8 @@ export const MOCK_SUB_PROTOCOL_VALIDATORS = {
|
|
|
112
112
|
/**
|
|
113
113
|
* @param numberOfNodes - the number of nodes to create
|
|
114
114
|
* @returns An array of the created nodes
|
|
115
|
-
*/ export const createNodes = (peerScoring, numberOfNodes)=>{
|
|
116
|
-
return timesParallel(numberOfNodes, ()=>createReqResp(peerScoring));
|
|
115
|
+
*/ export const createNodes = (peerScoring, numberOfNodes, rateLimits = {})=>{
|
|
116
|
+
return timesParallel(numberOfNodes, ()=>createReqResp(peerScoring, rateLimits));
|
|
117
117
|
};
|
|
118
118
|
export const startNodes = async (nodes, subProtocolHandlers = MOCK_SUB_PROTOCOL_HANDLERS, subProtocolValidators = MOCK_SUB_PROTOCOL_VALIDATORS)=>{
|
|
119
119
|
for (const node of nodes){
|
|
@@ -128,13 +128,13 @@ export const stopNodes = async (nodes)=>{
|
|
|
128
128
|
await Promise.all(stopPromises);
|
|
129
129
|
};
|
|
130
130
|
// Create a req resp node, exposing the underlying p2p node
|
|
131
|
-
export const createReqResp = async (peerScoring)=>{
|
|
131
|
+
export const createReqResp = async (peerScoring, rateLimits = {})=>{
|
|
132
132
|
const p2p = await createLibp2pNode();
|
|
133
133
|
const config = {
|
|
134
134
|
overallRequestTimeoutMs: 4000,
|
|
135
135
|
individualRequestTimeoutMs: 2000
|
|
136
136
|
};
|
|
137
|
-
const req = new ReqResp(config, p2p, peerScoring);
|
|
137
|
+
const req = new ReqResp(config, p2p, peerScoring, rateLimits);
|
|
138
138
|
return {
|
|
139
139
|
p2p,
|
|
140
140
|
req
|
|
@@ -33,7 +33,7 @@ function mockTxPool() {
|
|
|
33
33
|
getTxStatus: ()=>Promise.resolve(TxStatus.PENDING),
|
|
34
34
|
getTxsByHash: ()=>Promise.resolve([]),
|
|
35
35
|
hasTxs: ()=>Promise.resolve([]),
|
|
36
|
-
|
|
36
|
+
updateConfig: ()=>{},
|
|
37
37
|
markTxsAsNonEvictable: ()=>Promise.resolve()
|
|
38
38
|
};
|
|
39
39
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aztec/p2p",
|
|
3
|
-
"version": "0.87.
|
|
3
|
+
"version": "0.87.7",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./dest/index.js",
|
|
@@ -63,16 +63,16 @@
|
|
|
63
63
|
]
|
|
64
64
|
},
|
|
65
65
|
"dependencies": {
|
|
66
|
-
"@aztec/constants": "0.87.
|
|
67
|
-
"@aztec/epoch-cache": "0.87.
|
|
68
|
-
"@aztec/foundation": "0.87.
|
|
69
|
-
"@aztec/kv-store": "0.87.
|
|
70
|
-
"@aztec/noir-contracts.js": "0.87.
|
|
71
|
-
"@aztec/noir-protocol-circuits-types": "0.87.
|
|
72
|
-
"@aztec/protocol-contracts": "0.87.
|
|
73
|
-
"@aztec/simulator": "0.87.
|
|
74
|
-
"@aztec/stdlib": "0.87.
|
|
75
|
-
"@aztec/telemetry-client": "0.87.
|
|
66
|
+
"@aztec/constants": "0.87.7",
|
|
67
|
+
"@aztec/epoch-cache": "0.87.7",
|
|
68
|
+
"@aztec/foundation": "0.87.7",
|
|
69
|
+
"@aztec/kv-store": "0.87.7",
|
|
70
|
+
"@aztec/noir-contracts.js": "0.87.7",
|
|
71
|
+
"@aztec/noir-protocol-circuits-types": "0.87.7",
|
|
72
|
+
"@aztec/protocol-contracts": "0.87.7",
|
|
73
|
+
"@aztec/simulator": "0.87.7",
|
|
74
|
+
"@aztec/stdlib": "0.87.7",
|
|
75
|
+
"@aztec/telemetry-client": "0.87.7",
|
|
76
76
|
"@chainsafe/discv5": "9.0.0",
|
|
77
77
|
"@chainsafe/enr": "3.0.0",
|
|
78
78
|
"@chainsafe/libp2p-gossipsub": "13.0.0",
|
|
@@ -101,7 +101,7 @@
|
|
|
101
101
|
"xxhash-wasm": "^1.1.0"
|
|
102
102
|
},
|
|
103
103
|
"devDependencies": {
|
|
104
|
-
"@aztec/archiver": "0.87.
|
|
104
|
+
"@aztec/archiver": "0.87.7",
|
|
105
105
|
"@jest/globals": "^29.5.0",
|
|
106
106
|
"@types/jest": "^29.5.0",
|
|
107
107
|
"@types/node": "^22.15.17",
|
package/src/client/interface.ts
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import type { L2BlockId } from '@aztec/stdlib/block';
|
|
2
2
|
import type { P2PApi } from '@aztec/stdlib/interfaces/server';
|
|
3
|
-
import {
|
|
3
|
+
import type { BlockProposal, P2PClientType } from '@aztec/stdlib/p2p';
|
|
4
4
|
import type { Tx, TxHash } from '@aztec/stdlib/tx';
|
|
5
5
|
|
|
6
6
|
import type { ENR } from '@chainsafe/enr';
|
|
7
|
+
import type { PeerId } from '@libp2p/interface';
|
|
7
8
|
|
|
8
9
|
import type { P2PConfig } from '../config.js';
|
|
10
|
+
import type { P2PBlockReceivedCallback } from '../services/service.js';
|
|
9
11
|
|
|
10
12
|
/**
|
|
11
13
|
* Enum defining the possible states of the p2p client.
|
|
@@ -50,14 +52,15 @@ export type P2P<T extends P2PClientType = P2PClientType.Full> = P2PApi<T> & {
|
|
|
50
52
|
*/
|
|
51
53
|
// REVIEW: https://github.com/AztecProtocol/aztec-packages/issues/7963
|
|
52
54
|
// ^ This pattern is not my favorite (md)
|
|
53
|
-
registerBlockProposalHandler(
|
|
55
|
+
registerBlockProposalHandler(callback: P2PBlockReceivedCallback): void;
|
|
54
56
|
|
|
55
57
|
/**
|
|
56
58
|
* Request a list of transactions from another peer by their tx hashes.
|
|
57
59
|
* @param txHashes - Hashes of the txs to query.
|
|
60
|
+
* @param pinnedPeerId - An optional peer id that will be used to request the tx from (in addition to other random peers).
|
|
58
61
|
* @returns A list of transactions or undefined if the transactions are not found.
|
|
59
62
|
*/
|
|
60
|
-
requestTxsByHash(txHashes: TxHash[]): Promise<(Tx | undefined)[]>;
|
|
63
|
+
requestTxsByHash(txHashes: TxHash[], pinnedPeerId: PeerId): Promise<(Tx | undefined)[]>;
|
|
61
64
|
|
|
62
65
|
/**
|
|
63
66
|
* Request a transaction from another peer by its tx hash.
|
|
@@ -115,9 +118,10 @@ export type P2P<T extends P2PClientType = P2PClientType.Full> = P2PApi<T> & {
|
|
|
115
118
|
/**
|
|
116
119
|
* Returns transactions in the transaction pool by hash, requesting from the network if not found.
|
|
117
120
|
* @param txHashes - Hashes of tx to return.
|
|
121
|
+
* @param pinnedPeerId - An optional peer id that will be used to request the tx from (in addition to other random peers).
|
|
118
122
|
* @returns An array of tx or undefined.
|
|
119
123
|
*/
|
|
120
|
-
getTxsByHash(txHashes: TxHash[]): Promise<(Tx | undefined)[]>;
|
|
124
|
+
getTxsByHash(txHashes: TxHash[], pinnedPeerId: PeerId | undefined): Promise<(Tx | undefined)[]>;
|
|
121
125
|
|
|
122
126
|
/**
|
|
123
127
|
* Returns an archived transaction from the transaction pool by its hash.
|
package/src/client/p2p_client.ts
CHANGED
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
} from '@aztec/telemetry-client';
|
|
25
25
|
|
|
26
26
|
import type { ENR } from '@chainsafe/enr';
|
|
27
|
+
import type { PeerId } from '@libp2p/interface';
|
|
27
28
|
|
|
28
29
|
import { type P2PConfig, getP2PDefaultConfig } from '../config.js';
|
|
29
30
|
import type { AttestationPool } from '../mem_pools/attestation_pool/attestation_pool.js';
|
|
@@ -31,6 +32,7 @@ import type { MemPools } from '../mem_pools/interface.js';
|
|
|
31
32
|
import type { TxPool } from '../mem_pools/tx_pool/index.js';
|
|
32
33
|
import { ReqRespSubProtocol } from '../services/reqresp/interface.js';
|
|
33
34
|
import type { P2PService } from '../services/service.js';
|
|
35
|
+
import { TxCollector } from '../services/tx_collector.js';
|
|
34
36
|
import { type P2P, P2PClientState, type P2PSyncState } from './interface.js';
|
|
35
37
|
|
|
36
38
|
/**
|
|
@@ -87,6 +89,15 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
|
|
|
87
89
|
this.txPool = mempools.txPool;
|
|
88
90
|
this.attestationPool = mempools.attestationPool!;
|
|
89
91
|
|
|
92
|
+
// Default to collecting all txs when we see a valid proposal
|
|
93
|
+
// This can be overridden by the validator client to attest, and it will call collectForBlockProposal on its own
|
|
94
|
+
const txCollector = new TxCollector(this, this.log);
|
|
95
|
+
this.registerBlockProposalHandler(async (block, sender) => {
|
|
96
|
+
this.log.debug(`Received block proposal from ${sender.toString()}`);
|
|
97
|
+
await txCollector.collectForBlockProposal(block, sender);
|
|
98
|
+
return undefined;
|
|
99
|
+
});
|
|
100
|
+
|
|
90
101
|
// REFACTOR: Try replacing these with an L2TipsStore
|
|
91
102
|
this.synchedBlockHashes = store.openMap('p2p_pool_block_hashes');
|
|
92
103
|
this.synchedLatestBlockNumber = store.openSingleton('p2p_pool_last_l2_block');
|
|
@@ -111,11 +122,9 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
|
|
|
111
122
|
return this.synchedBlockHashes.getAsync(number);
|
|
112
123
|
}
|
|
113
124
|
|
|
114
|
-
public
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
this.config.maxTxPoolSize = config.maxTxPoolSize;
|
|
118
|
-
}
|
|
125
|
+
public updateP2PConfig(config: Partial<P2PConfig>): Promise<void> {
|
|
126
|
+
this.txPool.updateConfig(config);
|
|
127
|
+
return Promise.resolve();
|
|
119
128
|
}
|
|
120
129
|
|
|
121
130
|
public async getL2Tips(): Promise<L2Tips> {
|
|
@@ -328,7 +337,9 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
|
|
|
328
337
|
|
|
329
338
|
// REVIEW: https://github.com/AztecProtocol/aztec-packages/issues/7963
|
|
330
339
|
// ^ This pattern is not my favorite (md)
|
|
331
|
-
public registerBlockProposalHandler(
|
|
340
|
+
public registerBlockProposalHandler(
|
|
341
|
+
handler: (block: BlockProposal, sender: any) => Promise<BlockAttestation | undefined>,
|
|
342
|
+
): void {
|
|
332
343
|
this.p2pService.registerBlockReceivedCallback(handler);
|
|
333
344
|
}
|
|
334
345
|
|
|
@@ -357,7 +368,7 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
|
|
|
357
368
|
/**
|
|
358
369
|
* Uses the batched Request Response protocol to request a set of transactions from the network.
|
|
359
370
|
*/
|
|
360
|
-
public async requestTxsByHash(txHashes: TxHash[]): Promise<(Tx | undefined)[]> {
|
|
371
|
+
public async requestTxsByHash(txHashes: TxHash[], pinnedPeerId: PeerId | undefined): Promise<(Tx | undefined)[]> {
|
|
361
372
|
const timeoutMs = 8000; // Longer timeout for now
|
|
362
373
|
const maxPeers = Math.min(Math.ceil(txHashes.length / 3), 10);
|
|
363
374
|
const maxRetryAttempts = 10; // Keep retrying within the timeout
|
|
@@ -365,6 +376,7 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
|
|
|
365
376
|
const txs = await this.p2pService.sendBatchRequest(
|
|
366
377
|
ReqRespSubProtocol.TX,
|
|
367
378
|
txHashes,
|
|
379
|
+
pinnedPeerId,
|
|
368
380
|
timeoutMs,
|
|
369
381
|
maxPeers,
|
|
370
382
|
maxRetryAttempts,
|
|
@@ -462,7 +474,7 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
|
|
|
462
474
|
* @param txHashes - Hashes of the transactions to look for.
|
|
463
475
|
* @returns The txs found, or undefined if not found in the order requested.
|
|
464
476
|
*/
|
|
465
|
-
async getTxsByHash(txHashes: TxHash[]): Promise<(Tx | undefined)[]> {
|
|
477
|
+
async getTxsByHash(txHashes: TxHash[], pinnedPeerId: PeerId | undefined): Promise<(Tx | undefined)[]> {
|
|
466
478
|
const txs = await Promise.all(txHashes.map(txHash => this.txPool.getTxByHash(txHash)));
|
|
467
479
|
const missingTxHashes = txs
|
|
468
480
|
.map((tx, index) => [tx, index] as const)
|
|
@@ -473,7 +485,7 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
|
|
|
473
485
|
return txs as Tx[];
|
|
474
486
|
}
|
|
475
487
|
|
|
476
|
-
const missingTxs = await this.requestTxsByHash(missingTxHashes);
|
|
488
|
+
const missingTxs = await this.requestTxsByHash(missingTxHashes, pinnedPeerId);
|
|
477
489
|
const fetchedMissingTxs = missingTxs.filter((tx): tx is Tx => !!tx);
|
|
478
490
|
|
|
479
491
|
// TODO: optimize
|
|
@@ -678,7 +690,7 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
|
|
|
678
690
|
`Requesting ${missingTxHashes.length} missing txs from peers for ${unprovenBlocks.length} unproven mined blocks`,
|
|
679
691
|
{ missingTxHashes, unprovenBlockNumbers: unprovenBlocks.map(block => block.number) },
|
|
680
692
|
);
|
|
681
|
-
await this.requestTxsByHash(missingTxHashes);
|
|
693
|
+
await this.requestTxsByHash(missingTxHashes, undefined);
|
|
682
694
|
}
|
|
683
695
|
} catch (err) {
|
|
684
696
|
this.log.error(`Error requesting missing txs from unproven blocks`, err, {
|
package/src/config.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
type ConfigMappingsType,
|
|
3
3
|
booleanConfigHelper,
|
|
4
|
+
floatConfigHelper,
|
|
4
5
|
getConfigFromMappings,
|
|
5
6
|
getDefaultConfig,
|
|
6
7
|
numberConfigHelper,
|
|
@@ -196,6 +197,16 @@ export interface P2PConfig extends P2PReqRespConfig, ChainConfig {
|
|
|
196
197
|
* The maximum cumulative tx size (in bytes) of pending txs before evicting lower priority txs.
|
|
197
198
|
*/
|
|
198
199
|
maxTxPoolSize: number;
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* If the pool is full, it will still accept a few more txs until it reached maxTxPoolOverspillFactor * maxTxPoolSize. Then it will evict
|
|
203
|
+
*/
|
|
204
|
+
txPoolOverflowFactor: number;
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* The node's seen message ID cache size
|
|
208
|
+
*/
|
|
209
|
+
seenMessageCacheSize: number;
|
|
199
210
|
}
|
|
200
211
|
|
|
201
212
|
export const DEFAULT_P2P_PORT = 40400;
|
|
@@ -308,7 +319,7 @@ export const p2pConfigMappings: ConfigMappingsType<P2PConfig> = {
|
|
|
308
319
|
gossipsubFloodPublish: {
|
|
309
320
|
env: 'P2P_GOSSIPSUB_FLOOD_PUBLISH',
|
|
310
321
|
description: 'Whether to flood publish messages. - For testing purposes only',
|
|
311
|
-
...booleanConfigHelper(
|
|
322
|
+
...booleanConfigHelper(false),
|
|
312
323
|
},
|
|
313
324
|
gossipsubMcacheLength: {
|
|
314
325
|
env: 'P2P_GOSSIPSUB_MCACHE_LENGTH',
|
|
@@ -393,6 +404,16 @@ export const p2pConfigMappings: ConfigMappingsType<P2PConfig> = {
|
|
|
393
404
|
description: 'The maximum cumulative tx size of pending txs (in bytes) before evicting lower priority txs.',
|
|
394
405
|
...numberConfigHelper(100_000_000), // 100MB
|
|
395
406
|
},
|
|
407
|
+
txPoolOverflowFactor: {
|
|
408
|
+
env: 'P2P_TX_POOL_OVERFLOW_FACTOR',
|
|
409
|
+
description: 'How much the tx pool can overflow before it starts evicting txs. Must be greater than 1',
|
|
410
|
+
...floatConfigHelper(1.1), // 10% overflow
|
|
411
|
+
},
|
|
412
|
+
seenMessageCacheSize: {
|
|
413
|
+
env: 'P2P_SEEN_MSG_CACHE_SIZE',
|
|
414
|
+
description: 'The number of messages to keep in the seen message cache',
|
|
415
|
+
...numberConfigHelper(100_000), // 100K
|
|
416
|
+
},
|
|
396
417
|
...p2pReqRespConfigMappings,
|
|
397
418
|
...chainConfigMappings,
|
|
398
419
|
};
|