@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.
Files changed (79) hide show
  1. package/dest/bootstrap/bootstrap.js +1 -1
  2. package/dest/client/factory.d.ts.map +1 -1
  3. package/dest/client/factory.js +5 -2
  4. package/dest/client/p2p_client.d.ts +2 -0
  5. package/dest/client/p2p_client.d.ts.map +1 -1
  6. package/dest/client/p2p_client.js +4 -1
  7. package/dest/config.d.ts +15 -3
  8. package/dest/config.d.ts.map +1 -1
  9. package/dest/config.js +12 -1
  10. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts +56 -2
  11. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts.map +1 -1
  12. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.js +229 -16
  13. package/dest/msg_validators/tx_validator/archive_cache.d.ts +14 -0
  14. package/dest/msg_validators/tx_validator/archive_cache.d.ts.map +1 -0
  15. package/dest/msg_validators/tx_validator/archive_cache.js +22 -0
  16. package/dest/msg_validators/tx_validator/block_header_validator.d.ts.map +1 -1
  17. package/dest/msg_validators/tx_validator/block_header_validator.js +2 -2
  18. package/dest/msg_validators/tx_validator/data_validator.d.ts.map +1 -1
  19. package/dest/msg_validators/tx_validator/data_validator.js +8 -8
  20. package/dest/msg_validators/tx_validator/double_spend_validator.d.ts.map +1 -1
  21. package/dest/msg_validators/tx_validator/double_spend_validator.js +3 -3
  22. package/dest/msg_validators/tx_validator/gas_validator.d.ts +2 -1
  23. package/dest/msg_validators/tx_validator/gas_validator.d.ts.map +1 -1
  24. package/dest/msg_validators/tx_validator/gas_validator.js +32 -5
  25. package/dest/msg_validators/tx_validator/index.d.ts +1 -0
  26. package/dest/msg_validators/tx_validator/index.d.ts.map +1 -1
  27. package/dest/msg_validators/tx_validator/index.js +1 -0
  28. package/dest/msg_validators/tx_validator/metadata_validator.d.ts.map +1 -1
  29. package/dest/msg_validators/tx_validator/metadata_validator.js +4 -4
  30. package/dest/msg_validators/tx_validator/phases_validator.d.ts.map +1 -1
  31. package/dest/msg_validators/tx_validator/phases_validator.js +10 -2
  32. package/dest/msg_validators/tx_validator/tx_proof_validator.d.ts.map +1 -1
  33. package/dest/msg_validators/tx_validator/tx_proof_validator.js +2 -2
  34. package/dest/services/discv5/discV5_service.d.ts +1 -2
  35. package/dest/services/discv5/discV5_service.d.ts.map +1 -1
  36. package/dest/services/discv5/discV5_service.js +6 -8
  37. package/dest/services/dummy_service.d.ts +2 -1
  38. package/dest/services/dummy_service.d.ts.map +1 -1
  39. package/dest/services/dummy_service.js +1 -1
  40. package/dest/services/libp2p/libp2p_service.d.ts +14 -8
  41. package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
  42. package/dest/services/libp2p/libp2p_service.js +2 -2
  43. package/dest/services/peer-manager/peer_manager.d.ts.map +1 -1
  44. package/dest/services/peer-manager/peer_manager.js +0 -1
  45. package/dest/services/service.d.ts +1 -1
  46. package/dest/services/service.d.ts.map +1 -1
  47. package/dest/testbench/p2p_client_testbench_worker.js +46 -16
  48. package/dest/testbench/parse_log_file.js +4 -4
  49. package/dest/testbench/testbench.js +1 -1
  50. package/dest/testbench/worker_client_manager.d.ts.map +1 -1
  51. package/dest/testbench/worker_client_manager.js +3 -2
  52. package/dest/util.d.ts +7 -3
  53. package/dest/util.d.ts.map +1 -1
  54. package/dest/util.js +44 -7
  55. package/package.json +12 -12
  56. package/src/bootstrap/bootstrap.ts +1 -1
  57. package/src/client/factory.ts +7 -2
  58. package/src/client/p2p_client.ts +6 -1
  59. package/src/config.ts +26 -2
  60. package/src/mem_pools/tx_pool/aztec_kv_tx_pool.ts +312 -27
  61. package/src/msg_validators/tx_validator/archive_cache.ts +28 -0
  62. package/src/msg_validators/tx_validator/block_header_validator.ts +2 -2
  63. package/src/msg_validators/tx_validator/data_validator.ts +19 -8
  64. package/src/msg_validators/tx_validator/double_spend_validator.ts +10 -3
  65. package/src/msg_validators/tx_validator/gas_validator.ts +36 -6
  66. package/src/msg_validators/tx_validator/index.ts +1 -0
  67. package/src/msg_validators/tx_validator/metadata_validator.ts +12 -4
  68. package/src/msg_validators/tx_validator/phases_validator.ts +6 -1
  69. package/src/msg_validators/tx_validator/tx_proof_validator.ts +2 -2
  70. package/src/services/discv5/discV5_service.ts +10 -8
  71. package/src/services/dummy_service.ts +2 -1
  72. package/src/services/libp2p/libp2p_service.ts +9 -9
  73. package/src/services/peer-manager/peer_manager.ts +1 -1
  74. package/src/services/service.ts +1 -1
  75. package/src/testbench/p2p_client_testbench_worker.ts +97 -16
  76. package/src/testbench/parse_log_file.ts +4 -4
  77. package/src/testbench/testbench.ts +1 -1
  78. package/src/testbench/worker_client_manager.ts +4 -2
  79. 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: ['Block header not found'] };
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 { Tx, type TxValidationResult, type TxValidator } from '@aztec/stdlib/tx';
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 = 'Wrong number of calldata for public calls';
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 = 'Total calldata too large for enqueued public calls';
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 = 'Incorrect calldata for public call';
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: ['Mismatched number of contract class logs'] };
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: ['Incorrectly sorted contract class logs'] };
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: ['Mismatched contract class logs'] };
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: ['Mismatched contract class logs length'] };
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 { type AnyTx, Tx, type TxValidationResult, type TxValidator } from '@aztec/stdlib/tx';
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: ['Duplicate nullifier in tx'] };
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: ['Existing nullifier'] };
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 type { GasFees } from '@aztec/stdlib/gas';
7
+ import { Gas, GasFees } from '@aztec/stdlib/gas';
7
8
  import type { PublicStateSource } from '@aztec/stdlib/trees';
8
- import { type Tx, TxExecutionPhase, type TxValidationResult, type TxValidator } from '@aztec/stdlib/tx';
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: ['Insufficient fee per gas'] });
37
+ return Promise.resolve({ result: 'skipped', reason: [TX_ERROR_INSUFFICIENT_FEE_PER_GAS] });
25
38
  }
26
- return this.#validateTxFee(tx);
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
- async #validateTxFee(tx: Tx): Promise<TxValidationResult> {
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: ['Insufficient fee payer balance'] };
121
+ return { result: 'invalid', reason: [TX_ERROR_INSUFFICIENT_FEE_PAYER_BALANCE] };
92
122
  }
93
123
  return { result: 'valid' };
94
124
  }
@@ -8,3 +8,4 @@ export * from './gas_validator.js';
8
8
  export * from './phases_validator.js';
9
9
  export * from './test_utils.js';
10
10
  export * from './allowed_public_setup.js';
11
+ export * from './archive_cache.js';
@@ -1,6 +1,14 @@
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 {
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('Incorrect chain id');
21
+ errors.push(TX_ERROR_INCORRECT_CHAIN_ID);
14
22
  }
15
23
  if (!(await this.#hasCorrectRollupVersion(tx))) {
16
- errors.push('Incorrect rollup version');
24
+ errors.push(TX_ERROR_INCORRECT_ROLLUP_VERSION);
17
25
  }
18
26
  if (!(await this.#isValidForBlockNumber(tx))) {
19
- errors.push('Invalid block number');
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: ['Setup function not on allow list'] };
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: ['Invalid proof'] };
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
- private bootstrapNodeEnrs: ENR[] = [];
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.bootstrapNodes = bootstrapNodes ?? [];
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: multiaddr.toString() });
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.bootstrapNodes?.length) {
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(`Adding ${this.bootstrapNodes} bootstrap nodes ENRs: ${this.bootstrapNodes.join(', ')}`);
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.warn(`Peer node ${enr.nodeId} does not have aztec key in ENR`);
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 bootstrapNodes: string[] = [];
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
- private node: PubSubLibp2p,
118
+ protected node: PubSubLibp2p,
119
119
  private peerDiscoveryService: PeerDiscoveryService,
120
- private mempools: MemPools<T>,
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
- private logger = createLogger('p2p:libp2p_service'),
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.bootstrapNodes;
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
- private async handleNewGossipMessage(msg: Message, msgId: string, source: PeerId) {
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
- private async validateReceivedMessage<T>(
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
- private async handleGossipedTx(msg: Message, msgId: string, source: PeerId) {
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 === 'valid', severity };
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
- } = {} as any;
52
+ };
53
53
 
54
54
  constructor(
55
55
  private libP2PNode: PubSubLibp2p,
@@ -108,5 +108,5 @@ export interface PeerDiscoveryService extends EventEmitter {
108
108
 
109
109
  getEnr(): ENR | undefined;
110
110
 
111
- bootstrapNodes: string[];
111
+ bootstrapNodeEnrs: ENR[];
112
112
  }
@@ -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 { WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
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
- undefined,
177
+ telemetry,
104
178
  deps,
105
179
  );
106
180
 
107
- // Create spy for gossip messages
108
- let gossipMessageCount = 0;
109
- (client as any).p2pService.handleNewGossipMessage = (msg: Message, msgId: string, source: PeerId) => {
110
- gossipMessageCount++;
111
- process.send!({
112
- type: 'GOSSIP_RECEIVED',
113
- count: gossipMessageCount,
114
- });
115
- return (client as any).p2pService.constructor.prototype.handleNewGossipMessage.apply(
116
- (client as any).p2pService,
117
- [msg, msgId, source],
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 "rpc.from" event,
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
- // TODO: this is not correct - it is just the tx hash for now
56
- // Extract the peer ID after "Received tx"
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(30000);
45
+ await sleep(10000);
46
46
  logger.info('Checking message propagation results');
47
47
 
48
48
  // Check message propagation results