@aztec/p2p 0.0.1-commit.cf93bcc56 → 0.0.1-commit.d0fcfb7f

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 (226) hide show
  1. package/dest/client/factory.d.ts +4 -5
  2. package/dest/client/factory.d.ts.map +1 -1
  3. package/dest/client/factory.js +20 -26
  4. package/dest/client/interface.d.ts +8 -13
  5. package/dest/client/interface.d.ts.map +1 -1
  6. package/dest/client/p2p_client.d.ts +7 -13
  7. package/dest/client/p2p_client.d.ts.map +1 -1
  8. package/dest/client/p2p_client.js +35 -86
  9. package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.js +6 -7
  10. package/dest/config.d.ts +29 -10
  11. package/dest/config.d.ts.map +1 -1
  12. package/dest/config.js +80 -31
  13. package/dest/mem_pools/tx_pool/priority.d.ts +2 -2
  14. package/dest/mem_pools/tx_pool/priority.d.ts.map +1 -1
  15. package/dest/mem_pools/tx_pool/priority.js +4 -4
  16. package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts +1 -1
  17. package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts.map +1 -1
  18. package/dest/mem_pools/tx_pool/tx_pool_test_suite.js +3 -1
  19. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.js +1 -1
  20. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.d.ts +1 -1
  21. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.d.ts.map +1 -1
  22. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.js +2 -0
  23. package/dest/mem_pools/tx_pool_v2/eviction/interfaces.d.ts +7 -1
  24. package/dest/mem_pools/tx_pool_v2/eviction/interfaces.d.ts.map +1 -1
  25. package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.js +2 -2
  26. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.d.ts +2 -2
  27. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.d.ts.map +1 -1
  28. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.js +10 -6
  29. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.d.ts +1 -1
  30. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.d.ts.map +1 -1
  31. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.js +8 -6
  32. package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.d.ts +2 -2
  33. package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.d.ts.map +1 -1
  34. package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.js +2 -2
  35. package/dest/mem_pools/tx_pool_v2/index.d.ts +2 -2
  36. package/dest/mem_pools/tx_pool_v2/index.d.ts.map +1 -1
  37. package/dest/mem_pools/tx_pool_v2/index.js +1 -1
  38. package/dest/mem_pools/tx_pool_v2/interfaces.d.ts +10 -6
  39. package/dest/mem_pools/tx_pool_v2/interfaces.d.ts.map +1 -1
  40. package/dest/mem_pools/tx_pool_v2/interfaces.js +2 -1
  41. package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts +38 -7
  42. package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts.map +1 -1
  43. package/dest/mem_pools/tx_pool_v2/tx_metadata.js +74 -16
  44. package/dest/mem_pools/tx_pool_v2/tx_pool_indices.d.ts +1 -1
  45. package/dest/mem_pools/tx_pool_v2/tx_pool_indices.d.ts.map +1 -1
  46. package/dest/mem_pools/tx_pool_v2/tx_pool_indices.js +9 -10
  47. package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts +5 -3
  48. package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts.map +1 -1
  49. package/dest/mem_pools/tx_pool_v2/tx_pool_v2.js +2 -2
  50. package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts +5 -3
  51. package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts.map +1 -1
  52. package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.js +169 -141
  53. package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts +6 -4
  54. package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts.map +1 -1
  55. package/dest/msg_validators/proposal_validator/block_proposal_validator.js +10 -2
  56. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts +6 -4
  57. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts.map +1 -1
  58. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.js +16 -2
  59. package/dest/msg_validators/proposal_validator/proposal_validator.d.ts +13 -8
  60. package/dest/msg_validators/proposal_validator/proposal_validator.d.ts.map +1 -1
  61. package/dest/msg_validators/proposal_validator/proposal_validator.js +48 -36
  62. package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts +2 -2
  63. package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts.map +1 -1
  64. package/dest/msg_validators/tx_validator/aggregate_tx_validator.js +3 -3
  65. package/dest/msg_validators/tx_validator/allowed_public_setup.d.ts +2 -1
  66. package/dest/msg_validators/tx_validator/allowed_public_setup.d.ts.map +1 -1
  67. package/dest/msg_validators/tx_validator/allowed_public_setup.js +24 -20
  68. package/dest/msg_validators/tx_validator/allowed_setup_helpers.d.ts +17 -0
  69. package/dest/msg_validators/tx_validator/allowed_setup_helpers.d.ts.map +1 -0
  70. package/dest/msg_validators/tx_validator/allowed_setup_helpers.js +24 -0
  71. package/dest/msg_validators/tx_validator/factory.d.ts +125 -6
  72. package/dest/msg_validators/tx_validator/factory.d.ts.map +1 -1
  73. package/dest/msg_validators/tx_validator/factory.js +226 -58
  74. package/dest/msg_validators/tx_validator/fee_payer_balance.d.ts +1 -1
  75. package/dest/msg_validators/tx_validator/fee_payer_balance.d.ts.map +1 -1
  76. package/dest/msg_validators/tx_validator/fee_payer_balance.js +6 -2
  77. package/dest/msg_validators/tx_validator/gas_validator.d.ts +67 -3
  78. package/dest/msg_validators/tx_validator/gas_validator.d.ts.map +1 -1
  79. package/dest/msg_validators/tx_validator/gas_validator.js +104 -37
  80. package/dest/msg_validators/tx_validator/index.d.ts +3 -1
  81. package/dest/msg_validators/tx_validator/index.d.ts.map +1 -1
  82. package/dest/msg_validators/tx_validator/index.js +2 -0
  83. package/dest/msg_validators/tx_validator/nullifier_cache.d.ts +14 -0
  84. package/dest/msg_validators/tx_validator/nullifier_cache.d.ts.map +1 -0
  85. package/dest/msg_validators/tx_validator/nullifier_cache.js +24 -0
  86. package/dest/msg_validators/tx_validator/phases_validator.d.ts +2 -2
  87. package/dest/msg_validators/tx_validator/phases_validator.d.ts.map +1 -1
  88. package/dest/msg_validators/tx_validator/phases_validator.js +44 -23
  89. package/dest/services/dummy_service.d.ts +4 -4
  90. package/dest/services/dummy_service.d.ts.map +1 -1
  91. package/dest/services/dummy_service.js +4 -4
  92. package/dest/services/encoding.d.ts +2 -2
  93. package/dest/services/encoding.d.ts.map +1 -1
  94. package/dest/services/encoding.js +7 -7
  95. package/dest/services/gossipsub/topic_score_params.d.ts +18 -6
  96. package/dest/services/gossipsub/topic_score_params.d.ts.map +1 -1
  97. package/dest/services/gossipsub/topic_score_params.js +32 -10
  98. package/dest/services/libp2p/libp2p_service.d.ts +16 -13
  99. package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
  100. package/dest/services/libp2p/libp2p_service.js +92 -93
  101. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts +4 -3
  102. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts.map +1 -1
  103. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.js +5 -9
  104. package/dest/services/reqresp/batch-tx-requester/interface.d.ts +2 -6
  105. package/dest/services/reqresp/batch-tx-requester/interface.d.ts.map +1 -1
  106. package/dest/services/reqresp/batch-tx-requester/missing_txs.d.ts +10 -13
  107. package/dest/services/reqresp/batch-tx-requester/missing_txs.d.ts.map +1 -1
  108. package/dest/services/reqresp/batch-tx-requester/missing_txs.js +25 -46
  109. package/dest/services/reqresp/batch-tx-requester/tx_validator.js +2 -2
  110. package/dest/services/service.d.ts +5 -3
  111. package/dest/services/service.d.ts.map +1 -1
  112. package/dest/services/tx_collection/fast_tx_collection.d.ts +1 -1
  113. package/dest/services/tx_collection/fast_tx_collection.d.ts.map +1 -1
  114. package/dest/services/tx_collection/fast_tx_collection.js +39 -33
  115. package/dest/services/tx_collection/file_store_tx_collection.d.ts +1 -1
  116. package/dest/services/tx_collection/file_store_tx_collection.d.ts.map +1 -1
  117. package/dest/services/tx_collection/file_store_tx_collection.js +4 -2
  118. package/dest/services/tx_collection/file_store_tx_source.d.ts +4 -4
  119. package/dest/services/tx_collection/file_store_tx_source.d.ts.map +1 -1
  120. package/dest/services/tx_collection/file_store_tx_source.js +27 -16
  121. package/dest/services/tx_collection/missing_txs_tracker.d.ts +32 -0
  122. package/dest/services/tx_collection/missing_txs_tracker.d.ts.map +1 -0
  123. package/dest/services/tx_collection/missing_txs_tracker.js +27 -0
  124. package/dest/services/tx_collection/proposal_tx_collector.d.ts +7 -6
  125. package/dest/services/tx_collection/proposal_tx_collector.d.ts.map +1 -1
  126. package/dest/services/tx_collection/proposal_tx_collector.js +5 -4
  127. package/dest/services/tx_collection/slow_tx_collection.d.ts +2 -2
  128. package/dest/services/tx_collection/slow_tx_collection.d.ts.map +1 -1
  129. package/dest/services/tx_collection/slow_tx_collection.js +10 -8
  130. package/dest/services/tx_collection/tx_collection.d.ts +5 -4
  131. package/dest/services/tx_collection/tx_collection.d.ts.map +1 -1
  132. package/dest/services/tx_collection/tx_collection_sink.d.ts +6 -5
  133. package/dest/services/tx_collection/tx_collection_sink.d.ts.map +1 -1
  134. package/dest/services/tx_collection/tx_collection_sink.js +13 -22
  135. package/dest/services/tx_collection/tx_source.d.ts +8 -3
  136. package/dest/services/tx_collection/tx_source.d.ts.map +1 -1
  137. package/dest/services/tx_collection/tx_source.js +19 -2
  138. package/dest/services/tx_provider.d.ts +3 -3
  139. package/dest/services/tx_provider.d.ts.map +1 -1
  140. package/dest/services/tx_provider.js +4 -4
  141. package/dest/test-helpers/make-test-p2p-clients.d.ts +5 -6
  142. package/dest/test-helpers/make-test-p2p-clients.d.ts.map +1 -1
  143. package/dest/test-helpers/make-test-p2p-clients.js +1 -2
  144. package/dest/test-helpers/mock-pubsub.d.ts +4 -4
  145. package/dest/test-helpers/mock-pubsub.d.ts.map +1 -1
  146. package/dest/test-helpers/mock-pubsub.js +8 -2
  147. package/dest/test-helpers/reqresp-nodes.d.ts +2 -3
  148. package/dest/test-helpers/reqresp-nodes.d.ts.map +1 -1
  149. package/dest/test-helpers/reqresp-nodes.js +2 -2
  150. package/dest/test-helpers/testbench-utils.d.ts +5 -3
  151. package/dest/test-helpers/testbench-utils.d.ts.map +1 -1
  152. package/dest/test-helpers/testbench-utils.js +3 -2
  153. package/dest/testbench/p2p_client_testbench_worker.d.ts +2 -2
  154. package/dest/testbench/p2p_client_testbench_worker.d.ts.map +1 -1
  155. package/dest/testbench/p2p_client_testbench_worker.js +13 -12
  156. package/dest/testbench/worker_client_manager.d.ts +3 -1
  157. package/dest/testbench/worker_client_manager.d.ts.map +1 -1
  158. package/dest/testbench/worker_client_manager.js +4 -1
  159. package/dest/util.d.ts +2 -2
  160. package/dest/util.d.ts.map +1 -1
  161. package/package.json +14 -14
  162. package/src/client/factory.ts +28 -46
  163. package/src/client/interface.ts +8 -13
  164. package/src/client/p2p_client.ts +35 -113
  165. package/src/client/test/tx_proposal_collector/proposal_tx_collector_worker.ts +19 -10
  166. package/src/config.ts +115 -33
  167. package/src/mem_pools/tx_pool/priority.ts +4 -4
  168. package/src/mem_pools/tx_pool/tx_pool_test_suite.ts +3 -1
  169. package/src/mem_pools/tx_pool_v2/README.md +9 -1
  170. package/src/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.ts +1 -1
  171. package/src/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.ts +3 -0
  172. package/src/mem_pools/tx_pool_v2/eviction/interfaces.ts +11 -1
  173. package/src/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.ts +2 -2
  174. package/src/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.ts +10 -6
  175. package/src/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.ts +15 -6
  176. package/src/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.ts +2 -1
  177. package/src/mem_pools/tx_pool_v2/index.ts +1 -1
  178. package/src/mem_pools/tx_pool_v2/interfaces.ts +8 -5
  179. package/src/mem_pools/tx_pool_v2/tx_metadata.ts +102 -17
  180. package/src/mem_pools/tx_pool_v2/tx_pool_indices.ts +11 -11
  181. package/src/mem_pools/tx_pool_v2/tx_pool_v2.ts +3 -3
  182. package/src/mem_pools/tx_pool_v2/tx_pool_v2_impl.ts +178 -141
  183. package/src/msg_validators/proposal_validator/block_proposal_validator.ts +14 -4
  184. package/src/msg_validators/proposal_validator/checkpoint_proposal_validator.ts +20 -7
  185. package/src/msg_validators/proposal_validator/proposal_validator.ts +63 -40
  186. package/src/msg_validators/tx_validator/README.md +115 -0
  187. package/src/msg_validators/tx_validator/aggregate_tx_validator.ts +3 -3
  188. package/src/msg_validators/tx_validator/allowed_public_setup.ts +22 -27
  189. package/src/msg_validators/tx_validator/allowed_setup_helpers.ts +31 -0
  190. package/src/msg_validators/tx_validator/factory.ts +366 -77
  191. package/src/msg_validators/tx_validator/fee_payer_balance.ts +6 -2
  192. package/src/msg_validators/tx_validator/gas_validator.ts +123 -27
  193. package/src/msg_validators/tx_validator/index.ts +2 -0
  194. package/src/msg_validators/tx_validator/nullifier_cache.ts +30 -0
  195. package/src/msg_validators/tx_validator/phases_validator.ts +51 -26
  196. package/src/services/dummy_service.ts +6 -6
  197. package/src/services/encoding.ts +5 -6
  198. package/src/services/gossipsub/README.md +29 -14
  199. package/src/services/gossipsub/topic_score_params.ts +49 -13
  200. package/src/services/libp2p/libp2p_service.ts +106 -101
  201. package/src/services/reqresp/batch-tx-requester/batch_tx_requester.ts +6 -6
  202. package/src/services/reqresp/batch-tx-requester/interface.ts +1 -5
  203. package/src/services/reqresp/batch-tx-requester/missing_txs.ts +23 -71
  204. package/src/services/reqresp/batch-tx-requester/tx_validator.ts +2 -2
  205. package/src/services/service.ts +11 -2
  206. package/src/services/tx_collection/fast_tx_collection.ts +51 -30
  207. package/src/services/tx_collection/file_store_tx_collection.ts +7 -3
  208. package/src/services/tx_collection/file_store_tx_source.ts +32 -19
  209. package/src/services/tx_collection/missing_txs_tracker.ts +52 -0
  210. package/src/services/tx_collection/proposal_tx_collector.ts +8 -7
  211. package/src/services/tx_collection/slow_tx_collection.ts +8 -9
  212. package/src/services/tx_collection/tx_collection.ts +4 -3
  213. package/src/services/tx_collection/tx_collection_sink.ts +15 -29
  214. package/src/services/tx_collection/tx_source.ts +22 -3
  215. package/src/services/tx_provider.ts +2 -2
  216. package/src/test-helpers/make-test-p2p-clients.ts +0 -2
  217. package/src/test-helpers/mock-pubsub.ts +13 -6
  218. package/src/test-helpers/reqresp-nodes.ts +2 -5
  219. package/src/test-helpers/testbench-utils.ts +3 -2
  220. package/src/testbench/p2p_client_testbench_worker.ts +21 -17
  221. package/src/testbench/worker_client_manager.ts +11 -4
  222. package/src/util.ts +7 -1
  223. package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.d.ts +0 -23
  224. package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.d.ts.map +0 -1
  225. package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.js +0 -212
  226. package/src/msg_validators/proposal_validator/proposal_validator_test_suite.ts +0 -230
@@ -187,9 +187,35 @@ export class TxPoolV2Impl {
187
187
  const errors = new Map<string, TxPoolRejectionError>();
188
188
  const acceptedPending = new Set<string>();
189
189
 
190
+ // Phase 1: Pre-compute all throwable I/O outside the transaction.
191
+ // If any pre-computation throws, the entire call fails before mutations happen.
192
+ const precomputed = new Map<string, { meta: TxMetaData; minedBlockId: L2BlockId | undefined; isValid: boolean }>();
193
+
194
+ const validator = await this.#createTxValidator();
195
+
196
+ for (const tx of txs) {
197
+ const txHash = tx.getTxHash();
198
+ const txHashStr = txHash.toString();
199
+
200
+ const meta = await buildTxMetaData(tx);
201
+ const minedBlockId = await this.#getMinedBlockId(txHash);
202
+
203
+ // Validate non-mined txs (mined and pre-protected txs bypass validation inside the transaction)
204
+ let isValid = true;
205
+ if (!minedBlockId) {
206
+ isValid = await this.#validateMeta(meta, validator);
207
+ }
208
+
209
+ precomputed.set(txHashStr, { meta, minedBlockId, isValid });
210
+ }
211
+
212
+ // Phase 2: Apply mutations inside the transaction using only pre-computed results,
213
+ // in-memory reads, and buffered DB writes. Nothing here can throw an unhandled exception.
190
214
  const poolAccess = this.#createPreAddPoolAccess();
191
215
  const preAddContext: PreAddContext | undefined =
192
- opts.feeComparisonOnly !== undefined ? { feeComparisonOnly: opts.feeComparisonOnly } : undefined;
216
+ opts.feeComparisonOnly !== undefined
217
+ ? { feeComparisonOnly: opts.feeComparisonOnly, priceBumpPercentage: this.#config.priceBumpPercentage }
218
+ : undefined;
193
219
 
194
220
  await this.#store.transactionAsync(async () => {
195
221
  for (const tx of txs) {
@@ -202,22 +228,25 @@ export class TxPoolV2Impl {
202
228
  continue;
203
229
  }
204
230
 
205
- // Check mined status first (applies to all paths)
206
- const minedBlockId = await this.#getMinedBlockId(txHash);
231
+ const { meta, minedBlockId, isValid } = precomputed.get(txHashStr)!;
207
232
  const preProtectedSlot = this.#indices.getProtectionSlot(txHashStr);
208
233
 
209
234
  if (minedBlockId) {
210
235
  // Already mined - add directly (protection already set if pre-protected)
211
- await this.#addTx(tx, { mined: minedBlockId }, opts);
236
+ await this.#addTx(tx, { mined: minedBlockId }, opts, meta);
212
237
  accepted.push(txHash);
213
238
  } else if (preProtectedSlot !== undefined) {
214
239
  // Pre-protected and not mined - add as protected (bypass validation)
215
- await this.#addTx(tx, { protected: preProtectedSlot }, opts);
240
+ await this.#addTx(tx, { protected: preProtectedSlot }, opts, meta);
216
241
  accepted.push(txHash);
242
+ } else if (!isValid) {
243
+ // Failed pre-computed validation
244
+ rejected.push(txHash);
217
245
  } else {
218
- // Regular pending tx - validate and run pre-add rules
246
+ // Regular pending tx - run pre-add rules using pre-computed metadata
219
247
  const result = await this.#tryAddRegularPendingTx(
220
248
  tx,
249
+ meta,
221
250
  opts,
222
251
  poolAccess,
223
252
  acceptedPending,
@@ -227,13 +256,18 @@ export class TxPoolV2Impl {
227
256
  );
228
257
  if (result.status === 'accepted') {
229
258
  acceptedPending.add(txHashStr);
230
- } else if (result.status === 'rejected') {
231
- rejected.push(txHash);
232
259
  } else {
233
260
  ignored.push(txHash);
234
261
  }
235
262
  }
236
263
  }
264
+
265
+ // Run post-add eviction rules for pending txs (inside transaction for atomicity)
266
+ if (acceptedPending.size > 0) {
267
+ const feePayers = Array.from(acceptedPending).map(txHash => this.#indices.getMetadata(txHash)!.feePayer);
268
+ const uniqueFeePayers = new Set<string>(feePayers);
269
+ await this.#evictionManager.evictAfterNewTxs(Array.from(acceptedPending), [...uniqueFeePayers]);
270
+ }
237
271
  });
238
272
 
239
273
  // Build final accepted list for pending txs (excludes intra-batch evictions)
@@ -249,37 +283,24 @@ export class TxPoolV2Impl {
249
283
  this.#instrumentation.recordRejected(rejected.length);
250
284
  }
251
285
 
252
- // Run post-add eviction rules for pending txs
253
- if (acceptedPending.size > 0) {
254
- const feePayers = Array.from(acceptedPending).map(txHash => this.#indices.getMetadata(txHash)!.feePayer);
255
- const uniqueFeePayers = new Set<string>(feePayers);
256
- await this.#evictionManager.evictAfterNewTxs(Array.from(acceptedPending), [...uniqueFeePayers]);
257
- }
258
-
259
286
  return { accepted, ignored, rejected, ...(errors.size > 0 ? { errors } : {}) };
260
287
  }
261
288
 
262
- /** Validates and adds a regular pending tx. Returns status. */
289
+ /** Adds a validated pending tx, running pre-add rules and evicting conflicts. */
263
290
  async #tryAddRegularPendingTx(
264
291
  tx: Tx,
292
+ precomputedMeta: TxMetaData,
265
293
  opts: { source?: string },
266
294
  poolAccess: PreAddPoolAccess,
267
295
  acceptedPending: Set<string>,
268
296
  ignored: TxHash[],
269
297
  errors: Map<string, TxPoolRejectionError>,
270
298
  preAddContext?: PreAddContext,
271
- ): Promise<{ status: 'accepted' | 'ignored' | 'rejected' }> {
272
- const txHash = tx.getTxHash();
273
- const txHashStr = txHash.toString();
274
-
275
- // Build metadata and validate using metadata
276
- const meta = await buildTxMetaData(tx);
277
- if (!(await this.#validateMeta(meta))) {
278
- return { status: 'rejected' };
279
- }
299
+ ): Promise<{ status: 'accepted' | 'ignored' }> {
300
+ const txHashStr = tx.getTxHash().toString();
280
301
 
281
302
  // Run pre-add rules
282
- const preAddResult = await this.#evictionManager.runPreAddRules(meta, poolAccess, preAddContext);
303
+ const preAddResult = await this.#evictionManager.runPreAddRules(precomputedMeta, poolAccess, preAddContext);
283
304
 
284
305
  if (preAddResult.shouldIgnore) {
285
306
  this.#log.debug(`Ignoring tx ${txHashStr}: ${preAddResult.reason?.message ?? 'unknown reason'}`);
@@ -317,11 +338,11 @@ export class TxPoolV2Impl {
317
338
  }
318
339
 
319
340
  // Add the transaction
320
- await this.#addTx(tx, 'pending', opts);
341
+ await this.#addTx(tx, 'pending', opts, precomputedMeta);
321
342
  return { status: 'accepted' };
322
343
  }
323
344
 
324
- async canAddPendingTx(tx: Tx): Promise<'accepted' | 'ignored' | 'rejected'> {
345
+ async canAddPendingTx(tx: Tx): Promise<'accepted' | 'ignored'> {
325
346
  const txHashStr = tx.getTxHash().toString();
326
347
 
327
348
  // Check if already in pool
@@ -329,14 +350,8 @@ export class TxPoolV2Impl {
329
350
  return 'ignored';
330
351
  }
331
352
 
332
- // Build metadata and validate using metadata
353
+ // Build metadata and check pre-add rules
333
354
  const meta = await buildTxMetaData(tx);
334
- const validationResult = await this.#validateMeta(meta, undefined, 'can add pending');
335
- if (validationResult !== true) {
336
- return 'rejected';
337
- }
338
-
339
- // Use pre-add rules
340
355
  const poolAccess = this.#createPreAddPoolAccess();
341
356
  const preAddResult = await this.#evictionManager.runPreAddRules(meta, poolAccess);
342
357
 
@@ -379,33 +394,35 @@ export class TxPoolV2Impl {
379
394
  let softDeletedHits = 0;
380
395
  let missingPreviouslyEvicted = 0;
381
396
 
382
- for (const txHash of txHashes) {
383
- const txHashStr = txHash.toString();
397
+ await this.#store.transactionAsync(async () => {
398
+ for (const txHash of txHashes) {
399
+ const txHashStr = txHash.toString();
384
400
 
385
- if (this.#indices.has(txHashStr)) {
386
- // Update protection for existing tx
387
- this.#indices.updateProtection(txHashStr, slotNumber);
388
- } else if (this.#deletedPool.isSoftDeleted(txHashStr)) {
389
- // Resurrect soft-deleted tx as protected
390
- const buffer = await this.#txsDB.getAsync(txHashStr);
391
- if (buffer) {
392
- const tx = Tx.fromBuffer(buffer);
393
- await this.#addTx(tx, { protected: slotNumber });
394
- softDeletedHits++;
401
+ if (this.#indices.has(txHashStr)) {
402
+ // Update protection for existing tx
403
+ this.#indices.updateProtection(txHashStr, slotNumber);
404
+ } else if (this.#deletedPool.isSoftDeleted(txHashStr)) {
405
+ // Resurrect soft-deleted tx as protected
406
+ const buffer = await this.#txsDB.getAsync(txHashStr);
407
+ if (buffer) {
408
+ const tx = Tx.fromBuffer(buffer);
409
+ await this.#addTx(tx, { protected: slotNumber });
410
+ softDeletedHits++;
411
+ } else {
412
+ // Data missing despite soft-delete flag — treat as truly missing
413
+ this.#indices.setProtection(txHashStr, slotNumber);
414
+ missing.push(txHash);
415
+ }
395
416
  } else {
396
- // Data missing despite soft-delete flag treat as truly missing
417
+ // Truly missing pre-record protection for tx we don't have yet
397
418
  this.#indices.setProtection(txHashStr, slotNumber);
398
419
  missing.push(txHash);
399
- }
400
- } else {
401
- // Truly missing — pre-record protection for tx we don't have yet
402
- this.#indices.setProtection(txHashStr, slotNumber);
403
- missing.push(txHash);
404
- if (this.#evictedTxHashes.has(txHashStr)) {
405
- missingPreviouslyEvicted++;
420
+ if (this.#evictedTxHashes.has(txHashStr)) {
421
+ missingPreviouslyEvicted++;
422
+ }
406
423
  }
407
424
  }
408
- }
425
+ });
409
426
 
410
427
  // Record metrics
411
428
  if (softDeletedHits > 0) {
@@ -466,59 +483,63 @@ export class TxPoolV2Impl {
466
483
  }
467
484
  }
468
485
 
469
- // Step 4: Mark txs as mined (only those we have in the pool)
470
- for (const meta of found) {
471
- this.#indices.markAsMined(meta, blockId);
472
- await this.#deletedPool.clearIfMinedHigher(meta.txHash, blockId.number);
473
- }
486
+ await this.#store.transactionAsync(async () => {
487
+ // Step 4: Mark txs as mined (only those we have in the pool)
488
+ for (const meta of found) {
489
+ this.#indices.markAsMined(meta, blockId);
490
+ await this.#deletedPool.clearIfMinedHigher(meta.txHash, blockId.number);
491
+ }
474
492
 
475
- // Step 5: Run eviction rules (remove pending txs with conflicting nullifiers/expired timestamps)
476
- await this.#evictionManager.evictAfterNewBlock(block.header, nullifiers, feePayers);
493
+ // Step 5: Run post-event eviction rules (inside transaction for atomicity)
494
+ await this.#evictionManager.evictAfterNewBlock(block.header, nullifiers, feePayers);
495
+ });
477
496
 
478
497
  this.#log.info(`Marked ${found.length} txs as mined in block ${blockId.number}`);
479
498
  }
480
499
 
481
500
  async prepareForSlot(slotNumber: SlotNumber): Promise<void> {
482
- // Step 0: Clean up slot-deleted txs from previous slots
483
- await this.#deletedPool.cleanupSlotDeleted(slotNumber);
501
+ await this.#store.transactionAsync(async () => {
502
+ // Step 0: Clean up slot-deleted txs from previous slots
503
+ await this.#deletedPool.cleanupSlotDeleted(slotNumber);
484
504
 
485
- // Step 1: Find expired protected txs
486
- const expiredProtected = this.#indices.findExpiredProtectedTxs(slotNumber);
505
+ // Step 1: Find expired protected txs
506
+ const expiredProtected = this.#indices.findExpiredProtectedTxs(slotNumber);
487
507
 
488
- // Step 2: Clear protection for all expired entries (including those without metadata)
489
- this.#indices.clearProtection(expiredProtected);
508
+ // Step 2: Clear protection for all expired entries (including those without metadata)
509
+ this.#indices.clearProtection(expiredProtected);
490
510
 
491
- // Step 3: Filter to only txs that have metadata and are not mined
492
- const txsToRestore = this.#indices.filterRestorable(expiredProtected);
493
- if (txsToRestore.length === 0) {
494
- this.#log.debug(`Preparing for slot ${slotNumber}, no txs to unprotect`);
495
- return;
496
- }
511
+ // Step 3: Filter to only txs that have metadata and are not mined
512
+ const txsToRestore = this.#indices.filterRestorable(expiredProtected);
513
+ if (txsToRestore.length === 0) {
514
+ this.#log.debug(`Preparing for slot ${slotNumber}, no txs to unprotect`);
515
+ return;
516
+ }
497
517
 
498
- this.#log.info(`Preparing for slot ${slotNumber}: unprotecting ${txsToRestore.length} txs`);
518
+ this.#log.info(`Preparing for slot ${slotNumber}: unprotecting ${txsToRestore.length} txs`);
499
519
 
500
- // Step 4: Validate for pending pool
501
- const { valid, invalid } = await this.#revalidateMetadata(txsToRestore, 'during prepareForSlot');
520
+ // Step 4: Validate for pending pool
521
+ const { valid, invalid } = await this.#revalidateMetadata(txsToRestore, 'during prepareForSlot');
502
522
 
503
- // Step 5: Resolve nullifier conflicts and add winners to pending indices
504
- const { added, toEvict } = this.#applyNullifierConflictResolution(valid);
523
+ // Step 5: Resolve nullifier conflicts and add winners to pending indices
524
+ const { added, toEvict } = this.#applyNullifierConflictResolution(valid);
505
525
 
506
- // Step 6: Delete invalid txs and evict conflict losers
507
- await this.#deleteTxsBatch(invalid);
508
- await this.#evictTxs(toEvict, 'NullifierConflict');
526
+ // Step 6: Delete invalid txs and evict conflict losers
527
+ await this.#deleteTxsBatch(invalid);
528
+ await this.#evictTxs(toEvict, 'NullifierConflict');
509
529
 
510
- // Step 7: Run eviction rules (enforce pool size limit)
511
- if (added.length > 0) {
512
- const feePayers = added.map(meta => meta.feePayer);
513
- const uniqueFeePayers = new Set<string>(feePayers);
514
- await this.#evictionManager.evictAfterNewTxs(
515
- added.map(m => m.txHash),
516
- [...uniqueFeePayers],
517
- );
518
- }
530
+ // Step 7: Run eviction rules (enforce pool size limit)
531
+ if (added.length > 0) {
532
+ const feePayers = added.map(meta => meta.feePayer);
533
+ const uniqueFeePayers = new Set<string>(feePayers);
534
+ await this.#evictionManager.evictAfterNewTxs(
535
+ added.map(m => m.txHash),
536
+ [...uniqueFeePayers],
537
+ );
538
+ }
539
+ });
519
540
  }
520
541
 
521
- async handlePrunedBlocks(latestBlock: L2BlockId): Promise<void> {
542
+ async handlePrunedBlocks(latestBlock: L2BlockId, options?: { deleteAllTxs?: boolean }): Promise<void> {
522
543
  // Step 1: Find transactions mined after the prune point
523
544
  const txsToUnmine = this.#indices.findTxsMinedAfter(latestBlock.number);
524
545
  if (txsToUnmine.length === 0) {
@@ -528,47 +549,60 @@ export class TxPoolV2Impl {
528
549
 
529
550
  this.#log.info(`Handling prune to block ${latestBlock.number}: un-mining ${txsToUnmine.length} txs`);
530
551
 
531
- // Step 2: Mark ALL un-mined txs with their original mined block number
532
- // This ensures they get soft-deleted if removed later, and only hard-deleted
533
- // when their original mined block is finalized
534
- await this.#deletedPool.markFromPrunedBlock(
535
- txsToUnmine.map(m => ({
536
- txHash: m.txHash,
537
- minedAtBlock: BlockNumber(m.minedL2BlockId!.number),
538
- })),
539
- );
552
+ await this.#store.transactionAsync(async () => {
553
+ // Step 2: Mark ALL un-mined txs with their original mined block number
554
+ // This ensures they get soft-deleted if removed later, and only hard-deleted
555
+ // when their original mined block is finalized
556
+ await this.#deletedPool.markFromPrunedBlock(
557
+ txsToUnmine.map(m => ({
558
+ txHash: m.txHash,
559
+ minedAtBlock: BlockNumber(m.minedL2BlockId!.number),
560
+ })),
561
+ );
540
562
 
541
- // Step 3: Unmine - clear mined status from metadata
542
- for (const meta of txsToUnmine) {
543
- this.#indices.markAsUnmined(meta);
544
- }
563
+ // Step 3: Unmine - clear mined status from metadata
564
+ for (const meta of txsToUnmine) {
565
+ this.#indices.markAsUnmined(meta);
566
+ }
545
567
 
546
- // Step 4: Filter out protected txs (they'll be handled by prepareForSlot)
547
- const unprotectedTxs = this.#indices.filterUnprotected(txsToUnmine);
568
+ // If deleteAllTxs is set (epoch prune), delete all un-mined txs and return early
569
+ if (options?.deleteAllTxs) {
570
+ const allTxHashes = txsToUnmine.map(m => m.txHash);
571
+ await this.#deleteTxsBatch(allTxHashes);
572
+ this.#log.info(
573
+ `Handled prune to block ${latestBlock.number} with deleteAllTxs: deleted ${allTxHashes.length} txs`,
574
+ );
575
+ return;
576
+ }
548
577
 
549
- // Step 4: Validate for pending pool
550
- const { valid, invalid } = await this.#revalidateMetadata(unprotectedTxs, 'during handlePrunedBlocks');
578
+ // Step 4: Filter out protected txs (they'll be handled by prepareForSlot)
579
+ const unprotectedTxs = this.#indices.filterUnprotected(txsToUnmine);
551
580
 
552
- // Step 6: Resolve nullifier conflicts and add winners to pending indices
553
- const { toEvict } = this.#applyNullifierConflictResolution(valid);
581
+ // Step 5: Validate for pending pool
582
+ const { valid, invalid } = await this.#revalidateMetadata(unprotectedTxs, 'during handlePrunedBlocks');
554
583
 
555
- // Step 7: Delete invalid txs and evict conflict losers
556
- await this.#deleteTxsBatch(invalid);
557
- await this.#evictTxs(toEvict, 'NullifierConflict');
584
+ // Step 6: Resolve nullifier conflicts and add winners to pending indices
585
+ const { toEvict } = this.#applyNullifierConflictResolution(valid);
558
586
 
559
- this.#log.info(
560
- `Handled prune to block ${latestBlock.number}: ${valid.length} txs restored to pending, ${invalid.length} invalid, ${toEvict.length} evicted due to nullifier conflicts`,
561
- { txHashesRestored: valid.map(m => m.txHash), txHashesInvalid: invalid, txHashesEvicted: toEvict },
562
- );
587
+ // Step 7: Delete invalid txs and evict conflict losers
588
+ await this.#deleteTxsBatch(invalid);
589
+ await this.#evictTxs(toEvict, 'NullifierConflict');
563
590
 
564
- // Step 8: Run eviction rules for ALL pending txs (not just restored ones)
565
- // This handles cases like existing pending txs with invalid fee payer balances
566
- await this.#evictionManager.evictAfterChainPrune(latestBlock.number);
591
+ this.#log.info(
592
+ `Handled prune to block ${latestBlock.number}: ${valid.length} txs restored to pending, ${invalid.length} invalid, ${toEvict.length} evicted due to nullifier conflicts`,
593
+ { txHashesRestored: valid.map(m => m.txHash), txHashesInvalid: invalid, txHashesEvicted: toEvict },
594
+ );
595
+
596
+ // Step 8: Run eviction rules for ALL pending txs (not just restored ones)
597
+ // This handles cases like existing pending txs with invalid fee payer balances
598
+ await this.#evictionManager.evictAfterChainPrune(latestBlock.number);
599
+ });
567
600
  }
568
601
 
569
602
  async handleFailedExecution(txHashes: TxHash[]): Promise<void> {
570
- // Delete failed txs
571
- await this.#deleteTxsBatch(txHashes.map(h => h.toString()));
603
+ await this.#store.transactionAsync(async () => {
604
+ await this.#deleteTxsBatch(txHashes.map(h => h.toString()));
605
+ });
572
606
 
573
607
  this.#log.info(`Deleted ${txHashes.length} failed txs`, { txHashes: txHashes.map(h => h.toString()) });
574
608
  }
@@ -579,27 +613,29 @@ export class TxPoolV2Impl {
579
613
  // Step 1: Find mined txs at or before finalized block
580
614
  const minedTxsToFinalize = this.#indices.findTxsMinedAtOrBefore(blockNumber);
581
615
 
582
- // Step 2: Collect mined txs for archiving (before deletion)
583
- const txsToArchive: Tx[] = [];
584
- if (this.#archive.isEnabled()) {
585
- for (const txHashStr of minedTxsToFinalize) {
586
- const buffer = await this.#txsDB.getAsync(txHashStr);
587
- if (buffer) {
588
- txsToArchive.push(Tx.fromBuffer(buffer));
616
+ await this.#store.transactionAsync(async () => {
617
+ // Step 2: Collect mined txs for archiving (before deletion)
618
+ const txsToArchive: Tx[] = [];
619
+ if (this.#archive.isEnabled()) {
620
+ for (const txHashStr of minedTxsToFinalize) {
621
+ const buffer = await this.#txsDB.getAsync(txHashStr);
622
+ if (buffer) {
623
+ txsToArchive.push(Tx.fromBuffer(buffer));
624
+ }
589
625
  }
590
626
  }
591
- }
592
627
 
593
- // Step 3: Delete mined txs from active pool
594
- await this.#deleteTxsBatch(minedTxsToFinalize);
628
+ // Step 3: Delete mined txs from active pool
629
+ await this.#deleteTxsBatch(minedTxsToFinalize);
595
630
 
596
- // Step 4: Finalize soft-deleted txs
597
- await this.#deletedPool.finalizeBlock(blockNumber);
631
+ // Step 4: Finalize soft-deleted txs
632
+ await this.#deletedPool.finalizeBlock(blockNumber);
598
633
 
599
- // Step 5: Archive mined txs
600
- if (txsToArchive.length > 0) {
601
- await this.#archive.archiveTxs(txsToArchive);
602
- }
634
+ // Step 5: Archive mined txs
635
+ if (txsToArchive.length > 0) {
636
+ await this.#archive.archiveTxs(txsToArchive);
637
+ }
638
+ });
603
639
 
604
640
  if (minedTxsToFinalize.length > 0) {
605
641
  this.#log.info(`Finalized ${minedTxsToFinalize.length} mined txs from blocks up to ${blockNumber}`, {
@@ -744,9 +780,10 @@ export class TxPoolV2Impl {
744
780
  tx: Tx,
745
781
  state: 'pending' | { protected: SlotNumber } | { mined: L2BlockId },
746
782
  opts: { source?: string } = {},
783
+ precomputedMeta?: TxMetaData,
747
784
  ): Promise<TxMetaData> {
748
785
  const txHashStr = tx.getTxHash().toString();
749
- const meta = await buildTxMetaData(tx);
786
+ const meta = precomputedMeta ?? (await buildTxMetaData(tx));
750
787
  meta.receivedAt = this.#dateProvider.now();
751
788
 
752
789
  await this.#txsDB.set(txHashStr, tx.toBuffer());
@@ -1,10 +1,20 @@
1
1
  import type { EpochCacheInterface } from '@aztec/epoch-cache';
2
- import type { BlockProposal, P2PValidator } from '@aztec/stdlib/p2p';
2
+ import type { BlockProposal, P2PValidator, ValidationResult } from '@aztec/stdlib/p2p';
3
3
 
4
4
  import { ProposalValidator } from '../proposal_validator/proposal_validator.js';
5
5
 
6
- export class BlockProposalValidator extends ProposalValidator<BlockProposal> implements P2PValidator<BlockProposal> {
7
- constructor(epochCache: EpochCacheInterface, opts: { txsPermitted: boolean }) {
8
- super(epochCache, opts, 'p2p:block_proposal_validator');
6
+ export class BlockProposalValidator implements P2PValidator<BlockProposal> {
7
+ private proposalValidator: ProposalValidator;
8
+
9
+ constructor(epochCache: EpochCacheInterface, opts: { txsPermitted: boolean; maxTxsPerBlock?: number }) {
10
+ this.proposalValidator = new ProposalValidator(epochCache, opts, 'p2p:block_proposal_validator');
11
+ }
12
+
13
+ async validate(proposal: BlockProposal): Promise<ValidationResult> {
14
+ const headerResult = await this.proposalValidator.validate(proposal);
15
+ if (headerResult.result !== 'accept') {
16
+ return headerResult;
17
+ }
18
+ return this.proposalValidator.validateTxs(proposal);
9
19
  }
10
20
  }
@@ -1,13 +1,26 @@
1
1
  import type { EpochCacheInterface } from '@aztec/epoch-cache';
2
- import type { CheckpointProposal, P2PValidator } from '@aztec/stdlib/p2p';
2
+ import type { CheckpointProposal, P2PValidator, ValidationResult } from '@aztec/stdlib/p2p';
3
3
 
4
4
  import { ProposalValidator } from '../proposal_validator/proposal_validator.js';
5
5
 
6
- export class CheckpointProposalValidator
7
- extends ProposalValidator<CheckpointProposal>
8
- implements P2PValidator<CheckpointProposal>
9
- {
10
- constructor(epochCache: EpochCacheInterface, opts: { txsPermitted: boolean }) {
11
- super(epochCache, opts, 'p2p:checkpoint_proposal_validator');
6
+ export class CheckpointProposalValidator implements P2PValidator<CheckpointProposal> {
7
+ private proposalValidator: ProposalValidator;
8
+
9
+ constructor(epochCache: EpochCacheInterface, opts: { txsPermitted: boolean; maxTxsPerBlock?: number }) {
10
+ this.proposalValidator = new ProposalValidator(epochCache, opts, 'p2p:checkpoint_proposal_validator');
11
+ }
12
+
13
+ async validate(proposal: CheckpointProposal): Promise<ValidationResult> {
14
+ const headerResult = await this.proposalValidator.validate(proposal);
15
+ if (headerResult.result !== 'accept') {
16
+ return headerResult;
17
+ }
18
+
19
+ const blockProposal = proposal.getBlockProposal();
20
+ if (blockProposal) {
21
+ return this.proposalValidator.validateTxs(blockProposal);
22
+ }
23
+
24
+ return { result: 'accept' };
12
25
  }
13
26
  }