@aztec/p2p 1.0.0-staging.2 → 1.0.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.js +1 -1
- package/dest/client/p2p_client.js +1 -1
- package/dest/config.d.ts +2 -2
- package/dest/config.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts +4 -11
- 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 +10 -17
- package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts +2 -2
- package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/memory_tx_pool.js +2 -2
- package/dest/mem_pools/tx_pool/tx_pool.d.ts +2 -3
- 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 +3 -10
- package/dest/msg_validators/tx_validator/factory.d.ts +1 -2
- package/dest/msg_validators/tx_validator/factory.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/factory.js +2 -3
- package/dest/msg_validators/tx_validator/metadata_validator.d.ts +0 -2
- package/dest/msg_validators/tx_validator/metadata_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/metadata_validator.js +7 -13
- package/dest/msg_validators/tx_validator/phases_validator.d.ts +2 -3
- package/dest/msg_validators/tx_validator/phases_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/phases_validator.js +4 -4
- package/dest/services/libp2p/instrumentation.d.ts +1 -8
- package/dest/services/libp2p/instrumentation.d.ts.map +1 -1
- package/dest/services/libp2p/instrumentation.js +2 -130
- package/dest/services/libp2p/libp2p_service.d.ts +3 -8
- package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
- package/dest/services/libp2p/libp2p_service.js +14 -34
- package/dest/test-helpers/make-test-p2p-clients.d.ts.map +1 -1
- package/dest/test-helpers/make-test-p2p-clients.js +1 -2
- package/dest/test-helpers/reqresp-nodes.d.ts.map +1 -1
- package/dest/test-helpers/reqresp-nodes.js +2 -3
- package/dest/testbench/p2p_client_testbench_worker.js +0 -6
- package/dest/testbench/worker_client_manager.d.ts.map +1 -1
- package/dest/testbench/worker_client_manager.js +1 -2
- package/dest/util.d.ts +2 -3
- package/dest/util.d.ts.map +1 -1
- package/dest/util.js +5 -6
- package/package.json +13 -13
- package/src/bootstrap/bootstrap.ts +1 -1
- package/src/client/factory.ts +1 -1
- package/src/client/p2p_client.ts +1 -1
- package/src/config.ts +1 -2
- package/src/mem_pools/tx_pool/aztec_kv_tx_pool.ts +12 -22
- package/src/mem_pools/tx_pool/memory_tx_pool.ts +3 -3
- package/src/mem_pools/tx_pool/tx_pool.ts +2 -3
- package/src/mem_pools/tx_pool/tx_pool_test_suite.ts +4 -8
- package/src/msg_validators/tx_validator/factory.ts +1 -4
- package/src/msg_validators/tx_validator/metadata_validator.ts +9 -20
- package/src/msg_validators/tx_validator/phases_validator.ts +2 -3
- package/src/services/libp2p/instrumentation.ts +3 -122
- package/src/services/libp2p/libp2p_service.ts +15 -41
- package/src/test-helpers/make-test-p2p-clients.ts +1 -2
- package/src/test-helpers/reqresp-nodes.ts +2 -3
- package/src/testbench/p2p_client_testbench_worker.ts +0 -1
- package/src/testbench/worker_client_manager.ts +1 -2
- package/src/util.ts +7 -8
|
@@ -8,7 +8,7 @@ import type { MerkleTreeReadOperations, WorldStateSynchronizer } from '@aztec/st
|
|
|
8
8
|
import { ClientIvcProof } from '@aztec/stdlib/proofs';
|
|
9
9
|
import type { TxAddedToPoolStats } from '@aztec/stdlib/stats';
|
|
10
10
|
import { DatabasePublicStateSource } from '@aztec/stdlib/trees';
|
|
11
|
-
import {
|
|
11
|
+
import { Tx, TxHash } from '@aztec/stdlib/tx';
|
|
12
12
|
import { type TelemetryClient, getTelemetryClient } from '@aztec/telemetry-client';
|
|
13
13
|
|
|
14
14
|
import assert from 'assert';
|
|
@@ -129,14 +129,8 @@ export class AztecKVTxPool implements TxPool {
|
|
|
129
129
|
}
|
|
130
130
|
return true;
|
|
131
131
|
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
* Removes the transactions from the pending set and adds them to the mined set.
|
|
135
|
-
* Also evicts any transactions that become invalid after the block is mined.
|
|
136
|
-
* @param txHashes - Array of transaction hashes that were mined
|
|
137
|
-
* @param blockHeader - The header of the block the transactions were mined in
|
|
138
|
-
*/
|
|
139
|
-
public async markAsMined(txHashes: TxHash[], blockHeader: BlockHeader): Promise<void> {
|
|
132
|
+
|
|
133
|
+
public async markAsMined(txHashes: TxHash[], blockNumber: number): Promise<void> {
|
|
140
134
|
if (txHashes.length === 0) {
|
|
141
135
|
return Promise.resolve();
|
|
142
136
|
}
|
|
@@ -148,7 +142,7 @@ export class AztecKVTxPool implements TxPool {
|
|
|
148
142
|
let pendingTxSize = (await this.#pendingTxSize.getAsync()) ?? 0;
|
|
149
143
|
for (const hash of txHashes) {
|
|
150
144
|
const key = hash.toString();
|
|
151
|
-
await this.#minedTxHashToBlock.set(key,
|
|
145
|
+
await this.#minedTxHashToBlock.set(key, blockNumber);
|
|
152
146
|
|
|
153
147
|
const tx = await this.getPendingTxByHash(hash);
|
|
154
148
|
if (tx) {
|
|
@@ -161,7 +155,7 @@ export class AztecKVTxPool implements TxPool {
|
|
|
161
155
|
}
|
|
162
156
|
await this.#pendingTxSize.set(pendingTxSize);
|
|
163
157
|
|
|
164
|
-
await this.evictInvalidTxsAfterMining(txHashes,
|
|
158
|
+
await this.evictInvalidTxsAfterMining(txHashes, blockNumber, minedNullifiers, minedFeePayers);
|
|
165
159
|
});
|
|
166
160
|
// We update this after the transaction above. This ensures that the non-evictable transactions are not evicted
|
|
167
161
|
// until any that have been mined are marked as such.
|
|
@@ -541,15 +535,15 @@ export class AztecKVTxPool implements TxPool {
|
|
|
541
535
|
* Eviction criteria includes:
|
|
542
536
|
* - txs with nullifiers that are already included in the mined block
|
|
543
537
|
* - txs with an insufficient fee payer balance
|
|
544
|
-
* - txs with
|
|
538
|
+
* - txs with a max block number lower than the mined block
|
|
545
539
|
*
|
|
546
540
|
* @param minedTxHashes - The tx hashes of the txs mined in the block.
|
|
547
|
-
* @param
|
|
541
|
+
* @param blockNumber - The block number of the mined block.
|
|
548
542
|
* @returns The total number of txs evicted from the pool.
|
|
549
543
|
*/
|
|
550
544
|
private async evictInvalidTxsAfterMining(
|
|
551
545
|
minedTxHashes: TxHash[],
|
|
552
|
-
|
|
546
|
+
blockNumber: number,
|
|
553
547
|
minedNullifiers: Set<string>,
|
|
554
548
|
minedFeePayers: Set<string>,
|
|
555
549
|
): Promise<number> {
|
|
@@ -557,8 +551,6 @@ export class AztecKVTxPool implements TxPool {
|
|
|
557
551
|
return 0;
|
|
558
552
|
}
|
|
559
553
|
|
|
560
|
-
const { blockNumber, timestamp } = blockHeader.globalVariables;
|
|
561
|
-
|
|
562
554
|
// Wait for world state to be synced to at least the mined block number
|
|
563
555
|
await this.#worldStateSynchronizer.syncImmediate(blockNumber);
|
|
564
556
|
|
|
@@ -590,12 +582,10 @@ export class AztecKVTxPool implements TxPool {
|
|
|
590
582
|
continue;
|
|
591
583
|
}
|
|
592
584
|
|
|
593
|
-
// Evict pending txs with
|
|
594
|
-
const
|
|
595
|
-
if (
|
|
596
|
-
this.#log.verbose(
|
|
597
|
-
`Evicting tx ${txHash} from pool due to the tx being expired (includeByTimestamp: ${includeByTimestamp.value}, mined block timestamp: ${timestamp})`,
|
|
598
|
-
);
|
|
585
|
+
// Evict pending txs with a max block number less than or equal to the mined block
|
|
586
|
+
const maxBlockNumber = tx.data.rollupValidationRequests.maxBlockNumber;
|
|
587
|
+
if (maxBlockNumber.isSome && maxBlockNumber.value <= blockNumber) {
|
|
588
|
+
this.#log.verbose(`Evicting tx ${txHash} from pool due to an invalid max block number`);
|
|
599
589
|
txsToEvict.push(TxHash.fromString(txHash));
|
|
600
590
|
continue;
|
|
601
591
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createLogger } from '@aztec/foundation/log';
|
|
2
2
|
import type { TxAddedToPoolStats } from '@aztec/stdlib/stats';
|
|
3
|
-
import {
|
|
3
|
+
import { Tx, TxHash } from '@aztec/stdlib/tx';
|
|
4
4
|
import { type TelemetryClient, getTelemetryClient } from '@aztec/telemetry-client';
|
|
5
5
|
|
|
6
6
|
import { PoolInstrumentation, PoolName, type PoolStatsCallback } from '../instrumentation.js';
|
|
@@ -47,10 +47,10 @@ export class InMemoryTxPool implements TxPool {
|
|
|
47
47
|
return Promise.resolve(this.txs.size === 0);
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
public markAsMined(txHashes: TxHash[],
|
|
50
|
+
public markAsMined(txHashes: TxHash[], blockNumber: number): Promise<void> {
|
|
51
51
|
const keys = txHashes.map(x => x.toBigInt());
|
|
52
52
|
for (const key of keys) {
|
|
53
|
-
this.minedTxs.set(key,
|
|
53
|
+
this.minedTxs.set(key, blockNumber);
|
|
54
54
|
this.pendingTxs.delete(key);
|
|
55
55
|
}
|
|
56
56
|
return Promise.resolve();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Tx, TxHash } from '@aztec/stdlib/tx';
|
|
2
2
|
|
|
3
3
|
export type TxPoolOptions = {
|
|
4
4
|
maxTxPoolSize?: number;
|
|
@@ -48,9 +48,8 @@ export interface TxPool {
|
|
|
48
48
|
/**
|
|
49
49
|
* Marks the set of txs as mined, as opposed to pending.
|
|
50
50
|
* @param txHashes - Hashes of the txs to flag as mined.
|
|
51
|
-
* @param blockHeader - The header of the mined block.
|
|
52
51
|
*/
|
|
53
|
-
markAsMined(txHashes: TxHash[],
|
|
52
|
+
markAsMined(txHashes: TxHash[], blockNumber: number): Promise<void>;
|
|
54
53
|
|
|
55
54
|
/**
|
|
56
55
|
* Moves mined txs back to the pending set in the case of a reorg.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { unfreeze } from '@aztec/foundation/types';
|
|
2
2
|
import { GasFees } from '@aztec/stdlib/gas';
|
|
3
3
|
import { mockTx } from '@aztec/stdlib/testing';
|
|
4
|
-
import {
|
|
4
|
+
import type { Tx } from '@aztec/stdlib/tx';
|
|
5
5
|
|
|
6
6
|
import type { TxPool } from './tx_pool.js';
|
|
7
7
|
|
|
@@ -12,10 +12,6 @@ import type { TxPool } from './tx_pool.js';
|
|
|
12
12
|
export function describeTxPool(getTxPool: () => TxPool) {
|
|
13
13
|
let pool: TxPool;
|
|
14
14
|
|
|
15
|
-
const minedBlockHeader = BlockHeader.empty({
|
|
16
|
-
globalVariables: GlobalVariables.empty({ blockNumber: 1, timestamp: 0n }),
|
|
17
|
-
});
|
|
18
|
-
|
|
19
15
|
beforeEach(() => {
|
|
20
16
|
pool = getTxPool();
|
|
21
17
|
});
|
|
@@ -47,7 +43,7 @@ export function describeTxPool(getTxPool: () => TxPool) {
|
|
|
47
43
|
const tx2 = await mockTx(2);
|
|
48
44
|
|
|
49
45
|
await pool.addTxs([tx1, tx2]);
|
|
50
|
-
await pool.markAsMined([await tx1.getTxHash()],
|
|
46
|
+
await pool.markAsMined([await tx1.getTxHash()], 1);
|
|
51
47
|
|
|
52
48
|
await expect(pool.getTxByHash(await tx1.getTxHash())).resolves.toEqual(tx1);
|
|
53
49
|
await expect(pool.getTxStatus(await tx1.getTxHash())).resolves.toEqual('mined');
|
|
@@ -61,7 +57,7 @@ export function describeTxPool(getTxPool: () => TxPool) {
|
|
|
61
57
|
const tx2 = await mockTx(2);
|
|
62
58
|
|
|
63
59
|
await pool.addTxs([tx1, tx2]);
|
|
64
|
-
await pool.markAsMined([await tx1.getTxHash()],
|
|
60
|
+
await pool.markAsMined([await tx1.getTxHash()], 1);
|
|
65
61
|
|
|
66
62
|
await pool.markMinedAsPending([await tx1.getTxHash()]);
|
|
67
63
|
await expect(pool.getMinedTxHashes()).resolves.toEqual([]);
|
|
@@ -78,7 +74,7 @@ export function describeTxPool(getTxPool: () => TxPool) {
|
|
|
78
74
|
const someTxHashThatThisPeerDidNotSee = await tx2.getTxHash();
|
|
79
75
|
await pool.addTxs([tx1]);
|
|
80
76
|
// this peer knows that tx2 was mined, but it does not have the tx object
|
|
81
|
-
await pool.markAsMined([await tx1.getTxHash(), someTxHashThatThisPeerDidNotSee],
|
|
77
|
+
await pool.markAsMined([await tx1.getTxHash(), someTxHashThatThisPeerDidNotSee], 1);
|
|
82
78
|
expect(await pool.getMinedTxHashes()).toEqual(
|
|
83
79
|
expect.arrayContaining([
|
|
84
80
|
[await tx1.getTxHash(), 1],
|
|
@@ -11,7 +11,6 @@ import type {
|
|
|
11
11
|
import { PeerErrorSeverity } from '@aztec/stdlib/p2p';
|
|
12
12
|
import { DatabasePublicStateSource, MerkleTreeId } from '@aztec/stdlib/trees';
|
|
13
13
|
import type { Tx, TxValidationResult } from '@aztec/stdlib/tx';
|
|
14
|
-
import type { UInt64 } from '@aztec/stdlib/types';
|
|
15
14
|
|
|
16
15
|
import { ArchiveCache } from './archive_cache.js';
|
|
17
16
|
import { BlockHeaderTxValidator } from './block_header_validator.js';
|
|
@@ -30,7 +29,6 @@ export interface MessageValidator {
|
|
|
30
29
|
}
|
|
31
30
|
|
|
32
31
|
export function createTxMessageValidators(
|
|
33
|
-
timestamp: UInt64,
|
|
34
32
|
blockNumber: number,
|
|
35
33
|
worldStateSynchronizer: WorldStateSynchronizer,
|
|
36
34
|
gasFees: GasFees,
|
|
@@ -53,7 +51,6 @@ export function createTxMessageValidators(
|
|
|
53
51
|
validator: new MetadataTxValidator({
|
|
54
52
|
l1ChainId: new Fr(l1ChainId),
|
|
55
53
|
rollupVersion: new Fr(rollupVersion),
|
|
56
|
-
timestamp,
|
|
57
54
|
blockNumber,
|
|
58
55
|
protocolContractTreeRoot,
|
|
59
56
|
vkTreeRoot: getVKTreeRoot(),
|
|
@@ -79,7 +76,7 @@ export function createTxMessageValidators(
|
|
|
79
76
|
severity: PeerErrorSeverity.HighToleranceError,
|
|
80
77
|
},
|
|
81
78
|
phasesValidator: {
|
|
82
|
-
validator: new PhasesTxValidator(contractDataSource, allowedInSetup,
|
|
79
|
+
validator: new PhasesTxValidator(contractDataSource, allowedInSetup, blockNumber),
|
|
83
80
|
severity: PeerErrorSeverity.MidToleranceError,
|
|
84
81
|
},
|
|
85
82
|
blockHeaderValidator: {
|
|
@@ -6,12 +6,11 @@ import {
|
|
|
6
6
|
TX_ERROR_INCORRECT_PROTOCOL_CONTRACT_TREE_ROOT,
|
|
7
7
|
TX_ERROR_INCORRECT_ROLLUP_VERSION,
|
|
8
8
|
TX_ERROR_INCORRECT_VK_TREE_ROOT,
|
|
9
|
-
|
|
9
|
+
TX_ERROR_INVALID_MAX_BLOCK_NUMBER,
|
|
10
10
|
Tx,
|
|
11
11
|
type TxValidationResult,
|
|
12
12
|
type TxValidator,
|
|
13
13
|
} from '@aztec/stdlib/tx';
|
|
14
|
-
import type { UInt64 } from '@aztec/stdlib/types';
|
|
15
14
|
|
|
16
15
|
export class MetadataTxValidator<T extends AnyTx> implements TxValidator<T> {
|
|
17
16
|
#log = createLogger('p2p:tx_validator:tx_metadata');
|
|
@@ -20,10 +19,6 @@ export class MetadataTxValidator<T extends AnyTx> implements TxValidator<T> {
|
|
|
20
19
|
private values: {
|
|
21
20
|
l1ChainId: Fr;
|
|
22
21
|
rollupVersion: Fr;
|
|
23
|
-
// Timestamp at which we will validate that the tx is not expired. This is typically the timestamp of the block
|
|
24
|
-
// being built.
|
|
25
|
-
timestamp: UInt64;
|
|
26
|
-
// Block number in which the tx is considered to be included.
|
|
27
22
|
blockNumber: number;
|
|
28
23
|
vkTreeRoot: Fr;
|
|
29
24
|
protocolContractTreeRoot: Fr;
|
|
@@ -38,8 +33,8 @@ export class MetadataTxValidator<T extends AnyTx> implements TxValidator<T> {
|
|
|
38
33
|
if (!(await this.#hasCorrectRollupVersion(tx))) {
|
|
39
34
|
errors.push(TX_ERROR_INCORRECT_ROLLUP_VERSION);
|
|
40
35
|
}
|
|
41
|
-
if (!(await this.#
|
|
42
|
-
errors.push(
|
|
36
|
+
if (!(await this.#isValidForBlockNumber(tx))) {
|
|
37
|
+
errors.push(TX_ERROR_INVALID_MAX_BLOCK_NUMBER);
|
|
43
38
|
}
|
|
44
39
|
if (!(await this.#hasCorrectVkTreeRoot(tx))) {
|
|
45
40
|
errors.push(TX_ERROR_INCORRECT_VK_TREE_ROOT);
|
|
@@ -89,20 +84,14 @@ export class MetadataTxValidator<T extends AnyTx> implements TxValidator<T> {
|
|
|
89
84
|
}
|
|
90
85
|
}
|
|
91
86
|
|
|
92
|
-
async #
|
|
93
|
-
const
|
|
94
|
-
// If building block 1, we skip the expiration check. For details on why see the `validate_include_by_timestamp`
|
|
95
|
-
// function in `noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/components/validation_requests.nr`.
|
|
96
|
-
const buildingBlock1 = this.values.blockNumber === 1;
|
|
87
|
+
async #isValidForBlockNumber(tx: T): Promise<boolean> {
|
|
88
|
+
const maxBlockNumber = tx.data.rollupValidationRequests.maxBlockNumber;
|
|
97
89
|
|
|
98
|
-
if (
|
|
99
|
-
if (tx.data.constants.historicalHeader.globalVariables.blockNumber === 0) {
|
|
100
|
-
this.#log.warn(
|
|
101
|
-
`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
|
-
);
|
|
103
|
-
}
|
|
90
|
+
if (maxBlockNumber.isSome && maxBlockNumber.value < this.values.blockNumber) {
|
|
104
91
|
this.#log.verbose(
|
|
105
|
-
`Rejecting tx ${await Tx.getHash(tx)} for low
|
|
92
|
+
`Rejecting tx ${await Tx.getHash(tx)} for low max block number. Tx max block number: ${
|
|
93
|
+
maxBlockNumber.value
|
|
94
|
+
}, current block number: ${this.values.blockNumber}.`,
|
|
106
95
|
);
|
|
107
96
|
return false;
|
|
108
97
|
} else {
|
|
@@ -11,7 +11,6 @@ import {
|
|
|
11
11
|
type TxValidationResult,
|
|
12
12
|
type TxValidator,
|
|
13
13
|
} from '@aztec/stdlib/tx';
|
|
14
|
-
import type { UInt64 } from '@aztec/stdlib/types';
|
|
15
14
|
|
|
16
15
|
export class PhasesTxValidator implements TxValidator<Tx> {
|
|
17
16
|
#log = createLogger('sequencer:tx_validator:tx_phases');
|
|
@@ -20,7 +19,7 @@ export class PhasesTxValidator implements TxValidator<Tx> {
|
|
|
20
19
|
constructor(
|
|
21
20
|
contracts: ContractDataSource,
|
|
22
21
|
private setupAllowList: AllowedElement[],
|
|
23
|
-
private
|
|
22
|
+
private blockNumber: number,
|
|
24
23
|
) {
|
|
25
24
|
this.contractsDB = new PublicContractsDB(contracts);
|
|
26
25
|
}
|
|
@@ -87,7 +86,7 @@ export class PhasesTxValidator implements TxValidator<Tx> {
|
|
|
87
86
|
}
|
|
88
87
|
}
|
|
89
88
|
|
|
90
|
-
const contractClass = await this.contractsDB.getContractInstance(contractAddress, this.
|
|
89
|
+
const contractClass = await this.contractsDB.getContractInstance(contractAddress, this.blockNumber);
|
|
91
90
|
|
|
92
91
|
if (!contractClass) {
|
|
93
92
|
throw new Error(`Contract not found: ${contractAddress}`);
|
|
@@ -1,28 +1,17 @@
|
|
|
1
1
|
import type { Timer } from '@aztec/foundation/timer';
|
|
2
|
-
import { TopicType } from '@aztec/stdlib/p2p';
|
|
2
|
+
import type { TopicType } from '@aztec/stdlib/p2p';
|
|
3
3
|
import {
|
|
4
4
|
Attributes,
|
|
5
|
-
type BatchObservableResult,
|
|
6
5
|
type Histogram,
|
|
7
6
|
Metrics,
|
|
8
|
-
type ObservableGauge,
|
|
9
7
|
type TelemetryClient,
|
|
10
8
|
type UpDownCounter,
|
|
11
9
|
ValueType,
|
|
12
10
|
} from '@aztec/telemetry-client';
|
|
13
11
|
|
|
14
|
-
import { type RecordableHistogram, createHistogram } from 'node:perf_hooks';
|
|
15
|
-
|
|
16
12
|
export class P2PInstrumentation {
|
|
17
13
|
private messageValidationDuration: Histogram;
|
|
18
14
|
private messagePrevalidationCount: UpDownCounter;
|
|
19
|
-
private messageLatency: Histogram;
|
|
20
|
-
|
|
21
|
-
private aggLatencyHisto = new Map<TopicType, RecordableHistogram>();
|
|
22
|
-
private aggValidationHisto = new Map<TopicType, RecordableHistogram>();
|
|
23
|
-
|
|
24
|
-
private aggLatencyMetrics: Record<'min' | 'max' | 'p50' | 'p90' | 'avg', ObservableGauge>;
|
|
25
|
-
private aggValidationMetrics: Record<'min' | 'max' | 'p50' | 'p90' | 'avg', ObservableGauge>;
|
|
26
15
|
|
|
27
16
|
constructor(client: TelemetryClient, name: string) {
|
|
28
17
|
const meter = client.getMeter(name);
|
|
@@ -37,122 +26,14 @@ export class P2PInstrumentation {
|
|
|
37
26
|
description: 'How many message pass/fail prevalidation',
|
|
38
27
|
valueType: ValueType.INT,
|
|
39
28
|
});
|
|
40
|
-
|
|
41
|
-
this.messageLatency = meter.createHistogram(Metrics.P2P_GOSSIP_MESSAGE_LATENCY, {
|
|
42
|
-
unit: 'ms',
|
|
43
|
-
description: 'P2P message latency',
|
|
44
|
-
valueType: ValueType.INT,
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
this.aggLatencyMetrics = {
|
|
48
|
-
avg: meter.createObservableGauge(Metrics.P2P_GOSSIP_AGG_MESSAGE_LATENCY_AVG, {
|
|
49
|
-
valueType: ValueType.DOUBLE,
|
|
50
|
-
description: 'AVG msg latency',
|
|
51
|
-
unit: 'ms',
|
|
52
|
-
}),
|
|
53
|
-
max: meter.createObservableGauge(Metrics.P2P_GOSSIP_AGG_MESSAGE_LATENCY_MAX, {
|
|
54
|
-
valueType: ValueType.DOUBLE,
|
|
55
|
-
description: 'MAX msg latency',
|
|
56
|
-
unit: 'ms',
|
|
57
|
-
}),
|
|
58
|
-
min: meter.createObservableGauge(Metrics.P2P_GOSSIP_AGG_MESSAGE_LATENCY_MIN, {
|
|
59
|
-
valueType: ValueType.DOUBLE,
|
|
60
|
-
description: 'MIN msg latency',
|
|
61
|
-
unit: 'ms',
|
|
62
|
-
}),
|
|
63
|
-
p50: meter.createObservableGauge(Metrics.P2P_GOSSIP_AGG_MESSAGE_LATENCY_P50, {
|
|
64
|
-
valueType: ValueType.DOUBLE,
|
|
65
|
-
description: 'P50 msg latency',
|
|
66
|
-
unit: 'ms',
|
|
67
|
-
}),
|
|
68
|
-
p90: meter.createObservableGauge(Metrics.P2P_GOSSIP_AGG_MESSAGE_LATENCY_P90, {
|
|
69
|
-
valueType: ValueType.DOUBLE,
|
|
70
|
-
description: 'P90 msg latency',
|
|
71
|
-
unit: 'ms',
|
|
72
|
-
}),
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
this.aggValidationMetrics = {
|
|
76
|
-
avg: meter.createObservableGauge(Metrics.P2P_GOSSIP_AGG_MESSAGE_VALIDATION_DURATION_AVG, {
|
|
77
|
-
valueType: ValueType.DOUBLE,
|
|
78
|
-
description: 'AVG msg validation',
|
|
79
|
-
unit: 'ms',
|
|
80
|
-
}),
|
|
81
|
-
max: meter.createObservableGauge(Metrics.P2P_GOSSIP_AGG_MESSAGE_VALIDATION_DURATION_MAX, {
|
|
82
|
-
valueType: ValueType.DOUBLE,
|
|
83
|
-
description: 'MAX msg validation',
|
|
84
|
-
unit: 'ms',
|
|
85
|
-
}),
|
|
86
|
-
min: meter.createObservableGauge(Metrics.P2P_GOSSIP_AGG_MESSAGE_VALIDATION_DURATION_MIN, {
|
|
87
|
-
valueType: ValueType.DOUBLE,
|
|
88
|
-
description: 'MIN msg validation',
|
|
89
|
-
unit: 'ms',
|
|
90
|
-
}),
|
|
91
|
-
p50: meter.createObservableGauge(Metrics.P2P_GOSSIP_AGG_MESSAGE_VALIDATION_DURATION_P50, {
|
|
92
|
-
valueType: ValueType.DOUBLE,
|
|
93
|
-
description: 'P50 msg validation',
|
|
94
|
-
unit: 'ms',
|
|
95
|
-
}),
|
|
96
|
-
p90: meter.createObservableGauge(Metrics.P2P_GOSSIP_AGG_MESSAGE_VALIDATION_DURATION_P90, {
|
|
97
|
-
valueType: ValueType.DOUBLE,
|
|
98
|
-
description: 'P90 msg validation',
|
|
99
|
-
unit: 'ms',
|
|
100
|
-
}),
|
|
101
|
-
};
|
|
102
|
-
|
|
103
|
-
meter.addBatchObservableCallback(this.aggregate, [
|
|
104
|
-
...Object.values(this.aggValidationMetrics),
|
|
105
|
-
...Object.values(this.aggLatencyMetrics),
|
|
106
|
-
]);
|
|
107
29
|
}
|
|
108
30
|
|
|
109
31
|
public recordMessageValidation(topicName: TopicType, timerOrMs: Timer | number) {
|
|
110
|
-
const ms =
|
|
111
|
-
this.messageValidationDuration.record(ms, { [Attributes.TOPIC_NAME]: topicName });
|
|
112
|
-
|
|
113
|
-
let validationHistogram = this.aggValidationHisto.get(topicName);
|
|
114
|
-
if (!validationHistogram) {
|
|
115
|
-
validationHistogram = createHistogram({ min: 1, max: 5 * 60 * 1000 }); // 5 mins
|
|
116
|
-
this.aggValidationHisto.set(topicName, validationHistogram);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
validationHistogram.record(Math.max(ms, 1));
|
|
32
|
+
const ms = typeof timerOrMs === 'number' ? timerOrMs : timerOrMs.ms();
|
|
33
|
+
this.messageValidationDuration.record(Math.ceil(ms), { [Attributes.TOPIC_NAME]: topicName });
|
|
120
34
|
}
|
|
121
35
|
|
|
122
36
|
public incMessagePrevalidationStatus(passed: boolean, topicName: TopicType | undefined) {
|
|
123
37
|
this.messagePrevalidationCount.add(1, { [Attributes.TOPIC_NAME]: topicName, [Attributes.OK]: passed });
|
|
124
38
|
}
|
|
125
|
-
|
|
126
|
-
public recordMessageLatency(topicName: TopicType, timerOrMs: Timer | number) {
|
|
127
|
-
const ms = Math.ceil(typeof timerOrMs === 'number' ? timerOrMs : timerOrMs.ms());
|
|
128
|
-
this.messageLatency.record(ms, { [Attributes.TOPIC_NAME]: topicName });
|
|
129
|
-
|
|
130
|
-
let latencyHistogram = this.aggLatencyHisto.get(topicName);
|
|
131
|
-
if (!latencyHistogram) {
|
|
132
|
-
latencyHistogram = createHistogram({ min: 1, max: 24 * 60 * 60 * 1000 }); // 24hrs
|
|
133
|
-
this.aggLatencyHisto.set(topicName, latencyHistogram);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
latencyHistogram.record(Math.max(ms, 1));
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
private aggregate = (res: BatchObservableResult) => {
|
|
140
|
-
for (const [metrics, histograms] of [
|
|
141
|
-
[this.aggLatencyMetrics, this.aggLatencyHisto],
|
|
142
|
-
[this.aggValidationMetrics, this.aggValidationHisto],
|
|
143
|
-
] as const) {
|
|
144
|
-
for (const topicName of Object.values(TopicType)) {
|
|
145
|
-
const histogram = histograms.get(topicName);
|
|
146
|
-
if (!histogram) {
|
|
147
|
-
continue;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
res.observe(metrics.avg, histogram.mean, { [Attributes.TOPIC_NAME]: topicName });
|
|
151
|
-
res.observe(metrics.max, histogram.max, { [Attributes.TOPIC_NAME]: topicName });
|
|
152
|
-
res.observe(metrics.min, histogram.min, { [Attributes.TOPIC_NAME]: topicName });
|
|
153
|
-
res.observe(metrics.p50, histogram.percentile(50), { [Attributes.TOPIC_NAME]: topicName });
|
|
154
|
-
res.observe(metrics.p90, histogram.percentile(90), { [Attributes.TOPIC_NAME]: topicName });
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
};
|
|
158
39
|
}
|
|
@@ -23,7 +23,6 @@ import {
|
|
|
23
23
|
} from '@aztec/stdlib/p2p';
|
|
24
24
|
import { MerkleTreeId } from '@aztec/stdlib/trees';
|
|
25
25
|
import { Tx, type TxHash, type TxValidationResult } from '@aztec/stdlib/tx';
|
|
26
|
-
import type { UInt64 } from '@aztec/stdlib/types';
|
|
27
26
|
import { compressComponentVersions } from '@aztec/stdlib/versioning';
|
|
28
27
|
import { Attributes, OtelMetricsAdapter, type TelemetryClient, WithTracer, trackSpan } from '@aztec/telemetry-client';
|
|
29
28
|
|
|
@@ -126,7 +125,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
126
125
|
private peerManager: PeerManagerInterface,
|
|
127
126
|
protected mempools: MemPools<T>,
|
|
128
127
|
private archiver: L2BlockSource & ContractDataSource,
|
|
129
|
-
|
|
128
|
+
epochCache: EpochCacheInterface,
|
|
130
129
|
private proofVerifier: ClientProtocolCircuitVerifier,
|
|
131
130
|
private worldStateSynchronizer: WorldStateSynchronizer,
|
|
132
131
|
telemetry: TelemetryClient,
|
|
@@ -537,11 +536,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
537
536
|
return result.recipients.length;
|
|
538
537
|
}
|
|
539
538
|
|
|
540
|
-
protected preValidateReceivedMessage(
|
|
541
|
-
msg: Message,
|
|
542
|
-
msgId: string,
|
|
543
|
-
source: PeerId,
|
|
544
|
-
): { result: boolean; topicType?: TopicType } {
|
|
539
|
+
protected preValidateReceivedMessage(msg: Message, msgId: string, source: PeerId) {
|
|
545
540
|
let topicType: TopicType | undefined;
|
|
546
541
|
|
|
547
542
|
switch (msg.topic) {
|
|
@@ -564,12 +559,12 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
564
559
|
if (!validator || !validator.addMessage(msgId)) {
|
|
565
560
|
this.instrumentation.incMessagePrevalidationStatus(false, topicType);
|
|
566
561
|
this.node.services.pubsub.reportMessageValidationResult(msgId, source.toString(), TopicValidatorResult.Ignore);
|
|
567
|
-
return
|
|
562
|
+
return false;
|
|
568
563
|
}
|
|
569
564
|
|
|
570
565
|
this.instrumentation.incMessagePrevalidationStatus(true, topicType);
|
|
571
566
|
|
|
572
|
-
return
|
|
567
|
+
return true;
|
|
573
568
|
}
|
|
574
569
|
|
|
575
570
|
/**
|
|
@@ -587,15 +582,8 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
587
582
|
messageLatency,
|
|
588
583
|
});
|
|
589
584
|
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
if (!preValidationResult.result) {
|
|
585
|
+
if (!this.preValidateReceivedMessage(msg, msgId, source)) {
|
|
593
586
|
return;
|
|
594
|
-
} else if (preValidationResult.topicType !== undefined) {
|
|
595
|
-
// guard against clock skew & DST
|
|
596
|
-
if (messageLatency > 0) {
|
|
597
|
-
this.instrumentation.recordMessageLatency(preValidationResult.topicType, messageLatency);
|
|
598
|
-
}
|
|
599
587
|
}
|
|
600
588
|
|
|
601
589
|
if (msg.topic === this.topicStrings[TopicType.tx]) {
|
|
@@ -839,11 +827,8 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
839
827
|
[Attributes.TX_HASH]: (await tx.getTxHash()).toString(),
|
|
840
828
|
}))
|
|
841
829
|
private async validatePropagatedTx(tx: Tx, peerId: PeerId): Promise<boolean> {
|
|
842
|
-
const
|
|
843
|
-
|
|
844
|
-
// We accept transactions if they are not expired by the next slot (checked based on the IncludeByTimestamp field)
|
|
845
|
-
const { ts: nextSlotTimestamp } = this.epochCache.getEpochAndSlotInNextL1Slot();
|
|
846
|
-
const messageValidators = await this.createMessageValidators(currentBlockNumber, nextSlotTimestamp);
|
|
830
|
+
const blockNumber = (await this.archiver.getBlockNumber()) + 1;
|
|
831
|
+
const messageValidators = await this.createMessageValidators(blockNumber);
|
|
847
832
|
|
|
848
833
|
for (const validator of messageValidators) {
|
|
849
834
|
const outcome = await this.runValidations(tx, validator);
|
|
@@ -856,8 +841,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
856
841
|
|
|
857
842
|
// Double spend validator has a special case handler
|
|
858
843
|
if (name === 'doubleSpendValidator') {
|
|
859
|
-
|
|
860
|
-
severity = await this.handleDoubleSpendFailure(tx, txBlockNumber);
|
|
844
|
+
severity = await this.handleDoubleSpendFailure(tx, blockNumber);
|
|
861
845
|
}
|
|
862
846
|
|
|
863
847
|
this.peerManager.penalizePeer(peerId, severity);
|
|
@@ -878,11 +862,8 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
878
862
|
}
|
|
879
863
|
|
|
880
864
|
public async validate(txs: Tx[]): Promise<void> {
|
|
881
|
-
const
|
|
882
|
-
|
|
883
|
-
// We accept transactions if they are not expired by the next slot (checked based on the IncludeByTimestamp field)
|
|
884
|
-
const { ts: nextSlotTimestamp } = this.epochCache.getEpochAndSlotInNextL1Slot();
|
|
885
|
-
const messageValidators = await this.createMessageValidators(currentBlockNumber, nextSlotTimestamp);
|
|
865
|
+
const blockNumber = (await this.archiver.getBlockNumber()) + 1;
|
|
866
|
+
const messageValidators = await this.createMessageValidators(blockNumber);
|
|
886
867
|
|
|
887
868
|
await Promise.all(
|
|
888
869
|
txs.map(async tx => {
|
|
@@ -897,27 +878,20 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
897
878
|
}
|
|
898
879
|
|
|
899
880
|
/**
|
|
900
|
-
* Create message validators for the given block number
|
|
881
|
+
* Create message validators for the given block number.
|
|
901
882
|
*
|
|
902
883
|
* Each validator is a pair of a validator and a severity.
|
|
903
884
|
* If a validator fails, the peer is penalized with the severity of the validator.
|
|
904
885
|
*
|
|
905
|
-
* @param
|
|
906
|
-
* @param nextSlotTimestamp - The timestamp of the next slot (used to validate txs are not expired).
|
|
886
|
+
* @param blockNumber - The block number to create validators for.
|
|
907
887
|
* @returns The message validators.
|
|
908
888
|
*/
|
|
909
|
-
private async createMessageValidators(
|
|
910
|
-
|
|
911
|
-
nextSlotTimestamp: UInt64,
|
|
912
|
-
): Promise<Record<string, MessageValidator>[]> {
|
|
913
|
-
const gasFees = await this.getGasFees(currentBlockNumber);
|
|
889
|
+
private async createMessageValidators(blockNumber: number): Promise<Record<string, MessageValidator>[]> {
|
|
890
|
+
const gasFees = await this.getGasFees(blockNumber - 1);
|
|
914
891
|
const allowedInSetup = this.config.txPublicSetupAllowList ?? (await getDefaultAllowedSetupFunctions());
|
|
915
892
|
|
|
916
|
-
const blockNumberInWhichTheTxIsConsideredToBeIncluded = currentBlockNumber + 1;
|
|
917
|
-
|
|
918
893
|
return createTxMessageValidators(
|
|
919
|
-
|
|
920
|
-
blockNumberInWhichTheTxIsConsideredToBeIncluded,
|
|
894
|
+
blockNumber,
|
|
921
895
|
this.worldStateSynchronizer,
|
|
922
896
|
gasFees,
|
|
923
897
|
this.config.l1ChainId,
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { MockL2BlockSource } from '@aztec/archiver/test';
|
|
2
2
|
import type { EpochCache } from '@aztec/epoch-cache';
|
|
3
|
-
import { SecretValue } from '@aztec/foundation/config';
|
|
4
3
|
import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
5
4
|
import { sleep } from '@aztec/foundation/sleep';
|
|
6
5
|
import type { DataStoreConfig } from '@aztec/kv-store/config';
|
|
@@ -79,7 +78,7 @@ export async function makeTestP2PClient(
|
|
|
79
78
|
const config: P2PConfig & DataStoreConfig = {
|
|
80
79
|
...p2pBaseConfig,
|
|
81
80
|
p2pEnabled: true,
|
|
82
|
-
peerIdPrivateKey
|
|
81
|
+
peerIdPrivateKey,
|
|
83
82
|
p2pIp: `127.0.0.1`,
|
|
84
83
|
listenAddress: `127.0.0.1`,
|
|
85
84
|
p2pPort: port,
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { EpochCache } from '@aztec/epoch-cache';
|
|
2
2
|
import { timesParallel } from '@aztec/foundation/collection';
|
|
3
|
-
import { SecretValue } from '@aztec/foundation/config';
|
|
4
3
|
import { createLogger } from '@aztec/foundation/log';
|
|
5
4
|
import type { DataStoreConfig } from '@aztec/kv-store/config';
|
|
6
5
|
import { openTmpStore } from '@aztec/kv-store/lmdb-v2';
|
|
@@ -126,7 +125,7 @@ export async function createTestLibP2PService<T extends P2PClientType>(
|
|
|
126
125
|
peerCheckIntervalMS: 1000,
|
|
127
126
|
maxPeerCount: 5,
|
|
128
127
|
p2pEnabled: true,
|
|
129
|
-
peerIdPrivateKey:
|
|
128
|
+
peerIdPrivateKey: Buffer.from(peerId.privateKey!).toString('hex'),
|
|
130
129
|
bootstrapNodeEnrVersionCheck: false,
|
|
131
130
|
...chainConfig,
|
|
132
131
|
} as P2PConfig & DataStoreConfig;
|
|
@@ -279,7 +278,7 @@ export function createBootstrapNodeConfig(privateKey: string, port: number, chai
|
|
|
279
278
|
l1ChainId: chainConfig.l1ChainId,
|
|
280
279
|
p2pIp: '127.0.0.1',
|
|
281
280
|
p2pPort: port,
|
|
282
|
-
peerIdPrivateKey:
|
|
281
|
+
peerIdPrivateKey: privateKey,
|
|
283
282
|
dataDirectory: undefined,
|
|
284
283
|
dataStoreMapSizeKB: 0,
|
|
285
284
|
bootstrapNodes: [],
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { SecretValue } from '@aztec/foundation/config';
|
|
2
1
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
3
2
|
import type { Logger } from '@aztec/foundation/log';
|
|
4
3
|
import { sleep } from '@aztec/foundation/sleep';
|
|
@@ -56,7 +55,7 @@ class WorkerClientManager {
|
|
|
56
55
|
return {
|
|
57
56
|
...getP2PDefaultConfig(),
|
|
58
57
|
p2pEnabled: true,
|
|
59
|
-
peerIdPrivateKey:
|
|
58
|
+
peerIdPrivateKey: this.peerIdPrivateKeys[clientIndex],
|
|
60
59
|
listenAddress: '127.0.0.1',
|
|
61
60
|
p2pIp: '127.0.0.1',
|
|
62
61
|
p2pPort: port,
|