@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,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, type TxValidationResult, type TxValidator } from '@aztec/stdlib/tx';
|
|
3
|
+
import { type AnyTx, TX_ERROR_BLOCK_HEADER, Tx, type TxValidationResult, type TxValidator } from '@aztec/stdlib/tx';
|
|
4
4
|
|
|
5
5
|
export interface ArchiveSource {
|
|
6
6
|
getArchiveIndices: (archives: Fr[]) => Promise<(bigint | undefined)[]>;
|
|
@@ -18,7 +18,7 @@ export class BlockHeaderTxValidator<T extends AnyTx> implements TxValidator<T> {
|
|
|
18
18
|
const [index] = await this.#archiveSource.getArchiveIndices([await tx.data.constants.historicalHeader.hash()]);
|
|
19
19
|
if (index === undefined) {
|
|
20
20
|
this.#log.warn(`Rejecting tx ${await Tx.getHash(tx)} for referencing an unknown block header`);
|
|
21
|
-
return { result: 'invalid', reason: [
|
|
21
|
+
return { result: 'invalid', reason: [TX_ERROR_BLOCK_HEADER] };
|
|
22
22
|
}
|
|
23
23
|
return { result: 'valid' };
|
|
24
24
|
}
|
|
@@ -1,7 +1,18 @@
|
|
|
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 {
|
|
4
|
+
import {
|
|
5
|
+
TX_ERROR_CALLDATA_COUNT_MISMATCH,
|
|
6
|
+
TX_ERROR_CALLDATA_COUNT_TOO_LARGE,
|
|
7
|
+
TX_ERROR_CONTRACT_CLASS_LOGS,
|
|
8
|
+
TX_ERROR_CONTRACT_CLASS_LOG_COUNT,
|
|
9
|
+
TX_ERROR_CONTRACT_CLASS_LOG_LENGTH,
|
|
10
|
+
TX_ERROR_CONTRACT_CLASS_LOG_SORTING,
|
|
11
|
+
TX_ERROR_INCORRECT_CALLDATA,
|
|
12
|
+
Tx,
|
|
13
|
+
type TxValidationResult,
|
|
14
|
+
type TxValidator,
|
|
15
|
+
} from '@aztec/stdlib/tx';
|
|
5
16
|
|
|
6
17
|
export class DataTxValidator implements TxValidator<Tx> {
|
|
7
18
|
#log = createLogger('p2p:tx_validator:tx_data');
|
|
@@ -14,7 +25,7 @@ export class DataTxValidator implements TxValidator<Tx> {
|
|
|
14
25
|
|
|
15
26
|
async #hasCorrectCalldata(tx: Tx): Promise<TxValidationResult> {
|
|
16
27
|
if (tx.publicFunctionCalldata.length !== tx.numberOfPublicCalls()) {
|
|
17
|
-
const reason =
|
|
28
|
+
const reason = TX_ERROR_CALLDATA_COUNT_MISMATCH;
|
|
18
29
|
this.#log.warn(
|
|
19
30
|
`Rejecting tx ${await Tx.getHash(tx)}. Reason: ${reason}. Expected ${tx.numberOfPublicCalls()}. Got ${
|
|
20
31
|
tx.publicFunctionCalldata.length
|
|
@@ -24,7 +35,7 @@ export class DataTxValidator implements TxValidator<Tx> {
|
|
|
24
35
|
}
|
|
25
36
|
|
|
26
37
|
if (tx.getTotalPublicCalldataCount() > MAX_FR_CALLDATA_TO_ALL_ENQUEUED_CALLS) {
|
|
27
|
-
const reason =
|
|
38
|
+
const reason = TX_ERROR_CALLDATA_COUNT_TOO_LARGE;
|
|
28
39
|
this.#log.warn(
|
|
29
40
|
`Rejecting tx ${await Tx.getHash(
|
|
30
41
|
tx,
|
|
@@ -38,7 +49,7 @@ export class DataTxValidator implements TxValidator<Tx> {
|
|
|
38
49
|
const { request, calldata } = callRequests[i];
|
|
39
50
|
const hash = await computeCalldataHash(calldata);
|
|
40
51
|
if (!hash.equals(request.calldataHash)) {
|
|
41
|
-
const reason =
|
|
52
|
+
const reason = TX_ERROR_INCORRECT_CALLDATA;
|
|
42
53
|
this.#log.warn(`Rejecting tx ${await Tx.getHash(tx)}. Reason: ${reason}. Call request index: ${i}.`);
|
|
43
54
|
return { result: 'invalid', reason: [reason] };
|
|
44
55
|
}
|
|
@@ -56,7 +67,7 @@ export class DataTxValidator implements TxValidator<Tx> {
|
|
|
56
67
|
contractClassLogsHashes.length
|
|
57
68
|
}. Got ${hashedContractClasslogs.length}.`,
|
|
58
69
|
);
|
|
59
|
-
return { result: 'invalid', reason: [
|
|
70
|
+
return { result: 'invalid', reason: [TX_ERROR_CONTRACT_CLASS_LOG_COUNT] };
|
|
60
71
|
}
|
|
61
72
|
for (const [i, logHash] of contractClassLogsHashes.entries()) {
|
|
62
73
|
const hashedLog = hashedContractClasslogs[i];
|
|
@@ -68,14 +79,14 @@ export class DataTxValidator implements TxValidator<Tx> {
|
|
|
68
79
|
tx,
|
|
69
80
|
)} because of mismatched contract class logs indices. Expected ${i} from the kernel's log hashes. Got ${matchingLogIndex} in the tx.`,
|
|
70
81
|
);
|
|
71
|
-
return { result: 'invalid', reason: [
|
|
82
|
+
return { result: 'invalid', reason: [TX_ERROR_CONTRACT_CLASS_LOG_SORTING] };
|
|
72
83
|
} else {
|
|
73
84
|
this.#log.warn(
|
|
74
85
|
`Rejecting tx ${await Tx.getHash(tx)} because of mismatched contract class logs. Expected hash ${
|
|
75
86
|
logHash.value
|
|
76
87
|
} from the kernels. Got ${hashedLog} in the tx.`,
|
|
77
88
|
);
|
|
78
|
-
return { result: 'invalid', reason: [
|
|
89
|
+
return { result: 'invalid', reason: [TX_ERROR_CONTRACT_CLASS_LOGS] };
|
|
79
90
|
}
|
|
80
91
|
}
|
|
81
92
|
if (logHash.logHash.length !== tx.contractClassLogs[i].getEmittedLength()) {
|
|
@@ -84,7 +95,7 @@ export class DataTxValidator implements TxValidator<Tx> {
|
|
|
84
95
|
logHash.logHash.length
|
|
85
96
|
} from the kernel's log hashes. Got ${tx.contractClassLogs[i].getEmittedLength()} in the tx.`,
|
|
86
97
|
);
|
|
87
|
-
return { result: 'invalid', reason: [
|
|
98
|
+
return { result: 'invalid', reason: [TX_ERROR_CONTRACT_CLASS_LOG_LENGTH] };
|
|
88
99
|
}
|
|
89
100
|
}
|
|
90
101
|
return { result: 'valid' };
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import { createLogger } from '@aztec/foundation/log';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
type AnyTx,
|
|
4
|
+
TX_ERROR_DUPLICATE_NULLIFIER_IN_TX,
|
|
5
|
+
TX_ERROR_EXISTING_NULLIFIER,
|
|
6
|
+
Tx,
|
|
7
|
+
type TxValidationResult,
|
|
8
|
+
type TxValidator,
|
|
9
|
+
} from '@aztec/stdlib/tx';
|
|
3
10
|
|
|
4
11
|
export interface NullifierSource {
|
|
5
12
|
nullifiersExist: (nullifiers: Buffer[]) => Promise<boolean[]>;
|
|
@@ -20,12 +27,12 @@ export class DoubleSpendTxValidator<T extends AnyTx> implements TxValidator<T> {
|
|
|
20
27
|
const uniqueNullifiers = new Set(nullifiers);
|
|
21
28
|
if (uniqueNullifiers.size !== nullifiers.length) {
|
|
22
29
|
this.#log.warn(`Rejecting tx ${await Tx.getHash(tx)} for emitting duplicate nullifiers`);
|
|
23
|
-
return { result: 'invalid', reason: [
|
|
30
|
+
return { result: 'invalid', reason: [TX_ERROR_DUPLICATE_NULLIFIER_IN_TX] };
|
|
24
31
|
}
|
|
25
32
|
|
|
26
33
|
if ((await this.#nullifierSource.nullifiersExist(nullifiers.map(n => n.toBuffer()))).some(Boolean)) {
|
|
27
34
|
this.#log.warn(`Rejecting tx ${await Tx.getHash(tx)} for repeating a nullifier`);
|
|
28
|
-
return { result: 'invalid', reason: [
|
|
35
|
+
return { result: 'invalid', reason: [TX_ERROR_EXISTING_NULLIFIER] };
|
|
29
36
|
}
|
|
30
37
|
|
|
31
38
|
return { result: 'valid' };
|
|
@@ -1,11 +1,20 @@
|
|
|
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
6
|
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
6
|
-
import
|
|
7
|
+
import { Gas, GasFees } from '@aztec/stdlib/gas';
|
|
7
8
|
import type { PublicStateSource } from '@aztec/stdlib/trees';
|
|
8
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
TX_ERROR_INSUFFICIENT_FEE_PAYER_BALANCE,
|
|
11
|
+
TX_ERROR_INSUFFICIENT_FEE_PER_GAS,
|
|
12
|
+
TX_ERROR_INSUFFICIENT_GAS_LIMIT,
|
|
13
|
+
type Tx,
|
|
14
|
+
TxExecutionPhase,
|
|
15
|
+
type TxValidationResult,
|
|
16
|
+
type TxValidator,
|
|
17
|
+
} from '@aztec/stdlib/tx';
|
|
9
18
|
|
|
10
19
|
export class GasTxValidator implements TxValidator<Tx> {
|
|
11
20
|
#log = createLogger('sequencer:tx_validator:tx_gas');
|
|
@@ -20,10 +29,14 @@ export class GasTxValidator implements TxValidator<Tx> {
|
|
|
20
29
|
}
|
|
21
30
|
|
|
22
31
|
async validateTx(tx: Tx): Promise<TxValidationResult> {
|
|
32
|
+
const gasLimitValidation = this.#validateMinGasLimit(tx);
|
|
33
|
+
if (gasLimitValidation.result === 'invalid') {
|
|
34
|
+
return Promise.resolve(gasLimitValidation);
|
|
35
|
+
}
|
|
23
36
|
if (await this.#shouldSkip(tx)) {
|
|
24
|
-
return Promise.resolve({ result: 'skipped', reason: [
|
|
37
|
+
return Promise.resolve({ result: 'skipped', reason: [TX_ERROR_INSUFFICIENT_FEE_PER_GAS] });
|
|
25
38
|
}
|
|
26
|
-
return this
|
|
39
|
+
return this.validateTxFee(tx);
|
|
27
40
|
}
|
|
28
41
|
|
|
29
42
|
/**
|
|
@@ -50,7 +63,24 @@ export class GasTxValidator implements TxValidator<Tx> {
|
|
|
50
63
|
return notEnoughMaxFees;
|
|
51
64
|
}
|
|
52
65
|
|
|
53
|
-
|
|
66
|
+
/**
|
|
67
|
+
* Check whether the tx's gas limit is above the minimum amount.
|
|
68
|
+
*/
|
|
69
|
+
#validateMinGasLimit(tx: Tx): TxValidationResult {
|
|
70
|
+
const gasLimits = tx.data.constants.txContext.gasSettings.gasLimits;
|
|
71
|
+
const minGasLimits = new Gas(FIXED_DA_GAS, FIXED_L2_GAS);
|
|
72
|
+
|
|
73
|
+
if (minGasLimits.gtAny(gasLimits)) {
|
|
74
|
+
this.#log.warn(`Rejecting transaction due to the gas limit(s) not being above the minimum gas limit`, {
|
|
75
|
+
gasLimits,
|
|
76
|
+
minGasLimits,
|
|
77
|
+
});
|
|
78
|
+
return { result: 'invalid', reason: [TX_ERROR_INSUFFICIENT_GAS_LIMIT] };
|
|
79
|
+
}
|
|
80
|
+
return { result: 'valid' };
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
public async validateTxFee(tx: Tx): Promise<TxValidationResult> {
|
|
54
84
|
const feePayer = tx.data.feePayer;
|
|
55
85
|
|
|
56
86
|
// Compute the maximum fee that this tx may pay, based on its gasLimits and maxFeePerGas
|
|
@@ -88,7 +118,7 @@ export class GasTxValidator implements TxValidator<Tx> {
|
|
|
88
118
|
balance: balance.toBigInt(),
|
|
89
119
|
feeLimit: feeLimit.toBigInt(),
|
|
90
120
|
});
|
|
91
|
-
return { result: 'invalid', reason: [
|
|
121
|
+
return { result: 'invalid', reason: [TX_ERROR_INSUFFICIENT_FEE_PAYER_BALANCE] };
|
|
92
122
|
}
|
|
93
123
|
return { result: 'valid' };
|
|
94
124
|
}
|
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
import type { Fr } from '@aztec/foundation/fields';
|
|
2
2
|
import { createLogger } from '@aztec/foundation/log';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
type AnyTx,
|
|
5
|
+
TX_ERROR_INCORRECT_CHAIN_ID,
|
|
6
|
+
TX_ERROR_INCORRECT_ROLLUP_VERSION,
|
|
7
|
+
TX_ERROR_INVALID_BLOCK_NUMBER,
|
|
8
|
+
Tx,
|
|
9
|
+
type TxValidationResult,
|
|
10
|
+
type TxValidator,
|
|
11
|
+
} from '@aztec/stdlib/tx';
|
|
4
12
|
|
|
5
13
|
export class MetadataTxValidator<T extends AnyTx> implements TxValidator<T> {
|
|
6
14
|
#log = createLogger('p2p:tx_validator:tx_metadata');
|
|
@@ -10,13 +18,13 @@ export class MetadataTxValidator<T extends AnyTx> implements TxValidator<T> {
|
|
|
10
18
|
async validateTx(tx: T): Promise<TxValidationResult> {
|
|
11
19
|
const errors = [];
|
|
12
20
|
if (!(await this.#hasCorrectChainId(tx))) {
|
|
13
|
-
errors.push(
|
|
21
|
+
errors.push(TX_ERROR_INCORRECT_CHAIN_ID);
|
|
14
22
|
}
|
|
15
23
|
if (!(await this.#hasCorrectRollupVersion(tx))) {
|
|
16
|
-
errors.push(
|
|
24
|
+
errors.push(TX_ERROR_INCORRECT_ROLLUP_VERSION);
|
|
17
25
|
}
|
|
18
26
|
if (!(await this.#isValidForBlockNumber(tx))) {
|
|
19
|
-
errors.push(
|
|
27
|
+
errors.push(TX_ERROR_INVALID_BLOCK_NUMBER);
|
|
20
28
|
}
|
|
21
29
|
return errors.length > 0 ? { result: 'invalid', reason: errors } : { result: 'valid' };
|
|
22
30
|
}
|
|
@@ -4,6 +4,8 @@ import type { ContractDataSource } from '@aztec/stdlib/contract';
|
|
|
4
4
|
import type { AllowedElement } from '@aztec/stdlib/interfaces/server';
|
|
5
5
|
import {
|
|
6
6
|
type PublicCallRequestWithCalldata,
|
|
7
|
+
TX_ERROR_DURING_VALIDATION,
|
|
8
|
+
TX_ERROR_SETUP_FUNCTION_NOT_ALLOWED,
|
|
7
9
|
Tx,
|
|
8
10
|
TxExecutionPhase,
|
|
9
11
|
type TxValidationResult,
|
|
@@ -42,11 +44,14 @@ export class PhasesTxValidator implements TxValidator<Tx> {
|
|
|
42
44
|
{ allowList: this.setupAllowList },
|
|
43
45
|
);
|
|
44
46
|
|
|
45
|
-
return { result: 'invalid', reason: [
|
|
47
|
+
return { result: 'invalid', reason: [TX_ERROR_SETUP_FUNCTION_NOT_ALLOWED] };
|
|
46
48
|
}
|
|
47
49
|
}
|
|
48
50
|
|
|
49
51
|
return { result: 'valid' };
|
|
52
|
+
} catch (err) {
|
|
53
|
+
this.#log.error(`Error validating phases for tx`, err);
|
|
54
|
+
return { result: 'invalid', reason: [TX_ERROR_DURING_VALIDATION] };
|
|
50
55
|
} finally {
|
|
51
56
|
this.contractsDB.clearContractsForTx();
|
|
52
57
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createLogger } from '@aztec/foundation/log';
|
|
2
2
|
import type { ClientProtocolCircuitVerifier } from '@aztec/stdlib/interfaces/server';
|
|
3
|
-
import { Tx, type TxValidationResult, type TxValidator } from '@aztec/stdlib/tx';
|
|
3
|
+
import { TX_ERROR_INVALID_PROOF, Tx, type TxValidationResult, type TxValidator } from '@aztec/stdlib/tx';
|
|
4
4
|
|
|
5
5
|
export class TxProofValidator implements TxValidator<Tx> {
|
|
6
6
|
#log = createLogger('p2p:tx_validator:private_proof');
|
|
@@ -10,7 +10,7 @@ export class TxProofValidator implements TxValidator<Tx> {
|
|
|
10
10
|
async validateTx(tx: Tx): Promise<TxValidationResult> {
|
|
11
11
|
if (!(await this.verifier.verifyProof(tx))) {
|
|
12
12
|
this.#log.warn(`Rejecting tx ${await Tx.getHash(tx)} for invalid proof`);
|
|
13
|
-
return { result: 'invalid', reason: [
|
|
13
|
+
return { result: 'invalid', reason: [TX_ERROR_INVALID_PROOF] };
|
|
14
14
|
}
|
|
15
15
|
this.#log.trace(`Accepted ${await Tx.getHash(tx)} with valid proof`);
|
|
16
16
|
return { result: 'valid' };
|
|
@@ -32,9 +32,8 @@ export class DiscV5Service extends EventEmitter implements PeerDiscoveryService
|
|
|
32
32
|
|
|
33
33
|
private currentState = PeerDiscoveryState.STOPPED;
|
|
34
34
|
|
|
35
|
-
public readonly bootstrapNodes: string[] = [];
|
|
36
35
|
private bootstrapNodePeerIds: PeerId[] = [];
|
|
37
|
-
|
|
36
|
+
public bootstrapNodeEnrs: ENR[] = [];
|
|
38
37
|
|
|
39
38
|
private startTime = 0;
|
|
40
39
|
|
|
@@ -53,8 +52,7 @@ export class DiscV5Service extends EventEmitter implements PeerDiscoveryService
|
|
|
53
52
|
) {
|
|
54
53
|
super();
|
|
55
54
|
const { p2pIp, p2pPort, bootstrapNodes } = config;
|
|
56
|
-
this.
|
|
57
|
-
this.bootstrapNodeEnrs = this.bootstrapNodes.map(x => ENR.decodeTxt(x));
|
|
55
|
+
this.bootstrapNodeEnrs = bootstrapNodes.map(x => ENR.decodeTxt(x));
|
|
58
56
|
// create ENR from PeerId
|
|
59
57
|
this.enr = SignableENR.createFromPeerId(peerId);
|
|
60
58
|
// Add aztec identification to ENR
|
|
@@ -117,7 +115,7 @@ export class DiscV5Service extends EventEmitter implements PeerDiscoveryService
|
|
|
117
115
|
// We want to update our tcp port to match the udp port
|
|
118
116
|
const multiAddrTcp = multiaddr(convertToMultiaddr(m.nodeAddress().address, this.config.p2pPort, 'tcp'));
|
|
119
117
|
this.enr.setLocationMultiaddr(multiAddrTcp);
|
|
120
|
-
this.logger.info('Multiaddr updated', { multiaddr:
|
|
118
|
+
this.logger.info('Multiaddr updated', { multiaddr: multiAddrTcp.toString() });
|
|
121
119
|
}
|
|
122
120
|
|
|
123
121
|
public async start(): Promise<void> {
|
|
@@ -138,10 +136,14 @@ export class DiscV5Service extends EventEmitter implements PeerDiscoveryService
|
|
|
138
136
|
this.currentState = PeerDiscoveryState.RUNNING;
|
|
139
137
|
|
|
140
138
|
// Add bootnode ENR if provided
|
|
141
|
-
if (this.
|
|
139
|
+
if (this.bootstrapNodeEnrs?.length) {
|
|
142
140
|
// Do this conversion once since it involves an async function call
|
|
143
141
|
this.bootstrapNodePeerIds = await Promise.all(this.bootstrapNodeEnrs.map(enr => enr.peerId()));
|
|
144
|
-
this.logger.info(
|
|
142
|
+
this.logger.info(
|
|
143
|
+
`Adding ${this.bootstrapNodeEnrs.length} bootstrap nodes ENRs: ${this.bootstrapNodeEnrs
|
|
144
|
+
.map(enr => enr.encodeTxt())
|
|
145
|
+
.join(', ')}`,
|
|
146
|
+
);
|
|
145
147
|
for (const enr of this.bootstrapNodeEnrs) {
|
|
146
148
|
try {
|
|
147
149
|
if (this.config.bootstrapNodeEnrVersionCheck) {
|
|
@@ -244,7 +246,7 @@ export class DiscV5Service extends EventEmitter implements PeerDiscoveryService
|
|
|
244
246
|
// Check the peer is an aztec peer
|
|
245
247
|
const value = enr.kvs.get(AZTEC_ENR_KEY);
|
|
246
248
|
if (!value) {
|
|
247
|
-
this.logger.
|
|
249
|
+
this.logger.debug(`Peer node ${enr.nodeId} does not have aztec key in ENR`);
|
|
248
250
|
return false;
|
|
249
251
|
}
|
|
250
252
|
|
|
@@ -2,6 +2,7 @@ import type { PeerInfo } from '@aztec/stdlib/interfaces/server';
|
|
|
2
2
|
import type { BlockAttestation, BlockProposal, Gossipable } from '@aztec/stdlib/p2p';
|
|
3
3
|
import { TxHash } from '@aztec/stdlib/tx';
|
|
4
4
|
|
|
5
|
+
import type { ENR } from '@chainsafe/enr';
|
|
5
6
|
import type { PeerId } from '@libp2p/interface';
|
|
6
7
|
import EventEmitter from 'events';
|
|
7
8
|
|
|
@@ -90,7 +91,7 @@ export class DummyP2PService implements P2PService {
|
|
|
90
91
|
*/
|
|
91
92
|
export class DummyPeerDiscoveryService extends EventEmitter implements PeerDiscoveryService {
|
|
92
93
|
private currentState = PeerDiscoveryState.STOPPED;
|
|
93
|
-
public
|
|
94
|
+
public bootstrapNodeEnrs: ENR[] = [];
|
|
94
95
|
|
|
95
96
|
/**
|
|
96
97
|
* Starts the dummy implementation.
|
|
@@ -86,7 +86,7 @@ type ValidationOutcome = { allPassed: true } | { allPassed: false; failure: Vali
|
|
|
86
86
|
/**
|
|
87
87
|
* Lib P2P implementation of the P2PService interface.
|
|
88
88
|
*/
|
|
89
|
-
export class LibP2PService<T extends P2PClientType> extends WithTracer implements P2PService {
|
|
89
|
+
export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends WithTracer implements P2PService {
|
|
90
90
|
private jobQueue: SerialQueue = new SerialQueue();
|
|
91
91
|
private peerManager: PeerManager;
|
|
92
92
|
private discoveryRunningPromise?: RunningPromise;
|
|
@@ -115,15 +115,15 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
|
|
|
115
115
|
constructor(
|
|
116
116
|
private clientType: T,
|
|
117
117
|
private config: P2PConfig,
|
|
118
|
-
|
|
118
|
+
protected node: PubSubLibp2p,
|
|
119
119
|
private peerDiscoveryService: PeerDiscoveryService,
|
|
120
|
-
|
|
120
|
+
protected mempools: MemPools<T>,
|
|
121
121
|
private archiver: L2BlockSource & ContractDataSource,
|
|
122
122
|
epochCache: EpochCacheInterface,
|
|
123
123
|
private proofVerifier: ClientProtocolCircuitVerifier,
|
|
124
124
|
private worldStateSynchronizer: WorldStateSynchronizer,
|
|
125
125
|
telemetry: TelemetryClient,
|
|
126
|
-
|
|
126
|
+
protected logger = createLogger('p2p:libp2p_service'),
|
|
127
127
|
) {
|
|
128
128
|
super(telemetry, 'LibP2PService');
|
|
129
129
|
|
|
@@ -187,7 +187,7 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
|
|
|
187
187
|
|
|
188
188
|
const otelMetricsAdapter = new OtelMetricsAdapter(telemetry);
|
|
189
189
|
|
|
190
|
-
const bootstrapNodes = peerDiscoveryService.
|
|
190
|
+
const bootstrapNodes = peerDiscoveryService.bootstrapNodeEnrs.map(enr => enr.encodeTxt());
|
|
191
191
|
|
|
192
192
|
// If trusted peers are provided, also provide them to the p2p service
|
|
193
193
|
bootstrapNodes.push(...config.trustedPeers);
|
|
@@ -482,7 +482,7 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
|
|
|
482
482
|
* @param topic - The message's topic.
|
|
483
483
|
* @param data - The message data
|
|
484
484
|
*/
|
|
485
|
-
|
|
485
|
+
protected async handleNewGossipMessage(msg: Message, msgId: string, source: PeerId) {
|
|
486
486
|
if (msg.topic === Tx.p2pTopic) {
|
|
487
487
|
await this.handleGossipedTx(msg, msgId, source);
|
|
488
488
|
}
|
|
@@ -496,7 +496,7 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
|
|
|
496
496
|
return;
|
|
497
497
|
}
|
|
498
498
|
|
|
499
|
-
|
|
499
|
+
protected async validateReceivedMessage<T>(
|
|
500
500
|
validationFunc: () => Promise<{ result: boolean; obj: T }>,
|
|
501
501
|
msgId: string,
|
|
502
502
|
source: PeerId,
|
|
@@ -516,7 +516,7 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
|
|
|
516
516
|
return resultAndObj;
|
|
517
517
|
}
|
|
518
518
|
|
|
519
|
-
|
|
519
|
+
protected async handleGossipedTx(msg: Message, msgId: string, source: PeerId) {
|
|
520
520
|
const validationFunc = async () => {
|
|
521
521
|
const tx = Tx.fromBuffer(Buffer.from(msg.data));
|
|
522
522
|
const result = await this.validatePropagatedTx(tx, source);
|
|
@@ -792,7 +792,7 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
|
|
|
792
792
|
): Promise<ValidationOutcome> {
|
|
793
793
|
const validationPromises = Object.entries(messageValidators).map(async ([name, { validator, severity }]) => {
|
|
794
794
|
const { result } = await validator.validateTx(tx);
|
|
795
|
-
return { name, isValid: result
|
|
795
|
+
return { name, isValid: result !== 'invalid', severity };
|
|
796
796
|
});
|
|
797
797
|
|
|
798
798
|
// A promise that resolves when all validations have been run
|
|
@@ -49,7 +49,7 @@ export class PeerManager {
|
|
|
49
49
|
handleConnectedPeerEvent: (e: CustomEvent<PeerId>) => void;
|
|
50
50
|
handleDisconnectedPeerEvent: (e: CustomEvent<PeerId>) => void;
|
|
51
51
|
handleDiscoveredPeer: (enr: ENR) => Promise<void>;
|
|
52
|
-
}
|
|
52
|
+
};
|
|
53
53
|
|
|
54
54
|
constructor(
|
|
55
55
|
private libP2PNode: PubSubLibp2p,
|
package/src/services/service.ts
CHANGED
|
@@ -10,17 +10,25 @@ import { createLogger } from '@aztec/foundation/log';
|
|
|
10
10
|
import { sleep } from '@aztec/foundation/sleep';
|
|
11
11
|
import type { DataStoreConfig } from '@aztec/kv-store/config';
|
|
12
12
|
import { openTmpStore } from '@aztec/kv-store/lmdb-v2';
|
|
13
|
-
import type {
|
|
13
|
+
import type { L2BlockSource } from '@aztec/stdlib/block';
|
|
14
|
+
import type { ContractDataSource } from '@aztec/stdlib/contract';
|
|
15
|
+
import type { ClientProtocolCircuitVerifier, WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
|
|
14
16
|
import { P2PClientType } from '@aztec/stdlib/p2p';
|
|
15
17
|
import { Tx, TxStatus } from '@aztec/stdlib/tx';
|
|
18
|
+
import { type TelemetryClient, getTelemetryClient } from '@aztec/telemetry-client';
|
|
16
19
|
|
|
17
20
|
import type { Message, PeerId } from '@libp2p/interface';
|
|
21
|
+
import { TopicValidatorResult } from '@libp2p/interface';
|
|
18
22
|
|
|
19
23
|
import type { P2PConfig } from '../config.js';
|
|
20
24
|
import { createP2PClient } from '../index.js';
|
|
21
25
|
import type { AttestationPool } from '../mem_pools/attestation_pool/attestation_pool.js';
|
|
26
|
+
import type { MemPools } from '../mem_pools/interface.js';
|
|
22
27
|
import type { TxPool } from '../mem_pools/tx_pool/index.js';
|
|
28
|
+
import { LibP2PService } from '../services/libp2p/libp2p_service.js';
|
|
29
|
+
import type { PeerDiscoveryService } from '../services/service.js';
|
|
23
30
|
import { AlwaysTrueCircuitVerifier } from '../test-helpers/reqresp-nodes.js';
|
|
31
|
+
import type { PubSubLibp2p } from '../util.js';
|
|
24
32
|
|
|
25
33
|
// Simple mock implementation
|
|
26
34
|
function mockTxPool(): TxPool {
|
|
@@ -69,6 +77,72 @@ function mockEpochCache(): EpochCacheInterface {
|
|
|
69
77
|
};
|
|
70
78
|
}
|
|
71
79
|
|
|
80
|
+
class TestLibP2PService<T extends P2PClientType = P2PClientType.Full> extends LibP2PService<T> {
|
|
81
|
+
private disableTxValidation: boolean;
|
|
82
|
+
private gossipMessageCount: number = 0;
|
|
83
|
+
|
|
84
|
+
constructor(
|
|
85
|
+
clientType: T,
|
|
86
|
+
config: P2PConfig,
|
|
87
|
+
node: PubSubLibp2p,
|
|
88
|
+
peerDiscoveryService: PeerDiscoveryService,
|
|
89
|
+
mempools: MemPools<T>,
|
|
90
|
+
archiver: L2BlockSource & ContractDataSource,
|
|
91
|
+
epochCache: EpochCacheInterface,
|
|
92
|
+
proofVerifier: ClientProtocolCircuitVerifier,
|
|
93
|
+
worldStateSynchronizer: WorldStateSynchronizer,
|
|
94
|
+
telemetry: TelemetryClient,
|
|
95
|
+
logger = createLogger('p2p:test:libp2p_service'),
|
|
96
|
+
disableTxValidation = true,
|
|
97
|
+
) {
|
|
98
|
+
super(
|
|
99
|
+
clientType,
|
|
100
|
+
config,
|
|
101
|
+
node,
|
|
102
|
+
peerDiscoveryService,
|
|
103
|
+
mempools,
|
|
104
|
+
archiver,
|
|
105
|
+
epochCache,
|
|
106
|
+
proofVerifier,
|
|
107
|
+
worldStateSynchronizer,
|
|
108
|
+
telemetry,
|
|
109
|
+
logger,
|
|
110
|
+
);
|
|
111
|
+
this.disableTxValidation = disableTxValidation;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
public getGossipMessageCount(): number {
|
|
115
|
+
return this.gossipMessageCount;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
public setDisableTxValidation(disable: boolean): void {
|
|
119
|
+
this.disableTxValidation = disable;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
protected override async handleGossipedTx(msg: Message, msgId: string, source: PeerId) {
|
|
123
|
+
if (this.disableTxValidation) {
|
|
124
|
+
const tx = Tx.fromBuffer(Buffer.from(msg.data));
|
|
125
|
+
this.node.services.pubsub.reportMessageValidationResult(msgId, source.toString(), TopicValidatorResult.Accept);
|
|
126
|
+
|
|
127
|
+
const txHash = await tx.getTxHash();
|
|
128
|
+
const txHashString = txHash.toString();
|
|
129
|
+
this.logger.verbose(`Received tx ${txHashString} from external peer ${source.toString()}.`);
|
|
130
|
+
await this.mempools.txPool.addTxs([tx]);
|
|
131
|
+
} else {
|
|
132
|
+
await super.handleGossipedTx(msg, msgId, source);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
protected override async handleNewGossipMessage(msg: Message, msgId: string, source: PeerId) {
|
|
137
|
+
this.gossipMessageCount++;
|
|
138
|
+
process.send!({
|
|
139
|
+
type: 'GOSSIP_RECEIVED',
|
|
140
|
+
count: this.gossipMessageCount,
|
|
141
|
+
});
|
|
142
|
+
await super.handleNewGossipMessage(msg, msgId, source);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
72
146
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
|
73
147
|
process.on('message', async msg => {
|
|
74
148
|
const { type, config, clientIndex } = msg as { type: string; config: P2PConfig; clientIndex: number };
|
|
@@ -80,11 +154,11 @@ process.on('message', async msg => {
|
|
|
80
154
|
const epochCache = mockEpochCache();
|
|
81
155
|
const worldState = {} as WorldStateSynchronizer;
|
|
82
156
|
const l2BlockSource = new MockL2BlockSource();
|
|
83
|
-
await l2BlockSource.createBlocks(100);
|
|
84
157
|
|
|
85
158
|
const proofVerifier = new AlwaysTrueCircuitVerifier();
|
|
86
159
|
const kvStore = await openTmpStore(`test-${clientIndex}`);
|
|
87
160
|
const logger = createLogger(`p2p:${clientIndex}`);
|
|
161
|
+
const telemetry = getTelemetryClient();
|
|
88
162
|
|
|
89
163
|
const deps = {
|
|
90
164
|
txPool,
|
|
@@ -100,23 +174,30 @@ process.on('message', async msg => {
|
|
|
100
174
|
proofVerifier,
|
|
101
175
|
worldState,
|
|
102
176
|
epochCache,
|
|
103
|
-
|
|
177
|
+
telemetry,
|
|
104
178
|
deps,
|
|
105
179
|
);
|
|
106
180
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
181
|
+
const _client = client as any;
|
|
182
|
+
|
|
183
|
+
// Create test service with validation disabled
|
|
184
|
+
const testService = new TestLibP2PService(
|
|
185
|
+
P2PClientType.Full,
|
|
186
|
+
config,
|
|
187
|
+
(client as any).p2pService.node,
|
|
188
|
+
(client as any).p2pService.peerDiscoveryService,
|
|
189
|
+
(client as any).p2pService.mempools,
|
|
190
|
+
(client as any).p2pService.archiver,
|
|
191
|
+
epochCache,
|
|
192
|
+
proofVerifier,
|
|
193
|
+
worldState,
|
|
194
|
+
telemetry,
|
|
195
|
+
logger,
|
|
196
|
+
true, // disable validation
|
|
197
|
+
);
|
|
198
|
+
|
|
199
|
+
// Replace the existing p2pService with our test version
|
|
200
|
+
(client as any).p2pService = testService;
|
|
120
201
|
|
|
121
202
|
await client.start();
|
|
122
203
|
// Wait until the client is ready
|
|
@@ -37,7 +37,7 @@ function getTimestamp(line: string): number | null {
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
/**
|
|
40
|
-
* Parses a single log line. If the line contains an "
|
|
40
|
+
* Parses a single log line. If the line contains an "Received tx" event,
|
|
41
41
|
* it extracts the timestamp and the peer ID.
|
|
42
42
|
*/
|
|
43
43
|
function parseReceivedTx(line: string): LogEvent | null {
|
|
@@ -52,9 +52,9 @@ function parseReceivedTx(line: string): LogEvent | null {
|
|
|
52
52
|
return null;
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
//
|
|
56
|
-
//
|
|
57
|
-
const peerIdMatch = line.match(/p2p:(\d+)
|
|
55
|
+
// Extract the peer ID from the log line
|
|
56
|
+
// Example format: "module":"p2p:1","msg":"Received tx 0x0feeafa65f25fd8d613fe4aca44fd65fe41c149ef1941e2019d40925c40748f9 from external peer 16Uiu2HAm8w4oxXF3TwDKoGL9U66thMXWqCgPnb2CgkYwmUqFCWbC."
|
|
57
|
+
const peerIdMatch = line.match(/"module":"p2p:(\d+)"/);
|
|
58
58
|
if (!peerIdMatch) {
|
|
59
59
|
logger.error('No peer Number found in received tx log');
|
|
60
60
|
return null;
|
|
@@ -42,7 +42,7 @@ async function main() {
|
|
|
42
42
|
logger.info('Transaction sent from client 0');
|
|
43
43
|
|
|
44
44
|
// Give time for message propagation
|
|
45
|
-
await sleep(
|
|
45
|
+
await sleep(10000);
|
|
46
46
|
logger.info('Checking message propagation results');
|
|
47
47
|
|
|
48
48
|
// Check message propagation results
|