@aztec/p2p 0.0.1-commit.f2ce05ee → 0.0.1-commit.f8ca9b2f3
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 -3
- package/dest/client/factory.d.ts.map +1 -1
- package/dest/client/factory.js +38 -7
- package/dest/client/interface.d.ts +26 -15
- package/dest/client/interface.d.ts.map +1 -1
- package/dest/client/p2p_client.d.ts +31 -35
- package/dest/client/p2p_client.d.ts.map +1 -1
- package/dest/client/p2p_client.js +97 -138
- package/dest/config.d.ts +10 -2
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +9 -0
- package/dest/index.d.ts +2 -1
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +1 -0
- package/dest/mem_pools/attestation_pool/attestation_pool.d.ts +18 -11
- package/dest/mem_pools/attestation_pool/attestation_pool.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/attestation_pool.js +62 -37
- package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.d.ts +1 -1
- package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.js +53 -53
- package/dest/mem_pools/attestation_pool/index.d.ts +2 -2
- package/dest/mem_pools/attestation_pool/index.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/index.js +1 -1
- package/dest/mem_pools/index.d.ts +2 -1
- package/dest/mem_pools/index.d.ts.map +1 -1
- package/dest/mem_pools/interface.d.ts +3 -3
- package/dest/mem_pools/interface.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/deleted_pool.d.ts +87 -0
- package/dest/mem_pools/tx_pool_v2/deleted_pool.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/deleted_pool.js +180 -0
- package/dest/mem_pools/tx_pool_v2/index.d.ts +2 -1
- package/dest/mem_pools/tx_pool_v2/index.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/index.js +1 -0
- package/dest/mem_pools/tx_pool_v2/interfaces.d.ts +3 -3
- package/dest/mem_pools/tx_pool_v2/interfaces.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts +25 -3
- package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/tx_metadata.js +36 -4
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts +1 -1
- 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 +77 -74
- package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts +3 -3
- package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/block_header_validator.d.ts +16 -3
- package/dest/msg_validators/tx_validator/block_header_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/block_header_validator.js +1 -1
- package/dest/msg_validators/tx_validator/double_spend_validator.d.ts +13 -3
- package/dest/msg_validators/tx_validator/double_spend_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/double_spend_validator.js +4 -4
- package/dest/msg_validators/tx_validator/timestamp_validator.d.ts +20 -4
- package/dest/msg_validators/tx_validator/timestamp_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/timestamp_validator.js +2 -2
- package/dest/services/dummy_service.d.ts +6 -2
- package/dest/services/dummy_service.d.ts.map +1 -1
- package/dest/services/dummy_service.js +3 -0
- package/dest/services/encoding.d.ts +2 -2
- package/dest/services/encoding.d.ts.map +1 -1
- package/dest/services/encoding.js +2 -2
- package/dest/services/libp2p/libp2p_service.d.ts +11 -3
- package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
- package/dest/services/libp2p/libp2p_service.js +71 -35
- package/dest/services/reqresp/interface.d.ts +10 -1
- package/dest/services/reqresp/interface.d.ts.map +1 -1
- package/dest/services/reqresp/interface.js +15 -1
- package/dest/services/reqresp/protocols/block_txs/block_txs_handler.d.ts +3 -3
- package/dest/services/reqresp/protocols/block_txs/block_txs_handler.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.d.ts +7 -1
- package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.js +15 -0
- package/dest/services/reqresp/protocols/tx.d.ts +7 -1
- package/dest/services/reqresp/protocols/tx.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/tx.js +20 -0
- 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 +11 -4
- package/dest/services/service.d.ts +18 -1
- package/dest/services/service.d.ts.map +1 -1
- package/dest/services/tx_collection/config.d.ts +7 -1
- package/dest/services/tx_collection/config.d.ts.map +1 -1
- package/dest/services/tx_collection/config.js +16 -0
- package/dest/services/tx_collection/fast_tx_collection.d.ts +3 -1
- package/dest/services/tx_collection/fast_tx_collection.d.ts.map +1 -1
- package/dest/services/tx_collection/fast_tx_collection.js +17 -3
- package/dest/services/tx_collection/file_store_tx_collection.d.ts +44 -0
- package/dest/services/tx_collection/file_store_tx_collection.d.ts.map +1 -0
- package/dest/services/tx_collection/file_store_tx_collection.js +118 -0
- package/dest/services/tx_collection/file_store_tx_source.d.ts +27 -0
- package/dest/services/tx_collection/file_store_tx_source.d.ts.map +1 -0
- package/dest/services/tx_collection/file_store_tx_source.js +57 -0
- package/dest/services/tx_collection/index.d.ts +2 -1
- package/dest/services/tx_collection/index.d.ts.map +1 -1
- package/dest/services/tx_collection/index.js +1 -0
- package/dest/services/tx_collection/slow_tx_collection.d.ts +3 -1
- package/dest/services/tx_collection/slow_tx_collection.d.ts.map +1 -1
- package/dest/services/tx_collection/slow_tx_collection.js +48 -19
- package/dest/services/tx_collection/tx_collection.d.ts +17 -7
- package/dest/services/tx_collection/tx_collection.d.ts.map +1 -1
- package/dest/services/tx_collection/tx_collection.js +58 -2
- package/dest/services/tx_collection/tx_collection_sink.d.ts +15 -6
- package/dest/services/tx_collection/tx_collection_sink.d.ts.map +1 -1
- package/dest/services/tx_collection/tx_collection_sink.js +13 -7
- package/dest/services/tx_file_store/config.d.ts +1 -3
- package/dest/services/tx_file_store/config.d.ts.map +1 -1
- package/dest/services/tx_file_store/config.js +0 -4
- package/dest/services/tx_file_store/tx_file_store.d.ts +3 -3
- package/dest/services/tx_file_store/tx_file_store.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 +5 -4
- package/dest/test-helpers/make-test-p2p-clients.d.ts +3 -3
- package/dest/test-helpers/make-test-p2p-clients.d.ts.map +1 -1
- package/dest/test-helpers/mock-pubsub.d.ts +27 -1
- package/dest/test-helpers/mock-pubsub.d.ts.map +1 -1
- package/dest/test-helpers/mock-pubsub.js +97 -2
- package/dest/test-helpers/testbench-utils.d.ts +30 -24
- package/dest/test-helpers/testbench-utils.d.ts.map +1 -1
- package/dest/test-helpers/testbench-utils.js +87 -35
- package/dest/testbench/p2p_client_testbench_worker.js +1 -1
- package/package.json +14 -14
- package/src/client/factory.ts +65 -8
- package/src/client/interface.ts +26 -13
- package/src/client/p2p_client.ts +123 -158
- package/src/config.ts +16 -0
- package/src/index.ts +1 -0
- package/src/mem_pools/attestation_pool/attestation_pool.ts +87 -44
- package/src/mem_pools/attestation_pool/attestation_pool_test_suite.ts +57 -53
- package/src/mem_pools/attestation_pool/index.ts +3 -3
- package/src/mem_pools/index.ts +3 -0
- package/src/mem_pools/interface.ts +2 -2
- package/src/mem_pools/tx_pool_v2/README.md +59 -9
- package/src/mem_pools/tx_pool_v2/deleted_pool.ts +234 -0
- package/src/mem_pools/tx_pool_v2/index.ts +1 -0
- package/src/mem_pools/tx_pool_v2/interfaces.ts +2 -2
- package/src/mem_pools/tx_pool_v2/tx_metadata.ts +51 -5
- package/src/mem_pools/tx_pool_v2/tx_pool_v2_impl.ts +90 -77
- package/src/msg_validators/tx_validator/aggregate_tx_validator.ts +2 -2
- package/src/msg_validators/tx_validator/block_header_validator.ts +15 -3
- package/src/msg_validators/tx_validator/double_spend_validator.ts +11 -6
- package/src/msg_validators/tx_validator/timestamp_validator.ts +19 -14
- package/src/services/dummy_service.ts +6 -0
- package/src/services/encoding.ts +2 -2
- package/src/services/libp2p/libp2p_service.ts +70 -37
- package/src/services/reqresp/interface.ts +26 -1
- package/src/services/reqresp/protocols/block_txs/block_txs_handler.ts +2 -2
- package/src/services/reqresp/protocols/block_txs/block_txs_reqresp.ts +17 -0
- package/src/services/reqresp/protocols/tx.ts +22 -0
- package/src/services/reqresp/reqresp.ts +13 -3
- package/src/services/service.ts +20 -0
- package/src/services/tx_collection/config.ts +26 -0
- package/src/services/tx_collection/fast_tx_collection.ts +14 -2
- package/src/services/tx_collection/file_store_tx_collection.ts +152 -0
- package/src/services/tx_collection/file_store_tx_source.ts +70 -0
- package/src/services/tx_collection/index.ts +1 -0
- package/src/services/tx_collection/slow_tx_collection.ts +55 -26
- package/src/services/tx_collection/tx_collection.ts +78 -12
- package/src/services/tx_collection/tx_collection_sink.ts +17 -7
- package/src/services/tx_file_store/config.ts +0 -6
- package/src/services/tx_file_store/tx_file_store.ts +4 -4
- package/src/services/tx_provider.ts +8 -7
- package/src/test-helpers/make-test-p2p-clients.ts +3 -3
- package/src/test-helpers/mock-pubsub.ts +133 -3
- package/src/test-helpers/testbench-utils.ts +100 -40
- package/src/testbench/p2p_client_testbench_worker.ts +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { SlotNumber } from '@aztec/foundation/branded-types';
|
|
1
|
+
import { BlockNumber, SlotNumber } from '@aztec/foundation/branded-types';
|
|
2
2
|
import type { Logger } from '@aztec/foundation/log';
|
|
3
3
|
import type { AztecAsyncKVStore, AztecAsyncMap } from '@aztec/kv-store';
|
|
4
4
|
import { ProtocolContractAddress } from '@aztec/protocol-contracts';
|
|
@@ -10,6 +10,7 @@ import { DatabasePublicStateSource } from '@aztec/stdlib/trees';
|
|
|
10
10
|
import { BlockHeader, Tx, TxHash, type TxValidator } from '@aztec/stdlib/tx';
|
|
11
11
|
|
|
12
12
|
import { TxArchive } from './archive/index.js';
|
|
13
|
+
import { DeletedPool } from './deleted_pool.js';
|
|
13
14
|
import {
|
|
14
15
|
EvictionManager,
|
|
15
16
|
FeePayerBalanceEvictionRule,
|
|
@@ -53,7 +54,7 @@ export class TxPoolV2Impl {
|
|
|
53
54
|
// === Dependencies ===
|
|
54
55
|
#l2BlockSource: L2BlockSource;
|
|
55
56
|
#worldStateSynchronizer: WorldStateSynchronizer;
|
|
56
|
-
#
|
|
57
|
+
#createTxValidator: TxPoolV2Dependencies['createTxValidator'];
|
|
57
58
|
|
|
58
59
|
// === In-Memory Indices ===
|
|
59
60
|
#indices: TxPoolIndices = new TxPoolIndices();
|
|
@@ -61,6 +62,7 @@ export class TxPoolV2Impl {
|
|
|
61
62
|
// === Config & Services ===
|
|
62
63
|
#config: TxPoolV2Config;
|
|
63
64
|
#archive: TxArchive;
|
|
65
|
+
#deletedPool: DeletedPool;
|
|
64
66
|
#evictionManager: EvictionManager;
|
|
65
67
|
#log: Logger;
|
|
66
68
|
#callbacks: TxPoolV2Callbacks;
|
|
@@ -78,10 +80,11 @@ export class TxPoolV2Impl {
|
|
|
78
80
|
|
|
79
81
|
this.#l2BlockSource = deps.l2BlockSource;
|
|
80
82
|
this.#worldStateSynchronizer = deps.worldStateSynchronizer;
|
|
81
|
-
this.#
|
|
83
|
+
this.#createTxValidator = deps.createTxValidator;
|
|
82
84
|
|
|
83
85
|
this.#config = { ...DEFAULT_TX_POOL_V2_CONFIG, ...config };
|
|
84
86
|
this.#archive = new TxArchive(archiveStore, this.#config.archivedTxLimit, log);
|
|
87
|
+
this.#deletedPool = new DeletedPool(store, this.#txsDB, log);
|
|
85
88
|
this.#log = log;
|
|
86
89
|
this.#callbacks = callbacks;
|
|
87
90
|
|
|
@@ -116,7 +119,10 @@ export class TxPoolV2Impl {
|
|
|
116
119
|
* by running pre-add rules to resolve nullifier conflicts, balance checks, and pool size limits.
|
|
117
120
|
*/
|
|
118
121
|
async hydrateFromDatabase(): Promise<void> {
|
|
119
|
-
// Step
|
|
122
|
+
// Step 0: Hydrate deleted pool state
|
|
123
|
+
await this.#deletedPool.hydrateFromDatabase();
|
|
124
|
+
|
|
125
|
+
// Step 1: Load all transactions from DB (excluding soft-deleted)
|
|
120
126
|
const { loaded, errors: deserializationErrors } = await this.#loadAllTxsFromDb();
|
|
121
127
|
|
|
122
128
|
// Step 2: Check mined status for each tx
|
|
@@ -134,7 +140,10 @@ export class TxPoolV2Impl {
|
|
|
134
140
|
}
|
|
135
141
|
|
|
136
142
|
// Step 4: Validate non-mined transactions
|
|
137
|
-
const { valid, invalid } = await this.#
|
|
143
|
+
const { valid, invalid } = await this.#revalidateMetadata(
|
|
144
|
+
nonMined.map(e => e.meta),
|
|
145
|
+
'on startup',
|
|
146
|
+
);
|
|
138
147
|
|
|
139
148
|
// Step 5: Populate mined indices (these don't need conflict resolution)
|
|
140
149
|
for (const meta of mined) {
|
|
@@ -229,13 +238,13 @@ export class TxPoolV2Impl {
|
|
|
229
238
|
const txHash = tx.getTxHash();
|
|
230
239
|
const txHashStr = txHash.toString();
|
|
231
240
|
|
|
232
|
-
//
|
|
233
|
-
|
|
241
|
+
// Build metadata and validate using metadata
|
|
242
|
+
const meta = await buildTxMetaData(tx);
|
|
243
|
+
if (!(await this.#validateMeta(meta))) {
|
|
234
244
|
return { status: 'rejected' };
|
|
235
245
|
}
|
|
236
246
|
|
|
237
|
-
//
|
|
238
|
-
const meta = await buildTxMetaData(tx);
|
|
247
|
+
// Run pre-add rules
|
|
239
248
|
const preAddResult = await this.#evictionManager.runPreAddRules(meta, poolAccess);
|
|
240
249
|
|
|
241
250
|
if (preAddResult.shouldIgnore) {
|
|
@@ -267,14 +276,14 @@ export class TxPoolV2Impl {
|
|
|
267
276
|
return 'ignored';
|
|
268
277
|
}
|
|
269
278
|
|
|
270
|
-
//
|
|
271
|
-
const
|
|
272
|
-
|
|
279
|
+
// Build metadata and validate using metadata
|
|
280
|
+
const meta = await buildTxMetaData(tx);
|
|
281
|
+
const validationResult = await this.#validateMeta(meta, undefined, 'can add pending');
|
|
282
|
+
if (validationResult !== true) {
|
|
273
283
|
return 'rejected';
|
|
274
284
|
}
|
|
275
285
|
|
|
276
|
-
//
|
|
277
|
-
const meta = await buildTxMetaData(tx);
|
|
286
|
+
// Use pre-add rules
|
|
278
287
|
const poolAccess = this.#createPreAddPoolAccess();
|
|
279
288
|
const preAddResult = await this.#evictionManager.runPreAddRules(meta, poolAccess);
|
|
280
289
|
|
|
@@ -347,6 +356,7 @@ export class TxPoolV2Impl {
|
|
|
347
356
|
// Add new mined tx (callback emitted by #addTx)
|
|
348
357
|
await this.#addTx(tx, { mined: blockId }, opts);
|
|
349
358
|
}
|
|
359
|
+
await this.#deletedPool.clearIfMinedHigher(txHashStr, blockId.number);
|
|
350
360
|
}
|
|
351
361
|
});
|
|
352
362
|
}
|
|
@@ -373,6 +383,7 @@ export class TxPoolV2Impl {
|
|
|
373
383
|
// Step 4: Mark txs as mined (only those we have in the pool)
|
|
374
384
|
for (const meta of found) {
|
|
375
385
|
this.#indices.markAsMined(meta, blockId);
|
|
386
|
+
await this.#deletedPool.clearIfMinedHigher(meta.txHash, blockId.number);
|
|
376
387
|
}
|
|
377
388
|
|
|
378
389
|
// Step 5: Run eviction rules (remove pending txs with conflicting nullifiers/expired timestamps)
|
|
@@ -397,7 +408,7 @@ export class TxPoolV2Impl {
|
|
|
397
408
|
this.#log.info(`Preparing for slot ${slotNumber}: unprotecting ${txsToRestore.length} txs`);
|
|
398
409
|
|
|
399
410
|
// Step 4: Validate for pending pool
|
|
400
|
-
const { valid, invalid } = await this.#
|
|
411
|
+
const { valid, invalid } = await this.#revalidateMetadata(txsToRestore, 'during prepareForSlot');
|
|
401
412
|
|
|
402
413
|
// Step 5: Resolve nullifier conflicts and add winners to pending indices
|
|
403
414
|
const { added, toEvict } = this.#applyNullifierConflictResolution(valid);
|
|
@@ -426,24 +437,34 @@ export class TxPoolV2Impl {
|
|
|
426
437
|
|
|
427
438
|
this.#log.info(`Handling prune to block ${latestBlock.number}: un-mining ${txsToUnmine.length} txs`);
|
|
428
439
|
|
|
429
|
-
// Step 2:
|
|
440
|
+
// Step 2: Mark ALL un-mined txs with their original mined block number
|
|
441
|
+
// This ensures they get soft-deleted if removed later, and only hard-deleted
|
|
442
|
+
// when their original mined block is finalized
|
|
443
|
+
await this.#deletedPool.markFromPrunedBlock(
|
|
444
|
+
txsToUnmine.map(m => ({
|
|
445
|
+
txHash: m.txHash,
|
|
446
|
+
minedAtBlock: BlockNumber(m.minedL2BlockId!.number),
|
|
447
|
+
})),
|
|
448
|
+
);
|
|
449
|
+
|
|
450
|
+
// Step 3: Unmine - clear mined status from metadata
|
|
430
451
|
for (const meta of txsToUnmine) {
|
|
431
452
|
this.#indices.markAsUnmined(meta);
|
|
432
453
|
}
|
|
433
454
|
|
|
434
|
-
// Step
|
|
455
|
+
// Step 4: Filter out protected txs (they'll be handled by prepareForSlot)
|
|
435
456
|
const unprotectedTxs = this.#indices.filterUnprotected(txsToUnmine);
|
|
436
457
|
|
|
437
458
|
// Step 4: Validate for pending pool
|
|
438
|
-
const { valid, invalid } = await this.#
|
|
459
|
+
const { valid, invalid } = await this.#revalidateMetadata(unprotectedTxs, 'during handlePrunedBlocks');
|
|
439
460
|
|
|
440
|
-
// Step
|
|
461
|
+
// Step 6: Resolve nullifier conflicts and add winners to pending indices
|
|
441
462
|
const { toEvict } = this.#applyNullifierConflictResolution(valid);
|
|
442
463
|
|
|
443
|
-
// Step
|
|
464
|
+
// Step 7: Delete invalid and evicted txs
|
|
444
465
|
await this.#deleteTxsBatch([...invalid, ...toEvict]);
|
|
445
466
|
|
|
446
|
-
// Step
|
|
467
|
+
// Step 8: Run eviction rules for ALL pending txs (not just restored ones)
|
|
447
468
|
// This handles cases like existing pending txs with invalid fee payer balances
|
|
448
469
|
await this.#evictionManager.evictAfterChainPrune(latestBlock.number);
|
|
449
470
|
}
|
|
@@ -458,16 +479,13 @@ export class TxPoolV2Impl {
|
|
|
458
479
|
async handleFinalizedBlock(block: BlockHeader): Promise<void> {
|
|
459
480
|
const blockNumber = block.globalVariables.blockNumber;
|
|
460
481
|
|
|
461
|
-
// Step 1: Find txs
|
|
462
|
-
const
|
|
463
|
-
if (txsToFinalize.length === 0) {
|
|
464
|
-
return;
|
|
465
|
-
}
|
|
482
|
+
// Step 1: Find mined txs at or before finalized block
|
|
483
|
+
const minedTxsToFinalize = this.#indices.findTxsMinedAtOrBefore(blockNumber);
|
|
466
484
|
|
|
467
|
-
// Step 2: Collect txs for archiving (before deletion)
|
|
485
|
+
// Step 2: Collect mined txs for archiving (before deletion)
|
|
468
486
|
const txsToArchive: Tx[] = [];
|
|
469
487
|
if (this.#archive.isEnabled()) {
|
|
470
|
-
for (const txHashStr of
|
|
488
|
+
for (const txHashStr of minedTxsToFinalize) {
|
|
471
489
|
const buffer = await this.#txsDB.getAsync(txHashStr);
|
|
472
490
|
if (buffer) {
|
|
473
491
|
txsToArchive.push(Tx.fromBuffer(buffer));
|
|
@@ -475,15 +493,20 @@ export class TxPoolV2Impl {
|
|
|
475
493
|
}
|
|
476
494
|
}
|
|
477
495
|
|
|
478
|
-
// Step 3: Delete from active pool
|
|
479
|
-
await this.#deleteTxsBatch(
|
|
496
|
+
// Step 3: Delete mined txs from active pool
|
|
497
|
+
await this.#deleteTxsBatch(minedTxsToFinalize);
|
|
498
|
+
|
|
499
|
+
// Step 4: Finalize soft-deleted txs
|
|
500
|
+
await this.#deletedPool.finalizeBlock(blockNumber);
|
|
480
501
|
|
|
481
|
-
// Step
|
|
502
|
+
// Step 5: Archive mined txs
|
|
482
503
|
if (txsToArchive.length > 0) {
|
|
483
504
|
await this.#archive.archiveTxs(txsToArchive);
|
|
484
505
|
}
|
|
485
506
|
|
|
486
|
-
|
|
507
|
+
if (minedTxsToFinalize.length > 0) {
|
|
508
|
+
this.#log.info(`Finalized ${minedTxsToFinalize.length} mined txs from blocks up to ${blockNumber}`);
|
|
509
|
+
}
|
|
487
510
|
}
|
|
488
511
|
|
|
489
512
|
// === Query Methods ===
|
|
@@ -503,15 +526,23 @@ export class TxPoolV2Impl {
|
|
|
503
526
|
}
|
|
504
527
|
|
|
505
528
|
hasTxs(txHashes: TxHash[]): boolean[] {
|
|
506
|
-
return txHashes.map(h =>
|
|
529
|
+
return txHashes.map(h => {
|
|
530
|
+
const hashStr = h.toString();
|
|
531
|
+
return this.#indices.has(hashStr) || this.#deletedPool.isSoftDeleted(hashStr);
|
|
532
|
+
});
|
|
507
533
|
}
|
|
508
534
|
|
|
509
535
|
getTxStatus(txHash: TxHash): TxState | undefined {
|
|
510
|
-
const
|
|
511
|
-
|
|
512
|
-
|
|
536
|
+
const txHashStr = txHash.toString();
|
|
537
|
+
const meta = this.#indices.getMetadata(txHashStr);
|
|
538
|
+
if (meta) {
|
|
539
|
+
return this.#indices.getTxState(meta);
|
|
540
|
+
}
|
|
541
|
+
// Check if soft-deleted
|
|
542
|
+
if (this.#deletedPool.isSoftDeleted(txHashStr)) {
|
|
543
|
+
return 'deleted';
|
|
513
544
|
}
|
|
514
|
-
return
|
|
545
|
+
return undefined;
|
|
515
546
|
}
|
|
516
547
|
|
|
517
548
|
getPendingTxHashes(): TxHash[] {
|
|
@@ -624,10 +655,15 @@ export class TxPoolV2Impl {
|
|
|
624
655
|
* Deletes a transaction from both indices and DB.
|
|
625
656
|
* Emits onTxsRemoved callback immediately after DB delete.
|
|
626
657
|
*/
|
|
658
|
+
/**
|
|
659
|
+
* Deletes a transaction from the pool.
|
|
660
|
+
* Delegates to DeletedPool which decides soft vs hard delete based on whether
|
|
661
|
+
* the tx is from a pruned block.
|
|
662
|
+
*/
|
|
627
663
|
async #deleteTx(txHashStr: string): Promise<void> {
|
|
628
664
|
this.#indices.remove(txHashStr);
|
|
629
|
-
await this.#txsDB.delete(txHashStr);
|
|
630
665
|
this.#callbacks.onTxsRemoved([txHashStr]);
|
|
666
|
+
await this.#deletedPool.deleteTx(txHashStr);
|
|
631
667
|
}
|
|
632
668
|
|
|
633
669
|
/** Deletes a batch of transactions, emitting callbacks individually for each. */
|
|
@@ -641,64 +677,36 @@ export class TxPoolV2Impl {
|
|
|
641
677
|
// PRIVATE HELPERS - Validation & Conflict Resolution
|
|
642
678
|
// ============================================================================
|
|
643
679
|
|
|
644
|
-
/** Validates
|
|
645
|
-
async #
|
|
646
|
-
const
|
|
680
|
+
/** Validates transaction metadata, returning true if valid */
|
|
681
|
+
async #validateMeta(meta: TxMetaData, validator?: TxValidator<TxMetaData>, context?: string): Promise<boolean> {
|
|
682
|
+
const txValidator = validator ?? (await this.#createTxValidator());
|
|
683
|
+
const result = await txValidator.validateTx(meta);
|
|
647
684
|
if (result.result !== 'valid') {
|
|
648
685
|
const contextStr = context ? ` ${context}` : '';
|
|
649
|
-
this.#log.info(`Tx ${
|
|
686
|
+
this.#log.info(`Tx ${meta.txHash}${contextStr} failed validation: ${result.reason?.join(', ')}`);
|
|
650
687
|
return false;
|
|
651
688
|
}
|
|
652
689
|
return true;
|
|
653
690
|
}
|
|
654
691
|
|
|
655
|
-
/**
|
|
656
|
-
async #
|
|
657
|
-
|
|
658
|
-
const missing: string[] = [];
|
|
659
|
-
|
|
660
|
-
for (const meta of metas) {
|
|
661
|
-
const buffer = await this.#txsDB.getAsync(meta.txHash);
|
|
662
|
-
if (!buffer) {
|
|
663
|
-
this.#log.warn(`Tx ${meta.txHash} not found in DB`);
|
|
664
|
-
missing.push(meta.txHash);
|
|
665
|
-
continue;
|
|
666
|
-
}
|
|
667
|
-
loaded.push({ tx: Tx.fromBuffer(buffer), meta });
|
|
668
|
-
}
|
|
669
|
-
|
|
670
|
-
return { loaded, missing };
|
|
671
|
-
}
|
|
672
|
-
|
|
673
|
-
/** Validates a batch of transactions, returning valid and invalid groups */
|
|
674
|
-
async #validateTxBatch(
|
|
675
|
-
txs: { tx: Tx; meta: TxMetaData }[],
|
|
692
|
+
/** Validates metadata directly */
|
|
693
|
+
async #revalidateMetadata(
|
|
694
|
+
metas: TxMetaData[],
|
|
676
695
|
context?: string,
|
|
677
696
|
): Promise<{ valid: TxMetaData[]; invalid: string[] }> {
|
|
678
697
|
const valid: TxMetaData[] = [];
|
|
679
698
|
const invalid: string[] = [];
|
|
680
|
-
|
|
681
|
-
for (const
|
|
682
|
-
if (await this.#
|
|
699
|
+
const validator = await this.#createTxValidator();
|
|
700
|
+
for (const meta of metas) {
|
|
701
|
+
if (await this.#validateMeta(meta, validator, context)) {
|
|
683
702
|
valid.push(meta);
|
|
684
703
|
} else {
|
|
685
704
|
invalid.push(meta.txHash);
|
|
686
705
|
}
|
|
687
706
|
}
|
|
688
|
-
|
|
689
707
|
return { valid, invalid };
|
|
690
708
|
}
|
|
691
709
|
|
|
692
|
-
/** Loads transactions from DB and validates them */
|
|
693
|
-
async #loadAndValidateTxs(
|
|
694
|
-
metas: TxMetaData[],
|
|
695
|
-
context?: string,
|
|
696
|
-
): Promise<{ valid: TxMetaData[]; invalid: string[] }> {
|
|
697
|
-
const { loaded, missing } = await this.#loadTxsFromDb(metas);
|
|
698
|
-
const { valid, invalid } = await this.#validateTxBatch(loaded, context);
|
|
699
|
-
return { valid, invalid: [...missing, ...invalid] };
|
|
700
|
-
}
|
|
701
|
-
|
|
702
710
|
/**
|
|
703
711
|
* Resolves nullifier conflicts between incoming txs and existing pending txs.
|
|
704
712
|
* Modifies the pending indices during iteration to maintain consistent state
|
|
@@ -768,6 +776,11 @@ export class TxPoolV2Impl {
|
|
|
768
776
|
const errors: string[] = [];
|
|
769
777
|
|
|
770
778
|
for await (const [txHashStr, buffer] of this.#txsDB.entriesAsync()) {
|
|
779
|
+
// Skip soft-deleted transactions - they stay in DB but not in indices
|
|
780
|
+
if (this.#deletedPool.isSoftDeleted(txHashStr)) {
|
|
781
|
+
continue;
|
|
782
|
+
}
|
|
783
|
+
|
|
771
784
|
try {
|
|
772
785
|
const tx = Tx.fromBuffer(buffer);
|
|
773
786
|
const meta = await buildTxMetaData(tx);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { TxValidationResult, TxValidator } from '@aztec/stdlib/tx';
|
|
2
2
|
|
|
3
|
-
export class AggregateTxValidator<T
|
|
3
|
+
export class AggregateTxValidator<T> implements TxValidator<T> {
|
|
4
4
|
#validators: TxValidator<T>[];
|
|
5
5
|
constructor(...validators: TxValidator<T>[]) {
|
|
6
6
|
if (validators.length === 0) {
|
|
@@ -1,12 +1,24 @@
|
|
|
1
1
|
import { type Logger, type LoggerBindings, createLogger } from '@aztec/foundation/log';
|
|
2
2
|
import type { BlockHash } from '@aztec/stdlib/block';
|
|
3
|
-
import {
|
|
3
|
+
import { TX_ERROR_BLOCK_HEADER, type TxValidationResult, type TxValidator } from '@aztec/stdlib/tx';
|
|
4
4
|
|
|
5
5
|
export interface ArchiveSource {
|
|
6
6
|
getArchiveIndices: (archives: BlockHash[]) => Promise<(bigint | undefined)[]>;
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
/** Structural interface for block header validation. */
|
|
10
|
+
export interface HasBlockHeaderData {
|
|
11
|
+
txHash: { toString(): string };
|
|
12
|
+
data: {
|
|
13
|
+
constants: {
|
|
14
|
+
anchorBlockHeader: {
|
|
15
|
+
hash(): Promise<BlockHash>;
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export class BlockHeaderTxValidator<T extends HasBlockHeaderData> implements TxValidator<T> {
|
|
10
22
|
#log: Logger;
|
|
11
23
|
#archiveSource: ArchiveSource;
|
|
12
24
|
|
|
@@ -18,7 +30,7 @@ export class BlockHeaderTxValidator<T extends AnyTx> implements TxValidator<T> {
|
|
|
18
30
|
async validateTx(tx: T): Promise<TxValidationResult> {
|
|
19
31
|
const [index] = await this.#archiveSource.getArchiveIndices([await tx.data.constants.anchorBlockHeader.hash()]);
|
|
20
32
|
if (index === undefined) {
|
|
21
|
-
this.#log.verbose(`Rejecting tx ${
|
|
33
|
+
this.#log.verbose(`Rejecting tx ${tx.txHash} for referencing an unknown block header`);
|
|
22
34
|
return { result: 'invalid', reason: [TX_ERROR_BLOCK_HEADER] };
|
|
23
35
|
}
|
|
24
36
|
return { result: 'valid' };
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
+
import type { Fr } from '@aztec/foundation/curves/bn254';
|
|
1
2
|
import { type Logger, type LoggerBindings, createLogger } from '@aztec/foundation/log';
|
|
2
3
|
import {
|
|
3
|
-
type AnyTx,
|
|
4
4
|
TX_ERROR_DUPLICATE_NULLIFIER_IN_TX,
|
|
5
5
|
TX_ERROR_EXISTING_NULLIFIER,
|
|
6
|
-
Tx,
|
|
7
6
|
type TxValidationResult,
|
|
8
7
|
type TxValidator,
|
|
9
8
|
} from '@aztec/stdlib/tx';
|
|
@@ -12,7 +11,13 @@ export interface NullifierSource {
|
|
|
12
11
|
nullifiersExist: (nullifiers: Buffer[]) => Promise<boolean[]>;
|
|
13
12
|
}
|
|
14
13
|
|
|
15
|
-
|
|
14
|
+
/** Structural interface for double-spend validation. */
|
|
15
|
+
export interface HasNullifierData {
|
|
16
|
+
txHash: { toString(): string };
|
|
17
|
+
data: { getNonEmptyNullifiers(): Fr[] };
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export class DoubleSpendTxValidator<T extends HasNullifierData> implements TxValidator<T> {
|
|
16
21
|
#log: Logger;
|
|
17
22
|
#nullifierSource: NullifierSource;
|
|
18
23
|
|
|
@@ -22,17 +27,17 @@ export class DoubleSpendTxValidator<T extends AnyTx> implements TxValidator<T> {
|
|
|
22
27
|
}
|
|
23
28
|
|
|
24
29
|
async validateTx(tx: T): Promise<TxValidationResult> {
|
|
25
|
-
const nullifiers = tx
|
|
30
|
+
const nullifiers = tx.data.getNonEmptyNullifiers();
|
|
26
31
|
|
|
27
32
|
// Ditch this tx if it has repeated nullifiers
|
|
28
33
|
const uniqueNullifiers = new Set(nullifiers.map(n => n.toBigInt()));
|
|
29
34
|
if (uniqueNullifiers.size !== nullifiers.length) {
|
|
30
|
-
this.#log.verbose(`Rejecting tx ${
|
|
35
|
+
this.#log.verbose(`Rejecting tx ${tx.txHash} for emitting duplicate nullifiers`);
|
|
31
36
|
return { result: 'invalid', reason: [TX_ERROR_DUPLICATE_NULLIFIER_IN_TX] };
|
|
32
37
|
}
|
|
33
38
|
|
|
34
39
|
if ((await this.#nullifierSource.nullifiersExist(nullifiers.map(n => n.toBuffer()))).some(Boolean)) {
|
|
35
|
-
this.#log.verbose(`Rejecting tx ${
|
|
40
|
+
this.#log.verbose(`Rejecting tx ${tx.txHash} for repeating a nullifier`);
|
|
36
41
|
return { result: 'invalid', reason: [TX_ERROR_EXISTING_NULLIFIER] };
|
|
37
42
|
}
|
|
38
43
|
|
|
@@ -1,15 +1,24 @@
|
|
|
1
|
-
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
1
|
+
import type { BlockNumber } from '@aztec/foundation/branded-types';
|
|
2
2
|
import { type Logger, type LoggerBindings, createLogger } from '@aztec/foundation/log';
|
|
3
|
-
import {
|
|
4
|
-
type AnyTx,
|
|
5
|
-
TX_ERROR_INVALID_INCLUDE_BY_TIMESTAMP,
|
|
6
|
-
type TxValidationResult,
|
|
7
|
-
type TxValidator,
|
|
8
|
-
getTxHash,
|
|
9
|
-
} from '@aztec/stdlib/tx';
|
|
3
|
+
import { TX_ERROR_INVALID_INCLUDE_BY_TIMESTAMP, type TxValidationResult, type TxValidator } from '@aztec/stdlib/tx';
|
|
10
4
|
import type { UInt64 } from '@aztec/stdlib/types';
|
|
11
5
|
|
|
12
|
-
|
|
6
|
+
/** Structural interface for timestamp validation. */
|
|
7
|
+
export interface HasTimestampData {
|
|
8
|
+
txHash: { toString(): string };
|
|
9
|
+
data: {
|
|
10
|
+
includeByTimestamp: bigint;
|
|
11
|
+
constants: {
|
|
12
|
+
anchorBlockHeader: {
|
|
13
|
+
globalVariables: {
|
|
14
|
+
blockNumber: BlockNumber;
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export class TimestampTxValidator<T extends HasTimestampData> implements TxValidator<T> {
|
|
13
22
|
#log: Logger;
|
|
14
23
|
|
|
15
24
|
constructor(
|
|
@@ -38,11 +47,7 @@ export class TimestampTxValidator<T extends AnyTx> implements TxValidator<T> {
|
|
|
38
47
|
);
|
|
39
48
|
}
|
|
40
49
|
this.#log.verbose(
|
|
41
|
-
`Rejecting tx ${
|
|
42
|
-
tx,
|
|
43
|
-
)} for low expiration timestamp. Tx expiration timestamp: ${includeByTimestamp}, timestamp: ${
|
|
44
|
-
this.values.timestamp
|
|
45
|
-
}.`,
|
|
50
|
+
`Rejecting tx ${tx.txHash} for low expiration timestamp. Tx expiration timestamp: ${includeByTimestamp}, timestamp: ${this.values.timestamp}.`,
|
|
46
51
|
);
|
|
47
52
|
return Promise.resolve({ result: 'invalid', reason: [TX_ERROR_INVALID_INCLUDE_BY_TIMESTAMP] });
|
|
48
53
|
} else {
|
|
@@ -26,6 +26,7 @@ import { ReqRespStatus } from './reqresp/status.js';
|
|
|
26
26
|
import {
|
|
27
27
|
type P2PBlockReceivedCallback,
|
|
28
28
|
type P2PCheckpointReceivedCallback,
|
|
29
|
+
type P2PDuplicateAttestationCallback,
|
|
29
30
|
type P2PDuplicateProposalCallback,
|
|
30
31
|
type P2PService,
|
|
31
32
|
type PeerDiscoveryService,
|
|
@@ -88,6 +89,11 @@ export class DummyP2PService implements P2PService {
|
|
|
88
89
|
*/
|
|
89
90
|
public registerDuplicateProposalCallback(_callback: P2PDuplicateProposalCallback): void {}
|
|
90
91
|
|
|
92
|
+
/**
|
|
93
|
+
* Register a callback for when a duplicate attestation is detected
|
|
94
|
+
*/
|
|
95
|
+
public registerDuplicateAttestationCallback(_callback: P2PDuplicateAttestationCallback): void {}
|
|
96
|
+
|
|
91
97
|
/**
|
|
92
98
|
* Sends a request to a peer.
|
|
93
99
|
* @param _protocol - The protocol to send the request on.
|
package/src/services/encoding.ts
CHANGED
|
@@ -78,11 +78,11 @@ export class SnappyTransform implements DataTransform {
|
|
|
78
78
|
return this.inboundTransformData(Buffer.from(data), topic);
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
-
public inboundTransformData(data: Buffer, topic?: TopicType): Buffer {
|
|
81
|
+
public inboundTransformData(data: Buffer, topic?: TopicType, maxSizeKbOverride?: number): Buffer {
|
|
82
82
|
if (data.length === 0) {
|
|
83
83
|
return data;
|
|
84
84
|
}
|
|
85
|
-
const maxSizeKb = this.maxSizesKb[topic!] ?? this.defaultMaxSizeKb;
|
|
85
|
+
const maxSizeKb = maxSizeKbOverride ?? this.maxSizesKb[topic!] ?? this.defaultMaxSizeKb;
|
|
86
86
|
const { decompressedSize } = readSnappyPreamble(data);
|
|
87
87
|
if (decompressedSize > maxSizeKb * 1024) {
|
|
88
88
|
this.logger.warn(`Decompressed size ${decompressedSize} exceeds maximum allowed size of ${maxSizeKb}kb`);
|