@aztec/p2p 0.87.4 → 0.87.6
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/libp2p_service.d.ts +5 -3
- package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
- package/dest/services/libp2p/libp2p_service.js +42 -8
- 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 +73 -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/libp2p_service.ts +51 -9
- 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 +98 -0
- package/src/test-helpers/reqresp-nodes.ts +13 -8
- package/src/testbench/p2p_client_testbench_worker.ts +1 -1
|
@@ -0,0 +1,73 @@
|
|
|
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
|
+
const retrievedTxs = await this.p2pClient.getTxsByHash(txHashes, peerWhoSentTheProposal);
|
|
66
|
+
const missingTxs = compactArray(retrievedTxs.map((tx, index)=>tx === undefined ? txHashes[index] : undefined));
|
|
67
|
+
await this.p2pClient.validate(retrievedTxs);
|
|
68
|
+
return {
|
|
69
|
+
txs: retrievedTxs,
|
|
70
|
+
missing: missingTxs
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -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.6",
|
|
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.6",
|
|
67
|
+
"@aztec/epoch-cache": "0.87.6",
|
|
68
|
+
"@aztec/foundation": "0.87.6",
|
|
69
|
+
"@aztec/kv-store": "0.87.6",
|
|
70
|
+
"@aztec/noir-contracts.js": "0.87.6",
|
|
71
|
+
"@aztec/noir-protocol-circuits-types": "0.87.6",
|
|
72
|
+
"@aztec/protocol-contracts": "0.87.6",
|
|
73
|
+
"@aztec/simulator": "0.87.6",
|
|
74
|
+
"@aztec/stdlib": "0.87.6",
|
|
75
|
+
"@aztec/telemetry-client": "0.87.6",
|
|
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.6",
|
|
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
|
};
|
package/src/index.ts
CHANGED
|
@@ -11,11 +11,13 @@ import { DatabasePublicStateSource } from '@aztec/stdlib/trees';
|
|
|
11
11
|
import { Tx, TxHash } from '@aztec/stdlib/tx';
|
|
12
12
|
import { type TelemetryClient, getTelemetryClient } from '@aztec/telemetry-client';
|
|
13
13
|
|
|
14
|
+
import assert from 'assert';
|
|
15
|
+
|
|
14
16
|
import { ArchiveCache } from '../../msg_validators/tx_validator/archive_cache.js';
|
|
15
17
|
import { GasTxValidator } from '../../msg_validators/tx_validator/gas_validator.js';
|
|
16
18
|
import { PoolInstrumentation, PoolName } from '../instrumentation.js';
|
|
17
19
|
import { getPendingTxPriority } from './priority.js';
|
|
18
|
-
import type { TxPool } from './tx_pool.js';
|
|
20
|
+
import type { TxPool, TxPoolOptions } from './tx_pool.js';
|
|
19
21
|
|
|
20
22
|
/**
|
|
21
23
|
* KV implementation of the Transaction Pool.
|
|
@@ -27,7 +29,10 @@ export class AztecKVTxPool implements TxPool {
|
|
|
27
29
|
#txs: AztecAsyncMap<string, Buffer>;
|
|
28
30
|
|
|
29
31
|
/** The maximum cumulative tx size that the pending txs in the pool take up. */
|
|
30
|
-
#maxTxPoolSize: number
|
|
32
|
+
#maxTxPoolSize: number = 0;
|
|
33
|
+
|
|
34
|
+
/** The tx evicion logic will kick after pool size is greater than maxTxPoolSize * txPoolOverflowFactor */
|
|
35
|
+
txPoolOverflowFactor: number = 1;
|
|
31
36
|
|
|
32
37
|
/** Index from tx hash to the block number in which they were mined, filtered by mined txs. */
|
|
33
38
|
#minedTxHashToBlock: AztecAsyncMap<string, number>;
|
|
@@ -63,7 +68,7 @@ export class AztecKVTxPool implements TxPool {
|
|
|
63
68
|
#archivedTxIndices: AztecAsyncMap<number, string>;
|
|
64
69
|
|
|
65
70
|
/** Number of txs to archive. */
|
|
66
|
-
#archivedTxLimit: number;
|
|
71
|
+
#archivedTxLimit: number = 0;
|
|
67
72
|
|
|
68
73
|
/** The world state synchronizer used in the node. */
|
|
69
74
|
#worldStateSynchronizer: WorldStateSynchronizer;
|
|
@@ -85,12 +90,12 @@ export class AztecKVTxPool implements TxPool {
|
|
|
85
90
|
archive: AztecAsyncKVStore,
|
|
86
91
|
worldStateSynchronizer: WorldStateSynchronizer,
|
|
87
92
|
telemetry: TelemetryClient = getTelemetryClient(),
|
|
88
|
-
config: {
|
|
89
|
-
maxTxPoolSize?: number;
|
|
90
|
-
archivedTxLimit?: number;
|
|
91
|
-
} = {},
|
|
93
|
+
config: TxPoolOptions = {},
|
|
92
94
|
log = createLogger('p2p:tx_pool'),
|
|
93
95
|
) {
|
|
96
|
+
this.#log = log;
|
|
97
|
+
this.updateConfig(config);
|
|
98
|
+
|
|
94
99
|
this.#txs = store.openMap('txs');
|
|
95
100
|
this.#minedTxHashToBlock = store.openMap('txHashToBlockMined');
|
|
96
101
|
this.#pendingTxPriorityToHash = store.openMultiMap('pendingTxFeeToHash');
|
|
@@ -98,18 +103,16 @@ export class AztecKVTxPool implements TxPool {
|
|
|
98
103
|
this.#pendingTxHashToHeaderHash = store.openMap('pendingTxHashToHeaderHash');
|
|
99
104
|
this.#pendingTxSize = store.openSingleton('pendingTxSize');
|
|
100
105
|
this.#pendingTxCount = store.openSingleton('pendingTxCount');
|
|
101
|
-
|
|
106
|
+
|
|
102
107
|
this.#pendingTxs = new Map<string, Tx>();
|
|
103
108
|
this.#nonEvictableTxs = new Set<string>();
|
|
104
109
|
|
|
105
110
|
this.#archivedTxs = archive.openMap('archivedTxs');
|
|
106
111
|
this.#archivedTxIndices = archive.openMap('archivedTxIndices');
|
|
107
|
-
this.#archivedTxLimit = config.archivedTxLimit ?? 0;
|
|
108
112
|
|
|
109
113
|
this.#store = store;
|
|
110
114
|
this.#archive = archive;
|
|
111
115
|
this.#worldStateSynchronizer = worldStateSynchronizer;
|
|
112
|
-
this.#log = log;
|
|
113
116
|
this.#metrics = new PoolInstrumentation(telemetry, PoolName.TX_POOL, () => store.estimateSize());
|
|
114
117
|
}
|
|
115
118
|
|
|
@@ -386,9 +389,28 @@ export class AztecKVTxPool implements TxPool {
|
|
|
386
389
|
return vals.map(x => TxHash.fromString(x));
|
|
387
390
|
}
|
|
388
391
|
|
|
389
|
-
public
|
|
390
|
-
|
|
391
|
-
|
|
392
|
+
public updateConfig({ maxTxPoolSize, txPoolOverflowFactor, archivedTxLimit }: TxPoolOptions): void {
|
|
393
|
+
if (typeof maxTxPoolSize === 'number') {
|
|
394
|
+
assert(maxTxPoolSize >= 0, 'maxTxPoolSize must be greater or equal to 0');
|
|
395
|
+
this.#maxTxPoolSize = maxTxPoolSize;
|
|
396
|
+
|
|
397
|
+
if (maxTxPoolSize === 0) {
|
|
398
|
+
this.#log.info(`Disabling maximum tx mempool size. Tx eviction stopped`);
|
|
399
|
+
} else {
|
|
400
|
+
this.#log.info(`Setting maximum tx mempool size`, { maxTxPoolSize });
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
if (typeof txPoolOverflowFactor === 'number') {
|
|
405
|
+
assert(txPoolOverflowFactor >= 1, 'txPoolOveflowFactor must be greater or equal to 1');
|
|
406
|
+
this.txPoolOverflowFactor = txPoolOverflowFactor;
|
|
407
|
+
this.#log.info(`Allowing tx pool size to grow above limit`, { maxTxPoolSize, txPoolOverflowFactor });
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
if (typeof archivedTxLimit === 'number') {
|
|
411
|
+
assert(archivedTxLimit >= 0, 'archivedTxLimit must be greater or equal to 0');
|
|
412
|
+
this.#archivedTxLimit = archivedTxLimit;
|
|
413
|
+
}
|
|
392
414
|
}
|
|
393
415
|
|
|
394
416
|
public markTxsAsNonEvictable(txHashes: TxHash[]): Promise<void> {
|
|
@@ -483,7 +505,7 @@ export class AztecKVTxPool implements TxPool {
|
|
|
483
505
|
private async evictLowPriorityTxs(
|
|
484
506
|
newTxHashes: TxHash[],
|
|
485
507
|
): Promise<{ numLowPriorityTxsEvicted: number; numNewTxsEvicted: number }> {
|
|
486
|
-
if (this.#maxTxPoolSize === undefined) {
|
|
508
|
+
if (this.#maxTxPoolSize === undefined || this.#maxTxPoolSize === 0) {
|
|
487
509
|
return { numLowPriorityTxsEvicted: 0, numNewTxsEvicted: 0 };
|
|
488
510
|
}
|
|
489
511
|
|
|
@@ -491,17 +513,22 @@ export class AztecKVTxPool implements TxPool {
|
|
|
491
513
|
const txsToEvict: TxHash[] = [];
|
|
492
514
|
|
|
493
515
|
let pendingTxsSize = (await this.#pendingTxSize.getAsync()) ?? 0;
|
|
494
|
-
if (pendingTxsSize > this.#maxTxPoolSize) {
|
|
516
|
+
if (pendingTxsSize > this.#maxTxPoolSize * this.txPoolOverflowFactor) {
|
|
495
517
|
for await (const txHash of this.#pendingTxPriorityToHash.valuesAsync()) {
|
|
496
518
|
if (this.#nonEvictableTxs.has(txHash.toString())) {
|
|
497
519
|
continue;
|
|
498
520
|
}
|
|
499
|
-
this.#log.verbose(`Evicting tx ${txHash} from pool due to low priority to satisfy max tx size limit`);
|
|
500
|
-
txsToEvict.push(TxHash.fromString(txHash));
|
|
501
|
-
|
|
502
521
|
const txSize =
|
|
503
522
|
(await this.#pendingTxHashToSize.getAsync(txHash.toString())) ??
|
|
504
523
|
(await this.getPendingTxByHash(txHash))?.getSize();
|
|
524
|
+
|
|
525
|
+
this.#log.verbose(`Evicting tx ${txHash} from pool due to low priority to satisfy max tx size limit`, {
|
|
526
|
+
txHash,
|
|
527
|
+
txSize,
|
|
528
|
+
});
|
|
529
|
+
|
|
530
|
+
txsToEvict.push(TxHash.fromString(txHash));
|
|
531
|
+
|
|
505
532
|
if (txSize) {
|
|
506
533
|
pendingTxsSize -= txSize;
|
|
507
534
|
if (pendingTxsSize <= this.#maxTxPoolSize) {
|
|
@@ -5,7 +5,7 @@ import { type TelemetryClient, getTelemetryClient } from '@aztec/telemetry-clien
|
|
|
5
5
|
|
|
6
6
|
import { PoolInstrumentation, PoolName } from '../instrumentation.js';
|
|
7
7
|
import { getPendingTxPriority } from './priority.js';
|
|
8
|
-
import type { TxPool } from './tx_pool.js';
|
|
8
|
+
import type { TxPool, TxPoolOptions } from './tx_pool.js';
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* In-memory implementation of the Transaction Pool.
|
|
@@ -190,9 +190,7 @@ export class InMemoryTxPool implements TxPool {
|
|
|
190
190
|
return Promise.resolve(Array.from(this.txs.keys()).map(x => TxHash.fromBigInt(x)));
|
|
191
191
|
}
|
|
192
192
|
|
|
193
|
-
|
|
194
|
-
return Promise.resolve();
|
|
195
|
-
}
|
|
193
|
+
updateConfig(_config: TxPoolOptions): void {}
|
|
196
194
|
|
|
197
195
|
markTxsAsNonEvictable(_: TxHash[]): Promise<void> {
|
|
198
196
|
return Promise.resolve();
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import type { Tx, TxHash } from '@aztec/stdlib/tx';
|
|
2
2
|
|
|
3
|
+
export type TxPoolOptions = {
|
|
4
|
+
maxTxPoolSize?: number;
|
|
5
|
+
txPoolOverflowFactor?: number;
|
|
6
|
+
archivedTxLimit?: number;
|
|
7
|
+
};
|
|
8
|
+
|
|
3
9
|
/**
|
|
4
10
|
* Interface of a transaction pool. The pool includes tx requests and is kept up-to-date by a P2P client.
|
|
5
11
|
*/
|
|
@@ -95,7 +101,7 @@ export interface TxPool {
|
|
|
95
101
|
* Configure the maximum size of the tx pool
|
|
96
102
|
* @param maxSizeBytes - The maximum size in bytes of the mempool. Set to undefined to disable it
|
|
97
103
|
*/
|
|
98
|
-
|
|
104
|
+
updateConfig(config: TxPoolOptions): void;
|
|
99
105
|
|
|
100
106
|
/** Returns whether the pool is empty. */
|
|
101
107
|
isEmpty(): Promise<boolean>;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// Implements a queue of message IDs
|
|
2
|
+
export class MessageSeenValidator {
|
|
3
|
+
private queue: Array<string>;
|
|
4
|
+
private writePointer = 0;
|
|
5
|
+
private seenMessages: Set<string> = new Set();
|
|
6
|
+
|
|
7
|
+
constructor(private queueLength: number) {
|
|
8
|
+
if (this.queueLength <= 0) {
|
|
9
|
+
throw new Error('Queue length must be greater than 0');
|
|
10
|
+
}
|
|
11
|
+
this.queue = new Array<string>(this.queueLength);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// Adds a message if not seen before. Returns true if added, false if already seen.
|
|
15
|
+
public addMessage(msgId: string): boolean {
|
|
16
|
+
// Check if the message is already in the cache
|
|
17
|
+
if (this.seenMessages.has(msgId)) {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
// If we are at the cache limit, remove the oldest msg ID
|
|
21
|
+
if (this.seenMessages.size >= this.queueLength) {
|
|
22
|
+
const msgToRemove = this.queue[this.writePointer];
|
|
23
|
+
this.seenMessages.delete(msgToRemove);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Insert the message into the cache and the queue
|
|
27
|
+
this.seenMessages.add(msgId);
|
|
28
|
+
this.queue[this.writePointer] = msgId;
|
|
29
|
+
this.writePointer = this.writePointer === this.queueLength - 1 ? 0 : this.writePointer + 1;
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
public size() {
|
|
34
|
+
return this.seenMessages.size;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -51,7 +51,9 @@ export class DummyP2PService implements P2PService {
|
|
|
51
51
|
/**
|
|
52
52
|
* Register a callback into the validator client for when a block proposal is received
|
|
53
53
|
*/
|
|
54
|
-
public registerBlockReceivedCallback(
|
|
54
|
+
public registerBlockReceivedCallback(
|
|
55
|
+
_callback: (block: BlockProposal, sender: PeerId) => Promise<BlockAttestation>,
|
|
56
|
+
) {}
|
|
55
57
|
|
|
56
58
|
/**
|
|
57
59
|
* Sends a request to a peer.
|
package/src/services/index.ts
CHANGED