@aztec/p2p 0.0.1-commit.cd76b27 → 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.
- package/dest/client/factory.d.ts +4 -5
- package/dest/client/factory.d.ts.map +1 -1
- package/dest/client/factory.js +20 -26
- package/dest/client/interface.d.ts +6 -13
- package/dest/client/interface.d.ts.map +1 -1
- package/dest/client/p2p_client.d.ts +5 -13
- package/dest/client/p2p_client.d.ts.map +1 -1
- package/dest/client/p2p_client.js +11 -84
- package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.js +1 -2
- package/dest/config.d.ts +28 -10
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +80 -31
- package/dest/mem_pools/tx_pool/priority.d.ts +2 -2
- package/dest/mem_pools/tx_pool/priority.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/priority.js +4 -4
- package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts +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 +3 -1
- package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.js +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.d.ts +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.js +2 -0
- package/dest/mem_pools/tx_pool_v2/eviction/interfaces.d.ts +7 -1
- package/dest/mem_pools/tx_pool_v2/eviction/interfaces.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.js +2 -2
- package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.d.ts +2 -2
- package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.js +10 -6
- package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.d.ts +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.js +8 -6
- package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.d.ts +2 -2
- package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.js +2 -2
- package/dest/mem_pools/tx_pool_v2/index.d.ts +2 -2
- package/dest/mem_pools/tx_pool_v2/index.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/index.js +1 -1
- package/dest/mem_pools/tx_pool_v2/interfaces.d.ts +7 -5
- package/dest/mem_pools/tx_pool_v2/interfaces.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/interfaces.js +2 -1
- package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts +38 -7
- package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/tx_metadata.js +74 -16
- package/dest/mem_pools/tx_pool_v2/tx_pool_indices.d.ts +1 -1
- package/dest/mem_pools/tx_pool_v2/tx_pool_indices.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/tx_pool_indices.js +9 -10
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts +2 -2
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts +2 -2
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.js +168 -147
- package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts +6 -4
- package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts.map +1 -1
- package/dest/msg_validators/proposal_validator/block_proposal_validator.js +10 -2
- package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts +6 -4
- package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts.map +1 -1
- package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.js +16 -2
- package/dest/msg_validators/proposal_validator/proposal_validator.d.ts +13 -8
- package/dest/msg_validators/proposal_validator/proposal_validator.d.ts.map +1 -1
- package/dest/msg_validators/proposal_validator/proposal_validator.js +48 -36
- package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts +2 -2
- package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/aggregate_tx_validator.js +3 -3
- package/dest/msg_validators/tx_validator/allowed_public_setup.d.ts +2 -1
- package/dest/msg_validators/tx_validator/allowed_public_setup.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/allowed_public_setup.js +24 -20
- package/dest/msg_validators/tx_validator/allowed_setup_helpers.d.ts +17 -0
- package/dest/msg_validators/tx_validator/allowed_setup_helpers.d.ts.map +1 -0
- package/dest/msg_validators/tx_validator/allowed_setup_helpers.js +24 -0
- package/dest/msg_validators/tx_validator/factory.d.ts +125 -6
- package/dest/msg_validators/tx_validator/factory.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/factory.js +226 -58
- package/dest/msg_validators/tx_validator/fee_payer_balance.d.ts +1 -1
- package/dest/msg_validators/tx_validator/fee_payer_balance.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/fee_payer_balance.js +6 -2
- package/dest/msg_validators/tx_validator/gas_validator.d.ts +67 -3
- package/dest/msg_validators/tx_validator/gas_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/gas_validator.js +104 -37
- package/dest/msg_validators/tx_validator/index.d.ts +3 -1
- package/dest/msg_validators/tx_validator/index.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/index.js +2 -0
- package/dest/msg_validators/tx_validator/nullifier_cache.d.ts +14 -0
- package/dest/msg_validators/tx_validator/nullifier_cache.d.ts.map +1 -0
- package/dest/msg_validators/tx_validator/nullifier_cache.js +24 -0
- package/dest/msg_validators/tx_validator/phases_validator.d.ts +2 -2
- package/dest/msg_validators/tx_validator/phases_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/phases_validator.js +44 -23
- package/dest/services/dummy_service.d.ts +2 -3
- package/dest/services/dummy_service.d.ts.map +1 -1
- package/dest/services/dummy_service.js +1 -4
- package/dest/services/encoding.d.ts +2 -2
- package/dest/services/encoding.d.ts.map +1 -1
- package/dest/services/encoding.js +7 -7
- package/dest/services/libp2p/libp2p_service.d.ts +15 -13
- package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
- package/dest/services/libp2p/libp2p_service.js +87 -92
- package/dest/services/reqresp/batch-tx-requester/tx_validator.js +2 -2
- package/dest/services/service.d.ts +2 -2
- package/dest/services/service.d.ts.map +1 -1
- package/dest/services/tx_provider.d.ts +3 -3
- package/dest/services/tx_provider.d.ts.map +1 -1
- package/dest/services/tx_provider.js +4 -4
- package/dest/test-helpers/make-test-p2p-clients.d.ts +5 -6
- package/dest/test-helpers/make-test-p2p-clients.d.ts.map +1 -1
- package/dest/test-helpers/make-test-p2p-clients.js +1 -2
- package/dest/test-helpers/mock-pubsub.d.ts +2 -3
- package/dest/test-helpers/mock-pubsub.d.ts.map +1 -1
- package/dest/test-helpers/mock-pubsub.js +2 -2
- package/dest/test-helpers/reqresp-nodes.d.ts +2 -3
- package/dest/test-helpers/reqresp-nodes.d.ts.map +1 -1
- package/dest/test-helpers/reqresp-nodes.js +2 -2
- package/dest/test-helpers/testbench-utils.d.ts +2 -2
- package/dest/test-helpers/testbench-utils.d.ts.map +1 -1
- package/dest/test-helpers/testbench-utils.js +2 -1
- package/dest/testbench/p2p_client_testbench_worker.js +7 -6
- package/dest/testbench/worker_client_manager.d.ts +3 -1
- package/dest/testbench/worker_client_manager.d.ts.map +1 -1
- package/dest/testbench/worker_client_manager.js +4 -1
- package/package.json +14 -14
- package/src/client/factory.ts +28 -46
- package/src/client/interface.ts +5 -19
- package/src/client/p2p_client.ts +9 -114
- package/src/client/test/tx_proposal_collector/proposal_tx_collector_worker.ts +1 -2
- package/src/config.ts +115 -33
- package/src/mem_pools/tx_pool/priority.ts +4 -4
- package/src/mem_pools/tx_pool/tx_pool_test_suite.ts +3 -1
- package/src/mem_pools/tx_pool_v2/README.md +9 -1
- package/src/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.ts +1 -1
- package/src/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.ts +3 -0
- package/src/mem_pools/tx_pool_v2/eviction/interfaces.ts +11 -1
- package/src/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.ts +2 -2
- package/src/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.ts +10 -6
- package/src/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.ts +15 -6
- package/src/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.ts +2 -1
- package/src/mem_pools/tx_pool_v2/index.ts +1 -1
- package/src/mem_pools/tx_pool_v2/interfaces.ts +7 -4
- package/src/mem_pools/tx_pool_v2/tx_metadata.ts +102 -17
- package/src/mem_pools/tx_pool_v2/tx_pool_indices.ts +11 -11
- package/src/mem_pools/tx_pool_v2/tx_pool_v2.ts +1 -1
- package/src/mem_pools/tx_pool_v2/tx_pool_v2_impl.ts +176 -149
- package/src/msg_validators/proposal_validator/block_proposal_validator.ts +14 -4
- package/src/msg_validators/proposal_validator/checkpoint_proposal_validator.ts +20 -7
- package/src/msg_validators/proposal_validator/proposal_validator.ts +63 -40
- package/src/msg_validators/tx_validator/README.md +115 -0
- package/src/msg_validators/tx_validator/aggregate_tx_validator.ts +3 -3
- package/src/msg_validators/tx_validator/allowed_public_setup.ts +22 -27
- package/src/msg_validators/tx_validator/allowed_setup_helpers.ts +31 -0
- package/src/msg_validators/tx_validator/factory.ts +366 -77
- package/src/msg_validators/tx_validator/fee_payer_balance.ts +6 -2
- package/src/msg_validators/tx_validator/gas_validator.ts +123 -27
- package/src/msg_validators/tx_validator/index.ts +2 -0
- package/src/msg_validators/tx_validator/nullifier_cache.ts +30 -0
- package/src/msg_validators/tx_validator/phases_validator.ts +51 -26
- package/src/services/dummy_service.ts +1 -5
- package/src/services/encoding.ts +5 -6
- package/src/services/libp2p/libp2p_service.ts +101 -101
- package/src/services/reqresp/batch-tx-requester/tx_validator.ts +2 -2
- package/src/services/service.ts +1 -1
- package/src/services/tx_provider.ts +2 -2
- package/src/test-helpers/make-test-p2p-clients.ts +0 -2
- package/src/test-helpers/mock-pubsub.ts +3 -6
- package/src/test-helpers/reqresp-nodes.ts +2 -5
- package/src/test-helpers/testbench-utils.ts +2 -1
- package/src/testbench/p2p_client_testbench_worker.ts +3 -6
- package/src/testbench/worker_client_manager.ts +11 -4
- package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.d.ts +0 -23
- package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.d.ts.map +0 -1
- package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.js +0 -212
- 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
|
|
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
|
-
|
|
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 -
|
|
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
|
-
/**
|
|
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'
|
|
272
|
-
const
|
|
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(
|
|
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'
|
|
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
|
|
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
|
-
|
|
383
|
-
const
|
|
397
|
+
await this.#store.transactionAsync(async () => {
|
|
398
|
+
for (const txHash of txHashes) {
|
|
399
|
+
const txHashStr = txHash.toString();
|
|
384
400
|
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
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
|
-
//
|
|
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
|
-
|
|
401
|
-
|
|
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,56 +483,60 @@ export class TxPoolV2Impl {
|
|
|
466
483
|
}
|
|
467
484
|
}
|
|
468
485
|
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
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
|
-
|
|
476
|
-
|
|
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
|
-
|
|
483
|
-
|
|
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
|
-
|
|
486
|
-
|
|
505
|
+
// Step 1: Find expired protected txs
|
|
506
|
+
const expiredProtected = this.#indices.findExpiredProtectedTxs(slotNumber);
|
|
487
507
|
|
|
488
|
-
|
|
489
|
-
|
|
508
|
+
// Step 2: Clear protection for all expired entries (including those without metadata)
|
|
509
|
+
this.#indices.clearProtection(expiredProtected);
|
|
490
510
|
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
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
|
-
|
|
518
|
+
this.#log.info(`Preparing for slot ${slotNumber}: unprotecting ${txsToRestore.length} txs`);
|
|
499
519
|
|
|
500
|
-
|
|
501
|
-
|
|
520
|
+
// Step 4: Validate for pending pool
|
|
521
|
+
const { valid, invalid } = await this.#revalidateMetadata(txsToRestore, 'during prepareForSlot');
|
|
502
522
|
|
|
503
|
-
|
|
504
|
-
|
|
523
|
+
// Step 5: Resolve nullifier conflicts and add winners to pending indices
|
|
524
|
+
const { added, toEvict } = this.#applyNullifierConflictResolution(valid);
|
|
505
525
|
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
526
|
+
// Step 6: Delete invalid txs and evict conflict losers
|
|
527
|
+
await this.#deleteTxsBatch(invalid);
|
|
528
|
+
await this.#evictTxs(toEvict, 'NullifierConflict');
|
|
509
529
|
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
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
542
|
async handlePrunedBlocks(latestBlock: L2BlockId, options?: { deleteAllTxs?: boolean }): Promise<void> {
|
|
@@ -528,57 +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
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
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
|
-
|
|
542
|
-
|
|
543
|
-
|
|
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
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
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
|
+
}
|
|
555
577
|
|
|
556
|
-
|
|
557
|
-
|
|
578
|
+
// Step 4: Filter out protected txs (they'll be handled by prepareForSlot)
|
|
579
|
+
const unprotectedTxs = this.#indices.filterUnprotected(txsToUnmine);
|
|
558
580
|
|
|
559
|
-
|
|
560
|
-
|
|
581
|
+
// Step 5: Validate for pending pool
|
|
582
|
+
const { valid, invalid } = await this.#revalidateMetadata(unprotectedTxs, 'during handlePrunedBlocks');
|
|
561
583
|
|
|
562
|
-
|
|
563
|
-
|
|
584
|
+
// Step 6: Resolve nullifier conflicts and add winners to pending indices
|
|
585
|
+
const { toEvict } = this.#applyNullifierConflictResolution(valid);
|
|
564
586
|
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
587
|
+
// Step 7: Delete invalid txs and evict conflict losers
|
|
588
|
+
await this.#deleteTxsBatch(invalid);
|
|
589
|
+
await this.#evictTxs(toEvict, 'NullifierConflict');
|
|
568
590
|
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
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
|
+
);
|
|
573
595
|
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
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
|
+
});
|
|
577
600
|
}
|
|
578
601
|
|
|
579
602
|
async handleFailedExecution(txHashes: TxHash[]): Promise<void> {
|
|
580
|
-
|
|
581
|
-
|
|
603
|
+
await this.#store.transactionAsync(async () => {
|
|
604
|
+
await this.#deleteTxsBatch(txHashes.map(h => h.toString()));
|
|
605
|
+
});
|
|
582
606
|
|
|
583
607
|
this.#log.info(`Deleted ${txHashes.length} failed txs`, { txHashes: txHashes.map(h => h.toString()) });
|
|
584
608
|
}
|
|
@@ -589,27 +613,29 @@ export class TxPoolV2Impl {
|
|
|
589
613
|
// Step 1: Find mined txs at or before finalized block
|
|
590
614
|
const minedTxsToFinalize = this.#indices.findTxsMinedAtOrBefore(blockNumber);
|
|
591
615
|
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
const
|
|
597
|
-
|
|
598
|
-
|
|
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
|
+
}
|
|
599
625
|
}
|
|
600
626
|
}
|
|
601
|
-
}
|
|
602
627
|
|
|
603
|
-
|
|
604
|
-
|
|
628
|
+
// Step 3: Delete mined txs from active pool
|
|
629
|
+
await this.#deleteTxsBatch(minedTxsToFinalize);
|
|
605
630
|
|
|
606
|
-
|
|
607
|
-
|
|
631
|
+
// Step 4: Finalize soft-deleted txs
|
|
632
|
+
await this.#deletedPool.finalizeBlock(blockNumber);
|
|
608
633
|
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
634
|
+
// Step 5: Archive mined txs
|
|
635
|
+
if (txsToArchive.length > 0) {
|
|
636
|
+
await this.#archive.archiveTxs(txsToArchive);
|
|
637
|
+
}
|
|
638
|
+
});
|
|
613
639
|
|
|
614
640
|
if (minedTxsToFinalize.length > 0) {
|
|
615
641
|
this.#log.info(`Finalized ${minedTxsToFinalize.length} mined txs from blocks up to ${blockNumber}`, {
|
|
@@ -754,9 +780,10 @@ export class TxPoolV2Impl {
|
|
|
754
780
|
tx: Tx,
|
|
755
781
|
state: 'pending' | { protected: SlotNumber } | { mined: L2BlockId },
|
|
756
782
|
opts: { source?: string } = {},
|
|
783
|
+
precomputedMeta?: TxMetaData,
|
|
757
784
|
): Promise<TxMetaData> {
|
|
758
785
|
const txHashStr = tx.getTxHash().toString();
|
|
759
|
-
const meta = await buildTxMetaData(tx);
|
|
786
|
+
const meta = precomputedMeta ?? (await buildTxMetaData(tx));
|
|
760
787
|
meta.receivedAt = this.#dateProvider.now();
|
|
761
788
|
|
|
762
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
|
|
7
|
-
|
|
8
|
-
|
|
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
|
-
|
|
8
|
-
|
|
9
|
-
{
|
|
10
|
-
|
|
11
|
-
|
|
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
|
}
|