@aztec/p2p 0.55.0 → 0.56.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 (78) hide show
  1. package/dest/attestation_pool/memory_attestation_pool.d.ts.map +1 -1
  2. package/dest/attestation_pool/memory_attestation_pool.js +8 -7
  3. package/dest/attestation_pool/mocks.d.ts.map +1 -1
  4. package/dest/attestation_pool/mocks.js +6 -5
  5. package/dest/client/index.d.ts +2 -2
  6. package/dest/client/index.d.ts.map +1 -1
  7. package/dest/client/index.js +43 -38
  8. package/dest/client/p2p_client.d.ts.map +1 -1
  9. package/dest/client/p2p_client.js +1 -3
  10. package/dest/config.d.ts +49 -0
  11. package/dest/config.d.ts.map +1 -1
  12. package/dest/config.js +66 -2
  13. package/dest/index.d.ts +1 -0
  14. package/dest/index.d.ts.map +1 -1
  15. package/dest/index.js +2 -1
  16. package/dest/mocks/index.d.ts +13 -4
  17. package/dest/mocks/index.d.ts.map +1 -1
  18. package/dest/mocks/index.js +26 -9
  19. package/dest/service/libp2p_service.d.ts +25 -11
  20. package/dest/service/libp2p_service.d.ts.map +1 -1
  21. package/dest/service/libp2p_service.js +143 -28
  22. package/dest/service/peer_manager.d.ts +9 -13
  23. package/dest/service/peer_manager.d.ts.map +1 -1
  24. package/dest/service/peer_manager.js +15 -1
  25. package/dest/service/peer_scoring.d.ts +32 -0
  26. package/dest/service/peer_scoring.d.ts.map +1 -0
  27. package/dest/service/peer_scoring.js +67 -0
  28. package/dest/service/reqresp/interface.d.ts +7 -0
  29. package/dest/service/reqresp/interface.d.ts.map +1 -1
  30. package/dest/service/reqresp/interface.js +7 -1
  31. package/dest/service/reqresp/rate_limiter/rate_limiter.d.ts +13 -3
  32. package/dest/service/reqresp/rate_limiter/rate_limiter.d.ts.map +1 -1
  33. package/dest/service/reqresp/rate_limiter/rate_limiter.js +29 -7
  34. package/dest/service/reqresp/reqresp.d.ts +56 -5
  35. package/dest/service/reqresp/reqresp.d.ts.map +1 -1
  36. package/dest/service/reqresp/reqresp.js +73 -9
  37. package/dest/tx_validator/aggregate_tx_validator.d.ts +8 -0
  38. package/dest/tx_validator/aggregate_tx_validator.d.ts.map +1 -0
  39. package/dest/tx_validator/aggregate_tx_validator.js +32 -0
  40. package/dest/tx_validator/data_validator.d.ts +7 -0
  41. package/dest/tx_validator/data_validator.d.ts.map +1 -0
  42. package/dest/tx_validator/data_validator.js +50 -0
  43. package/dest/tx_validator/double_spend_validator.d.ts +13 -0
  44. package/dest/tx_validator/double_spend_validator.d.ts.map +1 -0
  45. package/dest/tx_validator/double_spend_validator.js +56 -0
  46. package/dest/tx_validator/index.d.ts +6 -0
  47. package/dest/tx_validator/index.d.ts.map +1 -0
  48. package/dest/tx_validator/index.js +6 -0
  49. package/dest/tx_validator/metadata_validator.d.ts +11 -0
  50. package/dest/tx_validator/metadata_validator.d.ts.map +1 -0
  51. package/dest/tx_validator/metadata_validator.js +53 -0
  52. package/dest/tx_validator/tx_proof_validator.d.ts +9 -0
  53. package/dest/tx_validator/tx_proof_validator.d.ts.map +1 -0
  54. package/dest/tx_validator/tx_proof_validator.js +29 -0
  55. package/dest/util.d.ts +7 -0
  56. package/dest/util.d.ts.map +1 -1
  57. package/dest/util.js +1 -1
  58. package/package.json +6 -6
  59. package/src/attestation_pool/memory_attestation_pool.ts +7 -6
  60. package/src/attestation_pool/mocks.ts +6 -4
  61. package/src/client/index.ts +65 -47
  62. package/src/client/p2p_client.ts +0 -2
  63. package/src/config.ts +127 -0
  64. package/src/index.ts +1 -0
  65. package/src/mocks/index.ts +35 -7
  66. package/src/service/libp2p_service.ts +182 -36
  67. package/src/service/peer_manager.ts +23 -4
  68. package/src/service/peer_scoring.ts +81 -0
  69. package/src/service/reqresp/interface.ts +20 -0
  70. package/src/service/reqresp/rate_limiter/rate_limiter.ts +30 -7
  71. package/src/service/reqresp/reqresp.ts +82 -8
  72. package/src/tx_validator/aggregate_tx_validator.ts +34 -0
  73. package/src/tx_validator/data_validator.ts +65 -0
  74. package/src/tx_validator/double_spend_validator.ts +69 -0
  75. package/src/tx_validator/index.ts +5 -0
  76. package/src/tx_validator/metadata_validator.ts +65 -0
  77. package/src/tx_validator/tx_proof_validator.ts +28 -0
  78. package/src/util.ts +8 -0
@@ -8,11 +8,17 @@ import { type Libp2p } from 'libp2p';
8
8
  import { type Uint8ArrayList } from 'uint8arraylist';
9
9
 
10
10
  import { CollectiveReqRespTimeoutError, IndiviualReqRespTimeoutError } from '../../errors/reqresp.error.js';
11
+ import { type PeerManager } from '../peer_manager.js';
12
+ import { PeerErrorSeverity } from '../peer_scoring.js';
11
13
  import { type P2PReqRespConfig } from './config.js';
12
14
  import {
13
15
  DEFAULT_SUB_PROTOCOL_HANDLERS,
16
+ DEFAULT_SUB_PROTOCOL_VALIDATORS,
14
17
  type ReqRespSubProtocol,
15
18
  type ReqRespSubProtocolHandlers,
19
+ type ReqRespSubProtocolValidators,
20
+ type SubProtocolMap,
21
+ subProtocolMap,
16
22
  } from './interface.js';
17
23
  import { RequestResponseRateLimiter } from './rate_limiter/rate_limiter.js';
18
24
 
@@ -35,23 +41,28 @@ export class ReqResp {
35
41
  private overallRequestTimeoutMs: number;
36
42
  private individualRequestTimeoutMs: number;
37
43
 
44
+ // Warning, if the `start` function is not called as the parent class constructor, then the default sub protocol handlers will be used ( not good )
38
45
  private subProtocolHandlers: ReqRespSubProtocolHandlers = DEFAULT_SUB_PROTOCOL_HANDLERS;
46
+ private subProtocolValidators: ReqRespSubProtocolValidators = DEFAULT_SUB_PROTOCOL_VALIDATORS;
47
+
39
48
  private rateLimiter: RequestResponseRateLimiter;
40
49
 
41
- constructor(config: P2PReqRespConfig, protected readonly libp2p: Libp2p) {
50
+ constructor(config: P2PReqRespConfig, protected readonly libp2p: Libp2p, private peerManager: PeerManager) {
42
51
  this.logger = createDebugLogger('aztec:p2p:reqresp');
43
52
 
44
53
  this.overallRequestTimeoutMs = config.overallRequestTimeoutMs;
45
54
  this.individualRequestTimeoutMs = config.individualRequestTimeoutMs;
46
55
 
47
- this.rateLimiter = new RequestResponseRateLimiter();
56
+ this.rateLimiter = new RequestResponseRateLimiter(peerManager);
48
57
  }
49
58
 
50
59
  /**
51
60
  * Start the reqresp service
52
61
  */
53
- async start(subProtocolHandlers: ReqRespSubProtocolHandlers) {
62
+ async start(subProtocolHandlers: ReqRespSubProtocolHandlers, subProtocolValidators: ReqRespSubProtocolValidators) {
54
63
  this.subProtocolHandlers = subProtocolHandlers;
64
+ this.subProtocolValidators = subProtocolValidators;
65
+
55
66
  // Register all protocol handlers
56
67
  for (const subProtocol of Object.keys(this.subProtocolHandlers)) {
57
68
  await this.libp2p.handle(subProtocol, this.streamHandler.bind(this, subProtocol as ReqRespSubProtocol));
@@ -76,29 +87,64 @@ export class ReqResp {
76
87
  * Send a request to peers, returns the first response
77
88
  *
78
89
  * @param subProtocol - The protocol being requested
79
- * @param payload - The payload to send
90
+ * @param request - The request to send
80
91
  * @returns - The response from the peer, otherwise undefined
92
+ *
93
+ * @description
94
+ * This method attempts to send a request to all active peers using the specified sub-protocol.
95
+ * It opens a stream with each peer, sends the request, and awaits a response.
96
+ * If a valid response is received, it returns the response; otherwise, it continues to the next peer.
97
+ * If no response is received from any peer, it returns undefined.
98
+ *
99
+ * The method performs the following steps:
100
+ * - Iterates over all active peers.
101
+ * - Opens a stream with each peer using the specified sub-protocol.
102
+ *
103
+ * When a response is received, it is validated using the given sub protocols response validator.
104
+ * To see the interface for the response validator - see `interface.ts`
105
+ *
106
+ * Failing a response validation requests in a severe peer penalty, and will
107
+ * prompt the node to continue to search to the next peer.
108
+ * For example, a transaction request validator will check that the payload returned does in fact
109
+ * match the txHash that was requested. A peer that fails this check an only be an extremely naughty peer.
110
+ *
111
+ * This entire operation is wrapped in an overall timeout, that is independent of the
112
+ * peer it is requesting data from.
113
+ *
81
114
  */
82
- async sendRequest(subProtocol: ReqRespSubProtocol, payload: Buffer): Promise<Buffer | undefined> {
115
+ async sendRequest<SubProtocol extends ReqRespSubProtocol>(
116
+ subProtocol: SubProtocol,
117
+ request: InstanceType<SubProtocolMap[SubProtocol]['request']>,
118
+ ): Promise<InstanceType<SubProtocolMap[SubProtocol]['response']> | undefined> {
83
119
  const requestFunction = async () => {
120
+ const responseValidator = this.subProtocolValidators[subProtocol];
121
+ const requestBuffer = request.toBuffer();
122
+
84
123
  // Get active peers
85
124
  const peers = this.libp2p.getPeers();
86
125
 
87
126
  // Attempt to ask all of our peers
88
127
  for (const peer of peers) {
89
- const response = await this.sendRequestToPeer(peer, subProtocol, payload);
128
+ const response = await this.sendRequestToPeer(peer, subProtocol, requestBuffer);
90
129
 
91
130
  // If we get a response, return it, otherwise we iterate onto the next peer
92
131
  // We do not consider it a success if we have an empty buffer
93
132
  if (response && response.length > 0) {
94
- return response;
133
+ const object = subProtocolMap[subProtocol].response.fromBuffer(response);
134
+ // The response validator handles peer punishment within
135
+ const isValid = await responseValidator(request, object, peer);
136
+ if (!isValid) {
137
+ this.logger.error(`Invalid response for ${subProtocol} from ${peer.toString()}`);
138
+ return undefined;
139
+ }
140
+ return object;
95
141
  }
96
142
  }
97
143
  return undefined;
98
144
  };
99
145
 
100
146
  try {
101
- return await executeTimeoutWithCustomError<Buffer | undefined>(
147
+ return await executeTimeoutWithCustomError<InstanceType<SubProtocolMap[SubProtocol]['response']> | undefined>(
102
148
  requestFunction,
103
149
  this.overallRequestTimeoutMs,
104
150
  () => new CollectiveReqRespTimeoutError(),
@@ -112,10 +158,26 @@ export class ReqResp {
112
158
  /**
113
159
  * Sends a request to a specific peer
114
160
  *
161
+ * We first dial a particular protocol for the peer, this ensures that the peer knows
162
+ * what to respond with
163
+ *
164
+ *
115
165
  * @param peerId - The peer to send the request to
116
166
  * @param subProtocol - The protocol to use to request
117
167
  * @param payload - The payload to send
118
168
  * @returns If the request is successful, the response is returned, otherwise undefined
169
+ *
170
+ * @description
171
+ * This method attempts to open a stream with the specified peer, send the payload,
172
+ * and await a response.
173
+ * If an error occurs, it penalizes the peer and returns undefined.
174
+ *
175
+ * The method performs the following steps:
176
+ * - Opens a stream with the peer using the specified sub-protocol.
177
+ * - Sends the payload and awaits a response with a timeout.
178
+ *
179
+ * If the stream is not closed by the dialled peer, and a timeout occurs, then
180
+ * the stream is closed on the requester's end and sender (us) updates its peer score
119
181
  */
120
182
  async sendRequestToPeer(
121
183
  peerId: PeerId,
@@ -128,6 +190,7 @@ export class ReqResp {
128
190
 
129
191
  this.logger.debug(`Stream opened with ${peerId.toString()} for ${subProtocol}`);
130
192
 
193
+ // Open the stream with a timeout
131
194
  const result = await executeTimeoutWithCustomError<Buffer>(
132
195
  (): Promise<Buffer> => pipe([payload], stream!, this.readMessage),
133
196
  this.individualRequestTimeoutMs,
@@ -140,6 +203,7 @@ export class ReqResp {
140
203
  return result;
141
204
  } catch (e: any) {
142
205
  this.logger.error(`${e.message} | peerId: ${peerId.toString()} | subProtocol: ${subProtocol}`);
206
+ this.peerManager.penalizePeer(peerId, PeerErrorSeverity.HighToleranceError);
143
207
  } finally {
144
208
  if (stream) {
145
209
  try {
@@ -172,6 +236,16 @@ export class ReqResp {
172
236
  * Reads the incoming stream, determines the protocol, then triggers the appropriate handler
173
237
  *
174
238
  * @param param0 - The incoming stream data
239
+ *
240
+ * @description
241
+ * An individual stream handler will be bound to each sub protocol, and handles returning data back
242
+ * to the requesting peer.
243
+ *
244
+ * The sub protocol handler interface is defined within `interface.ts` and will be assigned to the
245
+ * req resp service on start up.
246
+ *
247
+ * We check rate limits for each peer, note the peer will be penalised within the rate limiter implementation
248
+ * if they exceed their peer specific limits.
175
249
  */
176
250
  private async streamHandler(protocol: ReqRespSubProtocol, { stream, connection }: IncomingStreamData) {
177
251
  // Store a reference to from this for the async generator
@@ -0,0 +1,34 @@
1
+ import { type ProcessedTx, type Tx, type TxValidator } from '@aztec/circuit-types';
2
+
3
+ export class AggregateTxValidator<T extends Tx | ProcessedTx> implements TxValidator<T> {
4
+ #validators: TxValidator<T>[];
5
+ constructor(...validators: TxValidator<T>[]) {
6
+ if (validators.length === 0) {
7
+ throw new Error('At least one validator must be provided');
8
+ }
9
+
10
+ this.#validators = validators;
11
+ }
12
+
13
+ async validateTxs(txs: T[]): Promise<[validTxs: T[], invalidTxs: T[]]> {
14
+ const invalidTxs: T[] = [];
15
+ let txPool = txs;
16
+ for (const validator of this.#validators) {
17
+ const [valid, invalid] = await validator.validateTxs(txPool);
18
+ invalidTxs.push(...invalid);
19
+ txPool = valid;
20
+ }
21
+
22
+ return [txPool, invalidTxs];
23
+ }
24
+
25
+ async validateTx(tx: T): Promise<boolean> {
26
+ for (const validator of this.#validators) {
27
+ const valid = await validator.validateTx(tx);
28
+ if (!valid) {
29
+ return false;
30
+ }
31
+ }
32
+ return true;
33
+ }
34
+ }
@@ -0,0 +1,65 @@
1
+ import { Tx, type TxValidator } from '@aztec/circuit-types';
2
+ import { createDebugLogger } from '@aztec/foundation/log';
3
+
4
+ export class DataTxValidator implements TxValidator<Tx> {
5
+ #log = createDebugLogger('aztec:sequencer:tx_validator:tx_data');
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> {
23
+ return Promise.resolve(this.#hasCorrectExecutionRequests(tx));
24
+ }
25
+
26
+ #hasCorrectExecutionRequests(tx: Tx): boolean {
27
+ const callRequests = [
28
+ ...tx.data.getRevertiblePublicCallRequests(),
29
+ ...tx.data.getNonRevertiblePublicCallRequests(),
30
+ ];
31
+ if (callRequests.length !== tx.enqueuedPublicFunctionCalls.length) {
32
+ this.#log.warn(
33
+ `Rejecting tx ${Tx.getHash(tx)} because of mismatch number of execution requests for public calls. Expected ${
34
+ callRequests.length
35
+ }. Got ${tx.enqueuedPublicFunctionCalls.length}.`,
36
+ );
37
+ return false;
38
+ }
39
+
40
+ const invalidExecutionRequestIndex = tx.enqueuedPublicFunctionCalls.findIndex(
41
+ (execRequest, i) => !execRequest.isForCallRequest(callRequests[i]),
42
+ );
43
+ if (invalidExecutionRequestIndex !== -1) {
44
+ this.#log.warn(
45
+ `Rejecting tx ${Tx.getHash(
46
+ tx,
47
+ )} because of incorrect execution requests for public call at index ${invalidExecutionRequestIndex}.`,
48
+ );
49
+ return false;
50
+ }
51
+
52
+ const teardownCallRequest = tx.data.getTeardownPublicCallRequest();
53
+ const isInvalidTeardownExecutionRequest =
54
+ (!teardownCallRequest && !tx.publicTeardownFunctionCall.isEmpty()) ||
55
+ (teardownCallRequest && !tx.publicTeardownFunctionCall.isForCallRequest(teardownCallRequest));
56
+ if (isInvalidTeardownExecutionRequest) {
57
+ this.#log.warn(`Rejecting tx ${Tx.getHash(tx)} because of incorrect teardown execution requests.`);
58
+ return false;
59
+ }
60
+
61
+ return true;
62
+ }
63
+
64
+ // TODO: Check logs.
65
+ }
@@ -0,0 +1,69 @@
1
+ import { type AnyTx, Tx, type TxValidator } from '@aztec/circuit-types';
2
+ import { Fr } from '@aztec/circuits.js';
3
+ import { createDebugLogger } from '@aztec/foundation/log';
4
+
5
+ export interface NullifierSource {
6
+ getNullifierIndex: (nullifier: Fr) => Promise<bigint | undefined>;
7
+ }
8
+
9
+ export class DoubleSpendTxValidator<T extends AnyTx> implements TxValidator<T> {
10
+ #log = createDebugLogger('aztec:sequencer:tx_validator:tx_double_spend');
11
+ #nullifierSource: NullifierSource;
12
+
13
+ constructor(nullifierSource: NullifierSource, private readonly isValidatingBlock: boolean = true) {
14
+ this.#nullifierSource = nullifierSource;
15
+ }
16
+
17
+ async validateTxs(txs: T[]): Promise<[validTxs: T[], invalidTxs: T[]]> {
18
+ const validTxs: T[] = [];
19
+ const invalidTxs: T[] = [];
20
+ const thisBlockNullifiers = new Set<bigint>();
21
+
22
+ for (const tx of txs) {
23
+ if (!(await this.#uniqueNullifiers(tx, thisBlockNullifiers))) {
24
+ invalidTxs.push(tx);
25
+ continue;
26
+ }
27
+
28
+ validTxs.push(tx);
29
+ }
30
+
31
+ return [validTxs, invalidTxs];
32
+ }
33
+
34
+ validateTx(tx: T): Promise<boolean> {
35
+ return this.#uniqueNullifiers(tx, new Set<bigint>());
36
+ }
37
+
38
+ async #uniqueNullifiers(tx: AnyTx, thisBlockNullifiers: Set<bigint>): Promise<boolean> {
39
+ const nullifiers = tx.data.getNonEmptyNullifiers().map(x => x.toBigInt());
40
+
41
+ // Ditch this tx if it has repeated nullifiers
42
+ const uniqueNullifiers = new Set(nullifiers);
43
+ if (uniqueNullifiers.size !== nullifiers.length) {
44
+ this.#log.warn(`Rejecting tx ${Tx.getHash(tx)} for emitting duplicate nullifiers`);
45
+ return false;
46
+ }
47
+
48
+ if (this.isValidatingBlock) {
49
+ for (const nullifier of nullifiers) {
50
+ if (thisBlockNullifiers.has(nullifier)) {
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(nullifier);
56
+ }
57
+ }
58
+
59
+ const nullifierIndexes = await Promise.all(nullifiers.map(n => this.#nullifierSource.getNullifierIndex(new Fr(n))));
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;
65
+ }
66
+
67
+ return true;
68
+ }
69
+ }
@@ -0,0 +1,5 @@
1
+ export * from './aggregate_tx_validator.js';
2
+ export * from './data_validator.js';
3
+ export * from './double_spend_validator.js';
4
+ export * from './metadata_validator.js';
5
+ export * from './tx_proof_validator.js';
@@ -0,0 +1,65 @@
1
+ import { type AnyTx, Tx, type TxValidator } from '@aztec/circuit-types';
2
+ import { type Fr } from '@aztec/circuits.js';
3
+ import { createDebugLogger } from '@aztec/foundation/log';
4
+
5
+ export class MetadataTxValidator<T extends AnyTx> implements TxValidator<T> {
6
+ #log = createDebugLogger('aztec:sequencer:tx_validator:tx_metadata');
7
+
8
+ constructor(private chainId: Fr, private blockNumber: Fr) {}
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);
25
+ }
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));
32
+ }
33
+
34
+ #hasCorrectChainId(tx: T): boolean {
35
+ if (!tx.data.constants.txContext.chainId.equals(this.chainId)) {
36
+ this.#log.warn(
37
+ `Rejecting tx ${Tx.getHash(
38
+ tx,
39
+ )} because of incorrect chain ${tx.data.constants.txContext.chainId.toNumber()} != ${this.chainId.toNumber()}`,
40
+ );
41
+ return false;
42
+ } else {
43
+ return true;
44
+ }
45
+ }
46
+
47
+ #isValidForBlockNumber(tx: T): boolean {
48
+ const target =
49
+ tx instanceof Tx
50
+ ? tx.data.forRollup?.rollupValidationRequests || tx.data.forPublic!.validationRequests.forRollup
51
+ : tx.data.rollupValidationRequests;
52
+ const maxBlockNumber = target.maxBlockNumber;
53
+
54
+ if (maxBlockNumber.isSome && maxBlockNumber.value < this.blockNumber) {
55
+ this.#log.warn(
56
+ `Rejecting tx ${Tx.getHash(tx)} for low max block number. Tx max block number: ${
57
+ maxBlockNumber.value
58
+ }, current block number: ${this.blockNumber}.`,
59
+ );
60
+ return false;
61
+ } else {
62
+ return true;
63
+ }
64
+ }
65
+ }
@@ -0,0 +1,28 @@
1
+ import { type ClientProtocolCircuitVerifier, Tx, type TxValidator } from '@aztec/circuit-types';
2
+ import { createDebugLogger } from '@aztec/foundation/log';
3
+
4
+ export class TxProofValidator implements TxValidator<Tx> {
5
+ #log = createDebugLogger('aztec:sequencer:tx_validator:private_proof');
6
+
7
+ constructor(private verifier: ClientProtocolCircuitVerifier) {}
8
+
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
+ }
20
+ }
21
+
22
+ return [validTxs, invalidTxs];
23
+ }
24
+
25
+ validateTx(tx: Tx): Promise<boolean> {
26
+ return this.verifier.verifyProof(tx);
27
+ }
28
+ }
package/src/util.ts CHANGED
@@ -1,4 +1,12 @@
1
+ import type { GossipSub } from '@chainsafe/libp2p-gossipsub';
1
2
  import { resolve } from 'dns/promises';
3
+ import type { Libp2p } from 'libp2p';
4
+
5
+ export interface PubSubLibp2p extends Libp2p {
6
+ services: {
7
+ pubsub: GossipSub;
8
+ };
9
+ }
2
10
 
3
11
  /**
4
12
  * Converts an address string to a multiaddr string.