@aztec/p2p 0.0.1-commit.cd76b27 → 0.0.1-commit.d117d021b
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 +5 -6
- package/dest/client/factory.d.ts.map +1 -1
- package/dest/client/factory.js +16 -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 +3 -82
- package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.js +1 -2
- package/dest/config.d.ts +21 -15
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +66 -37
- package/dest/mem_pools/attestation_pool/attestation_pool.d.ts +1 -1
- package/dest/mem_pools/attestation_pool/attestation_pool.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/attestation_pool.js +5 -1
- package/dest/mem_pools/instrumentation.d.ts +4 -2
- package/dest/mem_pools/instrumentation.d.ts.map +1 -1
- package/dest/mem_pools/instrumentation.js +16 -14
- 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 +9 -5
- package/dest/mem_pools/tx_pool_v2/interfaces.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/interfaces.js +3 -1
- package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts +40 -10
- 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 +26 -44
- 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.js +3 -0
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts +3 -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 +177 -146
- 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 +114 -6
- package/dest/msg_validators/tx_validator/factory.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/factory.js +219 -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 +58 -3
- package/dest/msg_validators/tx_validator/gas_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/gas_validator.js +73 -36
- 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/metadata_validator.d.ts +1 -1
- package/dest/msg_validators/tx_validator/metadata_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/metadata_validator.js +4 -4
- 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 +79 -89
- package/dest/services/peer-manager/metrics.d.ts +3 -1
- package/dest/services/peer-manager/metrics.d.ts.map +1 -1
- package/dest/services/peer-manager/metrics.js +6 -0
- package/dest/services/peer-manager/peer_manager.d.ts +1 -1
- package/dest/services/peer-manager/peer_manager.d.ts.map +1 -1
- package/dest/services/peer-manager/peer_manager.js +2 -1
- package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts +1 -1
- package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts.map +1 -1
- package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.js +14 -37
- package/dest/services/reqresp/batch-tx-requester/peer_collection.d.ts +17 -11
- package/dest/services/reqresp/batch-tx-requester/peer_collection.d.ts.map +1 -1
- package/dest/services/reqresp/batch-tx-requester/peer_collection.js +49 -15
- package/dest/services/reqresp/batch-tx-requester/tx_validator.js +2 -2
- package/dest/services/reqresp/reqresp.d.ts +1 -1
- package/dest/services/reqresp/reqresp.d.ts.map +1 -1
- package/dest/services/reqresp/reqresp.js +2 -1
- 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/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 +6 -2
- package/dest/util.d.ts +1 -1
- package/package.json +14 -14
- package/src/client/factory.ts +24 -47
- package/src/client/interface.ts +5 -19
- package/src/client/p2p_client.ts +4 -110
- package/src/client/test/tx_proposal_collector/proposal_tx_collector_worker.ts +2 -3
- package/src/config.ts +92 -43
- package/src/mem_pools/attestation_pool/attestation_pool.ts +5 -4
- package/src/mem_pools/instrumentation.ts +17 -13
- 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 +10 -4
- package/src/mem_pools/tx_pool_v2/tx_metadata.ts +104 -19
- package/src/mem_pools/tx_pool_v2/tx_pool_indices.ts +29 -43
- package/src/mem_pools/tx_pool_v2/tx_pool_v2.ts +4 -1
- package/src/mem_pools/tx_pool_v2/tx_pool_v2_impl.ts +187 -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 +353 -77
- package/src/msg_validators/tx_validator/fee_payer_balance.ts +6 -2
- package/src/msg_validators/tx_validator/gas_validator.ts +90 -27
- package/src/msg_validators/tx_validator/index.ts +2 -0
- package/src/msg_validators/tx_validator/metadata_validator.ts +12 -4
- 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 +90 -96
- package/src/services/peer-manager/metrics.ts +7 -0
- package/src/services/peer-manager/peer_manager.ts +2 -1
- package/src/services/reqresp/batch-tx-requester/batch_tx_requester.ts +14 -42
- package/src/services/reqresp/batch-tx-requester/peer_collection.ts +63 -24
- package/src/services/reqresp/batch-tx-requester/tx_validator.ts +2 -2
- package/src/services/reqresp/reqresp.ts +3 -1
- package/src/services/service.ts +1 -1
- package/src/services/tx_provider.ts +2 -2
- package/src/test-helpers/make-test-p2p-clients.ts +1 -3
- package/src/test-helpers/mock-pubsub.ts +3 -6
- package/src/test-helpers/reqresp-nodes.ts +3 -6
- package/src/test-helpers/testbench-utils.ts +1 -1
- package/src/testbench/p2p_client_testbench_worker.ts +4 -7
- package/src/testbench/worker_client_manager.ts +13 -5
- package/src/util.ts +1 -1
- 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
|
@@ -45,6 +45,7 @@ import { TxPoolIndices } from './tx_pool_indices.js';
|
|
|
45
45
|
export interface TxPoolV2Callbacks {
|
|
46
46
|
onTxsAdded: (txs: Tx[], opts: { source?: string }) => void;
|
|
47
47
|
onTxsRemoved: (txHashes: string[] | bigint[]) => void;
|
|
48
|
+
onTxsMined: (txHashes: string[]) => void;
|
|
48
49
|
}
|
|
49
50
|
|
|
50
51
|
/**
|
|
@@ -187,9 +188,35 @@ export class TxPoolV2Impl {
|
|
|
187
188
|
const errors = new Map<string, TxPoolRejectionError>();
|
|
188
189
|
const acceptedPending = new Set<string>();
|
|
189
190
|
|
|
191
|
+
// Phase 1: Pre-compute all throwable I/O outside the transaction.
|
|
192
|
+
// If any pre-computation throws, the entire call fails before mutations happen.
|
|
193
|
+
const precomputed = new Map<string, { meta: TxMetaData; minedBlockId: L2BlockId | undefined; isValid: boolean }>();
|
|
194
|
+
|
|
195
|
+
const validator = await this.#createTxValidator();
|
|
196
|
+
|
|
197
|
+
for (const tx of txs) {
|
|
198
|
+
const txHash = tx.getTxHash();
|
|
199
|
+
const txHashStr = txHash.toString();
|
|
200
|
+
|
|
201
|
+
const meta = await buildTxMetaData(tx);
|
|
202
|
+
const minedBlockId = await this.#getMinedBlockId(txHash);
|
|
203
|
+
|
|
204
|
+
// Validate non-mined txs (mined and pre-protected txs bypass validation inside the transaction)
|
|
205
|
+
let isValid = true;
|
|
206
|
+
if (!minedBlockId) {
|
|
207
|
+
isValid = await this.#validateMeta(meta, validator);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
precomputed.set(txHashStr, { meta, minedBlockId, isValid });
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Phase 2: Apply mutations inside the transaction using only pre-computed results,
|
|
214
|
+
// in-memory reads, and buffered DB writes. Nothing here can throw an unhandled exception.
|
|
190
215
|
const poolAccess = this.#createPreAddPoolAccess();
|
|
191
216
|
const preAddContext: PreAddContext | undefined =
|
|
192
|
-
opts.feeComparisonOnly !== undefined
|
|
217
|
+
opts.feeComparisonOnly !== undefined
|
|
218
|
+
? { feeComparisonOnly: opts.feeComparisonOnly, priceBumpPercentage: this.#config.priceBumpPercentage }
|
|
219
|
+
: undefined;
|
|
193
220
|
|
|
194
221
|
await this.#store.transactionAsync(async () => {
|
|
195
222
|
for (const tx of txs) {
|
|
@@ -202,22 +229,25 @@ export class TxPoolV2Impl {
|
|
|
202
229
|
continue;
|
|
203
230
|
}
|
|
204
231
|
|
|
205
|
-
|
|
206
|
-
const minedBlockId = await this.#getMinedBlockId(txHash);
|
|
232
|
+
const { meta, minedBlockId, isValid } = precomputed.get(txHashStr)!;
|
|
207
233
|
const preProtectedSlot = this.#indices.getProtectionSlot(txHashStr);
|
|
208
234
|
|
|
209
235
|
if (minedBlockId) {
|
|
210
236
|
// Already mined - add directly (protection already set if pre-protected)
|
|
211
|
-
await this.#addTx(tx, { mined: minedBlockId }, opts);
|
|
237
|
+
await this.#addTx(tx, { mined: minedBlockId }, opts, meta);
|
|
212
238
|
accepted.push(txHash);
|
|
213
239
|
} else if (preProtectedSlot !== undefined) {
|
|
214
240
|
// Pre-protected and not mined - add as protected (bypass validation)
|
|
215
|
-
await this.#addTx(tx, { protected: preProtectedSlot }, opts);
|
|
241
|
+
await this.#addTx(tx, { protected: preProtectedSlot }, opts, meta);
|
|
216
242
|
accepted.push(txHash);
|
|
243
|
+
} else if (!isValid) {
|
|
244
|
+
// Failed pre-computed validation
|
|
245
|
+
rejected.push(txHash);
|
|
217
246
|
} else {
|
|
218
|
-
// Regular pending tx -
|
|
247
|
+
// Regular pending tx - run pre-add rules using pre-computed metadata
|
|
219
248
|
const result = await this.#tryAddRegularPendingTx(
|
|
220
249
|
tx,
|
|
250
|
+
meta,
|
|
221
251
|
opts,
|
|
222
252
|
poolAccess,
|
|
223
253
|
acceptedPending,
|
|
@@ -227,13 +257,18 @@ export class TxPoolV2Impl {
|
|
|
227
257
|
);
|
|
228
258
|
if (result.status === 'accepted') {
|
|
229
259
|
acceptedPending.add(txHashStr);
|
|
230
|
-
} else if (result.status === 'rejected') {
|
|
231
|
-
rejected.push(txHash);
|
|
232
260
|
} else {
|
|
233
261
|
ignored.push(txHash);
|
|
234
262
|
}
|
|
235
263
|
}
|
|
236
264
|
}
|
|
265
|
+
|
|
266
|
+
// Run post-add eviction rules for pending txs (inside transaction for atomicity)
|
|
267
|
+
if (acceptedPending.size > 0) {
|
|
268
|
+
const feePayers = Array.from(acceptedPending).map(txHash => this.#indices.getMetadata(txHash)!.feePayer);
|
|
269
|
+
const uniqueFeePayers = new Set<string>(feePayers);
|
|
270
|
+
await this.#evictionManager.evictAfterNewTxs(Array.from(acceptedPending), [...uniqueFeePayers]);
|
|
271
|
+
}
|
|
237
272
|
});
|
|
238
273
|
|
|
239
274
|
// Build final accepted list for pending txs (excludes intra-batch evictions)
|
|
@@ -249,37 +284,24 @@ export class TxPoolV2Impl {
|
|
|
249
284
|
this.#instrumentation.recordRejected(rejected.length);
|
|
250
285
|
}
|
|
251
286
|
|
|
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
287
|
return { accepted, ignored, rejected, ...(errors.size > 0 ? { errors } : {}) };
|
|
260
288
|
}
|
|
261
289
|
|
|
262
|
-
/**
|
|
290
|
+
/** Adds a validated pending tx, running pre-add rules and evicting conflicts. */
|
|
263
291
|
async #tryAddRegularPendingTx(
|
|
264
292
|
tx: Tx,
|
|
293
|
+
precomputedMeta: TxMetaData,
|
|
265
294
|
opts: { source?: string },
|
|
266
295
|
poolAccess: PreAddPoolAccess,
|
|
267
296
|
acceptedPending: Set<string>,
|
|
268
297
|
ignored: TxHash[],
|
|
269
298
|
errors: Map<string, TxPoolRejectionError>,
|
|
270
299
|
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
|
-
}
|
|
300
|
+
): Promise<{ status: 'accepted' | 'ignored' }> {
|
|
301
|
+
const txHashStr = tx.getTxHash().toString();
|
|
280
302
|
|
|
281
303
|
// Run pre-add rules
|
|
282
|
-
const preAddResult = await this.#evictionManager.runPreAddRules(
|
|
304
|
+
const preAddResult = await this.#evictionManager.runPreAddRules(precomputedMeta, poolAccess, preAddContext);
|
|
283
305
|
|
|
284
306
|
if (preAddResult.shouldIgnore) {
|
|
285
307
|
this.#log.debug(`Ignoring tx ${txHashStr}: ${preAddResult.reason?.message ?? 'unknown reason'}`);
|
|
@@ -316,12 +338,18 @@ export class TxPoolV2Impl {
|
|
|
316
338
|
}
|
|
317
339
|
}
|
|
318
340
|
|
|
341
|
+
// Randomly drop the transaction for testing purposes (report as accepted so it propagates)
|
|
342
|
+
if (this.#config.dropTransactionsProbability > 0 && Math.random() < this.#config.dropTransactionsProbability) {
|
|
343
|
+
this.#log.debug(`Dropping tx ${txHashStr} (simulated drop for testing)`);
|
|
344
|
+
return { status: 'accepted' };
|
|
345
|
+
}
|
|
346
|
+
|
|
319
347
|
// Add the transaction
|
|
320
|
-
await this.#addTx(tx, 'pending', opts);
|
|
348
|
+
await this.#addTx(tx, 'pending', opts, precomputedMeta);
|
|
321
349
|
return { status: 'accepted' };
|
|
322
350
|
}
|
|
323
351
|
|
|
324
|
-
async canAddPendingTx(tx: Tx): Promise<'accepted' | 'ignored'
|
|
352
|
+
async canAddPendingTx(tx: Tx): Promise<'accepted' | 'ignored'> {
|
|
325
353
|
const txHashStr = tx.getTxHash().toString();
|
|
326
354
|
|
|
327
355
|
// Check if already in pool
|
|
@@ -329,14 +357,8 @@ export class TxPoolV2Impl {
|
|
|
329
357
|
return 'ignored';
|
|
330
358
|
}
|
|
331
359
|
|
|
332
|
-
// Build metadata and
|
|
360
|
+
// Build metadata and check pre-add rules
|
|
333
361
|
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
362
|
const poolAccess = this.#createPreAddPoolAccess();
|
|
341
363
|
const preAddResult = await this.#evictionManager.runPreAddRules(meta, poolAccess);
|
|
342
364
|
|
|
@@ -379,33 +401,35 @@ export class TxPoolV2Impl {
|
|
|
379
401
|
let softDeletedHits = 0;
|
|
380
402
|
let missingPreviouslyEvicted = 0;
|
|
381
403
|
|
|
382
|
-
|
|
383
|
-
const
|
|
404
|
+
await this.#store.transactionAsync(async () => {
|
|
405
|
+
for (const txHash of txHashes) {
|
|
406
|
+
const txHashStr = txHash.toString();
|
|
384
407
|
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
408
|
+
if (this.#indices.has(txHashStr)) {
|
|
409
|
+
// Update protection for existing tx
|
|
410
|
+
this.#indices.updateProtection(txHashStr, slotNumber);
|
|
411
|
+
} else if (this.#deletedPool.isSoftDeleted(txHashStr)) {
|
|
412
|
+
// Resurrect soft-deleted tx as protected
|
|
413
|
+
const buffer = await this.#txsDB.getAsync(txHashStr);
|
|
414
|
+
if (buffer) {
|
|
415
|
+
const tx = Tx.fromBuffer(buffer);
|
|
416
|
+
await this.#addTx(tx, { protected: slotNumber });
|
|
417
|
+
softDeletedHits++;
|
|
418
|
+
} else {
|
|
419
|
+
// Data missing despite soft-delete flag — treat as truly missing
|
|
420
|
+
this.#indices.setProtection(txHashStr, slotNumber);
|
|
421
|
+
missing.push(txHash);
|
|
422
|
+
}
|
|
395
423
|
} else {
|
|
396
|
-
//
|
|
424
|
+
// Truly missing — pre-record protection for tx we don't have yet
|
|
397
425
|
this.#indices.setProtection(txHashStr, slotNumber);
|
|
398
426
|
missing.push(txHash);
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
this.#indices.setProtection(txHashStr, slotNumber);
|
|
403
|
-
missing.push(txHash);
|
|
404
|
-
if (this.#evictedTxHashes.has(txHashStr)) {
|
|
405
|
-
missingPreviouslyEvicted++;
|
|
427
|
+
if (this.#evictedTxHashes.has(txHashStr)) {
|
|
428
|
+
missingPreviouslyEvicted++;
|
|
429
|
+
}
|
|
406
430
|
}
|
|
407
431
|
}
|
|
408
|
-
}
|
|
432
|
+
});
|
|
409
433
|
|
|
410
434
|
// Record metrics
|
|
411
435
|
if (softDeletedHits > 0) {
|
|
@@ -466,56 +490,64 @@ export class TxPoolV2Impl {
|
|
|
466
490
|
}
|
|
467
491
|
}
|
|
468
492
|
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
493
|
+
await this.#store.transactionAsync(async () => {
|
|
494
|
+
// Step 4: Mark txs as mined (only those we have in the pool)
|
|
495
|
+
for (const meta of found) {
|
|
496
|
+
this.#indices.markAsMined(meta, blockId);
|
|
497
|
+
await this.#deletedPool.clearIfMinedHigher(meta.txHash, blockId.number);
|
|
498
|
+
}
|
|
474
499
|
|
|
475
|
-
|
|
476
|
-
|
|
500
|
+
// Step 5: Run post-event eviction rules (inside transaction for atomicity)
|
|
501
|
+
await this.#evictionManager.evictAfterNewBlock(block.header, nullifiers, feePayers);
|
|
502
|
+
});
|
|
503
|
+
|
|
504
|
+
if (found.length > 0) {
|
|
505
|
+
this.#callbacks.onTxsMined(found.map(m => m.txHash));
|
|
506
|
+
}
|
|
477
507
|
|
|
478
508
|
this.#log.info(`Marked ${found.length} txs as mined in block ${blockId.number}`);
|
|
479
509
|
}
|
|
480
510
|
|
|
481
511
|
async prepareForSlot(slotNumber: SlotNumber): Promise<void> {
|
|
482
|
-
|
|
483
|
-
|
|
512
|
+
await this.#store.transactionAsync(async () => {
|
|
513
|
+
// Step 0: Clean up slot-deleted txs from previous slots
|
|
514
|
+
await this.#deletedPool.cleanupSlotDeleted(slotNumber);
|
|
484
515
|
|
|
485
|
-
|
|
486
|
-
|
|
516
|
+
// Step 1: Find expired protected txs
|
|
517
|
+
const expiredProtected = this.#indices.findExpiredProtectedTxs(slotNumber);
|
|
487
518
|
|
|
488
|
-
|
|
489
|
-
|
|
519
|
+
// Step 2: Clear protection for all expired entries (including those without metadata)
|
|
520
|
+
this.#indices.clearProtection(expiredProtected);
|
|
490
521
|
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
522
|
+
// Step 3: Filter to only txs that have metadata and are not mined
|
|
523
|
+
const txsToRestore = this.#indices.filterRestorable(expiredProtected);
|
|
524
|
+
if (txsToRestore.length === 0) {
|
|
525
|
+
this.#log.debug(`Preparing for slot ${slotNumber}, no txs to unprotect`);
|
|
526
|
+
return;
|
|
527
|
+
}
|
|
497
528
|
|
|
498
|
-
|
|
529
|
+
this.#log.info(`Preparing for slot ${slotNumber}: unprotecting ${txsToRestore.length} txs`);
|
|
499
530
|
|
|
500
|
-
|
|
501
|
-
|
|
531
|
+
// Step 4: Validate for pending pool
|
|
532
|
+
const { valid, invalid } = await this.#revalidateMetadata(txsToRestore, 'during prepareForSlot');
|
|
502
533
|
|
|
503
|
-
|
|
504
|
-
|
|
534
|
+
// Step 5: Resolve nullifier conflicts and add winners to pending indices
|
|
535
|
+
const { added, toEvict } = this.#applyNullifierConflictResolution(valid);
|
|
505
536
|
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
537
|
+
// Step 6: Delete invalid txs and evict conflict losers
|
|
538
|
+
await this.#deleteTxsBatch(invalid);
|
|
539
|
+
await this.#evictTxs(toEvict, 'NullifierConflict');
|
|
509
540
|
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
541
|
+
// Step 7: Run eviction rules (enforce pool size limit)
|
|
542
|
+
if (added.length > 0) {
|
|
543
|
+
const feePayers = added.map(meta => meta.feePayer);
|
|
544
|
+
const uniqueFeePayers = new Set<string>(feePayers);
|
|
545
|
+
await this.#evictionManager.evictAfterNewTxs(
|
|
546
|
+
added.map(m => m.txHash),
|
|
547
|
+
[...uniqueFeePayers],
|
|
548
|
+
);
|
|
549
|
+
}
|
|
550
|
+
});
|
|
519
551
|
}
|
|
520
552
|
|
|
521
553
|
async handlePrunedBlocks(latestBlock: L2BlockId, options?: { deleteAllTxs?: boolean }): Promise<void> {
|
|
@@ -528,57 +560,60 @@ export class TxPoolV2Impl {
|
|
|
528
560
|
|
|
529
561
|
this.#log.info(`Handling prune to block ${latestBlock.number}: un-mining ${txsToUnmine.length} txs`);
|
|
530
562
|
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
563
|
+
await this.#store.transactionAsync(async () => {
|
|
564
|
+
// Step 2: Mark ALL un-mined txs with their original mined block number
|
|
565
|
+
// This ensures they get soft-deleted if removed later, and only hard-deleted
|
|
566
|
+
// when their original mined block is finalized
|
|
567
|
+
await this.#deletedPool.markFromPrunedBlock(
|
|
568
|
+
txsToUnmine.map(m => ({
|
|
569
|
+
txHash: m.txHash,
|
|
570
|
+
minedAtBlock: BlockNumber(m.minedL2BlockId!.number),
|
|
571
|
+
})),
|
|
572
|
+
);
|
|
540
573
|
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
574
|
+
// Step 3: Unmine - clear mined status from metadata
|
|
575
|
+
for (const meta of txsToUnmine) {
|
|
576
|
+
this.#indices.markAsUnmined(meta);
|
|
577
|
+
}
|
|
545
578
|
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
579
|
+
// If deleteAllTxs is set (epoch prune), delete all un-mined txs and return early
|
|
580
|
+
if (options?.deleteAllTxs) {
|
|
581
|
+
const allTxHashes = txsToUnmine.map(m => m.txHash);
|
|
582
|
+
await this.#deleteTxsBatch(allTxHashes);
|
|
583
|
+
this.#log.info(
|
|
584
|
+
`Handled prune to block ${latestBlock.number} with deleteAllTxs: deleted ${allTxHashes.length} txs`,
|
|
585
|
+
);
|
|
586
|
+
return;
|
|
587
|
+
}
|
|
555
588
|
|
|
556
|
-
|
|
557
|
-
|
|
589
|
+
// Step 4: Filter out protected txs (they'll be handled by prepareForSlot)
|
|
590
|
+
const unprotectedTxs = this.#indices.filterUnprotected(txsToUnmine);
|
|
558
591
|
|
|
559
|
-
|
|
560
|
-
|
|
592
|
+
// Step 5: Validate for pending pool
|
|
593
|
+
const { valid, invalid } = await this.#revalidateMetadata(unprotectedTxs, 'during handlePrunedBlocks');
|
|
561
594
|
|
|
562
|
-
|
|
563
|
-
|
|
595
|
+
// Step 6: Resolve nullifier conflicts and add winners to pending indices
|
|
596
|
+
const { toEvict } = this.#applyNullifierConflictResolution(valid);
|
|
564
597
|
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
598
|
+
// Step 7: Delete invalid txs and evict conflict losers
|
|
599
|
+
await this.#deleteTxsBatch(invalid);
|
|
600
|
+
await this.#evictTxs(toEvict, 'NullifierConflict');
|
|
568
601
|
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
602
|
+
this.#log.info(
|
|
603
|
+
`Handled prune to block ${latestBlock.number}: ${valid.length} txs restored to pending, ${invalid.length} invalid, ${toEvict.length} evicted due to nullifier conflicts`,
|
|
604
|
+
{ txHashesRestored: valid.map(m => m.txHash), txHashesInvalid: invalid, txHashesEvicted: toEvict },
|
|
605
|
+
);
|
|
573
606
|
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
607
|
+
// Step 8: Run eviction rules for ALL pending txs (not just restored ones)
|
|
608
|
+
// This handles cases like existing pending txs with invalid fee payer balances
|
|
609
|
+
await this.#evictionManager.evictAfterChainPrune(latestBlock.number);
|
|
610
|
+
});
|
|
577
611
|
}
|
|
578
612
|
|
|
579
613
|
async handleFailedExecution(txHashes: TxHash[]): Promise<void> {
|
|
580
|
-
|
|
581
|
-
|
|
614
|
+
await this.#store.transactionAsync(async () => {
|
|
615
|
+
await this.#deleteTxsBatch(txHashes.map(h => h.toString()));
|
|
616
|
+
});
|
|
582
617
|
|
|
583
618
|
this.#log.info(`Deleted ${txHashes.length} failed txs`, { txHashes: txHashes.map(h => h.toString()) });
|
|
584
619
|
}
|
|
@@ -589,27 +624,29 @@ export class TxPoolV2Impl {
|
|
|
589
624
|
// Step 1: Find mined txs at or before finalized block
|
|
590
625
|
const minedTxsToFinalize = this.#indices.findTxsMinedAtOrBefore(blockNumber);
|
|
591
626
|
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
const
|
|
597
|
-
|
|
598
|
-
|
|
627
|
+
await this.#store.transactionAsync(async () => {
|
|
628
|
+
// Step 2: Collect mined txs for archiving (before deletion)
|
|
629
|
+
const txsToArchive: Tx[] = [];
|
|
630
|
+
if (this.#archive.isEnabled()) {
|
|
631
|
+
for (const txHashStr of minedTxsToFinalize) {
|
|
632
|
+
const buffer = await this.#txsDB.getAsync(txHashStr);
|
|
633
|
+
if (buffer) {
|
|
634
|
+
txsToArchive.push(Tx.fromBuffer(buffer));
|
|
635
|
+
}
|
|
599
636
|
}
|
|
600
637
|
}
|
|
601
|
-
}
|
|
602
638
|
|
|
603
|
-
|
|
604
|
-
|
|
639
|
+
// Step 3: Delete mined txs from active pool
|
|
640
|
+
await this.#deleteTxsBatch(minedTxsToFinalize);
|
|
605
641
|
|
|
606
|
-
|
|
607
|
-
|
|
642
|
+
// Step 4: Finalize soft-deleted txs
|
|
643
|
+
await this.#deletedPool.finalizeBlock(blockNumber);
|
|
608
644
|
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
645
|
+
// Step 5: Archive mined txs
|
|
646
|
+
if (txsToArchive.length > 0) {
|
|
647
|
+
await this.#archive.archiveTxs(txsToArchive);
|
|
648
|
+
}
|
|
649
|
+
});
|
|
613
650
|
|
|
614
651
|
if (minedTxsToFinalize.length > 0) {
|
|
615
652
|
this.#log.info(`Finalized ${minedTxsToFinalize.length} mined txs from blocks up to ${blockNumber}`, {
|
|
@@ -754,9 +791,10 @@ export class TxPoolV2Impl {
|
|
|
754
791
|
tx: Tx,
|
|
755
792
|
state: 'pending' | { protected: SlotNumber } | { mined: L2BlockId },
|
|
756
793
|
opts: { source?: string } = {},
|
|
794
|
+
precomputedMeta?: TxMetaData,
|
|
757
795
|
): Promise<TxMetaData> {
|
|
758
796
|
const txHashStr = tx.getTxHash().toString();
|
|
759
|
-
const meta = await buildTxMetaData(tx);
|
|
797
|
+
const meta = precomputedMeta ?? (await buildTxMetaData(tx));
|
|
760
798
|
meta.receivedAt = this.#dateProvider.now();
|
|
761
799
|
|
|
762
800
|
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
|
}
|