@aztec/p2p 0.0.1-commit.8f9871590 → 0.0.1-commit.934299a21
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 +3 -2
- package/dest/client/factory.d.ts.map +1 -1
- package/dest/client/factory.js +13 -23
- package/dest/client/interface.d.ts +9 -18
- package/dest/client/interface.d.ts.map +1 -1
- package/dest/client/p2p_client.d.ts +5 -16
- package/dest/client/p2p_client.d.ts.map +1 -1
- package/dest/client/p2p_client.js +40 -71
- package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.js +5 -5
- package/dest/config.d.ts +4 -6
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +0 -5
- package/dest/errors/tx-pool.error.d.ts +8 -0
- package/dest/errors/tx-pool.error.d.ts.map +1 -0
- package/dest/errors/tx-pool.error.js +9 -0
- package/dest/mem_pools/tx_pool_v2/deleted_pool.d.ts +3 -1
- package/dest/mem_pools/tx_pool_v2/deleted_pool.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/deleted_pool.js +9 -0
- package/dest/mem_pools/tx_pool_v2/eviction/eviction_manager.d.ts +3 -3
- package/dest/mem_pools/tx_pool_v2/eviction/eviction_manager.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/eviction_manager.js +18 -9
- package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.js +3 -3
- package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.d.ts +3 -3
- 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 +10 -4
- package/dest/mem_pools/tx_pool_v2/eviction/index.d.ts +2 -2
- package/dest/mem_pools/tx_pool_v2/eviction/index.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/index.js +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/interfaces.d.ts +48 -5
- package/dest/mem_pools/tx_pool_v2/eviction/interfaces.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/interfaces.js +8 -0
- package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_mining_rule.js +2 -2
- package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.js +5 -5
- 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 +12 -6
- package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.d.ts +4 -4
- 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 +14 -4
- package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.d.ts +3 -3
- 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/instrumentation.d.ts +15 -0
- package/dest/mem_pools/tx_pool_v2/instrumentation.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/instrumentation.js +43 -0
- package/dest/mem_pools/tx_pool_v2/interfaces.d.ts +16 -6
- 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 +12 -2
- package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/tx_metadata.js +37 -1
- package/dest/mem_pools/tx_pool_v2/tx_pool_indices.d.ts +5 -2
- 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 +12 -2
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts +6 -3
- 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 +6 -5
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts +11 -5
- 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 +241 -130
- 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/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/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 +2 -1
- package/dest/msg_validators/tx_validator/index.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/index.js +1 -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/services/dummy_service.d.ts +4 -4
- package/dest/services/dummy_service.d.ts.map +1 -1
- package/dest/services/dummy_service.js +4 -4
- package/dest/services/encoding.d.ts +1 -1
- package/dest/services/encoding.d.ts.map +1 -1
- package/dest/services/encoding.js +2 -1
- package/dest/services/gossipsub/topic_score_params.d.ts +18 -6
- package/dest/services/gossipsub/topic_score_params.d.ts.map +1 -1
- package/dest/services/gossipsub/topic_score_params.js +32 -10
- package/dest/services/libp2p/libp2p_service.d.ts +11 -7
- package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
- package/dest/services/libp2p/libp2p_service.js +62 -71
- package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts +4 -3
- 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 +19 -46
- package/dest/services/reqresp/batch-tx-requester/interface.d.ts +2 -6
- package/dest/services/reqresp/batch-tx-requester/interface.d.ts.map +1 -1
- package/dest/services/reqresp/batch-tx-requester/missing_txs.d.ts +10 -13
- package/dest/services/reqresp/batch-tx-requester/missing_txs.d.ts.map +1 -1
- package/dest/services/reqresp/batch-tx-requester/missing_txs.js +25 -46
- 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/service.d.ts +5 -3
- package/dest/services/service.d.ts.map +1 -1
- package/dest/services/tx_collection/fast_tx_collection.d.ts +1 -1
- package/dest/services/tx_collection/fast_tx_collection.d.ts.map +1 -1
- package/dest/services/tx_collection/fast_tx_collection.js +39 -33
- package/dest/services/tx_collection/file_store_tx_collection.d.ts +1 -1
- package/dest/services/tx_collection/file_store_tx_collection.d.ts.map +1 -1
- package/dest/services/tx_collection/file_store_tx_collection.js +4 -2
- package/dest/services/tx_collection/file_store_tx_source.d.ts +15 -6
- package/dest/services/tx_collection/file_store_tx_source.d.ts.map +1 -1
- package/dest/services/tx_collection/file_store_tx_source.js +47 -16
- package/dest/services/tx_collection/instrumentation.d.ts +1 -1
- package/dest/services/tx_collection/instrumentation.d.ts.map +1 -1
- package/dest/services/tx_collection/instrumentation.js +2 -1
- package/dest/services/tx_collection/missing_txs_tracker.d.ts +32 -0
- package/dest/services/tx_collection/missing_txs_tracker.d.ts.map +1 -0
- package/dest/services/tx_collection/missing_txs_tracker.js +27 -0
- package/dest/services/tx_collection/proposal_tx_collector.d.ts +7 -6
- package/dest/services/tx_collection/proposal_tx_collector.d.ts.map +1 -1
- package/dest/services/tx_collection/proposal_tx_collector.js +5 -4
- package/dest/services/tx_collection/slow_tx_collection.d.ts +2 -2
- package/dest/services/tx_collection/slow_tx_collection.d.ts.map +1 -1
- package/dest/services/tx_collection/slow_tx_collection.js +10 -8
- package/dest/services/tx_collection/tx_collection.d.ts +5 -4
- package/dest/services/tx_collection/tx_collection.d.ts.map +1 -1
- package/dest/services/tx_collection/tx_collection_sink.d.ts +6 -5
- package/dest/services/tx_collection/tx_collection_sink.d.ts.map +1 -1
- package/dest/services/tx_collection/tx_collection_sink.js +13 -22
- package/dest/services/tx_collection/tx_source.d.ts +8 -3
- package/dest/services/tx_collection/tx_source.d.ts.map +1 -1
- package/dest/services/tx_collection/tx_source.js +19 -2
- package/dest/services/tx_file_store/tx_file_store.js +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/mock-pubsub.d.ts +3 -2
- package/dest/test-helpers/mock-pubsub.d.ts.map +1 -1
- package/dest/test-helpers/mock-pubsub.js +6 -0
- package/dest/test-helpers/testbench-utils.d.ts +6 -3
- package/dest/test-helpers/testbench-utils.d.ts.map +1 -1
- package/dest/test-helpers/testbench-utils.js +1 -1
- package/dest/testbench/p2p_client_testbench_worker.d.ts +2 -2
- package/dest/testbench/p2p_client_testbench_worker.d.ts.map +1 -1
- package/dest/testbench/p2p_client_testbench_worker.js +6 -6
- package/dest/util.d.ts +2 -2
- package/dest/util.d.ts.map +1 -1
- package/package.json +14 -14
- package/src/client/factory.ts +19 -35
- package/src/client/interface.ts +16 -19
- package/src/client/p2p_client.ts +46 -93
- package/src/client/test/tx_proposal_collector/proposal_tx_collector_worker.ts +18 -8
- package/src/config.ts +2 -10
- package/src/errors/tx-pool.error.ts +12 -0
- package/src/mem_pools/tx_pool_v2/deleted_pool.ts +11 -0
- package/src/mem_pools/tx_pool_v2/eviction/eviction_manager.ts +21 -8
- package/src/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.ts +3 -3
- package/src/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.ts +15 -4
- package/src/mem_pools/tx_pool_v2/eviction/index.ts +4 -0
- package/src/mem_pools/tx_pool_v2/eviction/interfaces.ts +49 -4
- package/src/mem_pools/tx_pool_v2/eviction/invalid_txs_after_mining_rule.ts +2 -2
- package/src/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.ts +5 -5
- package/src/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.ts +12 -9
- package/src/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.ts +24 -6
- package/src/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.ts +3 -3
- package/src/mem_pools/tx_pool_v2/instrumentation.ts +69 -0
- package/src/mem_pools/tx_pool_v2/interfaces.ts +15 -6
- package/src/mem_pools/tx_pool_v2/tx_metadata.ts +46 -2
- package/src/mem_pools/tx_pool_v2/tx_pool_indices.ts +14 -3
- package/src/mem_pools/tx_pool_v2/tx_pool_v2.ts +12 -7
- package/src/mem_pools/tx_pool_v2/tx_pool_v2_impl.ts +264 -125
- 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/factory.ts +353 -77
- package/src/msg_validators/tx_validator/gas_validator.ts +90 -27
- package/src/msg_validators/tx_validator/index.ts +1 -0
- package/src/msg_validators/tx_validator/nullifier_cache.ts +30 -0
- package/src/services/dummy_service.ts +6 -6
- package/src/services/encoding.ts +2 -1
- package/src/services/gossipsub/README.md +29 -14
- package/src/services/gossipsub/topic_score_params.ts +49 -13
- package/src/services/libp2p/libp2p_service.ts +75 -79
- package/src/services/reqresp/batch-tx-requester/batch_tx_requester.ts +20 -48
- package/src/services/reqresp/batch-tx-requester/interface.ts +1 -5
- package/src/services/reqresp/batch-tx-requester/missing_txs.ts +23 -71
- 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/service.ts +11 -2
- package/src/services/tx_collection/fast_tx_collection.ts +51 -30
- package/src/services/tx_collection/file_store_tx_collection.ts +7 -3
- package/src/services/tx_collection/file_store_tx_source.ts +61 -17
- package/src/services/tx_collection/instrumentation.ts +7 -1
- package/src/services/tx_collection/missing_txs_tracker.ts +52 -0
- package/src/services/tx_collection/proposal_tx_collector.ts +8 -7
- package/src/services/tx_collection/slow_tx_collection.ts +8 -9
- package/src/services/tx_collection/tx_collection.ts +4 -3
- package/src/services/tx_collection/tx_collection_sink.ts +15 -29
- package/src/services/tx_collection/tx_source.ts +22 -3
- package/src/services/tx_file_store/tx_file_store.ts +1 -1
- package/src/services/tx_provider.ts +2 -2
- package/src/test-helpers/mock-pubsub.ts +10 -0
- package/src/test-helpers/testbench-utils.ts +3 -3
- package/src/testbench/p2p_client_testbench_worker.ts +18 -11
- package/src/util.ts +7 -1
|
@@ -9,6 +9,7 @@ import type { L2Block, L2BlockId, L2BlockSource } from '@aztec/stdlib/block';
|
|
|
9
9
|
import type { WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
|
|
10
10
|
import { DatabasePublicStateSource } from '@aztec/stdlib/trees';
|
|
11
11
|
import { BlockHeader, Tx, TxHash, type TxValidator } from '@aztec/stdlib/tx';
|
|
12
|
+
import type { TelemetryClient } from '@aztec/telemetry-client';
|
|
12
13
|
|
|
13
14
|
import { TxArchive } from './archive/index.js';
|
|
14
15
|
import { DeletedPool } from './deleted_pool.js';
|
|
@@ -22,8 +23,12 @@ import {
|
|
|
22
23
|
LowPriorityPreAddRule,
|
|
23
24
|
NullifierConflictRule,
|
|
24
25
|
type PoolOperations,
|
|
26
|
+
type PreAddContext,
|
|
25
27
|
type PreAddPoolAccess,
|
|
28
|
+
TxPoolRejectionCode,
|
|
29
|
+
type TxPoolRejectionError,
|
|
26
30
|
} from './eviction/index.js';
|
|
31
|
+
import { TxPoolV2Instrumentation } from './instrumentation.js';
|
|
27
32
|
import {
|
|
28
33
|
type AddTxsResult,
|
|
29
34
|
DEFAULT_TX_POOL_V2_CONFIG,
|
|
@@ -66,6 +71,8 @@ export class TxPoolV2Impl {
|
|
|
66
71
|
#deletedPool: DeletedPool;
|
|
67
72
|
#evictionManager: EvictionManager;
|
|
68
73
|
#dateProvider: DateProvider;
|
|
74
|
+
#instrumentation: TxPoolV2Instrumentation;
|
|
75
|
+
#evictedTxHashes: Set<string> = new Set();
|
|
69
76
|
#log: Logger;
|
|
70
77
|
#callbacks: TxPoolV2Callbacks;
|
|
71
78
|
|
|
@@ -74,6 +81,7 @@ export class TxPoolV2Impl {
|
|
|
74
81
|
archiveStore: AztecAsyncKVStore,
|
|
75
82
|
deps: TxPoolV2Dependencies,
|
|
76
83
|
callbacks: TxPoolV2Callbacks,
|
|
84
|
+
telemetry: TelemetryClient,
|
|
77
85
|
config: Partial<TxPoolV2Config> = {},
|
|
78
86
|
dateProvider: DateProvider,
|
|
79
87
|
log: Logger,
|
|
@@ -89,6 +97,7 @@ export class TxPoolV2Impl {
|
|
|
89
97
|
this.#archive = new TxArchive(archiveStore, this.#config.archivedTxLimit, log);
|
|
90
98
|
this.#deletedPool = new DeletedPool(store, this.#txsDB, log);
|
|
91
99
|
this.#dateProvider = dateProvider;
|
|
100
|
+
this.#instrumentation = new TxPoolV2Instrumentation(telemetry, () => this.#indices.getTotalMetadataBytes());
|
|
92
101
|
this.#log = log;
|
|
93
102
|
this.#callbacks = callbacks;
|
|
94
103
|
|
|
@@ -171,13 +180,16 @@ export class TxPoolV2Impl {
|
|
|
171
180
|
this.#log.info(`Deleted ${toDelete.length} invalid/rejected transactions on startup`, { txHashes: toDelete });
|
|
172
181
|
}
|
|
173
182
|
|
|
174
|
-
async addPendingTxs(txs: Tx[], opts: { source?: string }): Promise<AddTxsResult> {
|
|
183
|
+
async addPendingTxs(txs: Tx[], opts: { source?: string; feeComparisonOnly?: boolean }): Promise<AddTxsResult> {
|
|
175
184
|
const accepted: TxHash[] = [];
|
|
176
185
|
const ignored: TxHash[] = [];
|
|
177
186
|
const rejected: TxHash[] = [];
|
|
187
|
+
const errors = new Map<string, TxPoolRejectionError>();
|
|
178
188
|
const acceptedPending = new Set<string>();
|
|
179
189
|
|
|
180
190
|
const poolAccess = this.#createPreAddPoolAccess();
|
|
191
|
+
const preAddContext: PreAddContext | undefined =
|
|
192
|
+
opts.feeComparisonOnly !== undefined ? { feeComparisonOnly: opts.feeComparisonOnly } : undefined;
|
|
181
193
|
|
|
182
194
|
await this.#store.transactionAsync(async () => {
|
|
183
195
|
for (const tx of txs) {
|
|
@@ -204,7 +216,15 @@ export class TxPoolV2Impl {
|
|
|
204
216
|
accepted.push(txHash);
|
|
205
217
|
} else {
|
|
206
218
|
// Regular pending tx - validate and run pre-add rules
|
|
207
|
-
const result = await this.#tryAddRegularPendingTx(
|
|
219
|
+
const result = await this.#tryAddRegularPendingTx(
|
|
220
|
+
tx,
|
|
221
|
+
opts,
|
|
222
|
+
poolAccess,
|
|
223
|
+
acceptedPending,
|
|
224
|
+
ignored,
|
|
225
|
+
errors,
|
|
226
|
+
preAddContext,
|
|
227
|
+
);
|
|
208
228
|
if (result.status === 'accepted') {
|
|
209
229
|
acceptedPending.add(txHashStr);
|
|
210
230
|
} else if (result.status === 'rejected') {
|
|
@@ -214,6 +234,13 @@ export class TxPoolV2Impl {
|
|
|
214
234
|
}
|
|
215
235
|
}
|
|
216
236
|
}
|
|
237
|
+
|
|
238
|
+
// Run post-add eviction rules for pending txs (inside transaction for atomicity)
|
|
239
|
+
if (acceptedPending.size > 0) {
|
|
240
|
+
const feePayers = Array.from(acceptedPending).map(txHash => this.#indices.getMetadata(txHash)!.feePayer);
|
|
241
|
+
const uniqueFeePayers = new Set<string>(feePayers);
|
|
242
|
+
await this.#evictionManager.evictAfterNewTxs(Array.from(acceptedPending), [...uniqueFeePayers]);
|
|
243
|
+
}
|
|
217
244
|
});
|
|
218
245
|
|
|
219
246
|
// Build final accepted list for pending txs (excludes intra-batch evictions)
|
|
@@ -221,14 +248,15 @@ export class TxPoolV2Impl {
|
|
|
221
248
|
accepted.push(TxHash.fromString(txHashStr));
|
|
222
249
|
}
|
|
223
250
|
|
|
224
|
-
//
|
|
225
|
-
if (
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
251
|
+
// Record metrics
|
|
252
|
+
if (ignored.length > 0) {
|
|
253
|
+
this.#instrumentation.recordIgnored(ignored.length);
|
|
254
|
+
}
|
|
255
|
+
if (rejected.length > 0) {
|
|
256
|
+
this.#instrumentation.recordRejected(rejected.length);
|
|
229
257
|
}
|
|
230
258
|
|
|
231
|
-
return { accepted, ignored, rejected };
|
|
259
|
+
return { accepted, ignored, rejected, ...(errors.size > 0 ? { errors } : {}) };
|
|
232
260
|
}
|
|
233
261
|
|
|
234
262
|
/** Validates and adds a regular pending tx. Returns status. */
|
|
@@ -238,6 +266,8 @@ export class TxPoolV2Impl {
|
|
|
238
266
|
poolAccess: PreAddPoolAccess,
|
|
239
267
|
acceptedPending: Set<string>,
|
|
240
268
|
ignored: TxHash[],
|
|
269
|
+
errors: Map<string, TxPoolRejectionError>,
|
|
270
|
+
preAddContext?: PreAddContext,
|
|
241
271
|
): Promise<{ status: 'accepted' | 'ignored' | 'rejected' }> {
|
|
242
272
|
const txHash = tx.getTxHash();
|
|
243
273
|
const txHashStr = txHash.toString();
|
|
@@ -249,25 +279,47 @@ export class TxPoolV2Impl {
|
|
|
249
279
|
}
|
|
250
280
|
|
|
251
281
|
// Run pre-add rules
|
|
252
|
-
const preAddResult = await this.#evictionManager.runPreAddRules(meta, poolAccess);
|
|
282
|
+
const preAddResult = await this.#evictionManager.runPreAddRules(meta, poolAccess, preAddContext);
|
|
253
283
|
|
|
254
284
|
if (preAddResult.shouldIgnore) {
|
|
255
|
-
this.#log.debug(`Ignoring tx ${txHashStr}: ${preAddResult.reason}`);
|
|
285
|
+
this.#log.debug(`Ignoring tx ${txHashStr}: ${preAddResult.reason?.message ?? 'unknown reason'}`);
|
|
286
|
+
if (preAddResult.reason && preAddResult.reason.code !== TxPoolRejectionCode.INTERNAL_ERROR) {
|
|
287
|
+
errors.set(txHashStr, preAddResult.reason);
|
|
288
|
+
}
|
|
256
289
|
return { status: 'ignored' };
|
|
257
290
|
}
|
|
258
291
|
|
|
259
|
-
// Evict conflicts
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
292
|
+
// Evict conflicts, grouped by rule name for metrics
|
|
293
|
+
if (preAddResult.evictions && preAddResult.evictions.length > 0) {
|
|
294
|
+
const byReason = new Map<string, string[]>();
|
|
295
|
+
for (const { txHash: evictHash, reason } of preAddResult.evictions) {
|
|
296
|
+
const group = byReason.get(reason);
|
|
297
|
+
if (group) {
|
|
298
|
+
group.push(evictHash);
|
|
299
|
+
} else {
|
|
300
|
+
byReason.set(reason, [evictHash]);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
for (const [reason, hashes] of byReason) {
|
|
304
|
+
await this.#evictTxs(hashes, reason);
|
|
270
305
|
}
|
|
306
|
+
for (const evictHashStr of preAddResult.txHashesToEvict) {
|
|
307
|
+
this.#log.debug(`Evicted tx ${evictHashStr} due to higher-fee tx ${txHashStr}`, {
|
|
308
|
+
evictedTxHash: evictHashStr,
|
|
309
|
+
replacementTxHash: txHashStr,
|
|
310
|
+
});
|
|
311
|
+
if (acceptedPending.has(evictHashStr)) {
|
|
312
|
+
// Evicted tx was from this batch - mark as ignored in result
|
|
313
|
+
acceptedPending.delete(evictHashStr);
|
|
314
|
+
ignored.push(TxHash.fromString(evictHashStr));
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// Randomly drop the transaction for testing purposes (report as accepted so it propagates)
|
|
320
|
+
if (this.#config.dropTransactionsProbability > 0 && Math.random() < this.#config.dropTransactionsProbability) {
|
|
321
|
+
this.#log.debug(`Dropping tx ${txHashStr} (simulated drop for testing)`);
|
|
322
|
+
return { status: 'accepted' };
|
|
271
323
|
}
|
|
272
324
|
|
|
273
325
|
// Add the transaction
|
|
@@ -275,7 +327,7 @@ export class TxPoolV2Impl {
|
|
|
275
327
|
return { status: 'accepted' };
|
|
276
328
|
}
|
|
277
329
|
|
|
278
|
-
async canAddPendingTx(tx: Tx): Promise<'accepted' | 'ignored'
|
|
330
|
+
async canAddPendingTx(tx: Tx): Promise<'accepted' | 'ignored'> {
|
|
279
331
|
const txHashStr = tx.getTxHash().toString();
|
|
280
332
|
|
|
281
333
|
// Check if already in pool
|
|
@@ -283,14 +335,8 @@ export class TxPoolV2Impl {
|
|
|
283
335
|
return 'ignored';
|
|
284
336
|
}
|
|
285
337
|
|
|
286
|
-
// Build metadata and
|
|
338
|
+
// Build metadata and check pre-add rules
|
|
287
339
|
const meta = await buildTxMetaData(tx);
|
|
288
|
-
const validationResult = await this.#validateMeta(meta, undefined, 'can add pending');
|
|
289
|
-
if (validationResult !== true) {
|
|
290
|
-
return 'rejected';
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
// Use pre-add rules
|
|
294
340
|
const poolAccess = this.#createPreAddPoolAccess();
|
|
295
341
|
const preAddResult = await this.#evictionManager.runPreAddRules(meta, poolAccess);
|
|
296
342
|
|
|
@@ -327,22 +373,57 @@ export class TxPoolV2Impl {
|
|
|
327
373
|
});
|
|
328
374
|
}
|
|
329
375
|
|
|
330
|
-
protectTxs(txHashes: TxHash[], block: BlockHeader): TxHash[] {
|
|
376
|
+
async protectTxs(txHashes: TxHash[], block: BlockHeader): Promise<TxHash[]> {
|
|
331
377
|
const slotNumber = block.globalVariables.slotNumber;
|
|
332
378
|
const missing: TxHash[] = [];
|
|
379
|
+
let softDeletedHits = 0;
|
|
380
|
+
let missingPreviouslyEvicted = 0;
|
|
333
381
|
|
|
334
|
-
|
|
335
|
-
const
|
|
382
|
+
await this.#store.transactionAsync(async () => {
|
|
383
|
+
for (const txHash of txHashes) {
|
|
384
|
+
const txHashStr = txHash.toString();
|
|
336
385
|
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
386
|
+
if (this.#indices.has(txHashStr)) {
|
|
387
|
+
// Update protection for existing tx
|
|
388
|
+
this.#indices.updateProtection(txHashStr, slotNumber);
|
|
389
|
+
} else if (this.#deletedPool.isSoftDeleted(txHashStr)) {
|
|
390
|
+
// Resurrect soft-deleted tx as protected
|
|
391
|
+
const buffer = await this.#txsDB.getAsync(txHashStr);
|
|
392
|
+
if (buffer) {
|
|
393
|
+
const tx = Tx.fromBuffer(buffer);
|
|
394
|
+
await this.#addTx(tx, { protected: slotNumber });
|
|
395
|
+
softDeletedHits++;
|
|
396
|
+
} else {
|
|
397
|
+
// Data missing despite soft-delete flag — treat as truly missing
|
|
398
|
+
this.#indices.setProtection(txHashStr, slotNumber);
|
|
399
|
+
missing.push(txHash);
|
|
400
|
+
}
|
|
401
|
+
} else {
|
|
402
|
+
// Truly missing — pre-record protection for tx we don't have yet
|
|
403
|
+
this.#indices.setProtection(txHashStr, slotNumber);
|
|
404
|
+
missing.push(txHash);
|
|
405
|
+
if (this.#evictedTxHashes.has(txHashStr)) {
|
|
406
|
+
missingPreviouslyEvicted++;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
344
409
|
}
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
// Record metrics
|
|
413
|
+
if (softDeletedHits > 0) {
|
|
414
|
+
this.#instrumentation.recordSoftDeletedHits(softDeletedHits);
|
|
345
415
|
}
|
|
416
|
+
if (missing.length > 0) {
|
|
417
|
+
this.#log.debug(`protectTxs missing tx hashes: ${missing.map(h => h.toString()).join(', ')}`);
|
|
418
|
+
this.#instrumentation.recordMissingOnProtect(missing.length);
|
|
419
|
+
}
|
|
420
|
+
if (missingPreviouslyEvicted > 0) {
|
|
421
|
+
this.#instrumentation.recordMissingPreviouslyEvicted(missingPreviouslyEvicted);
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
this.#log.info(
|
|
425
|
+
`Protected ${txHashes.length} txs, missing: ${missing.length}, soft-deleted hits: ${softDeletedHits}`,
|
|
426
|
+
);
|
|
346
427
|
|
|
347
428
|
return missing;
|
|
348
429
|
}
|
|
@@ -387,57 +468,63 @@ export class TxPoolV2Impl {
|
|
|
387
468
|
}
|
|
388
469
|
}
|
|
389
470
|
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
471
|
+
await this.#store.transactionAsync(async () => {
|
|
472
|
+
// Step 4: Mark txs as mined (only those we have in the pool)
|
|
473
|
+
for (const meta of found) {
|
|
474
|
+
this.#indices.markAsMined(meta, blockId);
|
|
475
|
+
await this.#deletedPool.clearIfMinedHigher(meta.txHash, blockId.number);
|
|
476
|
+
}
|
|
395
477
|
|
|
396
|
-
|
|
397
|
-
|
|
478
|
+
// Step 5: Run post-event eviction rules (inside transaction for atomicity)
|
|
479
|
+
await this.#evictionManager.evictAfterNewBlock(block.header, nullifiers, feePayers);
|
|
480
|
+
});
|
|
398
481
|
|
|
399
482
|
this.#log.info(`Marked ${found.length} txs as mined in block ${blockId.number}`);
|
|
400
483
|
}
|
|
401
484
|
|
|
402
485
|
async prepareForSlot(slotNumber: SlotNumber): Promise<void> {
|
|
403
|
-
|
|
404
|
-
|
|
486
|
+
await this.#store.transactionAsync(async () => {
|
|
487
|
+
// Step 0: Clean up slot-deleted txs from previous slots
|
|
488
|
+
await this.#deletedPool.cleanupSlotDeleted(slotNumber);
|
|
405
489
|
|
|
406
|
-
|
|
407
|
-
|
|
490
|
+
// Step 1: Find expired protected txs
|
|
491
|
+
const expiredProtected = this.#indices.findExpiredProtectedTxs(slotNumber);
|
|
408
492
|
|
|
409
|
-
|
|
410
|
-
|
|
493
|
+
// Step 2: Clear protection for all expired entries (including those without metadata)
|
|
494
|
+
this.#indices.clearProtection(expiredProtected);
|
|
411
495
|
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
496
|
+
// Step 3: Filter to only txs that have metadata and are not mined
|
|
497
|
+
const txsToRestore = this.#indices.filterRestorable(expiredProtected);
|
|
498
|
+
if (txsToRestore.length === 0) {
|
|
499
|
+
this.#log.debug(`Preparing for slot ${slotNumber}, no txs to unprotect`);
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
417
502
|
|
|
418
|
-
|
|
503
|
+
this.#log.info(`Preparing for slot ${slotNumber}: unprotecting ${txsToRestore.length} txs`);
|
|
419
504
|
|
|
420
|
-
|
|
421
|
-
|
|
505
|
+
// Step 4: Validate for pending pool
|
|
506
|
+
const { valid, invalid } = await this.#revalidateMetadata(txsToRestore, 'during prepareForSlot');
|
|
422
507
|
|
|
423
|
-
|
|
424
|
-
|
|
508
|
+
// Step 5: Resolve nullifier conflicts and add winners to pending indices
|
|
509
|
+
const { added, toEvict } = this.#applyNullifierConflictResolution(valid);
|
|
425
510
|
|
|
426
|
-
|
|
427
|
-
|
|
511
|
+
// Step 6: Delete invalid txs and evict conflict losers
|
|
512
|
+
await this.#deleteTxsBatch(invalid);
|
|
513
|
+
await this.#evictTxs(toEvict, 'NullifierConflict');
|
|
428
514
|
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
515
|
+
// Step 7: Run eviction rules (enforce pool size limit)
|
|
516
|
+
if (added.length > 0) {
|
|
517
|
+
const feePayers = added.map(meta => meta.feePayer);
|
|
518
|
+
const uniqueFeePayers = new Set<string>(feePayers);
|
|
519
|
+
await this.#evictionManager.evictAfterNewTxs(
|
|
520
|
+
added.map(m => m.txHash),
|
|
521
|
+
[...uniqueFeePayers],
|
|
522
|
+
);
|
|
523
|
+
}
|
|
524
|
+
});
|
|
438
525
|
}
|
|
439
526
|
|
|
440
|
-
async handlePrunedBlocks(latestBlock: L2BlockId): Promise<void> {
|
|
527
|
+
async handlePrunedBlocks(latestBlock: L2BlockId, options?: { deleteAllTxs?: boolean }): Promise<void> {
|
|
441
528
|
// Step 1: Find transactions mined after the prune point
|
|
442
529
|
const txsToUnmine = this.#indices.findTxsMinedAfter(latestBlock.number);
|
|
443
530
|
if (txsToUnmine.length === 0) {
|
|
@@ -447,46 +534,60 @@ export class TxPoolV2Impl {
|
|
|
447
534
|
|
|
448
535
|
this.#log.info(`Handling prune to block ${latestBlock.number}: un-mining ${txsToUnmine.length} txs`);
|
|
449
536
|
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
537
|
+
await this.#store.transactionAsync(async () => {
|
|
538
|
+
// Step 2: Mark ALL un-mined txs with their original mined block number
|
|
539
|
+
// This ensures they get soft-deleted if removed later, and only hard-deleted
|
|
540
|
+
// when their original mined block is finalized
|
|
541
|
+
await this.#deletedPool.markFromPrunedBlock(
|
|
542
|
+
txsToUnmine.map(m => ({
|
|
543
|
+
txHash: m.txHash,
|
|
544
|
+
minedAtBlock: BlockNumber(m.minedL2BlockId!.number),
|
|
545
|
+
})),
|
|
546
|
+
);
|
|
459
547
|
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
548
|
+
// Step 3: Unmine - clear mined status from metadata
|
|
549
|
+
for (const meta of txsToUnmine) {
|
|
550
|
+
this.#indices.markAsUnmined(meta);
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
// If deleteAllTxs is set (epoch prune), delete all un-mined txs and return early
|
|
554
|
+
if (options?.deleteAllTxs) {
|
|
555
|
+
const allTxHashes = txsToUnmine.map(m => m.txHash);
|
|
556
|
+
await this.#deleteTxsBatch(allTxHashes);
|
|
557
|
+
this.#log.info(
|
|
558
|
+
`Handled prune to block ${latestBlock.number} with deleteAllTxs: deleted ${allTxHashes.length} txs`,
|
|
559
|
+
);
|
|
560
|
+
return;
|
|
561
|
+
}
|
|
464
562
|
|
|
465
|
-
|
|
466
|
-
|
|
563
|
+
// Step 4: Filter out protected txs (they'll be handled by prepareForSlot)
|
|
564
|
+
const unprotectedTxs = this.#indices.filterUnprotected(txsToUnmine);
|
|
467
565
|
|
|
468
|
-
|
|
469
|
-
|
|
566
|
+
// Step 5: Validate for pending pool
|
|
567
|
+
const { valid, invalid } = await this.#revalidateMetadata(unprotectedTxs, 'during handlePrunedBlocks');
|
|
470
568
|
|
|
471
|
-
|
|
472
|
-
|
|
569
|
+
// Step 6: Resolve nullifier conflicts and add winners to pending indices
|
|
570
|
+
const { toEvict } = this.#applyNullifierConflictResolution(valid);
|
|
473
571
|
|
|
474
|
-
|
|
475
|
-
|
|
572
|
+
// Step 7: Delete invalid txs and evict conflict losers
|
|
573
|
+
await this.#deleteTxsBatch(invalid);
|
|
574
|
+
await this.#evictTxs(toEvict, 'NullifierConflict');
|
|
476
575
|
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
576
|
+
this.#log.info(
|
|
577
|
+
`Handled prune to block ${latestBlock.number}: ${valid.length} txs restored to pending, ${invalid.length} invalid, ${toEvict.length} evicted due to nullifier conflicts`,
|
|
578
|
+
{ txHashesRestored: valid.map(m => m.txHash), txHashesInvalid: invalid, txHashesEvicted: toEvict },
|
|
579
|
+
);
|
|
481
580
|
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
581
|
+
// Step 8: Run eviction rules for ALL pending txs (not just restored ones)
|
|
582
|
+
// This handles cases like existing pending txs with invalid fee payer balances
|
|
583
|
+
await this.#evictionManager.evictAfterChainPrune(latestBlock.number);
|
|
584
|
+
});
|
|
485
585
|
}
|
|
486
586
|
|
|
487
587
|
async handleFailedExecution(txHashes: TxHash[]): Promise<void> {
|
|
488
|
-
|
|
489
|
-
|
|
588
|
+
await this.#store.transactionAsync(async () => {
|
|
589
|
+
await this.#deleteTxsBatch(txHashes.map(h => h.toString()));
|
|
590
|
+
});
|
|
490
591
|
|
|
491
592
|
this.#log.info(`Deleted ${txHashes.length} failed txs`, { txHashes: txHashes.map(h => h.toString()) });
|
|
492
593
|
}
|
|
@@ -497,27 +598,29 @@ export class TxPoolV2Impl {
|
|
|
497
598
|
// Step 1: Find mined txs at or before finalized block
|
|
498
599
|
const minedTxsToFinalize = this.#indices.findTxsMinedAtOrBefore(blockNumber);
|
|
499
600
|
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
const
|
|
505
|
-
|
|
506
|
-
|
|
601
|
+
await this.#store.transactionAsync(async () => {
|
|
602
|
+
// Step 2: Collect mined txs for archiving (before deletion)
|
|
603
|
+
const txsToArchive: Tx[] = [];
|
|
604
|
+
if (this.#archive.isEnabled()) {
|
|
605
|
+
for (const txHashStr of minedTxsToFinalize) {
|
|
606
|
+
const buffer = await this.#txsDB.getAsync(txHashStr);
|
|
607
|
+
if (buffer) {
|
|
608
|
+
txsToArchive.push(Tx.fromBuffer(buffer));
|
|
609
|
+
}
|
|
507
610
|
}
|
|
508
611
|
}
|
|
509
|
-
}
|
|
510
612
|
|
|
511
|
-
|
|
512
|
-
|
|
613
|
+
// Step 3: Delete mined txs from active pool
|
|
614
|
+
await this.#deleteTxsBatch(minedTxsToFinalize);
|
|
513
615
|
|
|
514
|
-
|
|
515
|
-
|
|
616
|
+
// Step 4: Finalize soft-deleted txs
|
|
617
|
+
await this.#deletedPool.finalizeBlock(blockNumber);
|
|
516
618
|
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
619
|
+
// Step 5: Archive mined txs
|
|
620
|
+
if (txsToArchive.length > 0) {
|
|
621
|
+
await this.#archive.archiveTxs(txsToArchive);
|
|
622
|
+
}
|
|
623
|
+
});
|
|
521
624
|
|
|
522
625
|
if (minedTxsToFinalize.length > 0) {
|
|
523
626
|
this.#log.info(`Finalized ${minedTxsToFinalize.length} mined txs from blocks up to ${blockNumber}`, {
|
|
@@ -637,8 +740,17 @@ export class TxPoolV2Impl {
|
|
|
637
740
|
|
|
638
741
|
// === Metrics ===
|
|
639
742
|
|
|
640
|
-
countTxs(): {
|
|
641
|
-
|
|
743
|
+
countTxs(): {
|
|
744
|
+
pending: number;
|
|
745
|
+
protected: number;
|
|
746
|
+
mined: number;
|
|
747
|
+
softDeleted: number;
|
|
748
|
+
totalMetadataBytes: number;
|
|
749
|
+
} {
|
|
750
|
+
return {
|
|
751
|
+
...this.#indices.countTxs(),
|
|
752
|
+
softDeleted: this.#deletedPool.getSoftDeletedCount(),
|
|
753
|
+
};
|
|
642
754
|
}
|
|
643
755
|
|
|
644
756
|
// ============================================================================
|
|
@@ -672,9 +784,11 @@ export class TxPoolV2Impl {
|
|
|
672
784
|
}
|
|
673
785
|
|
|
674
786
|
const stateStr = typeof state === 'string' ? state : Object.keys(state)[0];
|
|
675
|
-
this.#log.
|
|
787
|
+
this.#log.debug(`Added tx ${txHashStr} as ${stateStr}`, {
|
|
676
788
|
eventName: 'tx-added-to-pool',
|
|
789
|
+
txHash: txHashStr,
|
|
677
790
|
state: stateStr,
|
|
791
|
+
source: opts.source,
|
|
678
792
|
});
|
|
679
793
|
|
|
680
794
|
return meta;
|
|
@@ -702,6 +816,29 @@ export class TxPoolV2Impl {
|
|
|
702
816
|
}
|
|
703
817
|
}
|
|
704
818
|
|
|
819
|
+
/** Evicts transactions: records eviction metric with reason, caches hashes, then deletes. */
|
|
820
|
+
async #evictTxs(txHashes: string[], reason: string): Promise<void> {
|
|
821
|
+
if (txHashes.length === 0) {
|
|
822
|
+
return;
|
|
823
|
+
}
|
|
824
|
+
this.#instrumentation.recordEvictions(txHashes.length, reason);
|
|
825
|
+
for (const txHashStr of txHashes) {
|
|
826
|
+
this.#log.debug(`Evicting tx ${txHashStr}`, { txHash: txHashStr, reason });
|
|
827
|
+
this.#addToEvictedCache(txHashStr);
|
|
828
|
+
}
|
|
829
|
+
await this.#deleteTxsBatch(txHashes);
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
/** Adds a tx hash to the bounded evicted cache, evicting the oldest entry if at capacity. */
|
|
833
|
+
#addToEvictedCache(txHashStr: string): void {
|
|
834
|
+
if (this.#evictedTxHashes.size >= this.#config.evictedTxCacheSize) {
|
|
835
|
+
// FIFO eviction: remove the first (oldest) entry
|
|
836
|
+
const oldest = this.#evictedTxHashes.values().next().value!;
|
|
837
|
+
this.#evictedTxHashes.delete(oldest);
|
|
838
|
+
}
|
|
839
|
+
this.#evictedTxHashes.add(txHashStr);
|
|
840
|
+
}
|
|
841
|
+
|
|
705
842
|
// ============================================================================
|
|
706
843
|
// PRIVATE HELPERS - Validation & Conflict Resolution
|
|
707
844
|
// ============================================================================
|
|
@@ -857,7 +994,9 @@ export class TxPoolV2Impl {
|
|
|
857
994
|
if (preAddResult.shouldIgnore) {
|
|
858
995
|
// Transaction rejected - mark for deletion from DB
|
|
859
996
|
rejected.push(meta.txHash);
|
|
860
|
-
this.#log.debug(
|
|
997
|
+
this.#log.debug(
|
|
998
|
+
`Rejected tx ${meta.txHash} during rebuild: ${preAddResult.reason?.message ?? 'unknown reason'}`,
|
|
999
|
+
);
|
|
861
1000
|
continue;
|
|
862
1001
|
}
|
|
863
1002
|
|
|
@@ -893,7 +1032,7 @@ export class TxPoolV2Impl {
|
|
|
893
1032
|
getFeePayerPendingTxs: (feePayer: string) => this.#indices.getFeePayerPendingTxs(feePayer),
|
|
894
1033
|
getPendingTxCount: () => this.#indices.getPendingTxCount(),
|
|
895
1034
|
getLowestPriorityPending: (limit: number) => this.#indices.getLowestPriorityPending(limit),
|
|
896
|
-
deleteTxs: (txHashes: string[]) => this.#
|
|
1035
|
+
deleteTxs: (txHashes: string[], reason?: string) => this.#evictTxs(txHashes, reason ?? 'unknown'),
|
|
897
1036
|
};
|
|
898
1037
|
}
|
|
899
1038
|
|