@aztec/p2p 0.0.1-commit.03f7ef2 → 0.0.1-commit.1142ef1
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.js +1 -1
- package/dest/client/interface.d.ts +18 -5
- package/dest/client/interface.d.ts.map +1 -1
- package/dest/client/p2p_client.d.ts +10 -13
- package/dest/client/p2p_client.d.ts.map +1 -1
- package/dest/client/p2p_client.js +450 -119
- package/dest/config.d.ts +4 -7
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +6 -9
- package/dest/mem_pools/attestation_pool/attestation_pool.d.ts +61 -42
- package/dest/mem_pools/attestation_pool/attestation_pool.d.ts.map +1 -1
- 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 +225 -262
- package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts +21 -18
- package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/kv_attestation_pool.js +113 -108
- package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts +17 -16
- package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/memory_attestation_pool.js +89 -128
- package/dest/mem_pools/attestation_pool/mocks.d.ts +7 -6
- package/dest/mem_pools/attestation_pool/mocks.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/mocks.js +9 -8
- package/dest/mem_pools/instrumentation.d.ts +3 -3
- package/dest/mem_pools/instrumentation.d.ts.map +1 -1
- package/dest/mem_pools/instrumentation.js +10 -17
- package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts +28 -24
- package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.js +260 -325
- package/dest/mem_pools/tx_pool/eviction/eviction_manager.d.ts +18 -0
- package/dest/mem_pools/tx_pool/eviction/eviction_manager.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool/eviction/eviction_manager.js +56 -0
- package/dest/mem_pools/tx_pool/eviction/eviction_strategy.d.ts +83 -0
- package/dest/mem_pools/tx_pool/eviction/eviction_strategy.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool/eviction/eviction_strategy.js +5 -0
- package/dest/mem_pools/tx_pool/eviction/insufficient_fee_payer_balance_rule.d.ts +15 -0
- package/dest/mem_pools/tx_pool/eviction/insufficient_fee_payer_balance_rule.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool/eviction/insufficient_fee_payer_balance_rule.js +88 -0
- package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.d.ts +17 -0
- package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.js +84 -0
- package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.d.ts +19 -0
- package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.js +76 -0
- package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.d.ts +26 -0
- package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.js +84 -0
- package/dest/mem_pools/tx_pool/index.d.ts +1 -2
- package/dest/mem_pools/tx_pool/index.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/index.js +0 -1
- package/dest/mem_pools/tx_pool/priority.d.ts +5 -1
- package/dest/mem_pools/tx_pool/priority.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/priority.js +6 -1
- package/dest/mem_pools/tx_pool/tx_pool.d.ts +8 -4
- package/dest/mem_pools/tx_pool/tx_pool.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/tx_pool_test_suite.js +7 -7
- package/dest/msg_validators/attestation_validator/attestation_validator.d.ts +4 -4
- package/dest/msg_validators/attestation_validator/attestation_validator.d.ts.map +1 -1
- package/dest/msg_validators/attestation_validator/attestation_validator.js +12 -10
- package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts +5 -5
- package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts.map +1 -1
- package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.js +7 -10
- package/dest/msg_validators/index.d.ts +2 -2
- package/dest/msg_validators/index.d.ts.map +1 -1
- package/dest/msg_validators/index.js +1 -1
- package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts +9 -0
- package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts.map +1 -0
- package/dest/msg_validators/proposal_validator/block_proposal_validator.js +6 -0
- package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts +9 -0
- package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts.map +1 -0
- package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.js +6 -0
- package/dest/msg_validators/proposal_validator/index.d.ts +4 -0
- package/dest/msg_validators/proposal_validator/index.d.ts.map +1 -0
- package/dest/msg_validators/proposal_validator/index.js +3 -0
- package/dest/msg_validators/proposal_validator/proposal_validator.d.ts +13 -0
- package/dest/msg_validators/proposal_validator/proposal_validator.d.ts.map +1 -0
- package/dest/msg_validators/{block_proposal_validator/block_proposal_validator.js → proposal_validator/proposal_validator.js} +19 -21
- package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.d.ts +23 -0
- package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.d.ts.map +1 -0
- package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.js +183 -0
- package/dest/msg_validators/tx_validator/data_validator.d.ts +1 -1
- package/dest/msg_validators/tx_validator/data_validator.d.ts.map +1 -1
- 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/timestamp_validator.d.ts +1 -1
- package/dest/msg_validators/tx_validator/timestamp_validator.d.ts.map +1 -1
- 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 +1 -1
- package/dest/services/encoding.d.ts.map +1 -1
- package/dest/services/encoding.js +4 -2
- package/dest/services/libp2p/instrumentation.d.ts +1 -1
- package/dest/services/libp2p/instrumentation.d.ts.map +1 -1
- package/dest/services/libp2p/instrumentation.js +15 -68
- package/dest/services/libp2p/libp2p_service.d.ts +27 -10
- package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
- package/dest/services/libp2p/libp2p_service.js +696 -137
- package/dest/services/peer-manager/metrics.d.ts +6 -1
- package/dest/services/peer-manager/metrics.d.ts.map +1 -1
- package/dest/services/peer-manager/metrics.js +18 -21
- package/dest/services/peer-manager/peer_manager.d.ts +2 -2
- package/dest/services/peer-manager/peer_manager.d.ts.map +1 -1
- package/dest/services/peer-manager/peer_manager.js +2 -10
- package/dest/services/peer-manager/peer_scoring.d.ts +1 -1
- package/dest/services/peer-manager/peer_scoring.d.ts.map +1 -1
- package/dest/services/peer-manager/peer_scoring.js +2 -5
- package/dest/services/reqresp/connection-sampler/connection_sampler.d.ts +1 -1
- package/dest/services/reqresp/connection-sampler/connection_sampler.d.ts.map +1 -1
- package/dest/services/reqresp/metrics.d.ts +1 -1
- package/dest/services/reqresp/metrics.d.ts.map +1 -1
- package/dest/services/reqresp/metrics.js +5 -21
- package/dest/services/reqresp/protocols/status.d.ts +1 -1
- package/dest/services/reqresp/protocols/status.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/status.js +2 -0
- package/dest/services/reqresp/reqresp.js +402 -24
- package/dest/services/service.d.ts +16 -3
- package/dest/services/service.d.ts.map +1 -1
- 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 +4 -14
- package/dest/services/tx_provider.d.ts +1 -1
- package/dest/services/tx_provider.d.ts.map +1 -1
- package/dest/services/tx_provider.js +3 -1
- package/dest/services/tx_provider_instrumentation.d.ts +1 -1
- package/dest/services/tx_provider_instrumentation.d.ts.map +1 -1
- package/dest/services/tx_provider_instrumentation.js +6 -19
- package/dest/testbench/p2p_client_testbench_worker.js +26 -11
- package/dest/testbench/worker_client_manager.d.ts +1 -1
- package/dest/testbench/worker_client_manager.d.ts.map +1 -1
- package/dest/testbench/worker_client_manager.js +6 -1
- package/package.json +14 -14
- package/src/client/factory.ts +1 -1
- package/src/client/interface.ts +19 -4
- package/src/client/p2p_client.ts +79 -129
- package/src/config.ts +8 -14
- package/src/mem_pools/attestation_pool/attestation_pool.ts +68 -41
- package/src/mem_pools/attestation_pool/attestation_pool_test_suite.ts +231 -287
- package/src/mem_pools/attestation_pool/kv_attestation_pool.ts +162 -140
- package/src/mem_pools/attestation_pool/memory_attestation_pool.ts +141 -164
- package/src/mem_pools/attestation_pool/mocks.ts +13 -9
- package/src/mem_pools/instrumentation.ts +18 -25
- package/src/mem_pools/tx_pool/README.md +255 -0
- package/src/mem_pools/tx_pool/aztec_kv_tx_pool.ts +307 -370
- package/src/mem_pools/tx_pool/eviction/eviction_manager.ts +71 -0
- package/src/mem_pools/tx_pool/eviction/eviction_strategy.ts +93 -0
- package/src/mem_pools/tx_pool/eviction/insufficient_fee_payer_balance_rule.ts +108 -0
- package/src/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.ts +104 -0
- package/src/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.ts +91 -0
- package/src/mem_pools/tx_pool/eviction/low_priority_eviction_rule.ts +106 -0
- package/src/mem_pools/tx_pool/index.ts +0 -1
- package/src/mem_pools/tx_pool/priority.ts +8 -1
- package/src/mem_pools/tx_pool/tx_pool.ts +8 -3
- package/src/mem_pools/tx_pool/tx_pool_test_suite.ts +7 -7
- package/src/msg_validators/attestation_validator/attestation_validator.ts +16 -13
- package/src/msg_validators/attestation_validator/fisherman_attestation_validator.ts +9 -12
- package/src/msg_validators/index.ts +1 -1
- package/src/msg_validators/proposal_validator/block_proposal_validator.ts +10 -0
- package/src/msg_validators/proposal_validator/checkpoint_proposal_validator.ts +13 -0
- package/src/msg_validators/proposal_validator/index.ts +3 -0
- package/src/msg_validators/{block_proposal_validator/block_proposal_validator.ts → proposal_validator/proposal_validator.ts} +23 -28
- package/src/msg_validators/proposal_validator/proposal_validator_test_suite.ts +206 -0
- package/src/msg_validators/tx_validator/data_validator.ts +12 -4
- package/src/msg_validators/tx_validator/metadata_validator.ts +12 -4
- package/src/msg_validators/tx_validator/timestamp_validator.ts +3 -1
- package/src/services/dummy_service.ts +6 -0
- package/src/services/encoding.ts +3 -1
- package/src/services/libp2p/instrumentation.ts +14 -68
- package/src/services/libp2p/libp2p_service.ts +324 -100
- package/src/services/peer-manager/metrics.ts +22 -21
- package/src/services/peer-manager/peer_manager.ts +3 -2
- package/src/services/peer-manager/peer_scoring.ts +1 -5
- package/src/services/reqresp/connection-sampler/connection_sampler.ts +3 -1
- package/src/services/reqresp/metrics.ts +7 -23
- package/src/services/reqresp/protocols/status.ts +2 -1
- package/src/services/service.ts +19 -4
- package/src/services/tx_collection/instrumentation.ts +4 -21
- package/src/services/tx_provider.ts +4 -1
- package/src/services/tx_provider_instrumentation.ts +11 -24
- package/src/testbench/p2p_client_testbench_worker.ts +35 -11
- package/src/testbench/worker_client_manager.ts +6 -1
- package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts +0 -81
- package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/memory_tx_pool.js +0 -242
- package/dest/msg_validators/block_proposal_validator/block_proposal_validator.d.ts +0 -12
- package/dest/msg_validators/block_proposal_validator/block_proposal_validator.d.ts.map +0 -1
- package/dest/msg_validators/block_proposal_validator/index.d.ts +0 -2
- package/dest/msg_validators/block_proposal_validator/index.d.ts.map +0 -1
- package/dest/msg_validators/block_proposal_validator/index.js +0 -1
- package/src/mem_pools/tx_pool/memory_tx_pool.ts +0 -288
- package/src/msg_validators/block_proposal_validator/index.ts +0 -1
|
@@ -1,15 +1,14 @@
|
|
|
1
|
+
import { insertIntoSortedArray } from '@aztec/foundation/array';
|
|
1
2
|
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
2
3
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
3
4
|
import { toArray } from '@aztec/foundation/iterable';
|
|
4
5
|
import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
5
6
|
import type { TypedEventEmitter } from '@aztec/foundation/types';
|
|
6
|
-
import type { AztecAsyncKVStore, AztecAsyncMap, AztecAsyncMultiMap
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import type { MerkleTreeReadOperations, WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
|
|
7
|
+
import type { AztecAsyncKVStore, AztecAsyncMap, AztecAsyncMultiMap } from '@aztec/kv-store';
|
|
8
|
+
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
9
|
+
import type { MerkleTreeReadOperations, ReadonlyWorldStateAccess } from '@aztec/stdlib/interfaces/server';
|
|
10
10
|
import { ChonkProof } from '@aztec/stdlib/proofs';
|
|
11
11
|
import type { TxAddedToPoolStats } from '@aztec/stdlib/stats';
|
|
12
|
-
import { DatabasePublicStateSource } from '@aztec/stdlib/trees';
|
|
13
12
|
import { BlockHeader, Tx, TxHash } from '@aztec/stdlib/tx';
|
|
14
13
|
import { type TelemetryClient, getTelemetryClient } from '@aztec/telemetry-client';
|
|
15
14
|
|
|
@@ -17,25 +16,30 @@ import assert from 'assert';
|
|
|
17
16
|
import EventEmitter from 'node:events';
|
|
18
17
|
|
|
19
18
|
import { ArchiveCache } from '../../msg_validators/tx_validator/archive_cache.js';
|
|
20
|
-
import { GasTxValidator } from '../../msg_validators/tx_validator/gas_validator.js';
|
|
21
19
|
import { PoolInstrumentation, PoolName, type PoolStatsCallback } from '../instrumentation.js';
|
|
20
|
+
import { EvictionManager } from './eviction/eviction_manager.js';
|
|
21
|
+
import type { PendingTxInfo, TxBlockReference, TxPoolOperations } from './eviction/eviction_strategy.js';
|
|
22
|
+
import { InsufficientFeePayerBalanceRule } from './eviction/insufficient_fee_payer_balance_rule.js';
|
|
23
|
+
import { InvalidTxsAfterMiningRule } from './eviction/invalid_txs_after_mining_rule.js';
|
|
24
|
+
import { InvalidTxsAfterReorgRule } from './eviction/invalid_txs_after_reorg_rule.js';
|
|
25
|
+
import { LowPriorityEvictionRule } from './eviction/low_priority_eviction_rule.js';
|
|
22
26
|
import { getPendingTxPriority } from './priority.js';
|
|
23
27
|
import type { TxPool, TxPoolEvents, TxPoolOptions } from './tx_pool.js';
|
|
24
28
|
|
|
25
29
|
/**
|
|
26
30
|
* KV implementation of the Transaction Pool.
|
|
27
31
|
*/
|
|
28
|
-
export class AztecKVTxPool
|
|
32
|
+
export class AztecKVTxPool
|
|
33
|
+
extends (EventEmitter as new () => TypedEventEmitter<TxPoolEvents>)
|
|
34
|
+
implements TxPool, TxPoolOperations
|
|
35
|
+
{
|
|
29
36
|
#store: AztecAsyncKVStore;
|
|
30
37
|
|
|
31
38
|
/** Our tx pool, stored as a Map, with K: tx hash and V: the transaction. */
|
|
32
39
|
#txs: AztecAsyncMap<string, Buffer>;
|
|
33
40
|
|
|
34
|
-
/**
|
|
35
|
-
#
|
|
36
|
-
|
|
37
|
-
/** The tx evicion logic will kick after pool size is greater than maxTxPoolSize * txPoolOverflowFactor */
|
|
38
|
-
txPoolOverflowFactor: number = 1;
|
|
41
|
+
/** Holds the historical block for each tx */
|
|
42
|
+
#pendingTxHashToHistoricalBlockHeaderHash: AztecAsyncMap<string, string>;
|
|
39
43
|
|
|
40
44
|
/** Index from tx hash to the block number in which they were mined, filtered by mined txs. */
|
|
41
45
|
#minedTxHashToBlock: AztecAsyncMap<string, BlockNumber>;
|
|
@@ -43,23 +47,15 @@ export class AztecKVTxPool extends (EventEmitter as new () => TypedEventEmitter<
|
|
|
43
47
|
/** Index from tx priority (stored as hex) to its tx hash, filtered by pending txs. */
|
|
44
48
|
#pendingTxPriorityToHash: AztecAsyncMultiMap<string, string>;
|
|
45
49
|
|
|
46
|
-
/** Index from tx hash to its tx size (in bytes), filtered by pending txs. */
|
|
47
|
-
#pendingTxHashToSize: AztecAsyncMap<string, number>;
|
|
48
|
-
|
|
49
|
-
/** Index from tx hash to its header hash, filtered by pending txs. */
|
|
50
|
-
#pendingTxHashToHeaderHash: AztecAsyncMap<string, string>;
|
|
51
|
-
|
|
52
50
|
/** Map from tx hash to the block number it was originally mined in (for soft-deleted txs). */
|
|
53
51
|
#deletedMinedTxHashes: AztecAsyncMap<string, BlockNumber>;
|
|
54
52
|
|
|
55
53
|
/** MultiMap from block number to deleted mined tx hashes for efficient cleanup. */
|
|
56
54
|
#blockToDeletedMinedTxHash: AztecAsyncMultiMap<BlockNumber, string>;
|
|
57
55
|
|
|
58
|
-
|
|
59
|
-
#pendingTxSize: AztecAsyncSingleton<number>;
|
|
56
|
+
#historicalHeaderToTxHash: AztecAsyncMultiMap<string, string>;
|
|
60
57
|
|
|
61
|
-
|
|
62
|
-
#pendingTxs: Map<string, Tx>;
|
|
58
|
+
#feePayerToTxHash: AztecAsyncMultiMap<string, string>;
|
|
63
59
|
|
|
64
60
|
/** In-memory set of txs that should not be evicted from the pool. */
|
|
65
61
|
#nonEvictableTxs: Set<string>;
|
|
@@ -76,8 +72,7 @@ export class AztecKVTxPool extends (EventEmitter as new () => TypedEventEmitter<
|
|
|
76
72
|
/** Number of txs to archive. */
|
|
77
73
|
#archivedTxLimit: number = 0;
|
|
78
74
|
|
|
79
|
-
|
|
80
|
-
#worldStateSynchronizer: WorldStateSynchronizer;
|
|
75
|
+
#evictionManager: EvictionManager;
|
|
81
76
|
|
|
82
77
|
#log: Logger;
|
|
83
78
|
|
|
@@ -94,7 +89,7 @@ export class AztecKVTxPool extends (EventEmitter as new () => TypedEventEmitter<
|
|
|
94
89
|
constructor(
|
|
95
90
|
store: AztecAsyncKVStore,
|
|
96
91
|
archive: AztecAsyncKVStore,
|
|
97
|
-
|
|
92
|
+
worldState: ReadonlyWorldStateAccess,
|
|
98
93
|
telemetry: TelemetryClient = getTelemetryClient(),
|
|
99
94
|
config: TxPoolOptions = {},
|
|
100
95
|
log = createLogger('p2p:tx_pool'),
|
|
@@ -102,18 +97,30 @@ export class AztecKVTxPool extends (EventEmitter as new () => TypedEventEmitter<
|
|
|
102
97
|
super();
|
|
103
98
|
|
|
104
99
|
this.#log = log;
|
|
100
|
+
|
|
101
|
+
this.#evictionManager = new EvictionManager(this);
|
|
102
|
+
this.#evictionManager.registerRule(new InvalidTxsAfterMiningRule());
|
|
103
|
+
this.#evictionManager.registerRule(new InvalidTxsAfterReorgRule(worldState));
|
|
104
|
+
this.#evictionManager.registerRule(new InsufficientFeePayerBalanceRule(worldState));
|
|
105
|
+
this.#evictionManager.registerRule(
|
|
106
|
+
new LowPriorityEvictionRule({
|
|
107
|
+
//NOTE: 0 effectively disables low priority eviction
|
|
108
|
+
maxPoolSize: config.maxPendingTxCount ?? 0,
|
|
109
|
+
}),
|
|
110
|
+
);
|
|
111
|
+
|
|
105
112
|
this.updateConfig(config);
|
|
106
113
|
|
|
107
114
|
this.#txs = store.openMap('txs');
|
|
108
115
|
this.#minedTxHashToBlock = store.openMap('txHashToBlockMined');
|
|
109
116
|
this.#pendingTxPriorityToHash = store.openMultiMap('pendingTxFeeToHash');
|
|
110
|
-
this.#pendingTxHashToSize = store.openMap('pendingTxHashToSize');
|
|
111
|
-
this.#pendingTxHashToHeaderHash = store.openMap('pendingTxHashToHeaderHash');
|
|
112
|
-
this.#pendingTxSize = store.openSingleton('pendingTxSize');
|
|
113
117
|
this.#deletedMinedTxHashes = store.openMap('deletedMinedTxHashes');
|
|
114
118
|
this.#blockToDeletedMinedTxHash = store.openMultiMap('blockToDeletedMinedTxHash');
|
|
115
119
|
|
|
116
|
-
this.#
|
|
120
|
+
this.#pendingTxHashToHistoricalBlockHeaderHash = store.openMap('txHistoricalBlock');
|
|
121
|
+
this.#historicalHeaderToTxHash = store.openMultiMap('historicalHeaderToPendingTxHash');
|
|
122
|
+
this.#feePayerToTxHash = store.openMultiMap('feePayerToPendingTxHash');
|
|
123
|
+
|
|
117
124
|
this.#nonEvictableTxs = new Set<string>();
|
|
118
125
|
|
|
119
126
|
this.#archivedTxs = archive.openMap('archivedTxs');
|
|
@@ -121,7 +128,7 @@ export class AztecKVTxPool extends (EventEmitter as new () => TypedEventEmitter<
|
|
|
121
128
|
|
|
122
129
|
this.#store = store;
|
|
123
130
|
this.#archive = archive;
|
|
124
|
-
|
|
131
|
+
|
|
125
132
|
this.#metrics = new PoolInstrumentation(telemetry, PoolName.TX_POOL, this.countTxs, () => store.estimateSize());
|
|
126
133
|
}
|
|
127
134
|
|
|
@@ -142,6 +149,7 @@ export class AztecKVTxPool extends (EventEmitter as new () => TypedEventEmitter<
|
|
|
142
149
|
}
|
|
143
150
|
return true;
|
|
144
151
|
}
|
|
152
|
+
|
|
145
153
|
/**
|
|
146
154
|
* Marks transactions as mined in a block and updates the pool state accordingly.
|
|
147
155
|
* Removes the transactions from the pending set and adds them to the mined set.
|
|
@@ -154,69 +162,72 @@ export class AztecKVTxPool extends (EventEmitter as new () => TypedEventEmitter<
|
|
|
154
162
|
return Promise.resolve();
|
|
155
163
|
}
|
|
156
164
|
|
|
157
|
-
const
|
|
158
|
-
const
|
|
165
|
+
const uniqueMinedNullifiers: Fr[] = [];
|
|
166
|
+
const uniqueMinedFeePayers: AztecAddress[] = [];
|
|
159
167
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
168
|
+
try {
|
|
169
|
+
await this.#store.transactionAsync(async () => {
|
|
170
|
+
for (const hash of txHashes) {
|
|
171
|
+
const key = hash.toString();
|
|
172
|
+
await this.#minedTxHashToBlock.set(key, blockHeader.globalVariables.blockNumber);
|
|
173
|
+
|
|
174
|
+
const tx = await this.getPendingTxByHash(hash);
|
|
175
|
+
if (tx) {
|
|
176
|
+
const nullifiers = tx.data.getNonEmptyNullifiers();
|
|
177
|
+
|
|
178
|
+
nullifiers.forEach(nullifier => insertIntoSortedArray(uniqueMinedNullifiers, nullifier, Fr.cmp, false));
|
|
179
|
+
insertIntoSortedArray(
|
|
180
|
+
uniqueMinedFeePayers,
|
|
181
|
+
tx.data.feePayer,
|
|
182
|
+
(a, b) => a.toField().cmp(b.toField()),
|
|
183
|
+
false,
|
|
184
|
+
);
|
|
185
|
+
|
|
186
|
+
await this.removePendingTxIndicesInDbTx(tx, key);
|
|
187
|
+
}
|
|
164
188
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
189
|
+
// If this tx was previously soft-deleted, remove it from the deleted sets
|
|
190
|
+
if (await this.#deletedMinedTxHashes.hasAsync(key)) {
|
|
191
|
+
const originalBlock = await this.#deletedMinedTxHashes.getAsync(key);
|
|
192
|
+
await this.#deletedMinedTxHashes.delete(key);
|
|
193
|
+
// Remove from block-to-hash mapping
|
|
194
|
+
if (originalBlock !== undefined) {
|
|
195
|
+
await this.#blockToDeletedMinedTxHash.deleteValue(originalBlock, key);
|
|
196
|
+
}
|
|
172
197
|
}
|
|
173
198
|
}
|
|
199
|
+
});
|
|
174
200
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
const tx = await this.getPendingTxByHash(hash);
|
|
178
|
-
if (tx) {
|
|
179
|
-
const nullifiers = tx.data.getNonEmptyNullifiers();
|
|
180
|
-
nullifiers.forEach(nullifier => minedNullifiers.add(nullifier.toString()));
|
|
181
|
-
minedFeePayers.add(tx.data.feePayer.toString());
|
|
182
|
-
pendingTxSize -= tx.getSize();
|
|
183
|
-
await this.removePendingTxIndices(tx, key);
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
await this.#pendingTxSize.set(pendingTxSize);
|
|
201
|
+
await this.#evictionManager.evictAfterNewBlock(blockHeader, uniqueMinedNullifiers, uniqueMinedFeePayers);
|
|
187
202
|
|
|
188
|
-
|
|
189
|
-
})
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
// until any that have been mined are marked as such.
|
|
193
|
-
// The non-evictable set is not considered when evicting transactions that are invalid after a block is mined.
|
|
194
|
-
this.#nonEvictableTxs.clear();
|
|
203
|
+
this.#metrics.transactionsRemoved(txHashes.map(hash => hash.toBigInt()));
|
|
204
|
+
} catch (err) {
|
|
205
|
+
this.#log.warn('Unexpected error when marking txs as mined', { err });
|
|
206
|
+
}
|
|
195
207
|
}
|
|
196
208
|
|
|
197
|
-
public async markMinedAsPending(txHashes: TxHash[]): Promise<void> {
|
|
209
|
+
public async markMinedAsPending(txHashes: TxHash[], latestBlock: BlockNumber): Promise<void> {
|
|
198
210
|
if (txHashes.length === 0) {
|
|
199
211
|
return Promise.resolve();
|
|
200
212
|
}
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
213
|
+
try {
|
|
214
|
+
await this.#store.transactionAsync(async () => {
|
|
215
|
+
for (const hash of txHashes) {
|
|
216
|
+
const key = hash.toString();
|
|
217
|
+
await this.#minedTxHashToBlock.delete(key);
|
|
218
|
+
|
|
219
|
+
// Rehydrate the tx in the in-memory pending txs mapping
|
|
220
|
+
const tx = await this.getPendingTxByHash(hash);
|
|
221
|
+
if (tx) {
|
|
222
|
+
await this.addPendingTxIndicesInDbTx(tx, key);
|
|
223
|
+
}
|
|
212
224
|
}
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
await this.#pendingTxSize.set(pendingTxSize);
|
|
216
|
-
});
|
|
225
|
+
});
|
|
217
226
|
|
|
218
|
-
|
|
219
|
-
|
|
227
|
+
await this.#evictionManager.evictAfterChainPrune(latestBlock);
|
|
228
|
+
} catch (err) {
|
|
229
|
+
this.#log.warn('Unexpected error when marking mined txs as pending', { err });
|
|
230
|
+
}
|
|
220
231
|
}
|
|
221
232
|
|
|
222
233
|
public async getPendingTxHashes(): Promise<TxHash[]> {
|
|
@@ -224,38 +235,6 @@ export class AztecKVTxPool extends (EventEmitter as new () => TypedEventEmitter<
|
|
|
224
235
|
return vals.map(TxHash.fromString);
|
|
225
236
|
}
|
|
226
237
|
|
|
227
|
-
public async getMinedTxHashes(): Promise<[TxHash, BlockNumber][]> {
|
|
228
|
-
const vals = await toArray(this.#minedTxHashToBlock.entriesAsync());
|
|
229
|
-
return vals.map(([txHash, blockNumber]) => [TxHash.fromString(txHash), blockNumber]);
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
public async getPendingTxCount(): Promise<number> {
|
|
233
|
-
return (await this.#pendingTxHashToHeaderHash.sizeAsync()) ?? 0;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
public async getMinedTxCount(): Promise<number> {
|
|
237
|
-
return (await this.#minedTxHashToBlock.sizeAsync()) ?? 0;
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
public async getTxStatus(txHash: TxHash): Promise<'pending' | 'mined' | 'deleted' | undefined> {
|
|
241
|
-
const key = txHash.toString();
|
|
242
|
-
const [isMined, isKnown, isDeleted] = await Promise.all([
|
|
243
|
-
this.#minedTxHashToBlock.hasAsync(key),
|
|
244
|
-
this.#txs.hasAsync(key),
|
|
245
|
-
this.#deletedMinedTxHashes.hasAsync(key),
|
|
246
|
-
]);
|
|
247
|
-
|
|
248
|
-
if (isDeleted) {
|
|
249
|
-
return 'deleted';
|
|
250
|
-
} else if (isMined) {
|
|
251
|
-
return 'mined';
|
|
252
|
-
} else if (isKnown) {
|
|
253
|
-
return 'pending';
|
|
254
|
-
} else {
|
|
255
|
-
return undefined;
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
|
|
259
238
|
/**
|
|
260
239
|
* Checks if a transaction exists in the pool and returns it.
|
|
261
240
|
* @param txHash - The generated tx hash.
|
|
@@ -293,41 +272,50 @@ export class AztecKVTxPool extends (EventEmitter as new () => TypedEventEmitter<
|
|
|
293
272
|
/**
|
|
294
273
|
* Adds a list of transactions to the pool. Duplicates are ignored.
|
|
295
274
|
* @param txs - An array of txs to be added to the pool.
|
|
296
|
-
* @returns
|
|
275
|
+
* @returns count of added transactions
|
|
297
276
|
*/
|
|
298
277
|
public async addTxs(txs: Tx[], opts: { source?: string } = {}): Promise<number> {
|
|
278
|
+
if (txs.length === 0) {
|
|
279
|
+
return Promise.resolve(0);
|
|
280
|
+
}
|
|
281
|
+
|
|
299
282
|
const addedTxs: Tx[] = [];
|
|
300
283
|
const hashesAndStats = txs.map(tx => ({ txHash: tx.getTxHash(), txStats: tx.getStats() }));
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
this.#log.verbose(`Adding tx ${txHash.toString()} to pool`, {
|
|
313
|
-
eventName: 'tx-added-to-pool',
|
|
314
|
-
...txStats,
|
|
315
|
-
} satisfies TxAddedToPoolStats);
|
|
316
|
-
|
|
317
|
-
await this.#txs.set(key, tx.toBuffer());
|
|
318
|
-
addedTxs.push(tx as Tx);
|
|
284
|
+
try {
|
|
285
|
+
await this.#store.transactionAsync(async () => {
|
|
286
|
+
await Promise.all(
|
|
287
|
+
txs.map(async (tx, i) => {
|
|
288
|
+
const { txHash, txStats } = hashesAndStats[i];
|
|
289
|
+
const key = txHash.toString();
|
|
290
|
+
if (await this.#txs.hasAsync(key)) {
|
|
291
|
+
this.#log.debug(`Tx ${txHash.toString()} already exists in the pool`);
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
319
294
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
295
|
+
this.#log.verbose(`Adding tx ${txHash.toString()} to pool`, {
|
|
296
|
+
eventName: 'tx-added-to-pool',
|
|
297
|
+
...txStats,
|
|
298
|
+
} satisfies TxAddedToPoolStats);
|
|
299
|
+
|
|
300
|
+
await this.#txs.set(key, tx.toBuffer());
|
|
301
|
+
addedTxs.push(tx as Tx);
|
|
302
|
+
await this.#pendingTxHashToHistoricalBlockHeaderHash.set(
|
|
303
|
+
key,
|
|
304
|
+
(await tx.data.constants.anchorBlockHeader.hash()).toString(),
|
|
305
|
+
);
|
|
306
|
+
|
|
307
|
+
if (!(await this.#minedTxHashToBlock.hasAsync(key))) {
|
|
308
|
+
await this.addPendingTxIndicesInDbTx(tx, key);
|
|
309
|
+
this.#metrics.recordSize(tx);
|
|
310
|
+
}
|
|
311
|
+
}),
|
|
312
|
+
);
|
|
313
|
+
});
|
|
327
314
|
|
|
328
|
-
await this.#
|
|
329
|
-
|
|
330
|
-
|
|
315
|
+
await this.#evictionManager.evictAfterNewTxs(addedTxs.map(({ txHash }) => txHash));
|
|
316
|
+
} catch (err) {
|
|
317
|
+
this.#log.warn('Unexpected error when adding txs', { err });
|
|
318
|
+
}
|
|
331
319
|
|
|
332
320
|
if (addedTxs.length > 0) {
|
|
333
321
|
this.#metrics.transactionsAdded(addedTxs);
|
|
@@ -342,55 +330,62 @@ export class AztecKVTxPool extends (EventEmitter as new () => TypedEventEmitter<
|
|
|
342
330
|
* @param txHashes - An array of tx hashes to be deleted from the tx pool.
|
|
343
331
|
* @returns Empty promise.
|
|
344
332
|
*/
|
|
345
|
-
public deleteTxs(txHashes: TxHash[], opts
|
|
333
|
+
public deleteTxs(txHashes: TxHash[], opts?: { permanently?: boolean }): Promise<void> {
|
|
346
334
|
if (txHashes.length === 0) {
|
|
347
335
|
return Promise.resolve();
|
|
348
336
|
}
|
|
337
|
+
|
|
349
338
|
const deletedTxs: Tx[] = [];
|
|
350
339
|
const poolDbTx = this.#store.transactionAsync(async () => {
|
|
351
|
-
let pendingTxSize = (await this.#pendingTxSize.getAsync()) ?? 0;
|
|
352
340
|
for (const hash of txHashes) {
|
|
353
341
|
const key = hash.toString();
|
|
354
342
|
const tx = await this.getTxByHash(hash);
|
|
343
|
+
if (!tx) {
|
|
344
|
+
this.#log.trace(`Skipping deletion of missing tx ${key} from pool`);
|
|
345
|
+
continue;
|
|
346
|
+
}
|
|
355
347
|
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
await this.#txs.delete(key);
|
|
365
|
-
} else {
|
|
366
|
-
// Soft-delete mined transactions: remove from mined set but keep in storage
|
|
367
|
-
this.#log.trace(`Soft-deleting mined tx ${key} from pool`);
|
|
368
|
-
await this.#deletedMinedTxHashes.set(key, minedBlockNumber);
|
|
369
|
-
await this.#blockToDeletedMinedTxHash.set(minedBlockNumber, key);
|
|
370
|
-
}
|
|
371
|
-
} else {
|
|
372
|
-
// Permanently delete pending transactions
|
|
373
|
-
this.#log.trace(`Deleting pending tx ${key} from pool`);
|
|
374
|
-
pendingTxSize -= tx.getSize();
|
|
375
|
-
await this.removePendingTxIndices(tx, key);
|
|
376
|
-
await this.#txs.delete(key);
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
if (!opts.eviction && this.#archivedTxLimit) {
|
|
348
|
+
const minedBlockNumber = await this.#minedTxHashToBlock.getAsync(key);
|
|
349
|
+
const txIsPending = minedBlockNumber === undefined;
|
|
350
|
+
if (txIsPending) {
|
|
351
|
+
await this.deletePendingTx(tx, key);
|
|
352
|
+
} else {
|
|
353
|
+
await this.deleteMinedTx(key, minedBlockNumber!, opts?.permanently ?? false);
|
|
354
|
+
const shouldArchiveTx = this.#archivedTxLimit && !opts?.permanently;
|
|
355
|
+
if (shouldArchiveTx) {
|
|
380
356
|
deletedTxs.push(tx);
|
|
381
357
|
}
|
|
382
|
-
} else {
|
|
383
|
-
this.#log.trace(`Skipping deletion of missing tx ${key} from pool`);
|
|
384
358
|
}
|
|
385
359
|
}
|
|
386
|
-
|
|
387
|
-
await this.#pendingTxSize.set(pendingTxSize);
|
|
388
360
|
});
|
|
389
|
-
this.#metrics.transactionsRemoved(txHashes);
|
|
361
|
+
this.#metrics.transactionsRemoved(txHashes.map(hash => hash.toBigInt()));
|
|
390
362
|
this.#log.debug(`Deleted ${txHashes.length} txs from pool`, { txHashes });
|
|
363
|
+
|
|
391
364
|
return this.#archivedTxLimit ? poolDbTx.then(() => this.archiveTxs(deletedTxs)) : poolDbTx;
|
|
392
365
|
}
|
|
393
366
|
|
|
367
|
+
private async deleteMinedTx(txHash: `0x${string}`, minedBlockNumber: BlockNumber, permanently: boolean) {
|
|
368
|
+
await this.#minedTxHashToBlock.delete(txHash);
|
|
369
|
+
if (permanently) {
|
|
370
|
+
this.#log.trace(`Deleting mined tx ${txHash} from pool`);
|
|
371
|
+
await this.#txs.delete(txHash);
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
// Soft-delete mined transactions: remove from mined set but keep in storage
|
|
376
|
+
this.#log.trace(`Soft-deleting mined tx ${txHash} from pool`);
|
|
377
|
+
await this.#deletedMinedTxHashes.set(txHash, minedBlockNumber);
|
|
378
|
+
await this.#blockToDeletedMinedTxHash.set(minedBlockNumber, txHash);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
private async deletePendingTx(tx: Tx, txHash: `0x${string}`) {
|
|
382
|
+
// We always permanently delete pending transactions
|
|
383
|
+
this.#log.trace(`Deleting pending tx ${txHash} from pool`);
|
|
384
|
+
await this.removePendingTxIndices(tx, txHash);
|
|
385
|
+
await this.#txs.delete(txHash);
|
|
386
|
+
await this.#pendingTxHashToHistoricalBlockHeaderHash.delete(txHash);
|
|
387
|
+
}
|
|
388
|
+
|
|
394
389
|
/**
|
|
395
390
|
* Gets all the transactions stored in the pool.
|
|
396
391
|
* @returns Array of tx objects in the order they were added to the pool.
|
|
@@ -409,30 +404,101 @@ export class AztecKVTxPool extends (EventEmitter as new () => TypedEventEmitter<
|
|
|
409
404
|
return vals.map(x => TxHash.fromString(x));
|
|
410
405
|
}
|
|
411
406
|
|
|
412
|
-
public
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
407
|
+
public async getPendingTxInfos(): Promise<PendingTxInfo[]> {
|
|
408
|
+
const vals = await toArray(this.#pendingTxPriorityToHash.valuesAsync());
|
|
409
|
+
const results = await Promise.all(vals.map(val => this.getPendingTxInfo(TxHash.fromString(val))));
|
|
410
|
+
return results.filter((info): info is PendingTxInfo => info !== undefined);
|
|
411
|
+
}
|
|
416
412
|
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
413
|
+
private async getPendingTxInfo(txHash: TxHash): Promise<PendingTxInfo | undefined> {
|
|
414
|
+
let historicalBlockHash = await this.#pendingTxHashToHistoricalBlockHeaderHash.getAsync(txHash.toString());
|
|
415
|
+
// Not all tx might have this index created.
|
|
416
|
+
if (!historicalBlockHash) {
|
|
417
|
+
const tx = await this.getPendingTxByHash(txHash);
|
|
418
|
+
if (!tx) {
|
|
419
|
+
this.#log.warn(`PendingTxInfo:tx ${txHash} not found`);
|
|
420
|
+
return undefined;
|
|
421
421
|
}
|
|
422
|
+
|
|
423
|
+
historicalBlockHash = (await tx.data.constants.anchorBlockHeader.hash()).toString();
|
|
424
|
+
await this.#pendingTxHashToHistoricalBlockHeaderHash.set(txHash.toString(), historicalBlockHash);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
return {
|
|
428
|
+
txHash,
|
|
429
|
+
blockHash: Fr.fromString(historicalBlockHash),
|
|
430
|
+
isEvictable: !this.#nonEvictableTxs.has(txHash.toString()),
|
|
431
|
+
};
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
public async getPendingTxsReferencingBlocks(blockHashes: Fr[]): Promise<TxBlockReference[]> {
|
|
435
|
+
const result: TxBlockReference[] = [];
|
|
436
|
+
for (const blockHash of blockHashes) {
|
|
437
|
+
const chunk = await toArray(this.#historicalHeaderToTxHash.getValuesAsync(blockHash.toString()));
|
|
438
|
+
result.push(
|
|
439
|
+
...chunk.map(txHash => ({
|
|
440
|
+
txHash: TxHash.fromString(txHash),
|
|
441
|
+
blockHash,
|
|
442
|
+
isEvictable: !this.#nonEvictableTxs.has(txHash),
|
|
443
|
+
})),
|
|
444
|
+
);
|
|
422
445
|
}
|
|
423
446
|
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
447
|
+
return result;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
public async getPendingTxsWithFeePayer(feePayers: AztecAddress[]): Promise<PendingTxInfo[]> {
|
|
451
|
+
const result: PendingTxInfo[] = [];
|
|
452
|
+
for (const feePayer of feePayers) {
|
|
453
|
+
const chunk = await toArray(this.#feePayerToTxHash.getValuesAsync(feePayer.toString()));
|
|
454
|
+
const infos = await Promise.all(chunk.map(txHash => this.getPendingTxInfo(TxHash.fromString(txHash))));
|
|
455
|
+
result.push(...infos.filter((info): info is PendingTxInfo => info !== undefined));
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
return result;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
public async getMinedTxHashes(): Promise<[TxHash, BlockNumber][]> {
|
|
462
|
+
const vals = await toArray(this.#minedTxHashToBlock.entriesAsync());
|
|
463
|
+
return vals.map(([txHash, blockNumber]) => [TxHash.fromString(txHash), blockNumber]);
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
public async getPendingTxCount(): Promise<number> {
|
|
467
|
+
return (await this.#pendingTxPriorityToHash.sizeAsync()) ?? 0;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
public async getMinedTxCount(): Promise<number> {
|
|
471
|
+
return (await this.#minedTxHashToBlock.sizeAsync()) ?? 0;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
public async getTxStatus(txHash: TxHash): Promise<'pending' | 'mined' | 'deleted' | undefined> {
|
|
475
|
+
const key = txHash.toString();
|
|
476
|
+
const [isMined, isKnown, isDeleted] = await Promise.all([
|
|
477
|
+
this.#minedTxHashToBlock.hasAsync(key),
|
|
478
|
+
this.#txs.hasAsync(key),
|
|
479
|
+
this.#deletedMinedTxHashes.hasAsync(key),
|
|
480
|
+
]);
|
|
481
|
+
|
|
482
|
+
if (isDeleted) {
|
|
483
|
+
return 'deleted';
|
|
484
|
+
} else if (isMined) {
|
|
485
|
+
return 'mined';
|
|
486
|
+
} else if (isKnown) {
|
|
487
|
+
return 'pending';
|
|
488
|
+
} else {
|
|
489
|
+
return undefined;
|
|
428
490
|
}
|
|
491
|
+
}
|
|
429
492
|
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
493
|
+
public updateConfig(cfg: TxPoolOptions): void {
|
|
494
|
+
if (typeof cfg.archivedTxLimit === 'number') {
|
|
495
|
+
assert(cfg.archivedTxLimit >= 0, 'archivedTxLimit must be greater or equal to 0');
|
|
496
|
+
this.#archivedTxLimit = cfg.archivedTxLimit;
|
|
433
497
|
}
|
|
434
498
|
|
|
435
|
-
|
|
499
|
+
if (this.#evictionManager) {
|
|
500
|
+
this.#evictionManager.updateConfig(cfg);
|
|
501
|
+
}
|
|
436
502
|
}
|
|
437
503
|
|
|
438
504
|
public markTxsAsNonEvictable(txHashes: TxHash[]): Promise<void> {
|
|
@@ -440,6 +506,15 @@ export class AztecKVTxPool extends (EventEmitter as new () => TypedEventEmitter<
|
|
|
440
506
|
return Promise.resolve();
|
|
441
507
|
}
|
|
442
508
|
|
|
509
|
+
public clearNonEvictableTxs(): Promise<void> {
|
|
510
|
+
// Clear the non-evictable set after completing the DB updates above.
|
|
511
|
+
// This ensures pinned (non-evictable) txs are protected while we mark mined txs,
|
|
512
|
+
// but they won't remain pinned indefinitely across blocks. Note that eviction rules
|
|
513
|
+
// (including post-mining invalidation) respect the non-evictable flag while it is set.
|
|
514
|
+
this.#nonEvictableTxs.clear();
|
|
515
|
+
return Promise.resolve();
|
|
516
|
+
}
|
|
517
|
+
|
|
443
518
|
/**
|
|
444
519
|
* Permanently deletes deleted mined transactions from blocks up to and including the specified block number.
|
|
445
520
|
* @param blockNumber - Block number threshold. Deleted mined txs from this block or earlier will be permanently deleted.
|
|
@@ -447,10 +522,10 @@ export class AztecKVTxPool extends (EventEmitter as new () => TypedEventEmitter<
|
|
|
447
522
|
*/
|
|
448
523
|
public async cleanupDeletedMinedTxs(blockNumber: BlockNumber): Promise<number> {
|
|
449
524
|
let deletedCount = 0;
|
|
450
|
-
const txHashesToDelete: string[] = [];
|
|
451
|
-
const blocksToDelete: BlockNumber[] = [];
|
|
452
|
-
|
|
453
525
|
await this.#store.transactionAsync(async () => {
|
|
526
|
+
const txHashesToDelete: string[] = [];
|
|
527
|
+
const blocksToDelete: BlockNumber[] = [];
|
|
528
|
+
|
|
454
529
|
// Iterate through all entries and check block numbers
|
|
455
530
|
for await (const [block, txHash] of this.#blockToDeletedMinedTxHash.entriesAsync()) {
|
|
456
531
|
if (block <= blockNumber) {
|
|
@@ -464,6 +539,7 @@ export class AztecKVTxPool extends (EventEmitter as new () => TypedEventEmitter<
|
|
|
464
539
|
deletedCount++;
|
|
465
540
|
}
|
|
466
541
|
}
|
|
542
|
+
this.#metrics.transactionsRemoved(txHashesToDelete);
|
|
467
543
|
|
|
468
544
|
// Clean up block-to-hash mapping - delete all values for each block
|
|
469
545
|
for (const block of blocksToDelete) {
|
|
@@ -480,15 +556,6 @@ export class AztecKVTxPool extends (EventEmitter as new () => TypedEventEmitter<
|
|
|
480
556
|
return deletedCount;
|
|
481
557
|
}
|
|
482
558
|
|
|
483
|
-
/**
|
|
484
|
-
* Creates a GasTxValidator instance.
|
|
485
|
-
* @param db - DB for the validator to use
|
|
486
|
-
* @returns A GasTxValidator instance
|
|
487
|
-
*/
|
|
488
|
-
protected createGasTxValidator(db: MerkleTreeReadOperations): GasTxValidator {
|
|
489
|
-
return new GasTxValidator(new DatabasePublicStateSource(db), ProtocolContractAddress.FeeJuice, GasFees.empty());
|
|
490
|
-
}
|
|
491
|
-
|
|
492
559
|
/**
|
|
493
560
|
* Creates an ArchiveCache instance.
|
|
494
561
|
* @param db - DB for the cache to use
|
|
@@ -505,20 +572,12 @@ export class AztecKVTxPool extends (EventEmitter as new () => TypedEventEmitter<
|
|
|
505
572
|
* @returns The transaction, if found, 'undefined' otherwise.
|
|
506
573
|
*/
|
|
507
574
|
private async getPendingTxByHash(txHash: TxHash | string): Promise<Tx | undefined> {
|
|
508
|
-
let key;
|
|
509
575
|
if (typeof txHash === 'string') {
|
|
510
|
-
key = txHash;
|
|
511
576
|
txHash = TxHash.fromString(txHash);
|
|
512
|
-
} else {
|
|
513
|
-
key = txHash.toString();
|
|
514
577
|
}
|
|
515
578
|
|
|
516
|
-
if (this.#pendingTxs.has(key)) {
|
|
517
|
-
return this.#pendingTxs.get(key);
|
|
518
|
-
}
|
|
519
579
|
const tx = await this.getTxByHash(txHash);
|
|
520
580
|
if (tx) {
|
|
521
|
-
this.#pendingTxs.set(key, tx);
|
|
522
581
|
return tx;
|
|
523
582
|
}
|
|
524
583
|
return undefined;
|
|
@@ -526,6 +585,7 @@ export class AztecKVTxPool extends (EventEmitter as new () => TypedEventEmitter<
|
|
|
526
585
|
|
|
527
586
|
/**
|
|
528
587
|
* Archives a list of txs for future reference. The number of archived txs is limited by the specified archivedTxLimit.
|
|
588
|
+
* Note: Pending txs should not be archived, only finalized txs
|
|
529
589
|
* @param txs - The list of transactions to archive.
|
|
530
590
|
* @returns Empty promise.
|
|
531
591
|
*/
|
|
@@ -533,6 +593,10 @@ export class AztecKVTxPool extends (EventEmitter as new () => TypedEventEmitter<
|
|
|
533
593
|
if (txs.length === 0) {
|
|
534
594
|
return;
|
|
535
595
|
}
|
|
596
|
+
if (this.#archivedTxLimit === 0) {
|
|
597
|
+
return;
|
|
598
|
+
}
|
|
599
|
+
|
|
536
600
|
try {
|
|
537
601
|
const txHashes = await Promise.all(txs.map(tx => tx.getTxHash()));
|
|
538
602
|
await this.#archive.transactionAsync(async () => {
|
|
@@ -572,183 +636,56 @@ export class AztecKVTxPool extends (EventEmitter as new () => TypedEventEmitter<
|
|
|
572
636
|
}
|
|
573
637
|
}
|
|
574
638
|
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
* @returns The total number of txs evicted from the pool and the number of new txs that were evicted.
|
|
581
|
-
*/
|
|
582
|
-
private async evictLowPriorityTxs(
|
|
583
|
-
newTxHashes: TxHash[],
|
|
584
|
-
): Promise<{ numLowPriorityTxsEvicted: number; numNewTxsEvicted: number }> {
|
|
585
|
-
if (this.#maxTxPoolSize === undefined || this.#maxTxPoolSize === 0) {
|
|
586
|
-
return { numLowPriorityTxsEvicted: 0, numNewTxsEvicted: 0 };
|
|
587
|
-
}
|
|
588
|
-
|
|
589
|
-
let numNewTxsEvicted = 0;
|
|
590
|
-
const txsToEvict: TxHash[] = [];
|
|
591
|
-
|
|
592
|
-
let pendingTxsSize = (await this.#pendingTxSize.getAsync()) ?? 0;
|
|
593
|
-
if (pendingTxsSize > this.#maxTxPoolSize * this.txPoolOverflowFactor) {
|
|
594
|
-
for await (const txHash of this.#pendingTxPriorityToHash.valuesAsync()) {
|
|
595
|
-
if (this.#nonEvictableTxs.has(txHash.toString())) {
|
|
596
|
-
continue;
|
|
597
|
-
}
|
|
598
|
-
const txSize =
|
|
599
|
-
(await this.#pendingTxHashToSize.getAsync(txHash.toString())) ??
|
|
600
|
-
(await this.getPendingTxByHash(txHash))?.getSize();
|
|
601
|
-
|
|
602
|
-
this.#log.verbose(`Evicting tx ${txHash} from pool due to low priority to satisfy max tx size limit`, {
|
|
603
|
-
txHash,
|
|
604
|
-
txSize,
|
|
605
|
-
});
|
|
606
|
-
|
|
607
|
-
txsToEvict.push(TxHash.fromString(txHash));
|
|
608
|
-
|
|
609
|
-
if (txSize) {
|
|
610
|
-
pendingTxsSize -= txSize;
|
|
611
|
-
if (pendingTxsSize <= this.#maxTxPoolSize) {
|
|
612
|
-
break;
|
|
613
|
-
}
|
|
614
|
-
}
|
|
615
|
-
}
|
|
616
|
-
numNewTxsEvicted += newTxHashes.filter(txHash => txsToEvict.includes(txHash)).length;
|
|
617
|
-
}
|
|
618
|
-
|
|
619
|
-
if (txsToEvict.length > 0) {
|
|
620
|
-
await this.deleteTxs(txsToEvict, { eviction: true });
|
|
621
|
-
}
|
|
622
|
-
return {
|
|
623
|
-
numLowPriorityTxsEvicted: txsToEvict.length,
|
|
624
|
-
numNewTxsEvicted,
|
|
625
|
-
};
|
|
639
|
+
// Assumes being called within a DB transaction
|
|
640
|
+
private async addPendingTxIndicesInDbTx(tx: Tx, txHash: string): Promise<void> {
|
|
641
|
+
await this.#pendingTxPriorityToHash.set(getPendingTxPriority(tx), txHash);
|
|
642
|
+
await this.#historicalHeaderToTxHash.set((await tx.data.constants.anchorBlockHeader.hash()).toString(), txHash);
|
|
643
|
+
await this.#feePayerToTxHash.set(tx.data.feePayer.toString(), txHash);
|
|
626
644
|
}
|
|
627
645
|
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
* - txs with an expiration timestamp lower than that of the mined block
|
|
634
|
-
*
|
|
635
|
-
* @param minedTxHashes - The tx hashes of the txs mined in the block.
|
|
636
|
-
* @param blockHeader - The header of the mined block.
|
|
637
|
-
* @returns The total number of txs evicted from the pool.
|
|
638
|
-
*/
|
|
639
|
-
private async evictInvalidTxsAfterMining(
|
|
640
|
-
minedTxHashes: TxHash[],
|
|
641
|
-
blockHeader: BlockHeader,
|
|
642
|
-
minedNullifiers: Set<string>,
|
|
643
|
-
minedFeePayers: Set<string>,
|
|
644
|
-
): Promise<number> {
|
|
645
|
-
if (minedTxHashes.length === 0) {
|
|
646
|
-
return 0;
|
|
647
|
-
}
|
|
648
|
-
|
|
649
|
-
const { blockNumber, timestamp } = blockHeader.globalVariables;
|
|
650
|
-
|
|
651
|
-
// Wait for world state to be synced to at least the mined block number
|
|
652
|
-
await this.#worldStateSynchronizer.syncImmediate(blockNumber);
|
|
653
|
-
|
|
654
|
-
const db = this.#worldStateSynchronizer.getCommitted();
|
|
655
|
-
const gasTxValidator = this.createGasTxValidator(db);
|
|
656
|
-
|
|
657
|
-
const txsToEvict: TxHash[] = [];
|
|
658
|
-
for await (const txHash of this.#pendingTxPriorityToHash.valuesAsync()) {
|
|
659
|
-
const tx = await this.getPendingTxByHash(txHash);
|
|
660
|
-
if (!tx) {
|
|
661
|
-
continue;
|
|
662
|
-
}
|
|
663
|
-
|
|
664
|
-
// Evict pending txs that share nullifiers with mined txs
|
|
665
|
-
const txNullifiers = tx.data.getNonEmptyNullifiers();
|
|
666
|
-
if (txNullifiers.some(nullifier => minedNullifiers.has(nullifier.toString()))) {
|
|
667
|
-
this.#log.verbose(`Evicting tx ${txHash} from pool due to a duplicate nullifier with a mined tx`);
|
|
668
|
-
txsToEvict.push(TxHash.fromString(txHash));
|
|
669
|
-
continue;
|
|
670
|
-
}
|
|
671
|
-
|
|
672
|
-
// Evict pending txs with an insufficient fee payer balance
|
|
673
|
-
if (
|
|
674
|
-
minedFeePayers.has(tx.data.feePayer.toString()) &&
|
|
675
|
-
(await gasTxValidator.validateTxFee(tx)).result === 'invalid'
|
|
676
|
-
) {
|
|
677
|
-
this.#log.verbose(`Evicting tx ${txHash} from pool due to an insufficient fee payer balance`);
|
|
678
|
-
txsToEvict.push(TxHash.fromString(txHash));
|
|
679
|
-
continue;
|
|
680
|
-
}
|
|
646
|
+
private async addPendingTxIndices(tx: Tx, txHash: string): Promise<void> {
|
|
647
|
+
return await this.#store.transactionAsync(async () => {
|
|
648
|
+
await this.addPendingTxIndicesInDbTx(tx, txHash);
|
|
649
|
+
});
|
|
650
|
+
}
|
|
681
651
|
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
}
|
|
652
|
+
// Assumes being called within a DB transaction
|
|
653
|
+
private async removePendingTxIndicesInDbTx(tx: Tx, txHash: string): Promise<void> {
|
|
654
|
+
await this.#pendingTxPriorityToHash.deleteValue(getPendingTxPriority(tx), txHash);
|
|
655
|
+
await this.#historicalHeaderToTxHash.deleteValue(
|
|
656
|
+
(await tx.data.constants.anchorBlockHeader.hash()).toString(),
|
|
657
|
+
txHash,
|
|
658
|
+
);
|
|
659
|
+
await this.#feePayerToTxHash.deleteValue(tx.data.feePayer.toString(), txHash);
|
|
660
|
+
}
|
|
692
661
|
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
662
|
+
private async removePendingTxIndices(tx: Tx, txHash: string): Promise<void> {
|
|
663
|
+
return await this.#store.transactionAsync(async () => {
|
|
664
|
+
await this.removePendingTxIndicesInDbTx(tx, txHash);
|
|
665
|
+
});
|
|
697
666
|
}
|
|
698
667
|
|
|
699
668
|
/**
|
|
700
|
-
*
|
|
701
|
-
*
|
|
702
|
-
* @param txHashes - The tx hashes of the txs that were moved from mined to pending.
|
|
703
|
-
* @returns The total number of txs evicted from the pool.
|
|
669
|
+
* Returns up to `limit` lowest-priority evictable pending tx hashes without hydrating transactions.
|
|
670
|
+
* Iterates the priority index in ascending order and skips non-evictable txs.
|
|
704
671
|
*/
|
|
705
|
-
|
|
706
|
-
if (txHashes.length === 0) {
|
|
707
|
-
return 0;
|
|
708
|
-
}
|
|
709
|
-
|
|
710
|
-
await this.#worldStateSynchronizer.syncImmediate();
|
|
711
|
-
const db = this.#worldStateSynchronizer.getCommitted();
|
|
712
|
-
const archiveCache = this.createArchiveCache(db);
|
|
713
|
-
const gasTxValidator = this.createGasTxValidator(db);
|
|
714
|
-
|
|
672
|
+
public async getLowestPriorityEvictable(limit: number): Promise<TxHash[]> {
|
|
715
673
|
const txsToEvict: TxHash[] = [];
|
|
674
|
+
if (limit <= 0) {
|
|
675
|
+
return txsToEvict;
|
|
676
|
+
}
|
|
716
677
|
|
|
717
|
-
for await (const
|
|
718
|
-
|
|
719
|
-
if (!tx) {
|
|
720
|
-
continue;
|
|
721
|
-
}
|
|
722
|
-
|
|
723
|
-
const [index] = await archiveCache.getArchiveIndices([Fr.fromString(headerHash)]);
|
|
724
|
-
if (index === undefined) {
|
|
725
|
-
this.#log.verbose(`Evicting tx ${txHash} from pool due to an invalid archive root`);
|
|
726
|
-
txsToEvict.push(TxHash.fromString(txHash));
|
|
678
|
+
for await (const txHashStr of this.#pendingTxPriorityToHash.valuesAsync()) {
|
|
679
|
+
if (this.#nonEvictableTxs.has(txHashStr)) {
|
|
727
680
|
continue;
|
|
728
681
|
}
|
|
729
682
|
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
683
|
+
txsToEvict.push(TxHash.fromString(txHashStr));
|
|
684
|
+
if (txsToEvict.length >= limit) {
|
|
685
|
+
break;
|
|
733
686
|
}
|
|
734
687
|
}
|
|
735
688
|
|
|
736
|
-
|
|
737
|
-
await this.deleteTxs(txsToEvict, { eviction: true });
|
|
738
|
-
}
|
|
739
|
-
return txsToEvict.length;
|
|
740
|
-
}
|
|
741
|
-
|
|
742
|
-
private async addPendingTxIndices(tx: Tx, txHash: string): Promise<void> {
|
|
743
|
-
await this.#pendingTxPriorityToHash.set(getPendingTxPriority(tx), txHash);
|
|
744
|
-
await this.#pendingTxHashToSize.set(txHash, tx.getSize());
|
|
745
|
-
await this.#pendingTxHashToHeaderHash.set(txHash, (await tx.data.constants.anchorBlockHeader.hash()).toString());
|
|
746
|
-
}
|
|
747
|
-
|
|
748
|
-
private async removePendingTxIndices(tx: Tx, txHash: string): Promise<void> {
|
|
749
|
-
await this.#pendingTxPriorityToHash.deleteValue(getPendingTxPriority(tx), txHash);
|
|
750
|
-
await this.#pendingTxHashToSize.delete(txHash);
|
|
751
|
-
await this.#pendingTxHashToHeaderHash.delete(txHash);
|
|
752
|
-
this.#pendingTxs.delete(txHash);
|
|
689
|
+
return txsToEvict;
|
|
753
690
|
}
|
|
754
691
|
}
|