@aztec/p2p 0.84.0 → 0.85.0
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/bootstrap/bootstrap.js +1 -1
- package/dest/client/factory.d.ts.map +1 -1
- package/dest/client/factory.js +5 -2
- package/dest/client/p2p_client.d.ts +2 -0
- package/dest/client/p2p_client.d.ts.map +1 -1
- package/dest/client/p2p_client.js +4 -1
- package/dest/config.d.ts +15 -3
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +12 -1
- package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts +56 -2
- 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 +229 -16
- package/dest/msg_validators/tx_validator/archive_cache.d.ts +14 -0
- package/dest/msg_validators/tx_validator/archive_cache.d.ts.map +1 -0
- package/dest/msg_validators/tx_validator/archive_cache.js +22 -0
- package/dest/msg_validators/tx_validator/block_header_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/block_header_validator.js +2 -2
- package/dest/msg_validators/tx_validator/data_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/data_validator.js +8 -8
- package/dest/msg_validators/tx_validator/double_spend_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/double_spend_validator.js +3 -3
- package/dest/msg_validators/tx_validator/gas_validator.d.ts +2 -1
- package/dest/msg_validators/tx_validator/gas_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/gas_validator.js +32 -5
- package/dest/msg_validators/tx_validator/index.d.ts +1 -0
- 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/metadata_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/metadata_validator.js +4 -4
- package/dest/msg_validators/tx_validator/phases_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/phases_validator.js +10 -2
- package/dest/msg_validators/tx_validator/tx_proof_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/tx_proof_validator.js +2 -2
- package/dest/services/discv5/discV5_service.d.ts +1 -2
- package/dest/services/discv5/discV5_service.d.ts.map +1 -1
- package/dest/services/discv5/discV5_service.js +6 -8
- package/dest/services/dummy_service.d.ts +2 -1
- package/dest/services/dummy_service.d.ts.map +1 -1
- package/dest/services/dummy_service.js +1 -1
- package/dest/services/libp2p/libp2p_service.d.ts +14 -8
- package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
- package/dest/services/libp2p/libp2p_service.js +2 -2
- package/dest/services/peer-manager/peer_manager.d.ts.map +1 -1
- package/dest/services/peer-manager/peer_manager.js +0 -1
- package/dest/services/service.d.ts +1 -1
- package/dest/services/service.d.ts.map +1 -1
- package/dest/testbench/p2p_client_testbench_worker.js +46 -16
- package/dest/testbench/parse_log_file.js +4 -4
- package/dest/testbench/testbench.js +1 -1
- package/dest/testbench/worker_client_manager.d.ts.map +1 -1
- package/dest/testbench/worker_client_manager.js +3 -2
- package/dest/util.d.ts +7 -3
- package/dest/util.d.ts.map +1 -1
- package/dest/util.js +44 -7
- package/package.json +12 -12
- package/src/bootstrap/bootstrap.ts +1 -1
- package/src/client/factory.ts +7 -2
- package/src/client/p2p_client.ts +6 -1
- package/src/config.ts +26 -2
- package/src/mem_pools/tx_pool/aztec_kv_tx_pool.ts +312 -27
- package/src/msg_validators/tx_validator/archive_cache.ts +28 -0
- package/src/msg_validators/tx_validator/block_header_validator.ts +2 -2
- package/src/msg_validators/tx_validator/data_validator.ts +19 -8
- package/src/msg_validators/tx_validator/double_spend_validator.ts +10 -3
- package/src/msg_validators/tx_validator/gas_validator.ts +36 -6
- package/src/msg_validators/tx_validator/index.ts +1 -0
- package/src/msg_validators/tx_validator/metadata_validator.ts +12 -4
- package/src/msg_validators/tx_validator/phases_validator.ts +6 -1
- package/src/msg_validators/tx_validator/tx_proof_validator.ts +2 -2
- package/src/services/discv5/discV5_service.ts +10 -8
- package/src/services/dummy_service.ts +2 -1
- package/src/services/libp2p/libp2p_service.ts +9 -9
- package/src/services/peer-manager/peer_manager.ts +1 -1
- package/src/services/service.ts +1 -1
- package/src/testbench/p2p_client_testbench_worker.ts +97 -16
- package/src/testbench/parse_log_file.ts +4 -4
- package/src/testbench/testbench.ts +1 -1
- package/src/testbench/worker_client_manager.ts +4 -2
- package/src/util.ts +57 -8
|
@@ -1,8 +1,14 @@
|
|
|
1
|
+
import { Fr } from '@aztec/foundation/fields';
|
|
1
2
|
import { toArray } from '@aztec/foundation/iterable';
|
|
2
3
|
import { createLogger } from '@aztec/foundation/log';
|
|
4
|
+
import { ProtocolContractAddress } from '@aztec/protocol-contracts';
|
|
5
|
+
import { GasFees } from '@aztec/stdlib/gas';
|
|
3
6
|
import { ClientIvcProof } from '@aztec/stdlib/proofs';
|
|
7
|
+
import { DatabasePublicStateSource } from '@aztec/stdlib/trees';
|
|
4
8
|
import { Tx, TxHash } from '@aztec/stdlib/tx';
|
|
5
9
|
import { getTelemetryClient } from '@aztec/telemetry-client';
|
|
10
|
+
import { ArchiveCache } from '../../msg_validators/tx_validator/archive_cache.js';
|
|
11
|
+
import { GasTxValidator } from '../../msg_validators/tx_validator/gas_validator.js';
|
|
6
12
|
import { PoolInstrumentation, PoolName } from '../instrumentation.js';
|
|
7
13
|
import { getPendingTxPriority } from './priority.js';
|
|
8
14
|
/**
|
|
@@ -10,12 +16,18 @@ import { getPendingTxPriority } from './priority.js';
|
|
|
10
16
|
*/ export class AztecKVTxPool {
|
|
11
17
|
#store;
|
|
12
18
|
/** Our tx pool, stored as a Map, with K: tx hash and V: the transaction. */ #txs;
|
|
19
|
+
/** The maximum cumulative tx size that the pending txs in the pool take up. */ #maxTxPoolSize;
|
|
13
20
|
/** Index from tx hash to the block number in which they were mined, filtered by mined txs. */ #minedTxHashToBlock;
|
|
14
21
|
/** Index from tx priority (stored as hex) to its tx hash, filtered by pending txs. */ #pendingTxPriorityToHash;
|
|
22
|
+
/** Index from tx hash to its tx size (in bytes), filtered by pending txs. */ #pendingTxHashToSize;
|
|
23
|
+
/** Index from tx hash to its header hash, filtered by pending txs. */ #pendingTxHashToHeaderHash;
|
|
24
|
+
/** The cumulative tx size in bytes that the pending txs in the pool take up. */ #pendingTxSize;
|
|
25
|
+
/** In-memory mapping of pending tx hashes to the hydrated pending tx in the pool. */ #pendingTxs;
|
|
15
26
|
/** KV store for archived txs. */ #archive;
|
|
16
27
|
/** Archived txs map for future lookup. */ #archivedTxs;
|
|
17
28
|
/** Indexes of the archived txs by insertion order. */ #archivedTxIndices;
|
|
18
29
|
/** Number of txs to archive. */ #archivedTxLimit;
|
|
30
|
+
/** The world state synchronizer used in the node. */ #worldStateSynchronizer;
|
|
19
31
|
#log;
|
|
20
32
|
#metrics;
|
|
21
33
|
/**
|
|
@@ -25,15 +37,21 @@ import { getPendingTxPriority } from './priority.js';
|
|
|
25
37
|
* @param telemetry - A telemetry client.
|
|
26
38
|
* @param archivedTxLimit - The number of txs to archive.
|
|
27
39
|
* @param log - A logger.
|
|
28
|
-
*/ constructor(store, archive, telemetry = getTelemetryClient(),
|
|
40
|
+
*/ constructor(store, archive, worldStateSynchronizer, telemetry = getTelemetryClient(), config = {}, log = createLogger('p2p:tx_pool')){
|
|
29
41
|
this.#txs = store.openMap('txs');
|
|
30
42
|
this.#minedTxHashToBlock = store.openMap('txHashToBlockMined');
|
|
31
43
|
this.#pendingTxPriorityToHash = store.openMultiMap('pendingTxFeeToHash');
|
|
44
|
+
this.#pendingTxHashToSize = store.openMap('pendingTxHashToSize');
|
|
45
|
+
this.#pendingTxHashToHeaderHash = store.openMap('pendingTxHashToHeaderHash');
|
|
46
|
+
this.#pendingTxSize = store.openSingleton('pendingTxSize');
|
|
47
|
+
this.#maxTxPoolSize = config.maxTxPoolSize;
|
|
48
|
+
this.#pendingTxs = new Map();
|
|
32
49
|
this.#archivedTxs = archive.openMap('archivedTxs');
|
|
33
50
|
this.#archivedTxIndices = archive.openMap('archivedTxIndices');
|
|
34
|
-
this.#archivedTxLimit = archivedTxLimit;
|
|
51
|
+
this.#archivedTxLimit = config.archivedTxLimit ?? 0;
|
|
35
52
|
this.#store = store;
|
|
36
53
|
this.#archive = archive;
|
|
54
|
+
this.#worldStateSynchronizer = worldStateSynchronizer;
|
|
37
55
|
this.#log = log;
|
|
38
56
|
this.#metrics = new PoolInstrumentation(telemetry, PoolName.TX_POOL, ()=>store.estimateSize());
|
|
39
57
|
}
|
|
@@ -42,19 +60,27 @@ import { getPendingTxPriority } from './priority.js';
|
|
|
42
60
|
return Promise.resolve();
|
|
43
61
|
}
|
|
44
62
|
let deletedPending = 0;
|
|
63
|
+
const minedNullifiers = new Set();
|
|
64
|
+
const minedFeePayers = new Set();
|
|
45
65
|
return this.#store.transactionAsync(async ()=>{
|
|
66
|
+
let pendingTxSize = await this.#pendingTxSize.getAsync() ?? 0;
|
|
46
67
|
for (const hash of txHashes){
|
|
47
68
|
const key = hash.toString();
|
|
48
69
|
await this.#minedTxHashToBlock.set(key, blockNumber);
|
|
49
|
-
const tx = await this.
|
|
70
|
+
const tx = await this.getPendingTxByHash(hash);
|
|
50
71
|
if (tx) {
|
|
72
|
+
const nullifiers = tx.data.getNonEmptyNullifiers();
|
|
73
|
+
nullifiers.forEach((nullifier)=>minedNullifiers.add(nullifier.toString()));
|
|
74
|
+
minedFeePayers.add(tx.data.feePayer.toString());
|
|
51
75
|
deletedPending++;
|
|
52
|
-
|
|
53
|
-
await this
|
|
76
|
+
pendingTxSize -= tx.getSize();
|
|
77
|
+
await this.removePendingTxIndices(tx, key);
|
|
54
78
|
}
|
|
55
79
|
}
|
|
56
80
|
this.#metrics.recordAddedObjects(txHashes.length, 'mined');
|
|
57
|
-
this.#
|
|
81
|
+
await this.#pendingTxSize.set(pendingTxSize);
|
|
82
|
+
const numTxsEvicted = await this.evictInvalidTxsAfterMining(txHashes, blockNumber, minedNullifiers, minedFeePayers);
|
|
83
|
+
this.#metrics.recordRemovedObjects(deletedPending + numTxsEvicted, 'pending');
|
|
58
84
|
});
|
|
59
85
|
}
|
|
60
86
|
markMinedAsPending(txHashes) {
|
|
@@ -63,16 +89,24 @@ import { getPendingTxPriority } from './priority.js';
|
|
|
63
89
|
}
|
|
64
90
|
let markedAsPending = 0;
|
|
65
91
|
return this.#store.transactionAsync(async ()=>{
|
|
92
|
+
let pendingTxSize = await this.#pendingTxSize.getAsync() ?? 0;
|
|
66
93
|
for (const hash of txHashes){
|
|
67
94
|
const key = hash.toString();
|
|
68
95
|
await this.#minedTxHashToBlock.delete(key);
|
|
69
|
-
|
|
96
|
+
// Rehydrate the tx in the in-memory pending txs mapping
|
|
97
|
+
const tx = await this.getPendingTxByHash(hash);
|
|
70
98
|
if (tx) {
|
|
71
|
-
await this
|
|
99
|
+
await this.addPendingTxIndices(tx, key);
|
|
100
|
+
pendingTxSize += tx.getSize();
|
|
72
101
|
markedAsPending++;
|
|
73
102
|
}
|
|
74
103
|
}
|
|
75
|
-
this.#
|
|
104
|
+
await this.#pendingTxSize.set(pendingTxSize);
|
|
105
|
+
}).then(async ()=>{
|
|
106
|
+
const numInvalidTxsEvicted = await this.evictInvalidTxsAfterReorg(txHashes);
|
|
107
|
+
const { numLowPriorityTxsEvicted, numNewTxsEvicted } = await this.evictLowPriorityTxs(txHashes);
|
|
108
|
+
this.#metrics.recordAddedObjects(markedAsPending - numNewTxsEvicted, 'pending');
|
|
109
|
+
this.#metrics.recordRemovedObjects(numInvalidTxsEvicted + numLowPriorityTxsEvicted - numNewTxsEvicted, 'pending');
|
|
76
110
|
this.#metrics.recordRemovedObjects(markedAsPending, 'mined');
|
|
77
111
|
});
|
|
78
112
|
}
|
|
@@ -140,6 +174,7 @@ import { getPendingTxPriority } from './priority.js';
|
|
|
140
174
|
})));
|
|
141
175
|
await this.#store.transactionAsync(async ()=>{
|
|
142
176
|
let pendingCount = 0;
|
|
177
|
+
let pendingTxSize = await this.#pendingTxSize.getAsync() ?? 0;
|
|
143
178
|
await Promise.all(txs.map(async (tx, i)=>{
|
|
144
179
|
const { txHash, txStats } = hashesAndStats[i];
|
|
145
180
|
this.#log.verbose(`Adding tx ${txHash.toString()} to pool`, {
|
|
@@ -150,42 +185,47 @@ import { getPendingTxPriority } from './priority.js';
|
|
|
150
185
|
await this.#txs.set(key, tx.toBuffer());
|
|
151
186
|
if (!await this.#minedTxHashToBlock.hasAsync(key)) {
|
|
152
187
|
pendingCount++;
|
|
153
|
-
|
|
154
|
-
await this
|
|
188
|
+
pendingTxSize += tx.getSize();
|
|
189
|
+
await this.addPendingTxIndices(tx, key);
|
|
155
190
|
this.#metrics.recordSize(tx);
|
|
156
191
|
}
|
|
157
192
|
}));
|
|
158
|
-
this.#
|
|
193
|
+
await this.#pendingTxSize.set(pendingTxSize);
|
|
194
|
+
const { numLowPriorityTxsEvicted, numNewTxsEvicted } = await this.evictLowPriorityTxs(hashesAndStats.map(({ txHash })=>txHash));
|
|
195
|
+
this.#metrics.recordAddedObjects(pendingCount - numNewTxsEvicted, 'pending');
|
|
196
|
+
this.#metrics.recordRemovedObjects(numLowPriorityTxsEvicted - numNewTxsEvicted, 'pending');
|
|
159
197
|
});
|
|
160
198
|
}
|
|
161
199
|
/**
|
|
162
200
|
* Deletes transactions from the pool. Tx hashes that are not present are ignored.
|
|
163
201
|
* @param txHashes - An array of tx hashes to be removed from the tx pool.
|
|
164
202
|
* @returns Empty promise.
|
|
165
|
-
*/ deleteTxs(txHashes) {
|
|
203
|
+
*/ deleteTxs(txHashes, eviction = false) {
|
|
166
204
|
let pendingDeleted = 0;
|
|
167
205
|
let minedDeleted = 0;
|
|
168
206
|
const deletedTxs = [];
|
|
169
207
|
const poolDbTx = this.#store.transactionAsync(async ()=>{
|
|
208
|
+
let pendingTxSize = await this.#pendingTxSize.getAsync() ?? 0;
|
|
170
209
|
for (const hash of txHashes){
|
|
171
210
|
const key = hash.toString();
|
|
172
211
|
const tx = await this.getTxByHash(hash);
|
|
173
212
|
if (tx) {
|
|
174
|
-
const fee = getPendingTxPriority(tx);
|
|
175
|
-
await this.#pendingTxPriorityToHash.deleteValue(fee, key);
|
|
176
213
|
const isMined = await this.#minedTxHashToBlock.hasAsync(key);
|
|
177
214
|
if (isMined) {
|
|
178
215
|
minedDeleted++;
|
|
179
216
|
} else {
|
|
180
217
|
pendingDeleted++;
|
|
218
|
+
pendingTxSize -= tx.getSize();
|
|
219
|
+
await this.removePendingTxIndices(tx, key);
|
|
181
220
|
}
|
|
182
|
-
if (this.#archivedTxLimit) {
|
|
221
|
+
if (!eviction && this.#archivedTxLimit) {
|
|
183
222
|
deletedTxs.push(tx);
|
|
184
223
|
}
|
|
185
224
|
await this.#txs.delete(key);
|
|
186
225
|
await this.#minedTxHashToBlock.delete(key);
|
|
187
226
|
}
|
|
188
227
|
}
|
|
228
|
+
await this.#pendingTxSize.set(pendingTxSize);
|
|
189
229
|
this.#metrics.recordRemovedObjects(pendingDeleted, 'pending');
|
|
190
230
|
this.#metrics.recordRemovedObjects(minedDeleted, 'mined');
|
|
191
231
|
});
|
|
@@ -210,6 +250,43 @@ import { getPendingTxPriority } from './priority.js';
|
|
|
210
250
|
return vals.map((x)=>TxHash.fromString(x));
|
|
211
251
|
}
|
|
212
252
|
/**
|
|
253
|
+
* Creates a GasTxValidator instance.
|
|
254
|
+
* @param db - DB for the validator to use
|
|
255
|
+
* @returns A GasTxValidator instance
|
|
256
|
+
*/ createGasTxValidator(db) {
|
|
257
|
+
return new GasTxValidator(new DatabasePublicStateSource(db), ProtocolContractAddress.FeeJuice, GasFees.empty());
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Creates an ArchiveCache instance.
|
|
261
|
+
* @param db - DB for the cache to use
|
|
262
|
+
* @returns An ArchiveCache instance
|
|
263
|
+
*/ createArchiveCache(db) {
|
|
264
|
+
return new ArchiveCache(db);
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Checks if a cached transaction exists in the in-memory pending tx pool and returns it.
|
|
268
|
+
* Otherwise, it checks the tx pool, updates the pending tx pool, and returns the tx.
|
|
269
|
+
* @param txHash - The generated tx hash.
|
|
270
|
+
* @returns The transaction, if found, 'undefined' otherwise.
|
|
271
|
+
*/ async getPendingTxByHash(txHash) {
|
|
272
|
+
let key;
|
|
273
|
+
if (typeof txHash === 'string') {
|
|
274
|
+
key = txHash;
|
|
275
|
+
txHash = TxHash.fromString(txHash);
|
|
276
|
+
} else {
|
|
277
|
+
key = txHash.toString();
|
|
278
|
+
}
|
|
279
|
+
if (this.#pendingTxs.has(key)) {
|
|
280
|
+
return this.#pendingTxs.get(key);
|
|
281
|
+
}
|
|
282
|
+
const tx = await this.getTxByHash(txHash);
|
|
283
|
+
if (tx) {
|
|
284
|
+
this.#pendingTxs.set(key, tx);
|
|
285
|
+
return tx;
|
|
286
|
+
}
|
|
287
|
+
return undefined;
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
213
290
|
* Archives a list of txs for future reference. The number of archived txs is limited by the specified archivedTxLimit.
|
|
214
291
|
* @param txs - The list of transactions to archive.
|
|
215
292
|
* @returns Empty promise.
|
|
@@ -242,4 +319,140 @@ import { getPendingTxPriority } from './priority.js';
|
|
|
242
319
|
}
|
|
243
320
|
});
|
|
244
321
|
}
|
|
322
|
+
/**
|
|
323
|
+
* Evicts pending txs with the lowest priority fees from the pool to accomodate the max tx count and cumulative max tx size
|
|
324
|
+
* after new txs are added.
|
|
325
|
+
*
|
|
326
|
+
* @param newTxHashes - The tx hashes of the new txs added to the pool.
|
|
327
|
+
* @returns The total number of txs evicted from the pool and the number of new txs that were evicted.
|
|
328
|
+
*/ async evictLowPriorityTxs(newTxHashes) {
|
|
329
|
+
if (this.#maxTxPoolSize === undefined) {
|
|
330
|
+
return {
|
|
331
|
+
numLowPriorityTxsEvicted: 0,
|
|
332
|
+
numNewTxsEvicted: 0
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
let numNewTxsEvicted = 0;
|
|
336
|
+
const txsToEvict = [];
|
|
337
|
+
let pendingTxsSize = await this.#pendingTxSize.getAsync() ?? 0;
|
|
338
|
+
if (pendingTxsSize > this.#maxTxPoolSize) {
|
|
339
|
+
for await (const txHash of this.#pendingTxPriorityToHash.valuesAsync()){
|
|
340
|
+
this.#log.verbose(`Evicting tx ${txHash} from pool due to low priority to satisfy max tx size limit`);
|
|
341
|
+
txsToEvict.push(TxHash.fromString(txHash));
|
|
342
|
+
const txSize = await this.#pendingTxHashToSize.getAsync(txHash.toString()) ?? (await this.getPendingTxByHash(txHash))?.getSize();
|
|
343
|
+
if (txSize) {
|
|
344
|
+
pendingTxsSize -= txSize;
|
|
345
|
+
if (pendingTxsSize <= this.#maxTxPoolSize) {
|
|
346
|
+
break;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
numNewTxsEvicted += newTxHashes.filter((txHash)=>txsToEvict.includes(txHash)).length;
|
|
351
|
+
}
|
|
352
|
+
if (txsToEvict.length > 0) {
|
|
353
|
+
await this.deleteTxs(txsToEvict, true);
|
|
354
|
+
}
|
|
355
|
+
return {
|
|
356
|
+
numLowPriorityTxsEvicted: txsToEvict.length,
|
|
357
|
+
numNewTxsEvicted
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* Evicts invalid pending txs from the pool after a txs from a block are mined.
|
|
362
|
+
* Eviction criteria includes:
|
|
363
|
+
* - txs with nullifiers that are already included in the mined block
|
|
364
|
+
* - txs with an insufficient fee payer balance
|
|
365
|
+
* - txs with a max block number lower than the mined block
|
|
366
|
+
*
|
|
367
|
+
* @param minedTxHashes - The tx hashes of the txs mined in the block.
|
|
368
|
+
* @param blockNumber - The block number of the mined block.
|
|
369
|
+
* @returns The total number of txs evicted from the pool.
|
|
370
|
+
*/ async evictInvalidTxsAfterMining(minedTxHashes, blockNumber, minedNullifiers, minedFeePayers) {
|
|
371
|
+
if (minedTxHashes.length === 0) {
|
|
372
|
+
return 0;
|
|
373
|
+
}
|
|
374
|
+
// Wait for world state to be synced to at least the mined block number
|
|
375
|
+
await this.#worldStateSynchronizer.syncImmediate(blockNumber);
|
|
376
|
+
const db = this.#worldStateSynchronizer.getCommitted();
|
|
377
|
+
const gasTxValidator = this.createGasTxValidator(db);
|
|
378
|
+
const txsToEvict = [];
|
|
379
|
+
for await (const txHash of this.#pendingTxPriorityToHash.valuesAsync()){
|
|
380
|
+
const tx = await this.getPendingTxByHash(txHash);
|
|
381
|
+
if (!tx) {
|
|
382
|
+
continue;
|
|
383
|
+
}
|
|
384
|
+
// Evict pending txs that share nullifiers with mined txs
|
|
385
|
+
const txNullifiers = tx.data.getNonEmptyNullifiers();
|
|
386
|
+
if (txNullifiers.some((nullifier)=>minedNullifiers.has(nullifier.toString()))) {
|
|
387
|
+
this.#log.verbose(`Evicting tx ${txHash} from pool due to a duplicate nullifier with a mined tx`);
|
|
388
|
+
txsToEvict.push(TxHash.fromString(txHash));
|
|
389
|
+
continue;
|
|
390
|
+
}
|
|
391
|
+
// Evict pending txs with an insufficient fee payer balance
|
|
392
|
+
if (minedFeePayers.has(tx.data.feePayer.toString()) && (await gasTxValidator.validateTxFee(tx)).result === 'invalid') {
|
|
393
|
+
this.#log.verbose(`Evicting tx ${txHash} from pool due to an insufficient fee payer balance`);
|
|
394
|
+
txsToEvict.push(TxHash.fromString(txHash));
|
|
395
|
+
continue;
|
|
396
|
+
}
|
|
397
|
+
// Evict pending txs with a max block number less than or equal to the mined block
|
|
398
|
+
const maxBlockNumber = tx.data.rollupValidationRequests.maxBlockNumber;
|
|
399
|
+
if (maxBlockNumber.isSome && maxBlockNumber.value.toNumber() <= blockNumber) {
|
|
400
|
+
this.#log.verbose(`Evicting tx ${txHash} from pool due to an invalid max block number`);
|
|
401
|
+
txsToEvict.push(TxHash.fromString(txHash));
|
|
402
|
+
continue;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
if (txsToEvict.length > 0) {
|
|
406
|
+
await this.deleteTxs(txsToEvict, true);
|
|
407
|
+
}
|
|
408
|
+
return txsToEvict.length;
|
|
409
|
+
}
|
|
410
|
+
/**
|
|
411
|
+
* Evicts pending txs that no longer have valid archive roots or fee payer balances from the pool after a reorg.
|
|
412
|
+
*
|
|
413
|
+
* @param txHashes - The tx hashes of the txs that were moved from mined to pending.
|
|
414
|
+
* @returns The total number of txs evicted from the pool.
|
|
415
|
+
*/ async evictInvalidTxsAfterReorg(txHashes) {
|
|
416
|
+
if (txHashes.length === 0) {
|
|
417
|
+
return 0;
|
|
418
|
+
}
|
|
419
|
+
await this.#worldStateSynchronizer.syncImmediate();
|
|
420
|
+
const db = this.#worldStateSynchronizer.getCommitted();
|
|
421
|
+
const archiveCache = this.createArchiveCache(db);
|
|
422
|
+
const gasTxValidator = this.createGasTxValidator(db);
|
|
423
|
+
const txsToEvict = [];
|
|
424
|
+
for await (const [txHash, headerHash] of this.#pendingTxHashToHeaderHash.entriesAsync()){
|
|
425
|
+
const tx = await this.getPendingTxByHash(txHash);
|
|
426
|
+
if (!tx) {
|
|
427
|
+
continue;
|
|
428
|
+
}
|
|
429
|
+
const [index] = await archiveCache.getArchiveIndices([
|
|
430
|
+
Fr.fromString(headerHash)
|
|
431
|
+
]);
|
|
432
|
+
if (index === undefined) {
|
|
433
|
+
this.#log.verbose(`Evicting tx ${txHash} from pool due to an invalid archive root`);
|
|
434
|
+
txsToEvict.push(TxHash.fromString(txHash));
|
|
435
|
+
continue;
|
|
436
|
+
}
|
|
437
|
+
if ((await gasTxValidator.validateTxFee(tx)).result === 'invalid') {
|
|
438
|
+
this.#log.verbose(`Evicting tx ${txHash} from pool due to an insufficient fee payer balance`);
|
|
439
|
+
txsToEvict.push(TxHash.fromString(txHash));
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
if (txsToEvict.length > 0) {
|
|
443
|
+
await this.deleteTxs(txsToEvict, true);
|
|
444
|
+
}
|
|
445
|
+
return txsToEvict.length;
|
|
446
|
+
}
|
|
447
|
+
async addPendingTxIndices(tx, txHash) {
|
|
448
|
+
await this.#pendingTxPriorityToHash.set(getPendingTxPriority(tx), txHash);
|
|
449
|
+
await this.#pendingTxHashToSize.set(txHash, tx.getSize());
|
|
450
|
+
await this.#pendingTxHashToHeaderHash.set(txHash, (await tx.data.constants.historicalHeader.hash()).toString());
|
|
451
|
+
}
|
|
452
|
+
async removePendingTxIndices(tx, txHash) {
|
|
453
|
+
await this.#pendingTxPriorityToHash.deleteValue(getPendingTxPriority(tx), txHash);
|
|
454
|
+
await this.#pendingTxHashToSize.delete(txHash);
|
|
455
|
+
await this.#pendingTxHashToHeaderHash.delete(txHash);
|
|
456
|
+
this.#pendingTxs.delete(txHash);
|
|
457
|
+
}
|
|
245
458
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Fr } from '@aztec/foundation/fields';
|
|
2
|
+
import type { ArchiveSource } from '@aztec/p2p';
|
|
3
|
+
import type { MerkleTreeReadOperations } from '@aztec/stdlib/interfaces/server';
|
|
4
|
+
/**
|
|
5
|
+
* Implements an archive source by checking a DB and an in-memory collection.
|
|
6
|
+
* Intended for validating transactions as they are added to a block.
|
|
7
|
+
*/
|
|
8
|
+
export declare class ArchiveCache implements ArchiveSource {
|
|
9
|
+
private db;
|
|
10
|
+
archives: Map<string, bigint>;
|
|
11
|
+
constructor(db: MerkleTreeReadOperations);
|
|
12
|
+
getArchiveIndices(archives: Fr[]): Promise<(bigint | undefined)[]>;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=archive_cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"archive_cache.d.ts","sourceRoot":"","sources":["../../../src/msg_validators/tx_validator/archive_cache.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,0BAA0B,CAAC;AACnD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,iCAAiC,CAAC;AAGhF;;;GAGG;AACH,qBAAa,YAAa,YAAW,aAAa;IAGpC,OAAO,CAAC,EAAE;IAFtB,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;gBAEV,EAAE,EAAE,wBAAwB;IAInC,iBAAiB,CAAC,QAAQ,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,CAAC,MAAM,GAAG,SAAS,CAAC,EAAE,CAAC;CAWhF"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { MerkleTreeId } from '@aztec/stdlib/trees';
|
|
2
|
+
/**
|
|
3
|
+
* Implements an archive source by checking a DB and an in-memory collection.
|
|
4
|
+
* Intended for validating transactions as they are added to a block.
|
|
5
|
+
*/ export class ArchiveCache {
|
|
6
|
+
db;
|
|
7
|
+
archives;
|
|
8
|
+
constructor(db){
|
|
9
|
+
this.db = db;
|
|
10
|
+
this.archives = new Map();
|
|
11
|
+
}
|
|
12
|
+
async getArchiveIndices(archives) {
|
|
13
|
+
const toCheckDb = archives.filter((n)=>!this.archives.has(n.toString()));
|
|
14
|
+
const dbHits = await this.db.findLeafIndices(MerkleTreeId.ARCHIVE, toCheckDb);
|
|
15
|
+
dbHits.forEach((x, index)=>{
|
|
16
|
+
if (x !== undefined) {
|
|
17
|
+
this.archives.set(toCheckDb[index].toString(), x);
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
return archives.map((n)=>this.archives.get(n.toString()));
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"block_header_validator.d.ts","sourceRoot":"","sources":["../../../src/msg_validators/tx_validator/block_header_validator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,0BAA0B,CAAC;AAEnD,OAAO,EAAE,KAAK,KAAK,
|
|
1
|
+
{"version":3,"file":"block_header_validator.d.ts","sourceRoot":"","sources":["../../../src/msg_validators/tx_validator/block_header_validator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,0BAA0B,CAAC;AAEnD,OAAO,EAAE,KAAK,KAAK,EAA6B,KAAK,kBAAkB,EAAE,KAAK,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEpH,MAAM,WAAW,aAAa;IAC5B,iBAAiB,EAAE,CAAC,QAAQ,EAAE,EAAE,EAAE,KAAK,OAAO,CAAC,CAAC,MAAM,GAAG,SAAS,CAAC,EAAE,CAAC,CAAC;CACxE;AAED,qBAAa,sBAAsB,CAAC,CAAC,SAAS,KAAK,CAAE,YAAW,WAAW,CAAC,CAAC,CAAC;;gBAIhE,aAAa,EAAE,aAAa;IAIlC,UAAU,CAAC,EAAE,EAAE,CAAC,GAAG,OAAO,CAAC,kBAAkB,CAAC;CAQrD"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createLogger } from '@aztec/foundation/log';
|
|
2
|
-
import { Tx } from '@aztec/stdlib/tx';
|
|
2
|
+
import { TX_ERROR_BLOCK_HEADER, Tx } from '@aztec/stdlib/tx';
|
|
3
3
|
export class BlockHeaderTxValidator {
|
|
4
4
|
#log = createLogger('p2p:tx_validator:tx_block_header');
|
|
5
5
|
#archiveSource;
|
|
@@ -15,7 +15,7 @@ export class BlockHeaderTxValidator {
|
|
|
15
15
|
return {
|
|
16
16
|
result: 'invalid',
|
|
17
17
|
reason: [
|
|
18
|
-
|
|
18
|
+
TX_ERROR_BLOCK_HEADER
|
|
19
19
|
]
|
|
20
20
|
};
|
|
21
21
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data_validator.d.ts","sourceRoot":"","sources":["../../../src/msg_validators/tx_validator/data_validator.ts"],"names":[],"mappings":"AAGA,OAAO,
|
|
1
|
+
{"version":3,"file":"data_validator.d.ts","sourceRoot":"","sources":["../../../src/msg_validators/tx_validator/data_validator.ts"],"names":[],"mappings":"AAGA,OAAO,EAQL,EAAE,EACF,KAAK,kBAAkB,EACvB,KAAK,WAAW,EACjB,MAAM,kBAAkB,CAAC;AAE1B,qBAAa,eAAgB,YAAW,WAAW,CAAC,EAAE,CAAC;;IAG/C,UAAU,CAAC,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,kBAAkB,CAAC;CAmFtD"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { MAX_FR_CALLDATA_TO_ALL_ENQUEUED_CALLS } from '@aztec/constants';
|
|
2
2
|
import { createLogger } from '@aztec/foundation/log';
|
|
3
3
|
import { computeCalldataHash } from '@aztec/stdlib/hash';
|
|
4
|
-
import { Tx } from '@aztec/stdlib/tx';
|
|
4
|
+
import { TX_ERROR_CALLDATA_COUNT_MISMATCH, TX_ERROR_CALLDATA_COUNT_TOO_LARGE, TX_ERROR_CONTRACT_CLASS_LOGS, TX_ERROR_CONTRACT_CLASS_LOG_COUNT, TX_ERROR_CONTRACT_CLASS_LOG_LENGTH, TX_ERROR_CONTRACT_CLASS_LOG_SORTING, TX_ERROR_INCORRECT_CALLDATA, Tx } from '@aztec/stdlib/tx';
|
|
5
5
|
export class DataTxValidator {
|
|
6
6
|
#log = createLogger('p2p:tx_validator:tx_data');
|
|
7
7
|
async validateTx(tx) {
|
|
@@ -11,7 +11,7 @@ export class DataTxValidator {
|
|
|
11
11
|
}
|
|
12
12
|
async #hasCorrectCalldata(tx) {
|
|
13
13
|
if (tx.publicFunctionCalldata.length !== tx.numberOfPublicCalls()) {
|
|
14
|
-
const reason =
|
|
14
|
+
const reason = TX_ERROR_CALLDATA_COUNT_MISMATCH;
|
|
15
15
|
this.#log.warn(`Rejecting tx ${await Tx.getHash(tx)}. Reason: ${reason}. Expected ${tx.numberOfPublicCalls()}. Got ${tx.publicFunctionCalldata.length}.`);
|
|
16
16
|
return {
|
|
17
17
|
result: 'invalid',
|
|
@@ -21,7 +21,7 @@ export class DataTxValidator {
|
|
|
21
21
|
};
|
|
22
22
|
}
|
|
23
23
|
if (tx.getTotalPublicCalldataCount() > MAX_FR_CALLDATA_TO_ALL_ENQUEUED_CALLS) {
|
|
24
|
-
const reason =
|
|
24
|
+
const reason = TX_ERROR_CALLDATA_COUNT_TOO_LARGE;
|
|
25
25
|
this.#log.warn(`Rejecting tx ${await Tx.getHash(tx)}. Reason: ${reason}. Expected no greater than ${MAX_FR_CALLDATA_TO_ALL_ENQUEUED_CALLS} fields. Got ${tx.getTotalPublicCalldataCount()}.`);
|
|
26
26
|
return {
|
|
27
27
|
result: 'invalid',
|
|
@@ -35,7 +35,7 @@ export class DataTxValidator {
|
|
|
35
35
|
const { request, calldata } = callRequests[i];
|
|
36
36
|
const hash = await computeCalldataHash(calldata);
|
|
37
37
|
if (!hash.equals(request.calldataHash)) {
|
|
38
|
-
const reason =
|
|
38
|
+
const reason = TX_ERROR_INCORRECT_CALLDATA;
|
|
39
39
|
this.#log.warn(`Rejecting tx ${await Tx.getHash(tx)}. Reason: ${reason}. Call request index: ${i}.`);
|
|
40
40
|
return {
|
|
41
41
|
result: 'invalid',
|
|
@@ -57,7 +57,7 @@ export class DataTxValidator {
|
|
|
57
57
|
return {
|
|
58
58
|
result: 'invalid',
|
|
59
59
|
reason: [
|
|
60
|
-
|
|
60
|
+
TX_ERROR_CONTRACT_CLASS_LOG_COUNT
|
|
61
61
|
]
|
|
62
62
|
};
|
|
63
63
|
}
|
|
@@ -70,7 +70,7 @@ export class DataTxValidator {
|
|
|
70
70
|
return {
|
|
71
71
|
result: 'invalid',
|
|
72
72
|
reason: [
|
|
73
|
-
|
|
73
|
+
TX_ERROR_CONTRACT_CLASS_LOG_SORTING
|
|
74
74
|
]
|
|
75
75
|
};
|
|
76
76
|
} else {
|
|
@@ -78,7 +78,7 @@ export class DataTxValidator {
|
|
|
78
78
|
return {
|
|
79
79
|
result: 'invalid',
|
|
80
80
|
reason: [
|
|
81
|
-
|
|
81
|
+
TX_ERROR_CONTRACT_CLASS_LOGS
|
|
82
82
|
]
|
|
83
83
|
};
|
|
84
84
|
}
|
|
@@ -88,7 +88,7 @@ export class DataTxValidator {
|
|
|
88
88
|
return {
|
|
89
89
|
result: 'invalid',
|
|
90
90
|
reason: [
|
|
91
|
-
|
|
91
|
+
TX_ERROR_CONTRACT_CLASS_LOG_LENGTH
|
|
92
92
|
]
|
|
93
93
|
};
|
|
94
94
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"double_spend_validator.d.ts","sourceRoot":"","sources":["../../../src/msg_validators/tx_validator/double_spend_validator.ts"],"names":[],"mappings":";;AACA,OAAO,
|
|
1
|
+
{"version":3,"file":"double_spend_validator.d.ts","sourceRoot":"","sources":["../../../src/msg_validators/tx_validator/double_spend_validator.ts"],"names":[],"mappings":";;AACA,OAAO,EACL,KAAK,KAAK,EAIV,KAAK,kBAAkB,EACvB,KAAK,WAAW,EACjB,MAAM,kBAAkB,CAAC;AAE1B,MAAM,WAAW,eAAe;IAC9B,eAAe,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;CAC/D;AAED,qBAAa,sBAAsB,CAAC,CAAC,SAAS,KAAK,CAAE,YAAW,WAAW,CAAC,CAAC,CAAC;;gBAIhE,eAAe,EAAE,eAAe;IAItC,UAAU,CAAC,EAAE,EAAE,CAAC,GAAG,OAAO,CAAC,kBAAkB,CAAC;CAiBrD"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createLogger } from '@aztec/foundation/log';
|
|
2
|
-
import { Tx } from '@aztec/stdlib/tx';
|
|
2
|
+
import { TX_ERROR_DUPLICATE_NULLIFIER_IN_TX, TX_ERROR_EXISTING_NULLIFIER, Tx } from '@aztec/stdlib/tx';
|
|
3
3
|
export class DoubleSpendTxValidator {
|
|
4
4
|
#log = createLogger('p2p:tx_validator:tx_double_spend');
|
|
5
5
|
#nullifierSource;
|
|
@@ -15,7 +15,7 @@ export class DoubleSpendTxValidator {
|
|
|
15
15
|
return {
|
|
16
16
|
result: 'invalid',
|
|
17
17
|
reason: [
|
|
18
|
-
|
|
18
|
+
TX_ERROR_DUPLICATE_NULLIFIER_IN_TX
|
|
19
19
|
]
|
|
20
20
|
};
|
|
21
21
|
}
|
|
@@ -24,7 +24,7 @@ export class DoubleSpendTxValidator {
|
|
|
24
24
|
return {
|
|
25
25
|
result: 'invalid',
|
|
26
26
|
reason: [
|
|
27
|
-
|
|
27
|
+
TX_ERROR_EXISTING_NULLIFIER
|
|
28
28
|
]
|
|
29
29
|
};
|
|
30
30
|
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
2
|
-
import
|
|
2
|
+
import { GasFees } from '@aztec/stdlib/gas';
|
|
3
3
|
import type { PublicStateSource } from '@aztec/stdlib/trees';
|
|
4
4
|
import { type Tx, type TxValidationResult, type TxValidator } from '@aztec/stdlib/tx';
|
|
5
5
|
export declare class GasTxValidator implements TxValidator<Tx> {
|
|
6
6
|
#private;
|
|
7
7
|
constructor(publicDataSource: PublicStateSource, feeJuiceAddress: AztecAddress, gasFees: GasFees);
|
|
8
8
|
validateTx(tx: Tx): Promise<TxValidationResult>;
|
|
9
|
+
validateTxFee(tx: Tx): Promise<TxValidationResult>;
|
|
9
10
|
}
|
|
10
11
|
//# sourceMappingURL=gas_validator.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gas_validator.d.ts","sourceRoot":"","sources":["../../../src/msg_validators/tx_validator/gas_validator.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"gas_validator.d.ts","sourceRoot":"","sources":["../../../src/msg_validators/tx_validator/gas_validator.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,EAAO,OAAO,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EAIL,KAAK,EAAE,EAEP,KAAK,kBAAkB,EACvB,KAAK,WAAW,EACjB,MAAM,kBAAkB,CAAC;AAE1B,qBAAa,cAAe,YAAW,WAAW,CAAC,EAAE,CAAC;;gBAMxC,gBAAgB,EAAE,iBAAiB,EAAE,eAAe,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO;IAM1F,UAAU,CAAC,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAoDxC,aAAa,CAAC,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,kBAAkB,CAAC;CA0ChE"}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import { FIXED_DA_GAS, FIXED_L2_GAS } from '@aztec/constants';
|
|
1
2
|
import { createLogger } from '@aztec/foundation/log';
|
|
2
3
|
import { computeFeePayerBalanceStorageSlot } from '@aztec/protocol-contracts/fee-juice';
|
|
3
4
|
import { getCallRequestsWithCalldataByPhase } from '@aztec/simulator/server';
|
|
4
5
|
import { FunctionSelector } from '@aztec/stdlib/abi';
|
|
5
|
-
import {
|
|
6
|
+
import { Gas } from '@aztec/stdlib/gas';
|
|
7
|
+
import { TX_ERROR_INSUFFICIENT_FEE_PAYER_BALANCE, TX_ERROR_INSUFFICIENT_FEE_PER_GAS, TX_ERROR_INSUFFICIENT_GAS_LIMIT, TxExecutionPhase } from '@aztec/stdlib/tx';
|
|
6
8
|
export class GasTxValidator {
|
|
7
9
|
#log = createLogger('sequencer:tx_validator:tx_gas');
|
|
8
10
|
#publicDataSource;
|
|
@@ -14,15 +16,19 @@ export class GasTxValidator {
|
|
|
14
16
|
this.#gasFees = gasFees;
|
|
15
17
|
}
|
|
16
18
|
async validateTx(tx) {
|
|
19
|
+
const gasLimitValidation = this.#validateMinGasLimit(tx);
|
|
20
|
+
if (gasLimitValidation.result === 'invalid') {
|
|
21
|
+
return Promise.resolve(gasLimitValidation);
|
|
22
|
+
}
|
|
17
23
|
if (await this.#shouldSkip(tx)) {
|
|
18
24
|
return Promise.resolve({
|
|
19
25
|
result: 'skipped',
|
|
20
26
|
reason: [
|
|
21
|
-
|
|
27
|
+
TX_ERROR_INSUFFICIENT_FEE_PER_GAS
|
|
22
28
|
]
|
|
23
29
|
});
|
|
24
30
|
}
|
|
25
|
-
return this
|
|
31
|
+
return this.validateTxFee(tx);
|
|
26
32
|
}
|
|
27
33
|
/**
|
|
28
34
|
* Check whether the tx's max fees are valid for the current block, and skip if not.
|
|
@@ -42,7 +48,28 @@ export class GasTxValidator {
|
|
|
42
48
|
}
|
|
43
49
|
return notEnoughMaxFees;
|
|
44
50
|
}
|
|
45
|
-
|
|
51
|
+
/**
|
|
52
|
+
* Check whether the tx's gas limit is above the minimum amount.
|
|
53
|
+
*/ #validateMinGasLimit(tx) {
|
|
54
|
+
const gasLimits = tx.data.constants.txContext.gasSettings.gasLimits;
|
|
55
|
+
const minGasLimits = new Gas(FIXED_DA_GAS, FIXED_L2_GAS);
|
|
56
|
+
if (minGasLimits.gtAny(gasLimits)) {
|
|
57
|
+
this.#log.warn(`Rejecting transaction due to the gas limit(s) not being above the minimum gas limit`, {
|
|
58
|
+
gasLimits,
|
|
59
|
+
minGasLimits
|
|
60
|
+
});
|
|
61
|
+
return {
|
|
62
|
+
result: 'invalid',
|
|
63
|
+
reason: [
|
|
64
|
+
TX_ERROR_INSUFFICIENT_GAS_LIMIT
|
|
65
|
+
]
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
return {
|
|
69
|
+
result: 'valid'
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
async validateTxFee(tx) {
|
|
46
73
|
const feePayer = tx.data.feePayer;
|
|
47
74
|
// Compute the maximum fee that this tx may pay, based on its gasLimits and maxFeePerGas
|
|
48
75
|
const feeLimit = tx.data.constants.txContext.gasSettings.getFeeLimit();
|
|
@@ -65,7 +92,7 @@ export class GasTxValidator {
|
|
|
65
92
|
return {
|
|
66
93
|
result: 'invalid',
|
|
67
94
|
reason: [
|
|
68
|
-
|
|
95
|
+
TX_ERROR_INSUFFICIENT_FEE_PAYER_BALANCE
|
|
69
96
|
]
|
|
70
97
|
};
|
|
71
98
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/msg_validators/tx_validator/index.ts"],"names":[],"mappings":"AAAA,cAAc,6BAA6B,CAAC;AAC5C,cAAc,qBAAqB,CAAC;AACpC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,yBAAyB,CAAC;AACxC,cAAc,yBAAyB,CAAC;AACxC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,oBAAoB,CAAC;AACnC,cAAc,uBAAuB,CAAC;AACtC,cAAc,iBAAiB,CAAC;AAChC,cAAc,2BAA2B,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/msg_validators/tx_validator/index.ts"],"names":[],"mappings":"AAAA,cAAc,6BAA6B,CAAC;AAC5C,cAAc,qBAAqB,CAAC;AACpC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,yBAAyB,CAAC;AACxC,cAAc,yBAAyB,CAAC;AACxC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,oBAAoB,CAAC;AACnC,cAAc,uBAAuB,CAAC;AACtC,cAAc,iBAAiB,CAAC;AAChC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,oBAAoB,CAAC"}
|