@aztec/p2p 0.69.1 → 0.71.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dest/client/factory.d.ts.map +1 -1
- package/dest/client/factory.js +6 -5
- package/dest/client/p2p_client.d.ts +16 -2
- package/dest/client/p2p_client.d.ts.map +1 -1
- package/dest/client/p2p_client.js +17 -9
- package/dest/config.d.ts +3 -0
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +6 -1
- package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts +1 -1
- package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/kv_attestation_pool.js +3 -2
- package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts +1 -1
- 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 -2
- package/dest/mem_pools/epoch_proof_quote_pool/memory_epoch_proof_quote_pool.d.ts +1 -1
- package/dest/mem_pools/epoch_proof_quote_pool/memory_epoch_proof_quote_pool.d.ts.map +1 -1
- package/dest/mem_pools/epoch_proof_quote_pool/memory_epoch_proof_quote_pool.js +3 -2
- package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts +20 -5
- 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 +134 -55
- package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts +2 -1
- package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/memory_tx_pool.js +11 -3
- package/dest/mem_pools/tx_pool/priority.d.ts +8 -0
- package/dest/mem_pools/tx_pool/priority.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool/priority.js +12 -0
- package/dest/mem_pools/tx_pool/tx_pool.d.ts +7 -1
- package/dest/mem_pools/tx_pool/tx_pool.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/tx_pool_test_suite.js +19 -3
- package/dest/mocks/index.d.ts.map +1 -1
- package/dest/mocks/index.js +4 -4
- package/dest/msg_validators/tx_validator/block_header_validator.d.ts +11 -0
- package/dest/msg_validators/tx_validator/block_header_validator.d.ts.map +1 -0
- package/dest/msg_validators/tx_validator/block_header_validator.js +21 -0
- package/dest/msg_validators/tx_validator/index.d.ts +1 -0
- package/dest/msg_validators/tx_validator/index.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/index.js +2 -1
- package/dest/services/discv5/discV5_service.d.ts +1 -1
- package/dest/services/discv5/discV5_service.d.ts.map +1 -1
- package/dest/services/discv5/discV5_service.js +3 -3
- package/package.json +7 -7
- package/src/client/factory.ts +5 -13
- package/src/client/p2p_client.ts +27 -9
- package/src/config.ts +9 -0
- package/src/mem_pools/attestation_pool/kv_attestation_pool.ts +2 -2
- package/src/mem_pools/attestation_pool/memory_attestation_pool.ts +2 -2
- package/src/mem_pools/epoch_proof_quote_pool/memory_epoch_proof_quote_pool.ts +2 -2
- package/src/mem_pools/tx_pool/aztec_kv_tx_pool.ts +161 -53
- package/src/mem_pools/tx_pool/memory_tx_pool.ts +11 -3
- package/src/mem_pools/tx_pool/priority.ts +13 -0
- package/src/mem_pools/tx_pool/tx_pool.ts +8 -1
- package/src/mem_pools/tx_pool/tx_pool_test_suite.ts +27 -5
- package/src/mocks/index.ts +3 -4
- package/src/msg_validators/tx_validator/block_header_validator.ts +25 -0
- package/src/msg_validators/tx_validator/index.ts +1 -0
- package/src/services/discv5/discV5_service.ts +2 -2
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import { Tx, TxHash } from '@aztec/circuit-types';
|
|
2
2
|
import { type TxAddedToPoolStats } from '@aztec/circuit-types/stats';
|
|
3
|
+
import { ClientIvcProof } from '@aztec/circuits.js';
|
|
3
4
|
import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
4
|
-
import { type AztecKVStore, type AztecMap, type
|
|
5
|
-
import { type TelemetryClient } from '@aztec/telemetry-client';
|
|
5
|
+
import { type AztecKVStore, type AztecMap, type AztecMultiMap } from '@aztec/kv-store';
|
|
6
|
+
import { type TelemetryClient, getTelemetryClient } from '@aztec/telemetry-client';
|
|
6
7
|
|
|
7
8
|
import { PoolInstrumentation, PoolName } from '../instrumentation.js';
|
|
9
|
+
import { getPendingTxPriority } from './priority.js';
|
|
8
10
|
import { type TxPool } from './tx_pool.js';
|
|
9
11
|
|
|
10
12
|
/**
|
|
11
|
-
*
|
|
13
|
+
* KV implementation of the Transaction Pool.
|
|
12
14
|
*/
|
|
13
15
|
export class AztecKVTxPool implements TxPool {
|
|
14
16
|
#store: AztecKVStore;
|
|
@@ -16,43 +18,77 @@ export class AztecKVTxPool implements TxPool {
|
|
|
16
18
|
/** Our tx pool, stored as a Map, with K: tx hash and V: the transaction. */
|
|
17
19
|
#txs: AztecMap<string, Buffer>;
|
|
18
20
|
|
|
19
|
-
/** Index
|
|
20
|
-
#
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
/** Index from tx hash to the block number in which they were mined, filtered by mined txs. */
|
|
22
|
+
#minedTxHashToBlock: AztecMap<string, number>;
|
|
23
|
+
|
|
24
|
+
/** Index from tx priority (stored as hex) to its tx hash, filtered by pending txs. */
|
|
25
|
+
#pendingTxPriorityToHash: AztecMultiMap<string, string>;
|
|
26
|
+
|
|
27
|
+
/** KV store for archived txs. */
|
|
28
|
+
#archive: AztecKVStore;
|
|
29
|
+
|
|
30
|
+
/** Archived txs map for future lookup. */
|
|
31
|
+
#archivedTxs: AztecMap<string, Buffer>;
|
|
32
|
+
|
|
33
|
+
/** Indexes of the archived txs by insertion order. */
|
|
34
|
+
#archivedTxIndices: AztecMap<number, string>;
|
|
35
|
+
|
|
36
|
+
/** Number of txs to archive. */
|
|
37
|
+
#archivedTxLimit: number;
|
|
23
38
|
|
|
24
39
|
#log: Logger;
|
|
25
40
|
|
|
26
41
|
#metrics: PoolInstrumentation<Tx>;
|
|
27
42
|
|
|
28
43
|
/**
|
|
29
|
-
* Class constructor for
|
|
30
|
-
* @param store - A KV store.
|
|
44
|
+
* Class constructor for KV TxPool. Initiates our transaction pool as an AztecMap.
|
|
45
|
+
* @param store - A KV store for live txs in the pool.
|
|
46
|
+
* @param archive - A KV store for archived txs.
|
|
47
|
+
* @param telemetry - A telemetry client.
|
|
48
|
+
* @param archivedTxLimit - The number of txs to archive.
|
|
31
49
|
* @param log - A logger.
|
|
32
50
|
*/
|
|
33
|
-
constructor(
|
|
51
|
+
constructor(
|
|
52
|
+
store: AztecKVStore,
|
|
53
|
+
archive: AztecKVStore,
|
|
54
|
+
telemetry: TelemetryClient = getTelemetryClient(),
|
|
55
|
+
archivedTxLimit: number = 0,
|
|
56
|
+
log = createLogger('p2p:tx_pool'),
|
|
57
|
+
) {
|
|
34
58
|
this.#txs = store.openMap('txs');
|
|
35
|
-
this.#
|
|
36
|
-
this.#
|
|
59
|
+
this.#minedTxHashToBlock = store.openMap('txHashToBlockMined');
|
|
60
|
+
this.#pendingTxPriorityToHash = store.openMultiMap('pendingTxFeeToHash');
|
|
61
|
+
|
|
62
|
+
this.#archivedTxs = archive.openMap('archivedTxs');
|
|
63
|
+
this.#archivedTxIndices = archive.openMap('archivedTxIndices');
|
|
64
|
+
this.#archivedTxLimit = archivedTxLimit;
|
|
37
65
|
|
|
38
66
|
this.#store = store;
|
|
67
|
+
this.#archive = archive;
|
|
39
68
|
this.#log = log;
|
|
40
69
|
this.#metrics = new PoolInstrumentation(telemetry, PoolName.TX_POOL, () => store.estimateSize());
|
|
41
70
|
}
|
|
42
71
|
|
|
43
72
|
public markAsMined(txHashes: TxHash[], blockNumber: number): Promise<void> {
|
|
73
|
+
if (txHashes.length === 0) {
|
|
74
|
+
return Promise.resolve();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
let deletedPending = 0;
|
|
44
78
|
return this.#store.transaction(() => {
|
|
45
|
-
let deleted = 0;
|
|
46
79
|
for (const hash of txHashes) {
|
|
47
80
|
const key = hash.toString();
|
|
48
|
-
void this.#
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
81
|
+
void this.#minedTxHashToBlock.set(key, blockNumber);
|
|
82
|
+
|
|
83
|
+
const tx = this.getTxByHash(hash);
|
|
84
|
+
if (tx) {
|
|
85
|
+
deletedPending++;
|
|
86
|
+
const fee = getPendingTxPriority(tx);
|
|
87
|
+
void this.#pendingTxPriorityToHash.deleteValue(fee, key);
|
|
52
88
|
}
|
|
53
89
|
}
|
|
54
|
-
this.#metrics.recordRemovedObjects(deleted, 'pending');
|
|
55
90
|
this.#metrics.recordAddedObjects(txHashes.length, 'mined');
|
|
91
|
+
this.#metrics.recordRemovedObjects(deletedPending, 'pending');
|
|
56
92
|
});
|
|
57
93
|
}
|
|
58
94
|
|
|
@@ -61,33 +97,30 @@ export class AztecKVTxPool implements TxPool {
|
|
|
61
97
|
return Promise.resolve();
|
|
62
98
|
}
|
|
63
99
|
|
|
100
|
+
let markedAsPending = 0;
|
|
64
101
|
return this.#store.transaction(() => {
|
|
65
|
-
let deleted = 0;
|
|
66
|
-
let added = 0;
|
|
67
102
|
for (const hash of txHashes) {
|
|
68
103
|
const key = hash.toString();
|
|
69
|
-
|
|
70
|
-
deleted++;
|
|
71
|
-
void this.#minedTxs.delete(key);
|
|
72
|
-
}
|
|
104
|
+
void this.#minedTxHashToBlock.delete(key);
|
|
73
105
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
void this.#
|
|
106
|
+
const tx = this.getTxByHash(hash);
|
|
107
|
+
if (tx) {
|
|
108
|
+
void this.#pendingTxPriorityToHash.set(getPendingTxPriority(tx), key);
|
|
109
|
+
markedAsPending++;
|
|
77
110
|
}
|
|
78
111
|
}
|
|
79
112
|
|
|
80
|
-
this.#metrics.
|
|
81
|
-
this.#metrics.
|
|
113
|
+
this.#metrics.recordAddedObjects(markedAsPending, 'pending');
|
|
114
|
+
this.#metrics.recordRemovedObjects(markedAsPending, 'mined');
|
|
82
115
|
});
|
|
83
116
|
}
|
|
84
117
|
|
|
85
118
|
public getPendingTxHashes(): TxHash[] {
|
|
86
|
-
return Array.from(this.#
|
|
119
|
+
return Array.from(this.#pendingTxPriorityToHash.values({ reverse: true })).map(x => TxHash.fromString(x));
|
|
87
120
|
}
|
|
88
121
|
|
|
89
122
|
public getMinedTxHashes(): [TxHash, number][] {
|
|
90
|
-
return Array.from(this.#
|
|
123
|
+
return Array.from(this.#minedTxHashToBlock.entries()).map(([txHash, blockNumber]) => [
|
|
91
124
|
TxHash.fromString(txHash),
|
|
92
125
|
blockNumber,
|
|
93
126
|
]);
|
|
@@ -95,10 +128,10 @@ export class AztecKVTxPool implements TxPool {
|
|
|
95
128
|
|
|
96
129
|
public getTxStatus(txHash: TxHash): 'pending' | 'mined' | undefined {
|
|
97
130
|
const key = txHash.toString();
|
|
98
|
-
if (this.#
|
|
99
|
-
return 'pending';
|
|
100
|
-
} else if (this.#minedTxs.has(key)) {
|
|
131
|
+
if (this.#minedTxHashToBlock.has(key)) {
|
|
101
132
|
return 'mined';
|
|
133
|
+
} else if (this.#txs.has(key)) {
|
|
134
|
+
return 'pending';
|
|
102
135
|
} else {
|
|
103
136
|
return undefined;
|
|
104
137
|
}
|
|
@@ -111,7 +144,27 @@ export class AztecKVTxPool implements TxPool {
|
|
|
111
144
|
*/
|
|
112
145
|
public getTxByHash(txHash: TxHash): Tx | undefined {
|
|
113
146
|
const buffer = this.#txs.get(txHash.toString());
|
|
114
|
-
|
|
147
|
+
if (buffer) {
|
|
148
|
+
const tx = Tx.fromBuffer(buffer);
|
|
149
|
+
tx.setTxHash(txHash);
|
|
150
|
+
return tx;
|
|
151
|
+
}
|
|
152
|
+
return undefined;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Checks if an archived tx exists and returns it.
|
|
157
|
+
* @param txHash - The tx hash.
|
|
158
|
+
* @returns The transaction metadata, if found, 'undefined' otherwise.
|
|
159
|
+
*/
|
|
160
|
+
public getArchivedTxByHash(txHash: TxHash): Tx | undefined {
|
|
161
|
+
const buffer = this.#archivedTxs.get(txHash.toString());
|
|
162
|
+
if (buffer) {
|
|
163
|
+
const tx = Tx.fromBuffer(buffer);
|
|
164
|
+
tx.setTxHash(txHash);
|
|
165
|
+
return tx;
|
|
166
|
+
}
|
|
167
|
+
return undefined;
|
|
115
168
|
}
|
|
116
169
|
|
|
117
170
|
/**
|
|
@@ -120,11 +173,10 @@ export class AztecKVTxPool implements TxPool {
|
|
|
120
173
|
* @returns Empty promise.
|
|
121
174
|
*/
|
|
122
175
|
public addTxs(txs: Tx[]): Promise<void> {
|
|
123
|
-
const txHashes = txs.map(tx => tx.getTxHash());
|
|
124
176
|
return this.#store.transaction(() => {
|
|
125
177
|
let pendingCount = 0;
|
|
126
|
-
for (const
|
|
127
|
-
const txHash =
|
|
178
|
+
for (const tx of txs) {
|
|
179
|
+
const txHash = tx.getTxHash();
|
|
128
180
|
this.#log.verbose(`Adding tx ${txHash.toString()} to pool`, {
|
|
129
181
|
eventName: 'tx-added-to-pool',
|
|
130
182
|
...tx.getStats(),
|
|
@@ -132,10 +184,11 @@ export class AztecKVTxPool implements TxPool {
|
|
|
132
184
|
|
|
133
185
|
const key = txHash.toString();
|
|
134
186
|
void this.#txs.set(key, tx.toBuffer());
|
|
135
|
-
|
|
187
|
+
|
|
188
|
+
if (!this.#minedTxHashToBlock.has(key)) {
|
|
136
189
|
pendingCount++;
|
|
137
190
|
// REFACTOR: Use an lmdb conditional write to avoid race conditions with this write tx
|
|
138
|
-
void this.#
|
|
191
|
+
void this.#pendingTxPriorityToHash.set(getPendingTxPriority(tx), key);
|
|
139
192
|
this.#metrics.recordSize(tx);
|
|
140
193
|
}
|
|
141
194
|
}
|
|
@@ -147,29 +200,43 @@ export class AztecKVTxPool implements TxPool {
|
|
|
147
200
|
/**
|
|
148
201
|
* Deletes transactions from the pool. Tx hashes that are not present are ignored.
|
|
149
202
|
* @param txHashes - An array of tx hashes to be removed from the tx pool.
|
|
150
|
-
* @returns
|
|
203
|
+
* @returns Empty promise.
|
|
151
204
|
*/
|
|
152
205
|
public deleteTxs(txHashes: TxHash[]): Promise<void> {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
206
|
+
let pendingDeleted = 0;
|
|
207
|
+
let minedDeleted = 0;
|
|
208
|
+
|
|
209
|
+
const deletedTxs: Tx[] = [];
|
|
210
|
+
const poolDbTx = this.#store.transaction(() => {
|
|
156
211
|
for (const hash of txHashes) {
|
|
157
212
|
const key = hash.toString();
|
|
158
|
-
|
|
159
|
-
if (this.#pendingTxs.has(key)) {
|
|
160
|
-
pendingDeleted++;
|
|
161
|
-
void this.#pendingTxs.delete(key);
|
|
162
|
-
}
|
|
213
|
+
const tx = this.getTxByHash(hash);
|
|
163
214
|
|
|
164
|
-
if (
|
|
165
|
-
|
|
166
|
-
void this.#
|
|
215
|
+
if (tx) {
|
|
216
|
+
const fee = getPendingTxPriority(tx);
|
|
217
|
+
void this.#pendingTxPriorityToHash.deleteValue(fee, key);
|
|
218
|
+
|
|
219
|
+
const isMined = this.#minedTxHashToBlock.has(key);
|
|
220
|
+
if (isMined) {
|
|
221
|
+
minedDeleted++;
|
|
222
|
+
} else {
|
|
223
|
+
pendingDeleted++;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if (this.#archivedTxLimit) {
|
|
227
|
+
deletedTxs.push(tx);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
void this.#txs.delete(key);
|
|
231
|
+
void this.#minedTxHashToBlock.delete(key);
|
|
167
232
|
}
|
|
168
233
|
}
|
|
169
234
|
|
|
170
235
|
this.#metrics.recordRemovedObjects(pendingDeleted, 'pending');
|
|
171
236
|
this.#metrics.recordRemovedObjects(minedDeleted, 'mined');
|
|
172
237
|
});
|
|
238
|
+
|
|
239
|
+
return this.#archivedTxLimit ? poolDbTx.then(() => this.archiveTxs(deletedTxs)) : poolDbTx;
|
|
173
240
|
}
|
|
174
241
|
|
|
175
242
|
/**
|
|
@@ -177,7 +244,11 @@ export class AztecKVTxPool implements TxPool {
|
|
|
177
244
|
* @returns Array of tx objects in the order they were added to the pool.
|
|
178
245
|
*/
|
|
179
246
|
public getAllTxs(): Tx[] {
|
|
180
|
-
return Array.from(this.#txs.
|
|
247
|
+
return Array.from(this.#txs.entries()).map(([hash, buffer]) => {
|
|
248
|
+
const tx = Tx.fromBuffer(buffer);
|
|
249
|
+
tx.setTxHash(TxHash.fromString(hash));
|
|
250
|
+
return tx;
|
|
251
|
+
});
|
|
181
252
|
}
|
|
182
253
|
|
|
183
254
|
/**
|
|
@@ -187,4 +258,41 @@ export class AztecKVTxPool implements TxPool {
|
|
|
187
258
|
public getAllTxHashes(): TxHash[] {
|
|
188
259
|
return Array.from(this.#txs.keys()).map(x => TxHash.fromString(x));
|
|
189
260
|
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Archives a list of txs for future reference. The number of archived txs is limited by the specified archivedTxLimit.
|
|
264
|
+
* @param txs - The list of transactions to archive.
|
|
265
|
+
* @returns Empty promise.
|
|
266
|
+
*/
|
|
267
|
+
private archiveTxs(txs: Tx[]): Promise<void> {
|
|
268
|
+
return this.#archive.transaction(() => {
|
|
269
|
+
// calcualte the head and tail indices of the archived txs by insertion order.
|
|
270
|
+
let headIdx = (this.#archivedTxIndices.entries({ limit: 1, reverse: true }).next().value?.[0] ?? -1) + 1;
|
|
271
|
+
let tailIdx = this.#archivedTxIndices.entries({ limit: 1 }).next().value?.[0] ?? 0;
|
|
272
|
+
|
|
273
|
+
for (const tx of txs) {
|
|
274
|
+
while (headIdx - tailIdx >= this.#archivedTxLimit) {
|
|
275
|
+
const txHash = this.#archivedTxIndices.get(tailIdx);
|
|
276
|
+
if (txHash) {
|
|
277
|
+
void this.#archivedTxs.delete(txHash);
|
|
278
|
+
void this.#archivedTxIndices.delete(tailIdx);
|
|
279
|
+
}
|
|
280
|
+
tailIdx++;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
const archivedTx: Tx = new Tx(
|
|
284
|
+
tx.data,
|
|
285
|
+
ClientIvcProof.empty(),
|
|
286
|
+
tx.unencryptedLogs,
|
|
287
|
+
tx.contractClassLogs,
|
|
288
|
+
tx.enqueuedPublicFunctionCalls,
|
|
289
|
+
tx.publicTeardownFunctionCall,
|
|
290
|
+
);
|
|
291
|
+
const txHash = tx.getTxHash().toString();
|
|
292
|
+
void this.#archivedTxs.set(txHash, archivedTx.toBuffer());
|
|
293
|
+
void this.#archivedTxIndices.set(headIdx, txHash);
|
|
294
|
+
headIdx++;
|
|
295
|
+
}
|
|
296
|
+
});
|
|
297
|
+
}
|
|
190
298
|
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { Tx, TxHash } from '@aztec/circuit-types';
|
|
2
2
|
import { type TxAddedToPoolStats } from '@aztec/circuit-types/stats';
|
|
3
3
|
import { createLogger } from '@aztec/foundation/log';
|
|
4
|
-
import { type TelemetryClient } from '@aztec/telemetry-client';
|
|
4
|
+
import { type TelemetryClient, getTelemetryClient } from '@aztec/telemetry-client';
|
|
5
5
|
|
|
6
6
|
import { PoolInstrumentation, PoolName } from '../instrumentation.js';
|
|
7
|
+
import { getPendingTxPriority } from './priority.js';
|
|
7
8
|
import { type TxPool } from './tx_pool.js';
|
|
8
9
|
|
|
9
10
|
/**
|
|
@@ -23,7 +24,7 @@ export class InMemoryTxPool implements TxPool {
|
|
|
23
24
|
* Class constructor for in-memory TxPool. Initiates our transaction pool as a JS Map.
|
|
24
25
|
* @param log - A logger.
|
|
25
26
|
*/
|
|
26
|
-
constructor(telemetry: TelemetryClient, private log = createLogger('p2p:tx_pool')) {
|
|
27
|
+
constructor(telemetry: TelemetryClient = getTelemetryClient(), private log = createLogger('p2p:tx_pool')) {
|
|
27
28
|
this.txs = new Map<bigint, Tx>();
|
|
28
29
|
this.minedTxs = new Map();
|
|
29
30
|
this.pendingTxs = new Set();
|
|
@@ -68,7 +69,10 @@ export class InMemoryTxPool implements TxPool {
|
|
|
68
69
|
}
|
|
69
70
|
|
|
70
71
|
public getPendingTxHashes(): TxHash[] {
|
|
71
|
-
return
|
|
72
|
+
return this.getAllTxs()
|
|
73
|
+
.sort((tx1, tx2) => -getPendingTxPriority(tx1).localeCompare(getPendingTxPriority(tx2)))
|
|
74
|
+
.map(tx => tx.getTxHash())
|
|
75
|
+
.filter(txHash => this.pendingTxs.has(txHash.toBigInt()));
|
|
72
76
|
}
|
|
73
77
|
|
|
74
78
|
public getMinedTxHashes(): [TxHash, number][] {
|
|
@@ -96,6 +100,10 @@ export class InMemoryTxPool implements TxPool {
|
|
|
96
100
|
return result === undefined ? undefined : Tx.clone(result);
|
|
97
101
|
}
|
|
98
102
|
|
|
103
|
+
public getArchivedTxByHash(): Tx | undefined {
|
|
104
|
+
return undefined;
|
|
105
|
+
}
|
|
106
|
+
|
|
99
107
|
/**
|
|
100
108
|
* Adds a list of transactions to the pool. Duplicates are ignored.
|
|
101
109
|
* @param txs - An array of txs to be added to the pool.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type Tx } from '@aztec/circuit-types';
|
|
2
|
+
import { Buffer32 } from '@aztec/foundation/buffer';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Returns a string representing the priority of a tx.
|
|
6
|
+
* Txs with a higher priority value are returned first when retrieving pending tx hashes.
|
|
7
|
+
* We currently use the sum of the priority fees for the tx for this value, represented as hex.
|
|
8
|
+
*/
|
|
9
|
+
export function getPendingTxPriority(tx: Tx): string {
|
|
10
|
+
const priorityFees = tx.getGasSettings().maxPriorityFeesPerGas;
|
|
11
|
+
const totalFees = priorityFees.feePerDaGas.toBigInt() + priorityFees.feePerL2Gas.toBigInt();
|
|
12
|
+
return Buffer32.fromBigInt(totalFees).toString();
|
|
13
|
+
}
|
|
@@ -17,6 +17,13 @@ export interface TxPool {
|
|
|
17
17
|
*/
|
|
18
18
|
getTxByHash(txHash: TxHash): Tx | undefined;
|
|
19
19
|
|
|
20
|
+
/**
|
|
21
|
+
* Checks if an archived transaction exists in the pool and returns it.
|
|
22
|
+
* @param txHash - The hash of the transaction, used as an ID.
|
|
23
|
+
* @returns The transaction, if found, 'undefined' otherwise.
|
|
24
|
+
*/
|
|
25
|
+
getArchivedTxByHash(txHash: TxHash): Tx | undefined;
|
|
26
|
+
|
|
20
27
|
/**
|
|
21
28
|
* Marks the set of txs as mined, as opposed to pending.
|
|
22
29
|
* @param txHashes - Hashes of the txs to flag as mined.
|
|
@@ -49,7 +56,7 @@ export interface TxPool {
|
|
|
49
56
|
getAllTxHashes(): TxHash[];
|
|
50
57
|
|
|
51
58
|
/**
|
|
52
|
-
* Gets the hashes of pending transactions currently in the tx pool.
|
|
59
|
+
* Gets the hashes of pending transactions currently in the tx pool sorted by priority (see getPendingTxPriority).
|
|
53
60
|
* @returns An array of pending transaction hashes found in the tx pool.
|
|
54
61
|
*/
|
|
55
62
|
getPendingTxHashes(): TxHash[];
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import { mockTx } from '@aztec/circuit-types';
|
|
1
|
+
import { type Tx, mockTx } from '@aztec/circuit-types';
|
|
2
|
+
import { GasFees } from '@aztec/circuits.js';
|
|
3
|
+
import { unfreeze } from '@aztec/foundation/types';
|
|
2
4
|
|
|
3
5
|
import { type TxPool } from './tx_pool.js';
|
|
4
6
|
|
|
@@ -67,10 +69,12 @@ export function describeTxPool(getTxPool: () => TxPool) {
|
|
|
67
69
|
await pool.addTxs([tx1]);
|
|
68
70
|
// this peer knows that tx2 was mined, but it does not have the tx object
|
|
69
71
|
await pool.markAsMined([tx1.getTxHash(), someTxHashThatThisPeerDidNotSee], 1);
|
|
70
|
-
expect(pool.getMinedTxHashes()).toEqual(
|
|
71
|
-
[
|
|
72
|
-
|
|
73
|
-
|
|
72
|
+
expect(new Set(pool.getMinedTxHashes())).toEqual(
|
|
73
|
+
new Set([
|
|
74
|
+
[tx1.getTxHash(), 1],
|
|
75
|
+
[someTxHashThatThisPeerDidNotSee, 1],
|
|
76
|
+
]),
|
|
77
|
+
);
|
|
74
78
|
|
|
75
79
|
// reorg: both txs should now become available again
|
|
76
80
|
await pool.markMinedAsPending([tx1.getTxHash(), someTxHashThatThisPeerDidNotSee]);
|
|
@@ -101,4 +105,22 @@ export function describeTxPool(getTxPool: () => TxPool) {
|
|
|
101
105
|
expect(poolTxHashes).toHaveLength(3);
|
|
102
106
|
expect(poolTxHashes).toEqual(expect.arrayContaining([tx1.getTxHash(), tx2.getTxHash(), tx3.getTxHash()]));
|
|
103
107
|
});
|
|
108
|
+
|
|
109
|
+
it('Returns pending tx hashes sorted by priority', async () => {
|
|
110
|
+
const withPriorityFee = (tx: Tx, fee: number) => {
|
|
111
|
+
unfreeze(tx.data.constants.txContext.gasSettings).maxPriorityFeesPerGas = new GasFees(fee, fee);
|
|
112
|
+
return tx;
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
const tx1 = withPriorityFee(mockTx(0), 1000);
|
|
116
|
+
const tx2 = withPriorityFee(mockTx(1), 100);
|
|
117
|
+
const tx3 = withPriorityFee(mockTx(2), 200);
|
|
118
|
+
const tx4 = withPriorityFee(mockTx(3), 3000);
|
|
119
|
+
|
|
120
|
+
await pool.addTxs([tx1, tx2, tx3, tx4]);
|
|
121
|
+
|
|
122
|
+
const poolTxHashes = pool.getPendingTxHashes();
|
|
123
|
+
expect(poolTxHashes).toHaveLength(4);
|
|
124
|
+
expect(poolTxHashes).toEqual([tx4, tx1, tx3, tx2].map(tx => tx.getTxHash()));
|
|
125
|
+
});
|
|
104
126
|
}
|
package/src/mocks/index.ts
CHANGED
|
@@ -8,8 +8,7 @@ import {
|
|
|
8
8
|
import { type EpochCache } from '@aztec/epoch-cache';
|
|
9
9
|
import { type DataStoreConfig } from '@aztec/kv-store/config';
|
|
10
10
|
import { openTmpStore } from '@aztec/kv-store/lmdb';
|
|
11
|
-
import { type TelemetryClient } from '@aztec/telemetry-client';
|
|
12
|
-
import { NoopTelemetryClient } from '@aztec/telemetry-client/noop';
|
|
11
|
+
import { type TelemetryClient, getTelemetryClient } from '@aztec/telemetry-client';
|
|
13
12
|
|
|
14
13
|
import { gossipsub } from '@chainsafe/libp2p-gossipsub';
|
|
15
14
|
import { noise } from '@chainsafe/libp2p-noise';
|
|
@@ -247,7 +246,7 @@ export function createBootstrapNodeConfig(privateKey: string, port: number): Boo
|
|
|
247
246
|
export function createBootstrapNodeFromPrivateKey(
|
|
248
247
|
privateKey: string,
|
|
249
248
|
port: number,
|
|
250
|
-
telemetry: TelemetryClient =
|
|
249
|
+
telemetry: TelemetryClient = getTelemetryClient(),
|
|
251
250
|
): Promise<BootstrapNode> {
|
|
252
251
|
const config = createBootstrapNodeConfig(privateKey, port);
|
|
253
252
|
return startBootstrapNode(config, telemetry);
|
|
@@ -255,7 +254,7 @@ export function createBootstrapNodeFromPrivateKey(
|
|
|
255
254
|
|
|
256
255
|
export async function createBootstrapNode(
|
|
257
256
|
port: number,
|
|
258
|
-
telemetry: TelemetryClient =
|
|
257
|
+
telemetry: TelemetryClient = getTelemetryClient(),
|
|
259
258
|
): Promise<BootstrapNode> {
|
|
260
259
|
const peerId = await createSecp256k1PeerId();
|
|
261
260
|
const config = createBootstrapNodeConfig(Buffer.from(peerId.privateKey!).toString('hex'), port);
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type AnyTx, Tx, type TxValidationResult, type TxValidator } from '@aztec/circuit-types';
|
|
2
|
+
import { type Fr } from '@aztec/circuits.js';
|
|
3
|
+
import { createLogger } from '@aztec/foundation/log';
|
|
4
|
+
|
|
5
|
+
export interface ArchiveSource {
|
|
6
|
+
getArchiveIndices: (archives: Fr[]) => Promise<(bigint | undefined)[]>;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export class BlockHeaderTxValidator<T extends AnyTx> implements TxValidator<T> {
|
|
10
|
+
#log = createLogger('p2p:tx_validator:tx_block_header');
|
|
11
|
+
#archiveSource: ArchiveSource;
|
|
12
|
+
|
|
13
|
+
constructor(archiveSource: ArchiveSource) {
|
|
14
|
+
this.#archiveSource = archiveSource;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async validateTx(tx: T): Promise<TxValidationResult> {
|
|
18
|
+
const [index] = await this.#archiveSource.getArchiveIndices([tx.data.constants.historicalHeader.hash()]);
|
|
19
|
+
if (index === undefined) {
|
|
20
|
+
this.#log.warn(`Rejecting tx ${Tx.getHash(tx)} for referencing an unknown block header`);
|
|
21
|
+
return { result: 'invalid', reason: ['Block header not found'] };
|
|
22
|
+
}
|
|
23
|
+
return { result: 'valid' };
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createLogger } from '@aztec/foundation/log';
|
|
2
2
|
import { sleep } from '@aztec/foundation/sleep';
|
|
3
|
-
import { OtelMetricsAdapter, type TelemetryClient } from '@aztec/telemetry-client';
|
|
3
|
+
import { OtelMetricsAdapter, type TelemetryClient, getTelemetryClient } from '@aztec/telemetry-client';
|
|
4
4
|
|
|
5
5
|
import { Discv5, type Discv5EventEmitter } from '@chainsafe/discv5';
|
|
6
6
|
import { ENR, SignableENR } from '@chainsafe/enr';
|
|
@@ -38,7 +38,7 @@ export class DiscV5Service extends EventEmitter implements PeerDiscoveryService
|
|
|
38
38
|
constructor(
|
|
39
39
|
private peerId: PeerId,
|
|
40
40
|
config: P2PConfig,
|
|
41
|
-
telemetry: TelemetryClient,
|
|
41
|
+
telemetry: TelemetryClient = getTelemetryClient(),
|
|
42
42
|
private logger = createLogger('p2p:discv5_service'),
|
|
43
43
|
) {
|
|
44
44
|
super();
|