@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.
Files changed (57) hide show
  1. package/dest/client/factory.d.ts.map +1 -1
  2. package/dest/client/factory.js +6 -5
  3. package/dest/client/p2p_client.d.ts +16 -2
  4. package/dest/client/p2p_client.d.ts.map +1 -1
  5. package/dest/client/p2p_client.js +17 -9
  6. package/dest/config.d.ts +3 -0
  7. package/dest/config.d.ts.map +1 -1
  8. package/dest/config.js +6 -1
  9. package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts +1 -1
  10. package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts.map +1 -1
  11. package/dest/mem_pools/attestation_pool/kv_attestation_pool.js +3 -2
  12. package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts +1 -1
  13. package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts.map +1 -1
  14. package/dest/mem_pools/attestation_pool/memory_attestation_pool.js +3 -2
  15. package/dest/mem_pools/epoch_proof_quote_pool/memory_epoch_proof_quote_pool.d.ts +1 -1
  16. package/dest/mem_pools/epoch_proof_quote_pool/memory_epoch_proof_quote_pool.d.ts.map +1 -1
  17. package/dest/mem_pools/epoch_proof_quote_pool/memory_epoch_proof_quote_pool.js +3 -2
  18. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts +20 -5
  19. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts.map +1 -1
  20. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.js +134 -55
  21. package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts +2 -1
  22. package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts.map +1 -1
  23. package/dest/mem_pools/tx_pool/memory_tx_pool.js +11 -3
  24. package/dest/mem_pools/tx_pool/priority.d.ts +8 -0
  25. package/dest/mem_pools/tx_pool/priority.d.ts.map +1 -0
  26. package/dest/mem_pools/tx_pool/priority.js +12 -0
  27. package/dest/mem_pools/tx_pool/tx_pool.d.ts +7 -1
  28. package/dest/mem_pools/tx_pool/tx_pool.d.ts.map +1 -1
  29. package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts.map +1 -1
  30. package/dest/mem_pools/tx_pool/tx_pool_test_suite.js +19 -3
  31. package/dest/mocks/index.d.ts.map +1 -1
  32. package/dest/mocks/index.js +4 -4
  33. package/dest/msg_validators/tx_validator/block_header_validator.d.ts +11 -0
  34. package/dest/msg_validators/tx_validator/block_header_validator.d.ts.map +1 -0
  35. package/dest/msg_validators/tx_validator/block_header_validator.js +21 -0
  36. package/dest/msg_validators/tx_validator/index.d.ts +1 -0
  37. package/dest/msg_validators/tx_validator/index.d.ts.map +1 -1
  38. package/dest/msg_validators/tx_validator/index.js +2 -1
  39. package/dest/services/discv5/discV5_service.d.ts +1 -1
  40. package/dest/services/discv5/discV5_service.d.ts.map +1 -1
  41. package/dest/services/discv5/discV5_service.js +3 -3
  42. package/package.json +7 -7
  43. package/src/client/factory.ts +5 -13
  44. package/src/client/p2p_client.ts +27 -9
  45. package/src/config.ts +9 -0
  46. package/src/mem_pools/attestation_pool/kv_attestation_pool.ts +2 -2
  47. package/src/mem_pools/attestation_pool/memory_attestation_pool.ts +2 -2
  48. package/src/mem_pools/epoch_proof_quote_pool/memory_epoch_proof_quote_pool.ts +2 -2
  49. package/src/mem_pools/tx_pool/aztec_kv_tx_pool.ts +161 -53
  50. package/src/mem_pools/tx_pool/memory_tx_pool.ts +11 -3
  51. package/src/mem_pools/tx_pool/priority.ts +13 -0
  52. package/src/mem_pools/tx_pool/tx_pool.ts +8 -1
  53. package/src/mem_pools/tx_pool/tx_pool_test_suite.ts +27 -5
  54. package/src/mocks/index.ts +3 -4
  55. package/src/msg_validators/tx_validator/block_header_validator.ts +25 -0
  56. package/src/msg_validators/tx_validator/index.ts +1 -0
  57. 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 AztecSet } from '@aztec/kv-store';
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
- * In-memory implementation of the Transaction Pool.
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 for pending txs. */
20
- #pendingTxs: AztecSet<string>;
21
- /** Index for mined txs. */
22
- #minedTxs: AztecMap<string, number>;
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 in-memory TxPool. Initiates our transaction pool as a JS Map.
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(store: AztecKVStore, telemetry: TelemetryClient, log = createLogger('p2p:tx_pool')) {
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.#minedTxs = store.openMap('minedTxs');
36
- this.#pendingTxs = store.openSet('pendingTxs');
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.#minedTxs.set(key, blockNumber);
49
- if (this.#pendingTxs.has(key)) {
50
- deleted++;
51
- void this.#pendingTxs.delete(key);
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
- if (this.#minedTxs.has(key)) {
70
- deleted++;
71
- void this.#minedTxs.delete(key);
72
- }
104
+ void this.#minedTxHashToBlock.delete(key);
73
105
 
74
- if (this.#txs.has(key)) {
75
- added++;
76
- void this.#pendingTxs.add(key);
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.recordRemovedObjects(deleted, 'mined');
81
- this.#metrics.recordAddedObjects(added, 'pending');
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.#pendingTxs.entries()).map(x => TxHash.fromString(x));
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.#minedTxs.entries()).map(([txHash, blockNumber]) => [
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.#pendingTxs.has(key)) {
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
- return buffer ? Tx.fromBuffer(buffer) : undefined;
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 [i, tx] of txs.entries()) {
127
- const txHash = txHashes[i];
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
- if (!this.#minedTxs.has(key)) {
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.#pendingTxs.add(key);
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 The number of transactions that was deleted from the pool.
203
+ * @returns Empty promise.
151
204
  */
152
205
  public deleteTxs(txHashes: TxHash[]): Promise<void> {
153
- return this.#store.transaction(() => {
154
- let pendingDeleted = 0;
155
- let minedDeleted = 0;
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
- void this.#txs.delete(key);
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 (this.#minedTxs.has(key)) {
165
- minedDeleted++;
166
- void this.#minedTxs.delete(key);
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.values()).map(buffer => Tx.fromBuffer(buffer));
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 Array.from(this.pendingTxs).map(x => TxHash.fromBigInt(x));
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
- [tx1.getTxHash(), 1],
72
- [someTxHashThatThisPeerDidNotSee, 1],
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
  }
@@ -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 = new NoopTelemetryClient(),
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 = new NoopTelemetryClient(),
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
+ }
@@ -3,3 +3,4 @@ export * from './data_validator.js';
3
3
  export * from './double_spend_validator.js';
4
4
  export * from './metadata_validator.js';
5
5
  export * from './tx_proof_validator.js';
6
+ export * from './block_header_validator.js';
@@ -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();