@aztec/p2p 0.69.0 → 0.69.1-devnet

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 (54) hide show
  1. package/dest/client/p2p_client.d.ts +6 -0
  2. package/dest/client/p2p_client.d.ts.map +1 -1
  3. package/dest/client/p2p_client.js +13 -3
  4. package/dest/mem_pools/attestation_pool/mocks.js +2 -2
  5. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts.map +1 -1
  6. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.js +65 -49
  7. package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts.map +1 -1
  8. package/dest/mem_pools/tx_pool/memory_tx_pool.js +6 -2
  9. package/dest/mem_pools/tx_pool/priority.d.ts +8 -0
  10. package/dest/mem_pools/tx_pool/priority.d.ts.map +1 -0
  11. package/dest/mem_pools/tx_pool/priority.js +12 -0
  12. package/dest/mem_pools/tx_pool/tx_pool.d.ts +1 -1
  13. package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts.map +1 -1
  14. package/dest/mem_pools/tx_pool/tx_pool_test_suite.js +19 -3
  15. package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts +2 -3
  16. package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts.map +1 -1
  17. package/dest/msg_validators/tx_validator/aggregate_tx_validator.js +16 -17
  18. package/dest/msg_validators/tx_validator/block_header_validator.d.ts +11 -0
  19. package/dest/msg_validators/tx_validator/block_header_validator.d.ts.map +1 -0
  20. package/dest/msg_validators/tx_validator/block_header_validator.js +21 -0
  21. package/dest/msg_validators/tx_validator/data_validator.d.ts +2 -3
  22. package/dest/msg_validators/tx_validator/data_validator.d.ts.map +1 -1
  23. package/dest/msg_validators/tx_validator/data_validator.js +5 -17
  24. package/dest/msg_validators/tx_validator/double_spend_validator.d.ts +4 -6
  25. package/dest/msg_validators/tx_validator/double_spend_validator.d.ts.map +1 -1
  26. package/dest/msg_validators/tx_validator/double_spend_validator.js +16 -45
  27. package/dest/msg_validators/tx_validator/index.d.ts +1 -0
  28. package/dest/msg_validators/tx_validator/index.d.ts.map +1 -1
  29. package/dest/msg_validators/tx_validator/index.js +2 -1
  30. package/dest/msg_validators/tx_validator/metadata_validator.d.ts +2 -3
  31. package/dest/msg_validators/tx_validator/metadata_validator.d.ts.map +1 -1
  32. package/dest/msg_validators/tx_validator/metadata_validator.js +9 -18
  33. package/dest/msg_validators/tx_validator/tx_proof_validator.d.ts +2 -3
  34. package/dest/msg_validators/tx_validator/tx_proof_validator.d.ts.map +1 -1
  35. package/dest/msg_validators/tx_validator/tx_proof_validator.js +8 -17
  36. package/dest/services/libp2p/libp2p_service.d.ts +1 -2
  37. package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
  38. package/dest/services/libp2p/libp2p_service.js +12 -11
  39. package/package.json +7 -7
  40. package/src/client/p2p_client.ts +20 -3
  41. package/src/mem_pools/attestation_pool/mocks.ts +2 -2
  42. package/src/mem_pools/tx_pool/aztec_kv_tx_pool.ts +68 -46
  43. package/src/mem_pools/tx_pool/memory_tx_pool.ts +5 -1
  44. package/src/mem_pools/tx_pool/priority.ts +13 -0
  45. package/src/mem_pools/tx_pool/tx_pool.ts +1 -1
  46. package/src/mem_pools/tx_pool/tx_pool_test_suite.ts +27 -5
  47. package/src/msg_validators/tx_validator/aggregate_tx_validator.ts +16 -20
  48. package/src/msg_validators/tx_validator/block_header_validator.ts +25 -0
  49. package/src/msg_validators/tx_validator/data_validator.ts +7 -22
  50. package/src/msg_validators/tx_validator/double_spend_validator.ts +9 -45
  51. package/src/msg_validators/tx_validator/index.ts +1 -0
  52. package/src/msg_validators/tx_validator/metadata_validator.ts +9 -22
  53. package/src/msg_validators/tx_validator/tx_proof_validator.ts +12 -18
  54. package/src/services/libp2p/libp2p_service.ts +14 -11
@@ -1,4 +1,4 @@
1
- import { type ProcessedTx, type Tx, type TxValidator } from '@aztec/circuit-types';
1
+ import { type ProcessedTx, type Tx, type TxValidationResult, type TxValidator } from '@aztec/circuit-types';
2
2
 
3
3
  export class AggregateTxValidator<T extends Tx | ProcessedTx> implements TxValidator<T> {
4
4
  #validators: TxValidator<T>[];
@@ -10,27 +10,23 @@ export class AggregateTxValidator<T extends Tx | ProcessedTx> implements TxValid
10
10
  this.#validators = validators;
11
11
  }
12
12
 
13
- async validateTxs(txs: T[]): Promise<[validTxs: T[], invalidTxs: T[], skippedTxs: T[]]> {
14
- const invalidTxs: T[] = [];
15
- const skippedTxs: T[] = [];
16
- let txPool = txs;
13
+ async validateTx(tx: T): Promise<TxValidationResult> {
14
+ const aggregate: { result: string; reason?: string[] } = { result: 'valid', reason: [] };
17
15
  for (const validator of this.#validators) {
18
- const [valid, invalid, skipped] = await validator.validateTxs(txPool);
19
- invalidTxs.push(...invalid);
20
- skippedTxs.push(...(skipped ?? []));
21
- txPool = valid;
22
- }
23
-
24
- return [txPool, invalidTxs, skippedTxs];
25
- }
26
-
27
- async validateTx(tx: T): Promise<boolean> {
28
- for (const validator of this.#validators) {
29
- const valid = await validator.validateTx(tx);
30
- if (!valid) {
31
- return false;
16
+ const result = await validator.validateTx(tx);
17
+ if (result.result === 'invalid') {
18
+ aggregate.result = 'invalid';
19
+ aggregate.reason!.push(...result.reason);
20
+ } else if (result.result === 'skipped') {
21
+ if (aggregate.result === 'valid') {
22
+ aggregate.result = 'skipped';
23
+ }
24
+ aggregate.reason!.push(...result.reason);
32
25
  }
33
26
  }
34
- return true;
27
+ if (aggregate.result === 'valid') {
28
+ delete aggregate.reason;
29
+ }
30
+ return aggregate as TxValidationResult;
35
31
  }
36
32
  }
@@ -0,0 +1,25 @@
1
+ import { type AnyTx, Tx, type TxValidationResult, type TxValidator } from '@aztec/circuit-types';
2
+ import { type Fr } from '@aztec/circuits.js';
3
+ import { createLogger } from '@aztec/foundation/log';
4
+
5
+ export interface ArchiveSource {
6
+ getArchiveIndices: (archives: Fr[]) => Promise<(bigint | undefined)[]>;
7
+ }
8
+
9
+ export class BlockHeaderTxValidator<T extends AnyTx> implements TxValidator<T> {
10
+ #log = createLogger('p2p:tx_validator:tx_block_header');
11
+ #archiveSource: ArchiveSource;
12
+
13
+ constructor(archiveSource: ArchiveSource) {
14
+ this.#archiveSource = archiveSource;
15
+ }
16
+
17
+ async validateTx(tx: T): Promise<TxValidationResult> {
18
+ const [index] = await this.#archiveSource.getArchiveIndices([tx.data.constants.historicalHeader.hash()]);
19
+ if (index === undefined) {
20
+ this.#log.warn(`Rejecting tx ${Tx.getHash(tx)} for referencing an unknown block header`);
21
+ return { result: 'invalid', reason: ['Block header not found'] };
22
+ }
23
+ return { result: 'valid' };
24
+ }
25
+ }
@@ -1,29 +1,14 @@
1
- import { Tx, type TxValidator } from '@aztec/circuit-types';
1
+ import { Tx, type TxValidationResult, type TxValidator } from '@aztec/circuit-types';
2
2
  import { createLogger } from '@aztec/foundation/log';
3
3
 
4
4
  export class DataTxValidator implements TxValidator<Tx> {
5
5
  #log = createLogger('p2p:tx_validator:tx_data');
6
6
 
7
- validateTxs(txs: Tx[]): Promise<[validTxs: Tx[], invalidTxs: Tx[]]> {
8
- const validTxs: Tx[] = [];
9
- const invalidTxs: Tx[] = [];
10
- for (const tx of txs) {
11
- if (!this.#hasCorrectExecutionRequests(tx)) {
12
- invalidTxs.push(tx);
13
- continue;
14
- }
15
-
16
- validTxs.push(tx);
17
- }
18
-
19
- return Promise.resolve([validTxs, invalidTxs]);
20
- }
21
-
22
- validateTx(tx: Tx): Promise<boolean> {
7
+ validateTx(tx: Tx): Promise<TxValidationResult> {
23
8
  return Promise.resolve(this.#hasCorrectExecutionRequests(tx));
24
9
  }
25
10
 
26
- #hasCorrectExecutionRequests(tx: Tx): boolean {
11
+ #hasCorrectExecutionRequests(tx: Tx): TxValidationResult {
27
12
  const callRequests = [
28
13
  ...tx.data.getRevertiblePublicCallRequests(),
29
14
  ...tx.data.getNonRevertiblePublicCallRequests(),
@@ -34,7 +19,7 @@ export class DataTxValidator implements TxValidator<Tx> {
34
19
  callRequests.length
35
20
  }. Got ${tx.enqueuedPublicFunctionCalls.length}.`,
36
21
  );
37
- return false;
22
+ return { result: 'invalid', reason: ['Wrong number of execution requests for public calls'] };
38
23
  }
39
24
 
40
25
  const invalidExecutionRequestIndex = tx.enqueuedPublicFunctionCalls.findIndex(
@@ -46,7 +31,7 @@ export class DataTxValidator implements TxValidator<Tx> {
46
31
  tx,
47
32
  )} because of incorrect execution requests for public call at index ${invalidExecutionRequestIndex}.`,
48
33
  );
49
- return false;
34
+ return { result: 'invalid', reason: ['Incorrect execution request for public call'] };
50
35
  }
51
36
 
52
37
  const teardownCallRequest = tx.data.getTeardownPublicCallRequest();
@@ -55,10 +40,10 @@ export class DataTxValidator implements TxValidator<Tx> {
55
40
  (teardownCallRequest && !tx.publicTeardownFunctionCall.isForCallRequest(teardownCallRequest));
56
41
  if (isInvalidTeardownExecutionRequest) {
57
42
  this.#log.warn(`Rejecting tx ${Tx.getHash(tx)} because of incorrect teardown execution requests.`);
58
- return false;
43
+ return { result: 'invalid', reason: ['Incorrect teardown execution request'] };
59
44
  }
60
45
 
61
- return true;
46
+ return { result: 'valid' };
62
47
  }
63
48
 
64
49
  // TODO: Check logs.
@@ -1,69 +1,33 @@
1
- import { type AnyTx, Tx, type TxValidator } from '@aztec/circuit-types';
1
+ import { type AnyTx, Tx, type TxValidationResult, type TxValidator } from '@aztec/circuit-types';
2
2
  import { createLogger } from '@aztec/foundation/log';
3
3
 
4
4
  export interface NullifierSource {
5
- getNullifierIndices: (nullifiers: Buffer[]) => Promise<(bigint | undefined)[]>;
5
+ nullifiersExist: (nullifiers: Buffer[]) => Promise<boolean[]>;
6
6
  }
7
7
 
8
8
  export class DoubleSpendTxValidator<T extends AnyTx> implements TxValidator<T> {
9
9
  #log = createLogger('p2p:tx_validator:tx_double_spend');
10
10
  #nullifierSource: NullifierSource;
11
11
 
12
- constructor(nullifierSource: NullifierSource, private readonly isValidatingBlock: boolean = true) {
12
+ constructor(nullifierSource: NullifierSource) {
13
13
  this.#nullifierSource = nullifierSource;
14
14
  }
15
15
 
16
- async validateTxs(txs: T[]): Promise<[validTxs: T[], invalidTxs: T[]]> {
17
- const validTxs: T[] = [];
18
- const invalidTxs: T[] = [];
19
- const thisBlockNullifiers = new Set<bigint>();
20
-
21
- for (const tx of txs) {
22
- if (!(await this.#uniqueNullifiers(tx, thisBlockNullifiers))) {
23
- invalidTxs.push(tx);
24
- continue;
25
- }
26
-
27
- validTxs.push(tx);
28
- }
29
-
30
- return [validTxs, invalidTxs];
31
- }
32
-
33
- validateTx(tx: T): Promise<boolean> {
34
- return this.#uniqueNullifiers(tx, new Set<bigint>());
35
- }
36
-
37
- async #uniqueNullifiers(tx: AnyTx, thisBlockNullifiers: Set<bigint>): Promise<boolean> {
16
+ async validateTx(tx: T): Promise<TxValidationResult> {
38
17
  const nullifiers = tx instanceof Tx ? tx.data.getNonEmptyNullifiers() : tx.txEffect.nullifiers;
39
18
 
40
19
  // Ditch this tx if it has repeated nullifiers
41
20
  const uniqueNullifiers = new Set(nullifiers);
42
21
  if (uniqueNullifiers.size !== nullifiers.length) {
43
22
  this.#log.warn(`Rejecting tx ${Tx.getHash(tx)} for emitting duplicate nullifiers`);
44
- return false;
45
- }
46
-
47
- if (this.isValidatingBlock) {
48
- for (const nullifier of nullifiers) {
49
- const nullifierBigInt = nullifier.toBigInt();
50
- if (thisBlockNullifiers.has(nullifierBigInt)) {
51
- this.#log.warn(`Rejecting tx ${Tx.getHash(tx)} for repeating a nullifier in the same block`);
52
- return false;
53
- }
54
-
55
- thisBlockNullifiers.add(nullifierBigInt);
56
- }
23
+ return { result: 'invalid', reason: ['Duplicate nullifier in tx'] };
57
24
  }
58
25
 
59
- const nullifierIndexes = await this.#nullifierSource.getNullifierIndices(nullifiers.map(n => n.toBuffer()));
60
-
61
- const hasDuplicates = nullifierIndexes.some(index => index !== undefined);
62
- if (hasDuplicates) {
63
- this.#log.warn(`Rejecting tx ${Tx.getHash(tx)} for repeating nullifiers present in state trees`);
64
- return false;
26
+ if ((await this.#nullifierSource.nullifiersExist(nullifiers.map(n => n.toBuffer()))).some(Boolean)) {
27
+ this.#log.warn(`Rejecting tx ${Tx.getHash(tx)} for repeating a nullifier`);
28
+ return { result: 'invalid', reason: ['Existing nullifier'] };
65
29
  }
66
30
 
67
- return true;
31
+ return { result: 'valid' };
68
32
  }
69
33
  }
@@ -3,3 +3,4 @@ export * from './data_validator.js';
3
3
  export * from './double_spend_validator.js';
4
4
  export * from './metadata_validator.js';
5
5
  export * from './tx_proof_validator.js';
6
+ export * from './block_header_validator.js';
@@ -1,4 +1,4 @@
1
- import { type AnyTx, Tx, type TxValidator } from '@aztec/circuit-types';
1
+ import { type AnyTx, Tx, type TxValidationResult, type TxValidator } from '@aztec/circuit-types';
2
2
  import { type Fr } from '@aztec/circuits.js';
3
3
  import { createLogger } from '@aztec/foundation/log';
4
4
 
@@ -7,28 +7,15 @@ export class MetadataTxValidator<T extends AnyTx> implements TxValidator<T> {
7
7
 
8
8
  constructor(private chainId: Fr, private blockNumber: Fr) {}
9
9
 
10
- validateTxs(txs: T[]): Promise<[validTxs: T[], invalidTxs: T[]]> {
11
- const validTxs: T[] = [];
12
- const invalidTxs: T[] = [];
13
- for (const tx of txs) {
14
- if (!this.#hasCorrectChainId(tx)) {
15
- invalidTxs.push(tx);
16
- continue;
17
- }
18
-
19
- if (!this.#isValidForBlockNumber(tx)) {
20
- invalidTxs.push(tx);
21
- continue;
22
- }
23
-
24
- validTxs.push(tx);
10
+ validateTx(tx: T): Promise<TxValidationResult> {
11
+ const errors = [];
12
+ if (!this.#hasCorrectChainId(tx)) {
13
+ errors.push('Incorrect chain id');
25
14
  }
26
-
27
- return Promise.resolve([validTxs, invalidTxs]);
28
- }
29
-
30
- validateTx(tx: T): Promise<boolean> {
31
- return Promise.resolve(this.#hasCorrectChainId(tx) && this.#isValidForBlockNumber(tx));
15
+ if (!this.#isValidForBlockNumber(tx)) {
16
+ errors.push('Invalid block number');
17
+ }
18
+ return Promise.resolve(errors.length > 0 ? { result: 'invalid', reason: errors } : { result: 'valid' });
32
19
  }
33
20
 
34
21
  #hasCorrectChainId(tx: T): boolean {
@@ -1,4 +1,9 @@
1
- import { type ClientProtocolCircuitVerifier, Tx, type TxValidator } from '@aztec/circuit-types';
1
+ import {
2
+ type ClientProtocolCircuitVerifier,
3
+ Tx,
4
+ type TxValidationResult,
5
+ type TxValidator,
6
+ } from '@aztec/circuit-types';
2
7
  import { createLogger } from '@aztec/foundation/log';
3
8
 
4
9
  export class TxProofValidator implements TxValidator<Tx> {
@@ -6,23 +11,12 @@ export class TxProofValidator implements TxValidator<Tx> {
6
11
 
7
12
  constructor(private verifier: ClientProtocolCircuitVerifier) {}
8
13
 
9
- async validateTxs(txs: Tx[]): Promise<[validTxs: Tx[], invalidTxs: Tx[]]> {
10
- const validTxs: Tx[] = [];
11
- const invalidTxs: Tx[] = [];
12
-
13
- for (const tx of txs) {
14
- if (await this.verifier.verifyProof(tx)) {
15
- validTxs.push(tx);
16
- } else {
17
- this.#log.warn(`Rejecting tx ${Tx.getHash(tx)} for invalid proof`);
18
- invalidTxs.push(tx);
19
- }
14
+ async validateTx(tx: Tx): Promise<TxValidationResult> {
15
+ if (!(await this.verifier.verifyProof(tx))) {
16
+ this.#log.warn(`Rejecting tx ${Tx.getHash(tx)} for invalid proof`);
17
+ return { result: 'invalid', reason: ['Invalid proof'] };
20
18
  }
21
-
22
- return [validTxs, invalidTxs];
23
- }
24
-
25
- validateTx(tx: Tx): Promise<boolean> {
26
- return this.verifier.verifyProof(tx);
19
+ this.#log.trace(`Accepted ${Tx.getHash(tx)} with valid proof`);
20
+ return { result: 'valid' };
27
21
  }
28
22
  }
@@ -6,17 +6,18 @@ import {
6
6
  type Gossipable,
7
7
  type L2BlockSource,
8
8
  MerkleTreeId,
9
+ P2PClientType,
9
10
  PeerErrorSeverity,
10
11
  type PeerInfo,
11
12
  type RawGossipMessage,
12
13
  TopicTypeMap,
13
14
  Tx,
14
15
  TxHash,
16
+ type TxValidationResult,
15
17
  type WorldStateSynchronizer,
16
18
  getTopicTypeForClientType,
17
19
  metricsTopicStrToLabels,
18
20
  } from '@aztec/circuit-types';
19
- import { P2PClientType } from '@aztec/circuit-types';
20
21
  import { Fr } from '@aztec/circuits.js';
21
22
  import { type EpochCache } from '@aztec/epoch-cache';
22
23
  import { createLogger } from '@aztec/foundation/log';
@@ -73,14 +74,14 @@ import { GossipSubEvent } from '../types.js';
73
74
 
74
75
  interface MessageValidator {
75
76
  validator: {
76
- validateTx(tx: Tx): Promise<boolean>;
77
+ validateTx(tx: Tx): Promise<TxValidationResult>;
77
78
  };
78
79
  severity: PeerErrorSeverity;
79
80
  }
80
81
 
81
82
  interface ValidationResult {
82
83
  name: string;
83
- isValid: boolean;
84
+ isValid: TxValidationResult;
84
85
  severity: PeerErrorSeverity;
85
86
  }
86
87
 
@@ -568,7 +569,7 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
568
569
  return false;
569
570
  }
570
571
 
571
- if (!validProof) {
572
+ if (validProof.result === 'invalid') {
572
573
  // If the proof is invalid, but the txHash is correct, then this is an active attack and we severly punish
573
574
  this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
574
575
  return false;
@@ -704,9 +705,10 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
704
705
  },
705
706
  doubleSpendValidator: {
706
707
  validator: new DoubleSpendTxValidator({
707
- getNullifierIndices: (nullifiers: Buffer[]) => {
708
+ nullifiersExist: async (nullifiers: Buffer[]) => {
708
709
  const merkleTree = this.worldStateSynchronizer.getCommitted();
709
- return merkleTree.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, nullifiers);
710
+ const indices = await merkleTree.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, nullifiers);
711
+ return indices.map(index => index !== undefined);
710
712
  },
711
713
  }),
712
714
  severity: PeerErrorSeverity.HighToleranceError,
@@ -725,8 +727,8 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
725
727
  messageValidators: Record<string, MessageValidator>,
726
728
  ): Promise<ValidationOutcome> {
727
729
  const validationPromises = Object.entries(messageValidators).map(async ([name, { validator, severity }]) => {
728
- const isValid = await validator.validateTx(tx);
729
- return { name, isValid, severity };
730
+ const { result } = await validator.validateTx(tx);
731
+ return { name, isValid: result === 'valid', severity };
730
732
  });
731
733
 
732
734
  // A promise that resolves when all validations have been run
@@ -767,16 +769,17 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
767
769
  }
768
770
 
769
771
  const snapshotValidator = new DoubleSpendTxValidator({
770
- getNullifierIndices: (nullifiers: Buffer[]) => {
772
+ nullifiersExist: async (nullifiers: Buffer[]) => {
771
773
  const merkleTree = this.worldStateSynchronizer.getSnapshot(
772
774
  blockNumber - this.config.severePeerPenaltyBlockLength,
773
775
  );
774
- return merkleTree.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, nullifiers);
776
+ const indices = await merkleTree.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, nullifiers);
777
+ return indices.map(index => index !== undefined);
775
778
  },
776
779
  });
777
780
 
778
781
  const validSnapshot = await snapshotValidator.validateTx(tx);
779
- if (!validSnapshot) {
782
+ if (validSnapshot.result !== 'valid') {
780
783
  this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
781
784
  return false;
782
785
  }