@aztec/p2p 1.2.1 → 2.0.0-nightly.20250813
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dest/client/factory.d.ts +5 -1
- package/dest/client/factory.d.ts.map +1 -1
- package/dest/client/factory.js +29 -12
- package/dest/client/interface.d.ts +8 -13
- package/dest/client/interface.d.ts.map +1 -1
- package/dest/client/p2p_client.d.ts +18 -22
- package/dest/client/p2p_client.d.ts.map +1 -1
- package/dest/client/p2p_client.js +86 -83
- package/dest/config.d.ts +30 -1
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +34 -1
- package/dest/index.d.ts +1 -0
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +1 -0
- package/dest/mem_pools/attestation_pool/attestation_pool.d.ts +13 -1
- 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.map +1 -1
- package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.js +117 -10
- package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts +4 -1
- package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/kv_attestation_pool.js +22 -1
- package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts +4 -1
- package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/memory_attestation_pool.js +21 -1
- package/dest/mem_pools/attestation_pool/mocks.d.ts +1 -2
- package/dest/mem_pools/attestation_pool/mocks.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/mocks.js +2 -10
- package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts +8 -3
- 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 +64 -37
- package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts +8 -3
- package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/memory_tx_pool.js +18 -10
- package/dest/mem_pools/tx_pool/tx_pool.d.ts +11 -2
- package/dest/mem_pools/tx_pool/tx_pool.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/tx_pool_test_suite.js +73 -44
- package/dest/msg_validators/attestation_validator/attestation_validator.js +1 -1
- 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 +35 -59
- package/dest/msg_validators/tx_validator/double_spend_validator.js +2 -2
- package/dest/msg_validators/tx_validator/gas_validator.js +4 -4
- package/dest/msg_validators/tx_validator/metadata_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/metadata_validator.js +21 -21
- package/dest/msg_validators/tx_validator/phases_validator.js +3 -3
- package/dest/msg_validators/tx_validator/tx_proof_validator.js +3 -3
- package/dest/services/discv5/discV5_service.d.ts.map +1 -1
- package/dest/services/discv5/discV5_service.js +4 -1
- package/dest/services/dummy_service.d.ts +13 -3
- package/dest/services/dummy_service.d.ts.map +1 -1
- package/dest/services/dummy_service.js +26 -3
- package/dest/services/index.d.ts +3 -1
- package/dest/services/index.d.ts.map +1 -1
- package/dest/services/index.js +3 -1
- package/dest/services/libp2p/libp2p_service.d.ts +13 -20
- package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
- package/dest/services/libp2p/libp2p_service.js +123 -46
- package/dest/services/peer-manager/interface.d.ts +8 -1
- package/dest/services/peer-manager/interface.d.ts.map +1 -1
- package/dest/services/peer-manager/peer_manager.d.ts +70 -3
- package/dest/services/peer-manager/peer_manager.d.ts.map +1 -1
- package/dest/services/peer-manager/peer_manager.js +369 -39
- package/dest/services/reqresp/config.d.ts +3 -3
- package/dest/services/reqresp/config.d.ts.map +1 -1
- package/dest/services/reqresp/config.js +3 -3
- package/dest/services/reqresp/connection-sampler/connection_sampler.d.ts +3 -4
- package/dest/services/reqresp/connection-sampler/connection_sampler.d.ts.map +1 -1
- package/dest/services/reqresp/connection-sampler/connection_sampler.js +35 -52
- package/dest/services/reqresp/index.d.ts +2 -1
- package/dest/services/reqresp/index.d.ts.map +1 -1
- package/dest/services/reqresp/index.js +2 -1
- package/dest/services/reqresp/interface.d.ts +61 -10
- package/dest/services/reqresp/interface.d.ts.map +1 -1
- package/dest/services/reqresp/interface.js +41 -6
- package/dest/services/reqresp/protocols/auth.d.ts +43 -0
- package/dest/services/reqresp/protocols/auth.d.ts.map +1 -0
- package/dest/services/reqresp/protocols/auth.js +71 -0
- package/dest/services/reqresp/protocols/block.d.ts +5 -0
- package/dest/services/reqresp/protocols/block.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/block.js +28 -5
- package/dest/services/reqresp/protocols/block_txs/bitvector.d.ts +30 -0
- package/dest/services/reqresp/protocols/block_txs/bitvector.d.ts.map +1 -0
- package/dest/services/reqresp/protocols/block_txs/bitvector.js +75 -0
- package/dest/services/reqresp/protocols/block_txs/block_txs_handler.d.ts +11 -0
- package/dest/services/reqresp/protocols/block_txs/block_txs_handler.d.ts.map +1 -0
- package/dest/services/reqresp/protocols/block_txs/block_txs_handler.js +39 -0
- package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.d.ts +49 -0
- package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.d.ts.map +1 -0
- package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.js +75 -0
- package/dest/services/reqresp/protocols/block_txs/index.d.ts +4 -0
- package/dest/services/reqresp/protocols/block_txs/index.d.ts.map +1 -0
- package/dest/services/reqresp/protocols/block_txs/index.js +3 -0
- package/dest/services/reqresp/protocols/goodbye.js +3 -5
- package/dest/services/reqresp/protocols/index.d.ts +2 -0
- package/dest/services/reqresp/protocols/index.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/index.js +2 -0
- package/dest/services/reqresp/protocols/status.d.ts +2 -0
- package/dest/services/reqresp/protocols/status.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/status.js +7 -0
- package/dest/services/reqresp/protocols/tx.d.ts +12 -1
- package/dest/services/reqresp/protocols/tx.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/tx.js +34 -6
- package/dest/services/reqresp/rate-limiter/rate_limits.d.ts.map +1 -1
- package/dest/services/reqresp/rate-limiter/rate_limits.js +20 -0
- package/dest/services/reqresp/reqresp.d.ts +37 -39
- package/dest/services/reqresp/reqresp.d.ts.map +1 -1
- package/dest/services/reqresp/reqresp.js +220 -220
- package/dest/services/reqresp/status.d.ts +8 -3
- package/dest/services/reqresp/status.d.ts.map +1 -1
- package/dest/services/reqresp/status.js +6 -2
- package/dest/services/service.d.ts +10 -10
- package/dest/services/service.d.ts.map +1 -1
- package/dest/services/tx_collection/config.d.ts +25 -0
- package/dest/services/tx_collection/config.d.ts.map +1 -0
- package/dest/services/tx_collection/config.js +58 -0
- package/dest/services/tx_collection/fast_tx_collection.d.ts +56 -0
- package/dest/services/tx_collection/fast_tx_collection.d.ts.map +1 -0
- package/dest/services/tx_collection/fast_tx_collection.js +295 -0
- package/dest/services/tx_collection/index.d.ts +3 -0
- package/dest/services/tx_collection/index.d.ts.map +1 -0
- package/dest/services/tx_collection/index.js +2 -0
- package/dest/services/tx_collection/instrumentation.d.ts +10 -0
- package/dest/services/tx_collection/instrumentation.d.ts.map +1 -0
- package/dest/services/tx_collection/instrumentation.js +34 -0
- package/dest/services/tx_collection/slow_tx_collection.d.ts +54 -0
- package/dest/services/tx_collection/slow_tx_collection.d.ts.map +1 -0
- package/dest/services/tx_collection/slow_tx_collection.js +176 -0
- package/dest/services/tx_collection/tx_collection.d.ts +109 -0
- package/dest/services/tx_collection/tx_collection.d.ts.map +1 -0
- package/dest/services/tx_collection/tx_collection.js +127 -0
- package/dest/services/tx_collection/tx_collection_sink.d.ts +30 -0
- package/dest/services/tx_collection/tx_collection_sink.d.ts.map +1 -0
- package/dest/services/tx_collection/tx_collection_sink.js +81 -0
- package/dest/services/tx_collection/tx_source.d.ts +18 -0
- package/dest/services/tx_collection/tx_source.d.ts.map +1 -0
- package/dest/services/tx_collection/tx_source.js +31 -0
- package/dest/services/tx_provider.d.ts +49 -0
- package/dest/services/tx_provider.d.ts.map +1 -0
- package/dest/services/tx_provider.js +206 -0
- package/dest/services/{tx_collect_instrumentation.d.ts → tx_provider_instrumentation.d.ts} +2 -2
- package/dest/services/tx_provider_instrumentation.d.ts.map +1 -0
- package/dest/services/{tx_collect_instrumentation.js → tx_provider_instrumentation.js} +5 -5
- package/dest/test-helpers/make-test-p2p-clients.d.ts.map +1 -1
- package/dest/test-helpers/make-test-p2p-clients.js +4 -3
- package/dest/test-helpers/mock-pubsub.d.ts +2 -1
- package/dest/test-helpers/mock-pubsub.d.ts.map +1 -1
- package/dest/test-helpers/mock-pubsub.js +2 -1
- package/dest/test-helpers/reqresp-nodes.d.ts.map +1 -1
- package/dest/test-helpers/reqresp-nodes.js +8 -4
- package/dest/testbench/p2p_client_testbench_worker.js +11 -5
- package/dest/util.d.ts +1 -1
- package/dest/util.d.ts.map +1 -1
- package/package.json +14 -15
- package/src/client/factory.ts +87 -12
- package/src/client/interface.ts +19 -15
- package/src/client/p2p_client.ts +108 -92
- package/src/config.ts +52 -1
- package/src/index.ts +1 -0
- package/src/mem_pools/attestation_pool/attestation_pool.ts +15 -1
- package/src/mem_pools/attestation_pool/attestation_pool_test_suite.ts +155 -4
- package/src/mem_pools/attestation_pool/kv_attestation_pool.ts +28 -1
- package/src/mem_pools/attestation_pool/memory_attestation_pool.ts +28 -2
- package/src/mem_pools/attestation_pool/mocks.ts +1 -3
- package/src/mem_pools/tx_pool/aztec_kv_tx_pool.ts +59 -41
- package/src/mem_pools/tx_pool/memory_tx_pool.ts +19 -9
- package/src/mem_pools/tx_pool/tx_pool.ts +7 -2
- package/src/mem_pools/tx_pool/tx_pool_test_suite.ts +63 -40
- package/src/msg_validators/attestation_validator/attestation_validator.ts +1 -1
- package/src/msg_validators/tx_validator/block_header_validator.ts +2 -2
- package/src/msg_validators/tx_validator/data_validator.ts +36 -27
- package/src/msg_validators/tx_validator/double_spend_validator.ts +2 -2
- package/src/msg_validators/tx_validator/gas_validator.ts +4 -4
- package/src/msg_validators/tx_validator/metadata_validator.ts +22 -28
- package/src/msg_validators/tx_validator/phases_validator.ts +2 -2
- package/src/msg_validators/tx_validator/tx_proof_validator.ts +2 -2
- package/src/services/discv5/discV5_service.ts +4 -1
- package/src/services/dummy_service.ts +44 -4
- package/src/services/index.ts +3 -1
- package/src/services/libp2p/libp2p_service.ts +147 -55
- package/src/services/peer-manager/interface.ts +10 -1
- package/src/services/peer-manager/peer_manager.ts +441 -41
- package/src/services/reqresp/config.ts +3 -3
- package/src/services/reqresp/connection-sampler/connection_sampler.ts +38 -63
- package/src/services/reqresp/index.ts +2 -0
- package/src/services/reqresp/interface.ts +63 -17
- package/src/services/reqresp/protocols/auth.ts +83 -0
- package/src/services/reqresp/protocols/block.ts +24 -3
- package/src/services/reqresp/protocols/block_txs/bitvector.ts +90 -0
- package/src/services/reqresp/protocols/block_txs/block_txs_handler.ts +53 -0
- package/src/services/reqresp/protocols/block_txs/block_txs_reqresp.ts +79 -0
- package/src/services/reqresp/protocols/block_txs/index.ts +3 -0
- package/src/services/reqresp/protocols/goodbye.ts +3 -3
- package/src/services/reqresp/protocols/index.ts +2 -0
- package/src/services/reqresp/protocols/status.ts +20 -0
- package/src/services/reqresp/protocols/tx.ts +35 -6
- package/src/services/reqresp/rate-limiter/rate_limits.ts +20 -0
- package/src/services/reqresp/reqresp.ts +294 -264
- package/src/services/reqresp/status.ts +9 -3
- package/src/services/service.ts +23 -14
- package/src/services/tx_collection/config.ts +84 -0
- package/src/services/tx_collection/fast_tx_collection.ts +338 -0
- package/src/services/tx_collection/index.ts +2 -0
- package/src/services/tx_collection/instrumentation.ts +43 -0
- package/src/services/tx_collection/slow_tx_collection.ts +232 -0
- package/src/services/tx_collection/tx_collection.ts +214 -0
- package/src/services/tx_collection/tx_collection_sink.ts +98 -0
- package/src/services/tx_collection/tx_source.ts +37 -0
- package/src/services/tx_provider.ts +215 -0
- package/src/services/{tx_collect_instrumentation.ts → tx_provider_instrumentation.ts} +5 -5
- package/src/test-helpers/make-test-p2p-clients.ts +4 -2
- package/src/test-helpers/mock-pubsub.ts +1 -0
- package/src/test-helpers/reqresp-nodes.ts +7 -1
- package/src/testbench/p2p_client_testbench_worker.ts +9 -2
- package/src/util.ts +1 -1
- package/dest/services/tx_collect_instrumentation.d.ts.map +0 -1
- package/dest/services/tx_collector.d.ts +0 -23
- package/dest/services/tx_collector.d.ts.map +0 -1
- package/dest/services/tx_collector.js +0 -95
- package/src/services/tx_collector.ts +0 -134
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
import { createLogger } from '@aztec/foundation/log';
|
|
2
|
+
import type { TypedEventEmitter } from '@aztec/foundation/types';
|
|
2
3
|
import type { TxAddedToPoolStats } from '@aztec/stdlib/stats';
|
|
3
4
|
import { BlockHeader, Tx, TxHash } from '@aztec/stdlib/tx';
|
|
4
5
|
import { type TelemetryClient, getTelemetryClient } from '@aztec/telemetry-client';
|
|
5
6
|
|
|
7
|
+
import EventEmitter from 'node:events';
|
|
8
|
+
|
|
6
9
|
import { PoolInstrumentation, PoolName, type PoolStatsCallback } from '../instrumentation.js';
|
|
7
10
|
import { getPendingTxPriority } from './priority.js';
|
|
8
|
-
import type { TxPool, TxPoolOptions } from './tx_pool.js';
|
|
11
|
+
import type { TxPool, TxPoolEvents, TxPoolOptions } from './tx_pool.js';
|
|
9
12
|
|
|
10
13
|
/**
|
|
11
14
|
* In-memory implementation of the Transaction Pool.
|
|
12
15
|
*/
|
|
13
|
-
export class InMemoryTxPool implements TxPool {
|
|
16
|
+
export class InMemoryTxPool extends (EventEmitter as new () => TypedEventEmitter<TxPoolEvents>) implements TxPool {
|
|
14
17
|
/**
|
|
15
18
|
* Our tx pool, stored as a Map in-memory, with K: tx hash and V: the transaction.
|
|
16
19
|
*/
|
|
@@ -28,6 +31,7 @@ export class InMemoryTxPool implements TxPool {
|
|
|
28
31
|
telemetry: TelemetryClient = getTelemetryClient(),
|
|
29
32
|
private log = createLogger('p2p:tx_pool'),
|
|
30
33
|
) {
|
|
34
|
+
super();
|
|
31
35
|
this.txs = new Map<bigint, Tx>();
|
|
32
36
|
this.minedTxs = new Map();
|
|
33
37
|
this.pendingTxs = new Set();
|
|
@@ -129,24 +133,30 @@ export class InMemoryTxPool implements TxPool {
|
|
|
129
133
|
* @param txs - An array of txs to be added to the pool.
|
|
130
134
|
* @returns Empty promise.
|
|
131
135
|
*/
|
|
132
|
-
public
|
|
133
|
-
|
|
136
|
+
public addTxs(txs: Tx[], opts: { source?: string } = {}): Promise<number> {
|
|
137
|
+
const added: Tx[] = [];
|
|
134
138
|
for (const tx of txs) {
|
|
135
|
-
const txHash =
|
|
139
|
+
const txHash = tx.getTxHash();
|
|
136
140
|
this.log.verbose(`Adding tx ${txHash.toString()} to pool`, {
|
|
137
141
|
eventName: 'tx-added-to-pool',
|
|
138
|
-
...
|
|
142
|
+
...tx.getStats(),
|
|
139
143
|
} satisfies TxAddedToPoolStats);
|
|
140
144
|
|
|
141
145
|
const key = txHash.toBigInt();
|
|
142
|
-
this.txs.
|
|
146
|
+
if (!this.txs.has(key)) {
|
|
147
|
+
added.push(tx as Tx);
|
|
148
|
+
this.txs.set(key, tx);
|
|
149
|
+
}
|
|
150
|
+
|
|
143
151
|
if (!this.minedTxs.has(key)) {
|
|
144
|
-
pending++;
|
|
145
152
|
this.metrics.recordSize(tx);
|
|
146
153
|
this.pendingTxs.add(key);
|
|
147
154
|
}
|
|
148
155
|
}
|
|
149
|
-
|
|
156
|
+
if (added.length > 0) {
|
|
157
|
+
this.emit('txs-added', { ...opts, txs: added });
|
|
158
|
+
}
|
|
159
|
+
return Promise.resolve(added.length);
|
|
150
160
|
}
|
|
151
161
|
|
|
152
162
|
/**
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { TypedEventEmitter } from '@aztec/foundation/types';
|
|
1
2
|
import type { BlockHeader, Tx, TxHash } from '@aztec/stdlib/tx';
|
|
2
3
|
|
|
3
4
|
export type TxPoolOptions = {
|
|
@@ -6,16 +7,20 @@ export type TxPoolOptions = {
|
|
|
6
7
|
archivedTxLimit?: number;
|
|
7
8
|
};
|
|
8
9
|
|
|
10
|
+
export type TxPoolEvents = {
|
|
11
|
+
['txs-added']: (args: { txs: Tx[]; source?: string }) => void | Promise<void>;
|
|
12
|
+
};
|
|
13
|
+
|
|
9
14
|
/**
|
|
10
15
|
* Interface of a transaction pool. The pool includes tx requests and is kept up-to-date by a P2P client.
|
|
11
16
|
*/
|
|
12
|
-
export interface TxPool {
|
|
17
|
+
export interface TxPool extends TypedEventEmitter<TxPoolEvents> {
|
|
13
18
|
/**
|
|
14
19
|
* Adds a list of transactions to the pool. Duplicates are ignored.
|
|
15
20
|
* @param txs - An array of txs to be added to the pool.
|
|
16
21
|
* @returns The number of txs added to the pool. Note if the transaction already exists, it will not be added again.
|
|
17
22
|
*/
|
|
18
|
-
addTxs(txs: Tx[]): Promise<number>;
|
|
23
|
+
addTxs(txs: Tx[], opts?: { source?: string }): Promise<number>;
|
|
19
24
|
|
|
20
25
|
/**
|
|
21
26
|
* Checks if a transaction exists in the pool and returns it.
|
|
@@ -20,80 +20,103 @@ export function describeTxPool(getTxPool: () => TxPool) {
|
|
|
20
20
|
pool = getTxPool();
|
|
21
21
|
});
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
afterEach(() => {
|
|
24
|
+
pool.removeAllListeners('txs-added');
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('adds txs to the pool as pending', async () => {
|
|
24
28
|
const tx1 = await mockTx();
|
|
25
29
|
|
|
26
30
|
await pool.addTxs([tx1]);
|
|
27
|
-
const poolTx = await pool.getTxByHash(
|
|
28
|
-
expect(
|
|
29
|
-
await expect(pool.getTxStatus(
|
|
30
|
-
await expect(pool.getPendingTxHashes()).resolves.toEqual([
|
|
31
|
+
const poolTx = await pool.getTxByHash(tx1.getTxHash());
|
|
32
|
+
expect(poolTx!.getTxHash()).toEqual(tx1.getTxHash());
|
|
33
|
+
await expect(pool.getTxStatus(tx1.getTxHash())).resolves.toEqual('pending');
|
|
34
|
+
await expect(pool.getPendingTxHashes()).resolves.toEqual([tx1.getTxHash()]);
|
|
31
35
|
await expect(pool.getPendingTxCount()).resolves.toEqual(1);
|
|
32
36
|
});
|
|
33
37
|
|
|
34
|
-
it('
|
|
38
|
+
it('emits txs-added event with new txs', async () => {
|
|
39
|
+
const tx1 = await mockTx(); // existing and pending
|
|
40
|
+
const tx2 = await mockTx(); // mined but not known
|
|
41
|
+
const tx3 = await mockTx(); // brand new
|
|
42
|
+
|
|
43
|
+
await pool.addTxs([tx1]);
|
|
44
|
+
await pool.markAsMined([tx2.getTxHash()], minedBlockHeader);
|
|
45
|
+
|
|
46
|
+
let txsFromEvent: Tx[] | undefined = undefined;
|
|
47
|
+
pool.once('txs-added', ({ txs }) => {
|
|
48
|
+
txsFromEvent = txs;
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
await pool.addTxs([tx1, tx2, tx3]);
|
|
52
|
+
expect(txsFromEvent).toBeDefined();
|
|
53
|
+
expect(txsFromEvent).toHaveLength(2);
|
|
54
|
+
expect(txsFromEvent).toEqual(expect.arrayContaining([tx2, tx3]));
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('removes txs from the pool', async () => {
|
|
35
58
|
const tx1 = await mockTx();
|
|
36
59
|
|
|
37
60
|
await pool.addTxs([tx1]);
|
|
38
|
-
await pool.deleteTxs([
|
|
61
|
+
await pool.deleteTxs([tx1.getTxHash()]);
|
|
39
62
|
|
|
40
|
-
await expect(pool.getTxByHash(
|
|
41
|
-
await expect(pool.getTxStatus(
|
|
63
|
+
await expect(pool.getTxByHash(tx1.getTxHash())).resolves.toBeFalsy();
|
|
64
|
+
await expect(pool.getTxStatus(tx1.getTxHash())).resolves.toBeUndefined();
|
|
42
65
|
await expect(pool.getPendingTxCount()).resolves.toEqual(0);
|
|
43
66
|
});
|
|
44
67
|
|
|
45
|
-
it('
|
|
68
|
+
it('marks txs as mined', async () => {
|
|
46
69
|
const tx1 = await mockTx(1);
|
|
47
70
|
const tx2 = await mockTx(2);
|
|
48
71
|
|
|
49
72
|
await pool.addTxs([tx1, tx2]);
|
|
50
|
-
await pool.markAsMined([
|
|
73
|
+
await pool.markAsMined([tx1.getTxHash()], minedBlockHeader);
|
|
51
74
|
|
|
52
|
-
await expect(pool.getTxByHash(
|
|
53
|
-
await expect(pool.getTxStatus(
|
|
54
|
-
await expect(pool.getMinedTxHashes()).resolves.toEqual([[
|
|
55
|
-
await expect(pool.getPendingTxHashes()).resolves.toEqual([
|
|
75
|
+
await expect(pool.getTxByHash(tx1.getTxHash())).resolves.toEqual(tx1);
|
|
76
|
+
await expect(pool.getTxStatus(tx1.getTxHash())).resolves.toEqual('mined');
|
|
77
|
+
await expect(pool.getMinedTxHashes()).resolves.toEqual([[tx1.getTxHash(), 1]]);
|
|
78
|
+
await expect(pool.getPendingTxHashes()).resolves.toEqual([tx2.getTxHash()]);
|
|
56
79
|
await expect(pool.getPendingTxCount()).resolves.toEqual(1);
|
|
57
80
|
});
|
|
58
81
|
|
|
59
|
-
it('
|
|
82
|
+
it('marks txs as pending after being mined', async () => {
|
|
60
83
|
const tx1 = await mockTx(1);
|
|
61
84
|
const tx2 = await mockTx(2);
|
|
62
85
|
|
|
63
86
|
await pool.addTxs([tx1, tx2]);
|
|
64
|
-
await pool.markAsMined([
|
|
87
|
+
await pool.markAsMined([tx1.getTxHash()], minedBlockHeader);
|
|
65
88
|
|
|
66
|
-
await pool.markMinedAsPending([
|
|
89
|
+
await pool.markMinedAsPending([tx1.getTxHash()]);
|
|
67
90
|
await expect(pool.getMinedTxHashes()).resolves.toEqual([]);
|
|
68
91
|
const pending = await pool.getPendingTxHashes();
|
|
69
92
|
expect(pending).toHaveLength(2);
|
|
70
|
-
expect(pending).toEqual(expect.arrayContaining([
|
|
93
|
+
expect(pending).toEqual(expect.arrayContaining([tx1.getTxHash(), tx2.getTxHash()]));
|
|
71
94
|
await expect(pool.getPendingTxCount()).resolves.toEqual(2);
|
|
72
95
|
});
|
|
73
96
|
|
|
74
|
-
it('
|
|
97
|
+
it('only marks txs as pending if they are known', async () => {
|
|
75
98
|
const tx1 = await mockTx(1);
|
|
76
99
|
// simulate a situation where not all peers have all the txs
|
|
77
100
|
const tx2 = await mockTx(2);
|
|
78
|
-
const someTxHashThatThisPeerDidNotSee =
|
|
101
|
+
const someTxHashThatThisPeerDidNotSee = tx2.getTxHash();
|
|
79
102
|
await pool.addTxs([tx1]);
|
|
80
103
|
// this peer knows that tx2 was mined, but it does not have the tx object
|
|
81
|
-
await pool.markAsMined([
|
|
104
|
+
await pool.markAsMined([tx1.getTxHash(), someTxHashThatThisPeerDidNotSee], minedBlockHeader);
|
|
82
105
|
expect(await pool.getMinedTxHashes()).toEqual(
|
|
83
106
|
expect.arrayContaining([
|
|
84
|
-
[
|
|
107
|
+
[tx1.getTxHash(), 1],
|
|
85
108
|
[someTxHashThatThisPeerDidNotSee, 1],
|
|
86
109
|
]),
|
|
87
110
|
);
|
|
88
111
|
|
|
89
112
|
// reorg: both txs should now become available again
|
|
90
|
-
await pool.markMinedAsPending([
|
|
113
|
+
await pool.markMinedAsPending([tx1.getTxHash(), someTxHashThatThisPeerDidNotSee]);
|
|
91
114
|
await expect(pool.getMinedTxHashes()).resolves.toEqual([]);
|
|
92
|
-
await expect(pool.getPendingTxHashes()).resolves.toEqual([
|
|
115
|
+
await expect(pool.getPendingTxHashes()).resolves.toEqual([tx1.getTxHash()]); // tx2 is not in the pool
|
|
93
116
|
await expect(pool.getPendingTxCount()).resolves.toEqual(1);
|
|
94
117
|
});
|
|
95
118
|
|
|
96
|
-
it('
|
|
119
|
+
it('returns all transactions in the pool', async () => {
|
|
97
120
|
const tx1 = await mockTx(1);
|
|
98
121
|
const tx2 = await mockTx(2);
|
|
99
122
|
const tx3 = await mockTx(3);
|
|
@@ -106,7 +129,7 @@ export function describeTxPool(getTxPool: () => TxPool) {
|
|
|
106
129
|
await expect(pool.getPendingTxCount()).resolves.toEqual(3);
|
|
107
130
|
});
|
|
108
131
|
|
|
109
|
-
it('
|
|
132
|
+
it('returns all txHashes in the pool', async () => {
|
|
110
133
|
const tx1 = await mockTx(1);
|
|
111
134
|
const tx2 = await mockTx(2);
|
|
112
135
|
const tx3 = await mockTx(3);
|
|
@@ -114,35 +137,35 @@ export function describeTxPool(getTxPool: () => TxPool) {
|
|
|
114
137
|
await pool.addTxs([tx1, tx2, tx3]);
|
|
115
138
|
|
|
116
139
|
const poolTxHashes = await pool.getAllTxHashes();
|
|
117
|
-
const expectedHashes =
|
|
140
|
+
const expectedHashes = [tx1, tx2, tx3].map(tx => tx.getTxHash());
|
|
118
141
|
expect(poolTxHashes).toHaveLength(3);
|
|
119
142
|
expect(poolTxHashes).toEqual(expect.arrayContaining(expectedHashes));
|
|
120
143
|
await expect(pool.getPendingTxCount()).resolves.toEqual(3);
|
|
121
144
|
});
|
|
122
145
|
|
|
123
|
-
it('
|
|
146
|
+
it('returns txs by their hash', async () => {
|
|
124
147
|
const tx1 = await mockTx(1);
|
|
125
148
|
const tx2 = await mockTx(2);
|
|
126
149
|
const tx3 = await mockTx(3);
|
|
127
150
|
|
|
128
151
|
await pool.addTxs([tx1, tx2, tx3]);
|
|
129
152
|
|
|
130
|
-
const requestedTxs = await pool.getTxsByHash([
|
|
153
|
+
const requestedTxs = await pool.getTxsByHash([tx1.getTxHash(), tx3.getTxHash()]);
|
|
131
154
|
expect(requestedTxs).toHaveLength(2);
|
|
132
155
|
expect(requestedTxs).toEqual(expect.arrayContaining([tx1, tx3]));
|
|
133
156
|
});
|
|
134
157
|
|
|
135
|
-
it('
|
|
158
|
+
it('returns a large number of transactions by their hash', async () => {
|
|
136
159
|
const numTxs = 1000;
|
|
137
160
|
const txs = await Promise.all(Array.from({ length: numTxs }, (_, i) => mockTx(i)));
|
|
138
|
-
const hashes =
|
|
161
|
+
const hashes = txs.map(tx => tx.getTxHash());
|
|
139
162
|
await pool.addTxs(txs);
|
|
140
163
|
const requestedTxs = await pool.getTxsByHash(hashes);
|
|
141
164
|
expect(requestedTxs).toHaveLength(numTxs);
|
|
142
165
|
expect(requestedTxs).toEqual(expect.arrayContaining(txs));
|
|
143
166
|
});
|
|
144
167
|
|
|
145
|
-
it('
|
|
168
|
+
it('returns whether or not txs exist', async () => {
|
|
146
169
|
const tx1 = await mockTx(1);
|
|
147
170
|
const tx2 = await mockTx(2);
|
|
148
171
|
const tx3 = await mockTx(3);
|
|
@@ -153,17 +176,17 @@ export function describeTxPool(getTxPool: () => TxPool) {
|
|
|
153
176
|
const tx5 = await mockTx(5);
|
|
154
177
|
|
|
155
178
|
const availability = await pool.hasTxs([
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
179
|
+
tx1.getTxHash(),
|
|
180
|
+
tx2.getTxHash(),
|
|
181
|
+
tx3.getTxHash(),
|
|
182
|
+
tx4.getTxHash(),
|
|
183
|
+
tx5.getTxHash(),
|
|
161
184
|
]);
|
|
162
185
|
expect(availability).toHaveLength(5);
|
|
163
186
|
expect(availability).toEqual(expect.arrayContaining([true, true, true, false, false]));
|
|
164
187
|
});
|
|
165
188
|
|
|
166
|
-
it('
|
|
189
|
+
it('returns pending tx hashes sorted by priority', async () => {
|
|
167
190
|
const withPriorityFee = (tx: Tx, fee: number) => {
|
|
168
191
|
unfreeze(tx.data.constants.txContext.gasSettings).maxPriorityFeesPerGas = new GasFees(fee, fee);
|
|
169
192
|
return tx;
|
|
@@ -178,6 +201,6 @@ export function describeTxPool(getTxPool: () => TxPool) {
|
|
|
178
201
|
|
|
179
202
|
const poolTxHashes = await pool.getPendingTxHashes();
|
|
180
203
|
expect(poolTxHashes).toHaveLength(4);
|
|
181
|
-
expect(poolTxHashes).toEqual(
|
|
204
|
+
expect(poolTxHashes).toEqual([tx4, tx1, tx3, tx2].map(tx => tx.getTxHash()));
|
|
182
205
|
});
|
|
183
206
|
}
|
|
@@ -19,7 +19,7 @@ export class AttestationValidator implements P2PValidator<BlockAttestation> {
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
const attester = message.getSender();
|
|
22
|
-
if (!(await this.epochCache.isInCommittee(attester))) {
|
|
22
|
+
if (!(await this.epochCache.isInCommittee(slotNumberBigInt, attester))) {
|
|
23
23
|
return PeerErrorSeverity.HighToleranceError;
|
|
24
24
|
}
|
|
25
25
|
return undefined;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Fr } from '@aztec/foundation/fields';
|
|
2
2
|
import { createLogger } from '@aztec/foundation/log';
|
|
3
|
-
import { type AnyTx, TX_ERROR_BLOCK_HEADER,
|
|
3
|
+
import { type AnyTx, TX_ERROR_BLOCK_HEADER, type TxValidationResult, type TxValidator } from '@aztec/stdlib/tx';
|
|
4
4
|
|
|
5
5
|
export interface ArchiveSource {
|
|
6
6
|
getArchiveIndices: (archives: Fr[]) => Promise<(bigint | undefined)[]>;
|
|
@@ -17,7 +17,7 @@ export class BlockHeaderTxValidator<T extends AnyTx> implements TxValidator<T> {
|
|
|
17
17
|
async validateTx(tx: T): Promise<TxValidationResult> {
|
|
18
18
|
const [index] = await this.#archiveSource.getArchiveIndices([await tx.data.constants.historicalHeader.hash()]);
|
|
19
19
|
if (index === undefined) {
|
|
20
|
-
this.#log.verbose(`Rejecting tx ${
|
|
20
|
+
this.#log.verbose(`Rejecting tx ${'txHash' in tx ? tx.txHash : tx.hash} for referencing an unknown block header`);
|
|
21
21
|
return { result: 'invalid', reason: [TX_ERROR_BLOCK_HEADER] };
|
|
22
22
|
}
|
|
23
23
|
return { result: 'valid' };
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
TX_ERROR_CONTRACT_CLASS_LOG_LENGTH,
|
|
10
10
|
TX_ERROR_CONTRACT_CLASS_LOG_SORTING,
|
|
11
11
|
TX_ERROR_INCORRECT_CALLDATA,
|
|
12
|
+
TX_ERROR_INCORRECT_HASH,
|
|
12
13
|
Tx,
|
|
13
14
|
type TxValidationResult,
|
|
14
15
|
type TxValidator,
|
|
@@ -18,30 +19,42 @@ export class DataTxValidator implements TxValidator<Tx> {
|
|
|
18
19
|
#log = createLogger('p2p:tx_validator:tx_data');
|
|
19
20
|
|
|
20
21
|
async validateTx(tx: Tx): Promise<TxValidationResult> {
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
const reason =
|
|
23
|
+
(await this.#hasCorrectHash(tx)) ??
|
|
24
|
+
(await this.#hasCorrectCalldata(tx)) ??
|
|
25
|
+
(await this.#hasCorrectContractClassLogs(tx));
|
|
26
|
+
return reason ? { result: 'invalid', reason: [reason] } : { result: 'valid' };
|
|
24
27
|
}
|
|
25
28
|
|
|
26
|
-
async #
|
|
29
|
+
async #hasCorrectHash(tx: Tx): Promise<string | undefined> {
|
|
30
|
+
const expected = await Tx.computeTxHash(tx);
|
|
31
|
+
if (!tx.getTxHash().equals(expected)) {
|
|
32
|
+
const reason = TX_ERROR_INCORRECT_HASH;
|
|
33
|
+
this.#log.verbose(
|
|
34
|
+
`Rejecting tx ${tx.getTxHash().toString()}. Reason: ${reason}. Expected hash ${expected.toString()}. Got ${tx.getTxHash().toString()}.`,
|
|
35
|
+
);
|
|
36
|
+
return reason;
|
|
37
|
+
}
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async #hasCorrectCalldata(tx: Tx): Promise<string | undefined> {
|
|
27
42
|
if (tx.publicFunctionCalldata.length !== tx.numberOfPublicCalls()) {
|
|
28
43
|
const reason = TX_ERROR_CALLDATA_COUNT_MISMATCH;
|
|
29
44
|
this.#log.verbose(
|
|
30
|
-
`Rejecting tx ${
|
|
45
|
+
`Rejecting tx ${tx.getTxHash().toString()}. Reason: ${reason}. Expected ${tx.numberOfPublicCalls()}. Got ${
|
|
31
46
|
tx.publicFunctionCalldata.length
|
|
32
47
|
}.`,
|
|
33
48
|
);
|
|
34
|
-
return
|
|
49
|
+
return reason;
|
|
35
50
|
}
|
|
36
51
|
|
|
37
52
|
if (tx.getTotalPublicCalldataCount() > MAX_FR_CALLDATA_TO_ALL_ENQUEUED_CALLS) {
|
|
38
53
|
const reason = TX_ERROR_CALLDATA_COUNT_TOO_LARGE;
|
|
39
54
|
this.#log.verbose(
|
|
40
|
-
`Rejecting tx ${
|
|
41
|
-
tx,
|
|
42
|
-
)}. Reason: ${reason}. Expected no greater than ${MAX_FR_CALLDATA_TO_ALL_ENQUEUED_CALLS} fields. Got ${tx.getTotalPublicCalldataCount()}.`,
|
|
55
|
+
`Rejecting tx ${tx.getTxHash().toString()}. Reason: ${reason}. Expected no greater than ${MAX_FR_CALLDATA_TO_ALL_ENQUEUED_CALLS} fields. Got ${tx.getTotalPublicCalldataCount()}.`,
|
|
43
56
|
);
|
|
44
|
-
return
|
|
57
|
+
return reason;
|
|
45
58
|
}
|
|
46
59
|
|
|
47
60
|
const callRequests = tx.getPublicCallRequestsWithCalldata();
|
|
@@ -50,23 +63,23 @@ export class DataTxValidator implements TxValidator<Tx> {
|
|
|
50
63
|
const hash = await computeCalldataHash(calldata);
|
|
51
64
|
if (!hash.equals(request.calldataHash)) {
|
|
52
65
|
const reason = TX_ERROR_INCORRECT_CALLDATA;
|
|
53
|
-
this.#log.verbose(`Rejecting tx ${
|
|
54
|
-
return
|
|
66
|
+
this.#log.verbose(`Rejecting tx ${tx.getTxHash().toString()}. Reason: ${reason}. Call request index: ${i}.`);
|
|
67
|
+
return reason;
|
|
55
68
|
}
|
|
56
69
|
}
|
|
57
70
|
|
|
58
|
-
return
|
|
71
|
+
return undefined;
|
|
59
72
|
}
|
|
60
73
|
|
|
61
|
-
async #hasCorrectContractClassLogs(tx: Tx): Promise<
|
|
74
|
+
async #hasCorrectContractClassLogs(tx: Tx): Promise<string | undefined> {
|
|
62
75
|
const contractClassLogsHashes = tx.data.getNonEmptyContractClassLogsHashes();
|
|
63
76
|
if (contractClassLogsHashes.length !== tx.contractClassLogFields.length) {
|
|
64
77
|
this.#log.verbose(
|
|
65
|
-
`Rejecting tx ${
|
|
78
|
+
`Rejecting tx ${tx.getTxHash().toString()} because of mismatched number of contract class logs. Expected ${
|
|
66
79
|
contractClassLogsHashes.length
|
|
67
80
|
}. Got ${tx.contractClassLogFields.length}.`,
|
|
68
81
|
);
|
|
69
|
-
return
|
|
82
|
+
return TX_ERROR_CONTRACT_CLASS_LOG_COUNT;
|
|
70
83
|
}
|
|
71
84
|
|
|
72
85
|
const expectedHashes = await Promise.all(tx.contractClassLogFields.map(l => l.hash()));
|
|
@@ -76,34 +89,30 @@ export class DataTxValidator implements TxValidator<Tx> {
|
|
|
76
89
|
if (expectedHashes.some(h => logHash.value.equals(h))) {
|
|
77
90
|
const matchingLogIndex = expectedHashes.findIndex(l => logHash.value.equals(l));
|
|
78
91
|
this.#log.verbose(
|
|
79
|
-
`Rejecting tx ${
|
|
80
|
-
tx,
|
|
81
|
-
)} because of mismatched contract class logs indices. Expected ${i} from the kernel's log hashes. Got ${matchingLogIndex} in the tx.`,
|
|
92
|
+
`Rejecting tx ${tx.getTxHash().toString()} because of mismatched contract class logs indices. Expected ${i} from the kernel's log hashes. Got ${matchingLogIndex} in the tx.`,
|
|
82
93
|
);
|
|
83
|
-
return
|
|
94
|
+
return TX_ERROR_CONTRACT_CLASS_LOG_SORTING;
|
|
84
95
|
} else {
|
|
85
96
|
this.#log.verbose(
|
|
86
|
-
`Rejecting tx ${
|
|
97
|
+
`Rejecting tx ${tx.getTxHash().toString()} because of mismatched contract class logs. Expected hash ${
|
|
87
98
|
logHash.value
|
|
88
99
|
} from the kernels. Got ${hash} in the tx.`,
|
|
89
100
|
);
|
|
90
|
-
return
|
|
101
|
+
return TX_ERROR_CONTRACT_CLASS_LOGS;
|
|
91
102
|
}
|
|
92
103
|
}
|
|
93
104
|
|
|
94
105
|
const expectedMinLength = 1 + tx.contractClassLogFields[i].fields.findLastIndex(f => !f.isZero());
|
|
95
106
|
if (logHash.logHash.length < expectedMinLength) {
|
|
96
107
|
this.#log.verbose(
|
|
97
|
-
`Rejecting tx ${
|
|
98
|
-
tx,
|
|
99
|
-
)} because of incorrect contract class log length. Expected the length to be at least ${expectedMinLength}. Got ${
|
|
108
|
+
`Rejecting tx ${tx.getTxHash().toString()} because of incorrect contract class log length. Expected the length to be at least ${expectedMinLength}. Got ${
|
|
100
109
|
logHash.logHash.length
|
|
101
110
|
}.`,
|
|
102
111
|
);
|
|
103
|
-
return
|
|
112
|
+
return TX_ERROR_CONTRACT_CLASS_LOG_LENGTH;
|
|
104
113
|
}
|
|
105
114
|
}
|
|
106
115
|
|
|
107
|
-
return
|
|
116
|
+
return undefined;
|
|
108
117
|
}
|
|
109
118
|
}
|
|
@@ -26,12 +26,12 @@ export class DoubleSpendTxValidator<T extends AnyTx> implements TxValidator<T> {
|
|
|
26
26
|
// Ditch this tx if it has repeated nullifiers
|
|
27
27
|
const uniqueNullifiers = new Set(nullifiers);
|
|
28
28
|
if (uniqueNullifiers.size !== nullifiers.length) {
|
|
29
|
-
this.#log.verbose(`Rejecting tx ${
|
|
29
|
+
this.#log.verbose(`Rejecting tx ${'txHash' in tx ? tx.txHash : tx.hash} for emitting duplicate nullifiers`);
|
|
30
30
|
return { result: 'invalid', reason: [TX_ERROR_DUPLICATE_NULLIFIER_IN_TX] };
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
if ((await this.#nullifierSource.nullifiersExist(nullifiers.map(n => n.toBuffer()))).some(Boolean)) {
|
|
34
|
-
this.#log.verbose(`Rejecting tx ${
|
|
34
|
+
this.#log.verbose(`Rejecting tx ${'txHash' in tx ? tx.txHash : tx.hash} for repeating a nullifier`);
|
|
35
35
|
return { result: 'invalid', reason: [TX_ERROR_EXISTING_NULLIFIER] };
|
|
36
36
|
}
|
|
37
37
|
|
|
@@ -33,10 +33,10 @@ export class GasTxValidator implements TxValidator<Tx> {
|
|
|
33
33
|
if (gasLimitValidation.result === 'invalid') {
|
|
34
34
|
return Promise.resolve(gasLimitValidation);
|
|
35
35
|
}
|
|
36
|
-
if (
|
|
36
|
+
if (this.#shouldSkip(tx)) {
|
|
37
37
|
return Promise.resolve({ result: 'skipped', reason: [TX_ERROR_INSUFFICIENT_FEE_PER_GAS] });
|
|
38
38
|
}
|
|
39
|
-
return this.validateTxFee(tx);
|
|
39
|
+
return await this.validateTxFee(tx);
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
/**
|
|
@@ -45,7 +45,7 @@ export class GasTxValidator implements TxValidator<Tx> {
|
|
|
45
45
|
* Note that circuits check max fees even if fee payer is unset, so we
|
|
46
46
|
* keep this validation even if the tx does not pay fees.
|
|
47
47
|
*/
|
|
48
|
-
|
|
48
|
+
#shouldSkip(tx: Tx): boolean {
|
|
49
49
|
const gasSettings = tx.data.constants.txContext.gasSettings;
|
|
50
50
|
|
|
51
51
|
// Skip the tx if its max fees are not enough for the current block's gas fees.
|
|
@@ -54,7 +54,7 @@ export class GasTxValidator implements TxValidator<Tx> {
|
|
|
54
54
|
maxFeesPerGas.feePerDaGas < this.#gasFees.feePerDaGas || maxFeesPerGas.feePerL2Gas < this.#gasFees.feePerL2Gas;
|
|
55
55
|
|
|
56
56
|
if (notEnoughMaxFees) {
|
|
57
|
-
this.#log.verbose(`Skipping transaction ${
|
|
57
|
+
this.#log.verbose(`Skipping transaction ${tx.getTxHash().toString()} due to insufficient fee per gas`, {
|
|
58
58
|
txMaxFeesPerGas: maxFeesPerGas.toInspect(),
|
|
59
59
|
currentGasFees: this.#gasFees.toInspect(),
|
|
60
60
|
});
|
|
@@ -7,9 +7,9 @@ import {
|
|
|
7
7
|
TX_ERROR_INCORRECT_ROLLUP_VERSION,
|
|
8
8
|
TX_ERROR_INCORRECT_VK_TREE_ROOT,
|
|
9
9
|
TX_ERROR_INVALID_INCLUDE_BY_TIMESTAMP,
|
|
10
|
-
Tx,
|
|
11
10
|
type TxValidationResult,
|
|
12
11
|
type TxValidator,
|
|
12
|
+
getTxHash,
|
|
13
13
|
} from '@aztec/stdlib/tx';
|
|
14
14
|
import type { UInt64 } from '@aztec/stdlib/types';
|
|
15
15
|
|
|
@@ -30,33 +30,31 @@ export class MetadataTxValidator<T extends AnyTx> implements TxValidator<T> {
|
|
|
30
30
|
},
|
|
31
31
|
) {}
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
validateTx(tx: T): Promise<TxValidationResult> {
|
|
34
34
|
const errors = [];
|
|
35
|
-
if (!
|
|
35
|
+
if (!this.#hasCorrectL1ChainId(tx)) {
|
|
36
36
|
errors.push(TX_ERROR_INCORRECT_L1_CHAIN_ID);
|
|
37
37
|
}
|
|
38
|
-
if (!
|
|
38
|
+
if (!this.#hasCorrectRollupVersion(tx)) {
|
|
39
39
|
errors.push(TX_ERROR_INCORRECT_ROLLUP_VERSION);
|
|
40
40
|
}
|
|
41
|
-
if (!
|
|
41
|
+
if (!this.#isValidForTimestamp(tx)) {
|
|
42
42
|
errors.push(TX_ERROR_INVALID_INCLUDE_BY_TIMESTAMP);
|
|
43
43
|
}
|
|
44
|
-
if (!
|
|
44
|
+
if (!this.#hasCorrectVkTreeRoot(tx)) {
|
|
45
45
|
errors.push(TX_ERROR_INCORRECT_VK_TREE_ROOT);
|
|
46
46
|
}
|
|
47
|
-
if (!
|
|
47
|
+
if (!this.#hasCorrectProtocolContractTreeRoot(tx)) {
|
|
48
48
|
errors.push(TX_ERROR_INCORRECT_PROTOCOL_CONTRACT_TREE_ROOT);
|
|
49
49
|
}
|
|
50
|
-
return errors.length > 0 ? { result: 'invalid', reason: errors } : { result: 'valid' };
|
|
50
|
+
return Promise.resolve(errors.length > 0 ? { result: 'invalid', reason: errors } : { result: 'valid' });
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
|
|
53
|
+
#hasCorrectVkTreeRoot(tx: T): boolean {
|
|
54
54
|
// This gets implicitly tested in the proof validator, but we can get a much cheaper check here by looking early at the vk.
|
|
55
55
|
if (!tx.data.constants.vkTreeRoot.equals(this.values.vkTreeRoot)) {
|
|
56
56
|
this.#log.verbose(
|
|
57
|
-
`Rejecting tx ${
|
|
58
|
-
tx,
|
|
59
|
-
)} because of incorrect vk tree root ${tx.data.constants.vkTreeRoot.toString()} != ${this.values.vkTreeRoot.toString()}`,
|
|
57
|
+
`Rejecting tx ${'txHash' in tx ? tx.txHash : tx.hash} because of incorrect vk tree root ${tx.data.constants.vkTreeRoot.toString()} != ${this.values.vkTreeRoot.toString()}`,
|
|
60
58
|
);
|
|
61
59
|
return false;
|
|
62
60
|
} else {
|
|
@@ -64,24 +62,20 @@ export class MetadataTxValidator<T extends AnyTx> implements TxValidator<T> {
|
|
|
64
62
|
}
|
|
65
63
|
}
|
|
66
64
|
|
|
67
|
-
|
|
65
|
+
#hasCorrectProtocolContractTreeRoot(tx: T): boolean {
|
|
68
66
|
if (!tx.data.constants.protocolContractTreeRoot.equals(this.values.protocolContractTreeRoot)) {
|
|
69
67
|
this.#log.verbose(
|
|
70
|
-
`Rejecting tx ${
|
|
71
|
-
tx,
|
|
72
|
-
)} because of incorrect protocol contract tree root ${tx.data.constants.protocolContractTreeRoot.toString()} != ${this.values.protocolContractTreeRoot.toString()}`,
|
|
68
|
+
`Rejecting tx ${'txHash' in tx ? tx.txHash : tx.hash} because of incorrect protocol contract tree root ${tx.data.constants.protocolContractTreeRoot.toString()} != ${this.values.protocolContractTreeRoot.toString()}`,
|
|
73
69
|
);
|
|
74
70
|
return false;
|
|
75
71
|
}
|
|
76
72
|
return true;
|
|
77
73
|
}
|
|
78
74
|
|
|
79
|
-
|
|
75
|
+
#hasCorrectL1ChainId(tx: T): boolean {
|
|
80
76
|
if (!tx.data.constants.txContext.chainId.equals(this.values.l1ChainId)) {
|
|
81
77
|
this.#log.verbose(
|
|
82
|
-
`Rejecting tx ${
|
|
83
|
-
tx,
|
|
84
|
-
)} because of incorrect L1 chain ${tx.data.constants.txContext.chainId.toNumber()} != ${this.values.l1ChainId.toNumber()}`,
|
|
78
|
+
`Rejecting tx ${'txHash' in tx ? tx.txHash : tx.hash} because of incorrect L1 chain ${tx.data.constants.txContext.chainId.toNumber()} != ${this.values.l1ChainId.toNumber()}`,
|
|
85
79
|
);
|
|
86
80
|
return false;
|
|
87
81
|
} else {
|
|
@@ -89,20 +83,22 @@ export class MetadataTxValidator<T extends AnyTx> implements TxValidator<T> {
|
|
|
89
83
|
}
|
|
90
84
|
}
|
|
91
85
|
|
|
92
|
-
|
|
93
|
-
const includeByTimestamp = tx.data.
|
|
86
|
+
#isValidForTimestamp(tx: T): boolean {
|
|
87
|
+
const includeByTimestamp = tx.data.includeByTimestamp;
|
|
94
88
|
// If building block 1, we skip the expiration check. For details on why see the `validate_include_by_timestamp`
|
|
95
89
|
// function in `noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/components/validation_requests.nr`.
|
|
96
90
|
const buildingBlock1 = this.values.blockNumber === 1;
|
|
97
91
|
|
|
98
|
-
if (!buildingBlock1 && includeByTimestamp
|
|
92
|
+
if (!buildingBlock1 && includeByTimestamp < this.values.timestamp) {
|
|
99
93
|
if (tx.data.constants.historicalHeader.globalVariables.blockNumber === 0) {
|
|
100
94
|
this.#log.warn(
|
|
101
95
|
`A tx built against a genesis block failed to be included in block 1 which is the only block in which txs built against a genesis block are allowed to be included.`,
|
|
102
96
|
);
|
|
103
97
|
}
|
|
104
98
|
this.#log.verbose(
|
|
105
|
-
`Rejecting tx ${
|
|
99
|
+
`Rejecting tx ${getTxHash(tx)} for low expiration timestamp. Tx expiration timestamp: ${includeByTimestamp}, timestamp: ${
|
|
100
|
+
this.values.timestamp
|
|
101
|
+
}.`,
|
|
106
102
|
);
|
|
107
103
|
return false;
|
|
108
104
|
} else {
|
|
@@ -110,12 +106,10 @@ export class MetadataTxValidator<T extends AnyTx> implements TxValidator<T> {
|
|
|
110
106
|
}
|
|
111
107
|
}
|
|
112
108
|
|
|
113
|
-
|
|
109
|
+
#hasCorrectRollupVersion(tx: T): boolean {
|
|
114
110
|
if (!tx.data.constants.txContext.version.equals(this.values.rollupVersion)) {
|
|
115
111
|
this.#log.verbose(
|
|
116
|
-
`Rejecting tx ${
|
|
117
|
-
tx,
|
|
118
|
-
)} because of incorrect rollup version ${tx.data.constants.txContext.version.toNumber()} != ${this.values.rollupVersion.toNumber()}`,
|
|
112
|
+
`Rejecting tx ${'txHash' in tx ? tx.txHash : tx.hash} because of incorrect rollup version ${tx.data.constants.txContext.version.toNumber()} != ${this.values.rollupVersion.toNumber()}`,
|
|
119
113
|
);
|
|
120
114
|
return false;
|
|
121
115
|
} else {
|