@aztec/validator-client 0.85.0-alpha-testnet.5 → 0.85.0-alpha-testnet.7

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.
@@ -1,6 +1,6 @@
1
1
  import type { Fr } from '@aztec/foundation/fields';
2
2
  import { BlockAttestation, BlockProposal } from '@aztec/stdlib/p2p';
3
- import type { BlockHeader, TxHash } from '@aztec/stdlib/tx';
3
+ import type { BlockHeader, Tx } from '@aztec/stdlib/tx';
4
4
  import type { ValidatorKeyStore } from '../key_store/interface.js';
5
5
  export declare class ValidationService {
6
6
  private keyStore;
@@ -14,7 +14,7 @@ export declare class ValidationService {
14
14
  *
15
15
  * @returns A block proposal signing the above information (not the current implementation!!!)
16
16
  */
17
- createBlockProposal(header: BlockHeader, archive: Fr, txs: TxHash[]): Promise<BlockProposal>;
17
+ createBlockProposal(header: BlockHeader, archive: Fr, txs: Tx[]): Promise<BlockProposal>;
18
18
  /**
19
19
  * Attest to the given block proposal constructed by the current sequencer
20
20
  *
@@ -1 +1 @@
1
- {"version":3,"file":"validation_service.d.ts","sourceRoot":"","sources":["../../src/duties/validation_service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,0BAA0B,CAAC;AACnD,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAA8C,MAAM,mBAAmB,CAAC;AAChH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAE5D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAEnE,qBAAa,iBAAiB;IAChB,OAAO,CAAC,QAAQ;gBAAR,QAAQ,EAAE,iBAAiB;IAE/C;;;;;;;;OAQG;IACH,mBAAmB,CAAC,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,aAAa,CAAC;IAM5F;;;;;;;;OAQG;IACG,gBAAgB,CAAC,QAAQ,EAAE,aAAa,GAAG,OAAO,CAAC,gBAAgB,CAAC;CAS3E"}
1
+ {"version":3,"file":"validation_service.d.ts","sourceRoot":"","sources":["../../src/duties/validation_service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,0BAA0B,CAAC;AACnD,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAA8C,MAAM,mBAAmB,CAAC;AAChH,OAAO,KAAK,EAAE,WAAW,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AAExD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAEnE,qBAAa,iBAAiB;IAChB,OAAO,CAAC,QAAQ;gBAAR,QAAQ,EAAE,iBAAiB;IAE/C;;;;;;;;OAQG;IACG,mBAAmB,CAAC,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,aAAa,CAAC;IAQ9F;;;;;;;;OAQG;IACG,gBAAgB,CAAC,QAAQ,EAAE,aAAa,GAAG,OAAO,CAAC,gBAAgB,CAAC;CAS3E"}
@@ -14,9 +14,11 @@ export class ValidationService {
14
14
  * @param txs - TxHash[] ordered list of transactions
15
15
  *
16
16
  * @returns A block proposal signing the above information (not the current implementation!!!)
17
- */ createBlockProposal(header, archive, txs) {
17
+ */ async createBlockProposal(header, archive, txs) {
18
18
  const payloadSigner = (payload)=>this.keyStore.signMessage(payload);
19
- return BlockProposal.createProposalFromSigner(new ConsensusPayload(header, archive, txs), payloadSigner);
19
+ // TODO: check if this is calculated earlier / can not be recomputed
20
+ const txHashes = await Promise.all(txs.map((tx)=>tx.getTxHash()));
21
+ return BlockProposal.createProposalFromSigner(new ConsensusPayload(header, archive, txHashes), txs, payloadSigner);
20
22
  }
21
23
  /**
22
24
  * Attest to the given block proposal constructed by the current sequencer
@@ -5,7 +5,7 @@ import { DateProvider, type Timer } from '@aztec/foundation/timer';
5
5
  import type { P2P } from '@aztec/p2p';
6
6
  import type { L2Block } from '@aztec/stdlib/block';
7
7
  import type { BlockAttestation, BlockProposal } from '@aztec/stdlib/p2p';
8
- import type { BlockHeader, GlobalVariables, Tx, TxHash } from '@aztec/stdlib/tx';
8
+ import type { BlockHeader, GlobalVariables, Tx } from '@aztec/stdlib/tx';
9
9
  import { type TelemetryClient, WithTracer } from '@aztec/telemetry-client';
10
10
  import type { ValidatorClientConfig } from './config.js';
11
11
  import type { ValidatorKeyStore } from './key_store/interface.js';
@@ -27,7 +27,7 @@ export interface Validator {
27
27
  start(): Promise<void>;
28
28
  registerBlockProposalHandler(): void;
29
29
  registerBlockBuilder(blockBuilder: BlockBuilderCallback): void;
30
- createBlockProposal(header: BlockHeader, archive: Fr, txs: TxHash[]): Promise<BlockProposal | undefined>;
30
+ createBlockProposal(header: BlockHeader, archive: Fr, txs: Tx[]): Promise<BlockProposal | undefined>;
31
31
  attestToProposal(proposal: BlockProposal): void;
32
32
  broadcastBlockProposal(proposal: BlockProposal): void;
33
33
  collectAttestations(proposal: BlockProposal, required: number, deadline: Date): Promise<BlockAttestation[]>;
@@ -68,7 +68,7 @@ export declare class ValidatorClient extends WithTracer implements Validator {
68
68
  * Re-execute the transactions in the proposal and check that the state updates match the header state
69
69
  * @param proposal - The proposal to re-execute
70
70
  */
71
- reExecuteTransactions(proposal: BlockProposal): Promise<void>;
71
+ reExecuteTransactions(proposal: BlockProposal, txs: Tx[]): Promise<void>;
72
72
  /**
73
73
  * Ensure that all of the transactions in the proposal are available in the tx pool before attesting
74
74
  *
@@ -77,8 +77,8 @@ export declare class ValidatorClient extends WithTracer implements Validator {
77
77
  * 3. If we cannot retrieve them from the network, throw an error
78
78
  * @param proposal - The proposal to attest to
79
79
  */
80
- ensureTransactionsAreAvailable(proposal: BlockProposal): Promise<void>;
81
- createBlockProposal(header: BlockHeader, archive: Fr, txs: TxHash[]): Promise<BlockProposal | undefined>;
80
+ ensureTransactionsAreAvailable(proposal: BlockProposal): Promise<Tx[]>;
81
+ createBlockProposal(header: BlockHeader, archive: Fr, txs: Tx[]): Promise<BlockProposal | undefined>;
82
82
  broadcastBlockProposal(proposal: BlockProposal): void;
83
83
  collectAttestations(proposal: BlockProposal, required: number, deadline: Date): Promise<BlockAttestation[]>;
84
84
  private doAttestToProposal;
@@ -1 +1 @@
1
- {"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../src/validator.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../src/validator.ts"],"names":[],"mappings":"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"}
package/dest/validator.js CHANGED
@@ -122,10 +122,10 @@ import { ValidatorMetrics } from './metrics.js';
122
122
  // Check that all of the transactions in the proposal are available in the tx pool before attesting
123
123
  this.log.verbose(`Processing attestation for slot ${slotNumber}`, proposalInfo);
124
124
  try {
125
- await this.ensureTransactionsAreAvailable(proposal);
125
+ const txs = await this.ensureTransactionsAreAvailable(proposal);
126
126
  if (this.config.validatorReexecute) {
127
127
  this.log.verbose(`Re-executing transactions in the proposal before attesting`);
128
- await this.reExecuteTransactions(proposal);
128
+ await this.reExecuteTransactions(proposal, txs);
129
129
  }
130
130
  } catch (error) {
131
131
  if (error instanceof Error) {
@@ -152,12 +152,13 @@ import { ValidatorMetrics } from './metrics.js';
152
152
  /**
153
153
  * Re-execute the transactions in the proposal and check that the state updates match the header state
154
154
  * @param proposal - The proposal to re-execute
155
- */ async reExecuteTransactions(proposal) {
155
+ */ async reExecuteTransactions(proposal, txs) {
156
156
  const { header, txHashes } = proposal.payload;
157
- const txs = (await Promise.all(txHashes.map((tx)=>this.p2pClient.getTxByHash(tx)))).filter((tx)=>tx !== undefined);
158
- // If we cannot request all of the transactions, then we should fail
157
+ // If we do not have all of the transactions, then we should fail
159
158
  if (txs.length !== txHashes.length) {
160
- throw new TransactionsNotAvailableError(txHashes);
159
+ const foundTxHashes = await Promise.all(txs.map(async (tx)=>(await tx.getTxHash()).toString()));
160
+ const missingTxHashes = txHashes.filter((txHash)=>!foundTxHashes.includes(txHash.toString()));
161
+ throw new TransactionsNotAvailableError(missingTxHashes);
161
162
  }
162
163
  // Assertion: This check will fail if re-execution is not enabled
163
164
  if (this.blockBuilder === undefined) {
@@ -192,17 +193,70 @@ import { ValidatorMetrics } from './metrics.js';
192
193
  * 3. If we cannot retrieve them from the network, throw an error
193
194
  * @param proposal - The proposal to attest to
194
195
  */ async ensureTransactionsAreAvailable(proposal) {
196
+ if (proposal.payload.txHashes.length === 0) {
197
+ this.log.verbose(`Received block proposal with no transactions, skipping transaction availability check`);
198
+ return [];
199
+ }
200
+ // Is this a new style proposal?
201
+ if (proposal.txs && proposal.txs.length > 0 && proposal.txs.length === proposal.payload.txHashes.length) {
202
+ // Yes, any txs that we already have we should use
203
+ this.log.info(`Using new style proposal with ${proposal.txs.length} transactions`);
204
+ // Request from the pool based on the signed hashes in the payload
205
+ const hashesFromPayload = proposal.payload.txHashes;
206
+ const txsToUse = await this.p2pClient.getTxsByHashFromPool(hashesFromPayload);
207
+ const missingTxs = txsToUse.filter((tx)=>tx === undefined).length;
208
+ if (missingTxs > 0) {
209
+ this.log.verbose(`Missing ${missingTxs}/${hashesFromPayload.length} transactions in the tx pool, will attempt to take from the proposal`);
210
+ }
211
+ let usedFromProposal = 0;
212
+ // Fill any holes with txs in the proposal, provided their hash matches the hash in the payload
213
+ for(let i = 0; i < txsToUse.length; i++){
214
+ if (txsToUse[i] === undefined) {
215
+ // We don't have the transaction, take from the proposal, provided the hash is the same
216
+ const hashOfTxInProposal = await proposal.txs[i].getTxHash();
217
+ if (hashOfTxInProposal.equals(hashesFromPayload[i])) {
218
+ // Hash is equal, we can use the tx from the proposal
219
+ txsToUse[i] = proposal.txs[i];
220
+ usedFromProposal++;
221
+ } else {
222
+ this.log.warn(`Unable to take tx: ${hashOfTxInProposal.toString()} from the proposal, it does not match payload hash: ${hashesFromPayload[i].toString()}`);
223
+ }
224
+ }
225
+ }
226
+ // See if we still have any holes, if there are then we were not successful and will try the old method
227
+ if (txsToUse.some((tx)=>tx === undefined)) {
228
+ this.log.warn(`Failed to use transactions from proposal. Falling back to old proposal logic`);
229
+ } else {
230
+ this.log.info(`Successfully used ${usedFromProposal}/${hashesFromPayload.length} transactions from the proposal`);
231
+ await this.p2pClient.validate(txsToUse);
232
+ return txsToUse;
233
+ }
234
+ }
235
+ this.log.info(`Using old style proposal with ${proposal.payload.txHashes.length} transactions`);
236
+ // Old style proposal, we will perform a request by hash from pool
237
+ // This will request from network any txs that are missing
195
238
  const txHashes = proposal.payload.txHashes;
239
+ // This part is just for logging that we are requesting from the network
196
240
  const availability = await this.p2pClient.hasTxsInPool(txHashes);
197
- const missingTxs = txHashes.filter((_, index)=>!availability[index]);
198
- if (missingTxs.length === 0) {
199
- return; // All transactions are available
241
+ const notAvailable = availability.filter((availability)=>availability === false);
242
+ if (notAvailable.length) {
243
+ this.log.verbose(`Missing ${notAvailable.length} transactions in the tx pool, will need to request from the network`);
200
244
  }
201
- this.log.verbose(`Missing ${missingTxs.length} transactions in the tx pool, requesting from the network`);
202
- const requestedTxs = await this.p2pClient.requestTxsByHash(missingTxs);
203
- if (requestedTxs.some((tx)=>tx === undefined)) {
245
+ // This will request from the network any txs that are missing
246
+ const retrievedTxs = await this.p2pClient.getTxsByHash(txHashes);
247
+ const missingTxs = retrievedTxs.map((tx, index)=>{
248
+ // Return the hash of any that we did not get
249
+ if (tx === undefined) {
250
+ return txHashes[index];
251
+ } else {
252
+ return undefined;
253
+ }
254
+ }).filter((hash)=>hash !== undefined);
255
+ if (missingTxs.length > 0) {
204
256
  throw new TransactionsNotAvailableError(missingTxs);
205
257
  }
258
+ await this.p2pClient.validate(retrievedTxs);
259
+ return retrievedTxs;
206
260
  }
207
261
  async createBlockProposal(header, archive, txs) {
208
262
  if (this.previousProposal?.slotNumber.equals(header.globalVariables.slotNumber)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aztec/validator-client",
3
- "version": "0.85.0-alpha-testnet.5",
3
+ "version": "0.85.0-alpha-testnet.7",
4
4
  "main": "dest/index.js",
5
5
  "type": "module",
6
6
  "exports": {
@@ -62,12 +62,12 @@
62
62
  ]
63
63
  },
64
64
  "dependencies": {
65
- "@aztec/epoch-cache": "0.85.0-alpha-testnet.5",
66
- "@aztec/ethereum": "0.85.0-alpha-testnet.5",
67
- "@aztec/foundation": "0.85.0-alpha-testnet.5",
68
- "@aztec/p2p": "0.85.0-alpha-testnet.5",
69
- "@aztec/stdlib": "0.85.0-alpha-testnet.5",
70
- "@aztec/telemetry-client": "0.85.0-alpha-testnet.5",
65
+ "@aztec/epoch-cache": "0.85.0-alpha-testnet.7",
66
+ "@aztec/ethereum": "0.85.0-alpha-testnet.7",
67
+ "@aztec/foundation": "0.85.0-alpha-testnet.7",
68
+ "@aztec/p2p": "0.85.0-alpha-testnet.7",
69
+ "@aztec/stdlib": "0.85.0-alpha-testnet.7",
70
+ "@aztec/telemetry-client": "0.85.0-alpha-testnet.7",
71
71
  "koa": "^2.16.1",
72
72
  "koa-router": "^12.0.0",
73
73
  "tslib": "^2.4.0",
@@ -2,7 +2,7 @@ import { Buffer32 } from '@aztec/foundation/buffer';
2
2
  import { keccak256 } from '@aztec/foundation/crypto';
3
3
  import type { Fr } from '@aztec/foundation/fields';
4
4
  import { BlockAttestation, BlockProposal, ConsensusPayload, SignatureDomainSeparator } from '@aztec/stdlib/p2p';
5
- import type { BlockHeader, TxHash } from '@aztec/stdlib/tx';
5
+ import type { BlockHeader, Tx } from '@aztec/stdlib/tx';
6
6
 
7
7
  import type { ValidatorKeyStore } from '../key_store/interface.js';
8
8
 
@@ -18,10 +18,12 @@ export class ValidationService {
18
18
  *
19
19
  * @returns A block proposal signing the above information (not the current implementation!!!)
20
20
  */
21
- createBlockProposal(header: BlockHeader, archive: Fr, txs: TxHash[]): Promise<BlockProposal> {
21
+ async createBlockProposal(header: BlockHeader, archive: Fr, txs: Tx[]): Promise<BlockProposal> {
22
22
  const payloadSigner = (payload: Buffer32) => this.keyStore.signMessage(payload);
23
+ // TODO: check if this is calculated earlier / can not be recomputed
24
+ const txHashes = await Promise.all(txs.map(tx => tx.getTxHash()));
23
25
 
24
- return BlockProposal.createProposalFromSigner(new ConsensusPayload(header, archive, txs), payloadSigner);
26
+ return BlockProposal.createProposalFromSigner(new ConsensusPayload(header, archive, txHashes), txs, payloadSigner);
25
27
  }
26
28
 
27
29
  /**
package/src/validator.ts CHANGED
@@ -51,7 +51,7 @@ export interface Validator {
51
51
  registerBlockBuilder(blockBuilder: BlockBuilderCallback): void;
52
52
 
53
53
  // Block validation responsibilities
54
- createBlockProposal(header: BlockHeader, archive: Fr, txs: TxHash[]): Promise<BlockProposal | undefined>;
54
+ createBlockProposal(header: BlockHeader, archive: Fr, txs: Tx[]): Promise<BlockProposal | undefined>;
55
55
  attestToProposal(proposal: BlockProposal): void;
56
56
 
57
57
  broadcastBlockProposal(proposal: BlockProposal): void;
@@ -204,11 +204,11 @@ export class ValidatorClient extends WithTracer implements Validator {
204
204
  // Check that all of the transactions in the proposal are available in the tx pool before attesting
205
205
  this.log.verbose(`Processing attestation for slot ${slotNumber}`, proposalInfo);
206
206
  try {
207
- await this.ensureTransactionsAreAvailable(proposal);
207
+ const txs = await this.ensureTransactionsAreAvailable(proposal);
208
208
 
209
209
  if (this.config.validatorReexecute) {
210
210
  this.log.verbose(`Re-executing transactions in the proposal before attesting`);
211
- await this.reExecuteTransactions(proposal);
211
+ await this.reExecuteTransactions(proposal, txs);
212
212
  }
213
213
  } catch (error: any) {
214
214
  if (error instanceof Error) {
@@ -240,16 +240,14 @@ export class ValidatorClient extends WithTracer implements Validator {
240
240
  * Re-execute the transactions in the proposal and check that the state updates match the header state
241
241
  * @param proposal - The proposal to re-execute
242
242
  */
243
- async reExecuteTransactions(proposal: BlockProposal) {
243
+ async reExecuteTransactions(proposal: BlockProposal, txs: Tx[]) {
244
244
  const { header, txHashes } = proposal.payload;
245
245
 
246
- const txs = (await Promise.all(txHashes.map(tx => this.p2pClient.getTxByHash(tx)))).filter(
247
- tx => tx !== undefined,
248
- ) as Tx[];
249
-
250
- // If we cannot request all of the transactions, then we should fail
246
+ // If we do not have all of the transactions, then we should fail
251
247
  if (txs.length !== txHashes.length) {
252
- throw new TransactionsNotAvailableError(txHashes);
248
+ const foundTxHashes = await Promise.all(txs.map(async tx => (await tx.getTxHash()).toString()));
249
+ const missingTxHashes = txHashes.filter(txHash => !foundTxHashes.includes(txHash.toString()));
250
+ throw new TransactionsNotAvailableError(missingTxHashes);
253
251
  }
254
252
 
255
253
  // Assertion: This check will fail if re-execution is not enabled
@@ -291,24 +289,98 @@ export class ValidatorClient extends WithTracer implements Validator {
291
289
  * 3. If we cannot retrieve them from the network, throw an error
292
290
  * @param proposal - The proposal to attest to
293
291
  */
294
- async ensureTransactionsAreAvailable(proposal: BlockProposal) {
292
+ async ensureTransactionsAreAvailable(proposal: BlockProposal): Promise<Tx[]> {
293
+ if (proposal.payload.txHashes.length === 0) {
294
+ this.log.verbose(`Received block proposal with no transactions, skipping transaction availability check`);
295
+ return [];
296
+ }
297
+ // Is this a new style proposal?
298
+ if (proposal.txs && proposal.txs.length > 0 && proposal.txs.length === proposal.payload.txHashes.length) {
299
+ // Yes, any txs that we already have we should use
300
+ this.log.info(`Using new style proposal with ${proposal.txs.length} transactions`);
301
+
302
+ // Request from the pool based on the signed hashes in the payload
303
+ const hashesFromPayload = proposal.payload.txHashes;
304
+ const txsToUse = await this.p2pClient.getTxsByHashFromPool(hashesFromPayload);
305
+
306
+ const missingTxs = txsToUse.filter(tx => tx === undefined).length;
307
+ if (missingTxs > 0) {
308
+ this.log.verbose(
309
+ `Missing ${missingTxs}/${hashesFromPayload.length} transactions in the tx pool, will attempt to take from the proposal`,
310
+ );
311
+ }
312
+
313
+ let usedFromProposal = 0;
314
+
315
+ // Fill any holes with txs in the proposal, provided their hash matches the hash in the payload
316
+ for (let i = 0; i < txsToUse.length; i++) {
317
+ if (txsToUse[i] === undefined) {
318
+ // We don't have the transaction, take from the proposal, provided the hash is the same
319
+ const hashOfTxInProposal = await proposal.txs[i].getTxHash();
320
+ if (hashOfTxInProposal.equals(hashesFromPayload[i])) {
321
+ // Hash is equal, we can use the tx from the proposal
322
+ txsToUse[i] = proposal.txs[i];
323
+ usedFromProposal++;
324
+ } else {
325
+ this.log.warn(
326
+ `Unable to take tx: ${hashOfTxInProposal.toString()} from the proposal, it does not match payload hash: ${hashesFromPayload[
327
+ i
328
+ ].toString()}`,
329
+ );
330
+ }
331
+ }
332
+ }
333
+
334
+ // See if we still have any holes, if there are then we were not successful and will try the old method
335
+ if (txsToUse.some(tx => tx === undefined)) {
336
+ this.log.warn(`Failed to use transactions from proposal. Falling back to old proposal logic`);
337
+ } else {
338
+ this.log.info(
339
+ `Successfully used ${usedFromProposal}/${hashesFromPayload.length} transactions from the proposal`,
340
+ );
341
+
342
+ await this.p2pClient.validate(txsToUse as Tx[]);
343
+ return txsToUse as Tx[];
344
+ }
345
+ }
346
+
347
+ this.log.info(`Using old style proposal with ${proposal.payload.txHashes.length} transactions`);
348
+
349
+ // Old style proposal, we will perform a request by hash from pool
350
+ // This will request from network any txs that are missing
295
351
  const txHashes: TxHash[] = proposal.payload.txHashes;
352
+
353
+ // This part is just for logging that we are requesting from the network
296
354
  const availability = await this.p2pClient.hasTxsInPool(txHashes);
297
- const missingTxs = txHashes.filter((_, index) => !availability[index]);
355
+ const notAvailable = availability.filter(availability => availability === false);
356
+ if (notAvailable.length) {
357
+ this.log.verbose(
358
+ `Missing ${notAvailable.length} transactions in the tx pool, will need to request from the network`,
359
+ );
360
+ }
298
361
 
299
- if (missingTxs.length === 0) {
300
- return; // All transactions are available
362
+ // This will request from the network any txs that are missing
363
+ const retrievedTxs = await this.p2pClient.getTxsByHash(txHashes);
364
+ const missingTxs = retrievedTxs
365
+ .map((tx, index) => {
366
+ // Return the hash of any that we did not get
367
+ if (tx === undefined) {
368
+ return txHashes[index];
369
+ } else {
370
+ return undefined;
371
+ }
372
+ })
373
+ .filter(hash => hash !== undefined);
374
+ if (missingTxs.length > 0) {
375
+ throw new TransactionsNotAvailableError(missingTxs as TxHash[]);
301
376
  }
302
377
 
303
- this.log.verbose(`Missing ${missingTxs.length} transactions in the tx pool, requesting from the network`);
378
+ await this.p2pClient.validate(retrievedTxs as Tx[]);
304
379
 
305
- const requestedTxs = await this.p2pClient.requestTxsByHash(missingTxs);
306
- if (requestedTxs.some(tx => tx === undefined)) {
307
- throw new TransactionsNotAvailableError(missingTxs);
308
- }
380
+ return retrievedTxs as Tx[];
309
381
  }
310
382
 
311
- async createBlockProposal(header: BlockHeader, archive: Fr, txs: TxHash[]): Promise<BlockProposal | undefined> {
383
+ async createBlockProposal(header: BlockHeader, archive: Fr, txs: Tx[]): Promise<BlockProposal | undefined> {
312
384
  if (this.previousProposal?.slotNumber.equals(header.globalVariables.slotNumber)) {
313
385
  this.log.verbose(`Already made a proposal for the same slot, skipping proposal`);
314
386
  return Promise.resolve(undefined);