@aztec/validator-client 0.0.1-commit.1bea0213 → 0.0.1-commit.1de2a32

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 (50) hide show
  1. package/README.md +63 -18
  2. package/dest/block_proposal_handler.d.ts +5 -6
  3. package/dest/block_proposal_handler.d.ts.map +1 -1
  4. package/dest/block_proposal_handler.js +66 -60
  5. package/dest/checkpoint_builder.d.ts +21 -12
  6. package/dest/checkpoint_builder.d.ts.map +1 -1
  7. package/dest/checkpoint_builder.js +107 -39
  8. package/dest/config.d.ts +1 -1
  9. package/dest/config.d.ts.map +1 -1
  10. package/dest/config.js +28 -4
  11. package/dest/duties/validation_service.d.ts +2 -2
  12. package/dest/duties/validation_service.d.ts.map +1 -1
  13. package/dest/duties/validation_service.js +5 -11
  14. package/dest/factory.d.ts +1 -1
  15. package/dest/factory.d.ts.map +1 -1
  16. package/dest/factory.js +2 -1
  17. package/dest/index.d.ts +1 -2
  18. package/dest/index.d.ts.map +1 -1
  19. package/dest/index.js +0 -1
  20. package/dest/key_store/ha_key_store.d.ts +1 -1
  21. package/dest/key_store/ha_key_store.d.ts.map +1 -1
  22. package/dest/key_store/ha_key_store.js +2 -2
  23. package/dest/metrics.d.ts +12 -3
  24. package/dest/metrics.d.ts.map +1 -1
  25. package/dest/metrics.js +46 -5
  26. package/dest/validator.d.ts +40 -14
  27. package/dest/validator.d.ts.map +1 -1
  28. package/dest/validator.js +212 -56
  29. package/package.json +19 -17
  30. package/src/block_proposal_handler.ts +81 -81
  31. package/src/checkpoint_builder.ts +144 -38
  32. package/src/config.ts +28 -4
  33. package/src/duties/validation_service.ts +11 -10
  34. package/src/factory.ts +1 -0
  35. package/src/index.ts +0 -1
  36. package/src/key_store/ha_key_store.ts +2 -2
  37. package/src/metrics.ts +63 -6
  38. package/src/validator.ts +260 -66
  39. package/dest/tx_validator/index.d.ts +0 -3
  40. package/dest/tx_validator/index.d.ts.map +0 -1
  41. package/dest/tx_validator/index.js +0 -2
  42. package/dest/tx_validator/nullifier_cache.d.ts +0 -14
  43. package/dest/tx_validator/nullifier_cache.d.ts.map +0 -1
  44. package/dest/tx_validator/nullifier_cache.js +0 -24
  45. package/dest/tx_validator/tx_validator_factory.d.ts +0 -18
  46. package/dest/tx_validator/tx_validator_factory.d.ts.map +0 -1
  47. package/dest/tx_validator/tx_validator_factory.js +0 -54
  48. package/src/tx_validator/index.ts +0 -2
  49. package/src/tx_validator/nullifier_cache.ts +0 -30
  50. package/src/tx_validator/tx_validator_factory.ts +0 -135
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aztec/validator-client",
3
- "version": "0.0.1-commit.1bea0213",
3
+ "version": "0.0.1-commit.1de2a32",
4
4
  "main": "dest/index.js",
5
5
  "type": "module",
6
6
  "exports": {
@@ -64,28 +64,30 @@
64
64
  ]
65
65
  },
66
66
  "dependencies": {
67
- "@aztec/blob-client": "0.0.1-commit.1bea0213",
68
- "@aztec/blob-lib": "0.0.1-commit.1bea0213",
69
- "@aztec/constants": "0.0.1-commit.1bea0213",
70
- "@aztec/epoch-cache": "0.0.1-commit.1bea0213",
71
- "@aztec/ethereum": "0.0.1-commit.1bea0213",
72
- "@aztec/foundation": "0.0.1-commit.1bea0213",
73
- "@aztec/node-keystore": "0.0.1-commit.1bea0213",
74
- "@aztec/noir-protocol-circuits-types": "0.0.1-commit.1bea0213",
75
- "@aztec/p2p": "0.0.1-commit.1bea0213",
76
- "@aztec/protocol-contracts": "0.0.1-commit.1bea0213",
77
- "@aztec/prover-client": "0.0.1-commit.1bea0213",
78
- "@aztec/simulator": "0.0.1-commit.1bea0213",
79
- "@aztec/slasher": "0.0.1-commit.1bea0213",
80
- "@aztec/stdlib": "0.0.1-commit.1bea0213",
81
- "@aztec/telemetry-client": "0.0.1-commit.1bea0213",
82
- "@aztec/validator-ha-signer": "0.0.1-commit.1bea0213",
67
+ "@aztec/blob-client": "0.0.1-commit.1de2a32",
68
+ "@aztec/blob-lib": "0.0.1-commit.1de2a32",
69
+ "@aztec/constants": "0.0.1-commit.1de2a32",
70
+ "@aztec/epoch-cache": "0.0.1-commit.1de2a32",
71
+ "@aztec/ethereum": "0.0.1-commit.1de2a32",
72
+ "@aztec/foundation": "0.0.1-commit.1de2a32",
73
+ "@aztec/node-keystore": "0.0.1-commit.1de2a32",
74
+ "@aztec/noir-protocol-circuits-types": "0.0.1-commit.1de2a32",
75
+ "@aztec/p2p": "0.0.1-commit.1de2a32",
76
+ "@aztec/protocol-contracts": "0.0.1-commit.1de2a32",
77
+ "@aztec/prover-client": "0.0.1-commit.1de2a32",
78
+ "@aztec/simulator": "0.0.1-commit.1de2a32",
79
+ "@aztec/slasher": "0.0.1-commit.1de2a32",
80
+ "@aztec/stdlib": "0.0.1-commit.1de2a32",
81
+ "@aztec/telemetry-client": "0.0.1-commit.1de2a32",
82
+ "@aztec/validator-ha-signer": "0.0.1-commit.1de2a32",
83
83
  "koa": "^2.16.1",
84
84
  "koa-router": "^13.1.1",
85
85
  "tslib": "^2.4.0",
86
86
  "viem": "npm:@aztec/viem@2.38.2"
87
87
  },
88
88
  "devDependencies": {
89
+ "@aztec/archiver": "0.0.1-commit.1de2a32",
90
+ "@aztec/world-state": "0.0.1-commit.1de2a32",
89
91
  "@electric-sql/pglite": "^0.3.14",
90
92
  "@jest/globals": "^30.0.0",
91
93
  "@types/jest": "^30.0.0",
@@ -1,25 +1,21 @@
1
1
  import { INITIAL_L2_BLOCK_NUM } from '@aztec/constants';
2
2
  import type { EpochCache } from '@aztec/epoch-cache';
3
3
  import { BlockNumber, CheckpointNumber, SlotNumber } from '@aztec/foundation/branded-types';
4
- import { chunkBy } from '@aztec/foundation/collection';
4
+ import { pick } from '@aztec/foundation/collection';
5
5
  import { Fr } from '@aztec/foundation/curves/bn254';
6
6
  import { TimeoutError } from '@aztec/foundation/error';
7
7
  import { createLogger } from '@aztec/foundation/log';
8
8
  import { retryUntil } from '@aztec/foundation/retry';
9
9
  import { DateProvider, Timer } from '@aztec/foundation/timer';
10
10
  import type { P2P, PeerId } from '@aztec/p2p';
11
- import { TxProvider } from '@aztec/p2p';
12
11
  import { BlockProposalValidator } from '@aztec/p2p/msg_validators';
13
- import type { L2Block, L2BlockSink, L2BlockSource } from '@aztec/stdlib/block';
12
+ import type { BlockData, L2Block, L2BlockSink, L2BlockSource } from '@aztec/stdlib/block';
14
13
  import { getEpochAtSlot, getTimestampForSlot } from '@aztec/stdlib/epoch-helpers';
15
- import type { ValidatorClientFullConfig, WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
16
- import {
17
- type L1ToL2MessageSource,
18
- computeCheckpointOutHash,
19
- computeInHashFromL1ToL2Messages,
20
- } from '@aztec/stdlib/messaging';
14
+ import { Gas } from '@aztec/stdlib/gas';
15
+ import type { ITxProvider, ValidatorClientFullConfig, WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
16
+ import { type L1ToL2MessageSource, computeInHashFromL1ToL2Messages } from '@aztec/stdlib/messaging';
21
17
  import type { BlockProposal } from '@aztec/stdlib/p2p';
22
- import { BlockHeader, type CheckpointGlobalVariables, type FailedTx, type Tx } from '@aztec/stdlib/tx';
18
+ import type { CheckpointGlobalVariables, FailedTx, Tx } from '@aztec/stdlib/tx';
23
19
  import {
24
20
  ReExFailedTxsError,
25
21
  ReExStateMismatchError,
@@ -78,7 +74,7 @@ export class BlockProposalHandler {
78
74
  private worldState: WorldStateSynchronizer,
79
75
  private blockSource: L2BlockSource & L2BlockSink,
80
76
  private l1ToL2MessageSource: L1ToL2MessageSource,
81
- private txProvider: TxProvider,
77
+ private txProvider: ITxProvider,
82
78
  private blockProposalValidator: BlockProposalValidator,
83
79
  private epochCache: EpochCache,
84
80
  private config: ValidatorClientFullConfig,
@@ -93,25 +89,28 @@ export class BlockProposalHandler {
93
89
  this.tracer = telemetry.getTracer('BlockProposalHandler');
94
90
  }
95
91
 
96
- registerForReexecution(p2pClient: P2P): BlockProposalHandler {
97
- // Non-validator handler that re-executes for monitoring but does not attest.
92
+ register(p2pClient: P2P, shouldReexecute: boolean): BlockProposalHandler {
93
+ // Non-validator handler that processes or re-executes for monitoring but does not attest.
98
94
  // Returns boolean indicating whether the proposal was valid.
99
95
  const handler = async (proposal: BlockProposal, proposalSender: PeerId): Promise<boolean> => {
100
96
  try {
101
- const result = await this.handleBlockProposal(proposal, proposalSender, true);
97
+ const { slotNumber, blockNumber } = proposal;
98
+ const result = await this.handleBlockProposal(proposal, proposalSender, shouldReexecute);
102
99
  if (result.isValid) {
103
- this.log.info(`Non-validator reexecution completed for slot ${proposal.slotNumber}`, {
100
+ this.log.info(`Non-validator block proposal ${blockNumber} at slot ${slotNumber} handled`, {
104
101
  blockNumber: result.blockNumber,
102
+ slotNumber,
105
103
  reexecutionTimeMs: result.reexecutionResult?.reexecutionTimeMs,
106
104
  totalManaUsed: result.reexecutionResult?.totalManaUsed,
107
105
  numTxs: result.reexecutionResult?.block?.body?.txEffects?.length ?? 0,
106
+ reexecuted: shouldReexecute,
108
107
  });
109
108
  return true;
110
109
  } else {
111
- this.log.warn(`Non-validator reexecution failed for slot ${proposal.slotNumber}`, {
112
- blockNumber: result.blockNumber,
113
- reason: result.reason,
114
- });
110
+ this.log.warn(
111
+ `Non-validator block proposal ${blockNumber} at slot ${slotNumber} failed processing with ${result.reason}`,
112
+ { blockNumber: result.blockNumber, slotNumber, reason: result.reason },
113
+ );
115
114
  return false;
116
115
  }
117
116
  } catch (error) {
@@ -154,16 +153,16 @@ export class BlockProposalHandler {
154
153
  }
155
154
 
156
155
  // Check that the parent proposal is a block we know, otherwise reexecution would fail
157
- const parentBlockHeader = await this.getParentBlock(proposal);
158
- if (parentBlockHeader === undefined) {
156
+ const parentBlock = await this.getParentBlock(proposal);
157
+ if (parentBlock === undefined) {
159
158
  this.log.warn(`Parent block for proposal not found, skipping processing`, proposalInfo);
160
159
  return { isValid: false, reason: 'parent_block_not_found' };
161
160
  }
162
161
 
163
- // Check that the parent block's slot is less than the proposal's slot (should not happen, but we check anyway)
164
- if (parentBlockHeader !== 'genesis' && parentBlockHeader.getSlot() >= slotNumber) {
165
- this.log.warn(`Parent block slot is greater than or equal to proposal slot, skipping processing`, {
166
- parentBlockSlot: parentBlockHeader.getSlot().toString(),
162
+ // Check that the parent block's slot is not greater than the proposal's slot.
163
+ if (parentBlock !== 'genesis' && parentBlock.header.getSlot() > slotNumber) {
164
+ this.log.warn(`Parent block slot is greater than proposal slot, skipping processing`, {
165
+ parentBlockSlot: parentBlock.header.getSlot().toString(),
167
166
  proposalSlot: slotNumber.toString(),
168
167
  ...proposalInfo,
169
168
  });
@@ -172,9 +171,9 @@ export class BlockProposalHandler {
172
171
 
173
172
  // Compute the block number based on the parent block
174
173
  const blockNumber =
175
- parentBlockHeader === 'genesis'
174
+ parentBlock === 'genesis'
176
175
  ? BlockNumber(INITIAL_L2_BLOCK_NUM)
177
- : BlockNumber(parentBlockHeader.getBlockNumber() + 1);
176
+ : BlockNumber(parentBlock.header.getBlockNumber() + 1);
178
177
 
179
178
  // Check that this block number does not exist already
180
179
  const existingBlock = await this.blockSource.getBlockHeader(blockNumber);
@@ -190,8 +189,17 @@ export class BlockProposalHandler {
190
189
  deadline: this.getReexecutionDeadline(slotNumber, config),
191
190
  });
192
191
 
192
+ // If reexecution is disabled, bail. We are just interested in triggering tx collection.
193
+ if (!shouldReexecute) {
194
+ this.log.info(
195
+ `Received valid block ${blockNumber} proposal at index ${proposal.indexWithinCheckpoint} on slot ${slotNumber}`,
196
+ proposalInfo,
197
+ );
198
+ return { isValid: true, blockNumber };
199
+ }
200
+
193
201
  // Compute the checkpoint number for this block and validate checkpoint consistency
194
- const checkpointResult = await this.computeCheckpointNumber(proposal, parentBlockHeader, proposalInfo);
202
+ const checkpointResult = this.computeCheckpointNumber(proposal, parentBlock, proposalInfo);
195
203
  if (checkpointResult.reason) {
196
204
  return { isValid: false, blockNumber, reason: checkpointResult.reason };
197
205
  }
@@ -216,36 +224,28 @@ export class BlockProposalHandler {
216
224
  return { isValid: false, blockNumber, reason: 'txs_not_available' };
217
225
  }
218
226
 
227
+ // Collect the out hashes of all the checkpoints before this one in the same epoch
228
+ const epoch = getEpochAtSlot(slotNumber, this.epochCache.getL1Constants());
229
+ const previousCheckpointOutHashes = (await this.blockSource.getCheckpointsDataForEpoch(epoch))
230
+ .filter(c => c.checkpointNumber < checkpointNumber)
231
+ .map(c => c.checkpointOutHash);
232
+
219
233
  // Try re-executing the transactions in the proposal if needed
220
234
  let reexecutionResult;
221
- if (shouldReexecute) {
222
- // Compute the previous checkpoint out hashes for the epoch.
223
- // TODO(leila/mbps): There can be a more efficient way to get the previous checkpoint out
224
- // hashes without having to fetch all the blocks.
225
- const epoch = getEpochAtSlot(slotNumber, this.epochCache.getL1Constants());
226
- const checkpointedBlocks = (await this.blockSource.getCheckpointedBlocksForEpoch(epoch))
227
- .filter(b => b.block.number < blockNumber)
228
- .sort((a, b) => a.block.number - b.block.number);
229
- const blocksByCheckpoint = chunkBy(checkpointedBlocks, b => b.checkpointNumber);
230
- const previousCheckpointOutHashes = blocksByCheckpoint.map(checkpointBlocks =>
231
- computeCheckpointOutHash(checkpointBlocks.map(b => b.block.body.txEffects.map(tx => tx.l2ToL1Msgs))),
235
+ try {
236
+ this.log.verbose(`Re-executing transactions in the proposal`, proposalInfo);
237
+ reexecutionResult = await this.reexecuteTransactions(
238
+ proposal,
239
+ blockNumber,
240
+ checkpointNumber,
241
+ txs,
242
+ l1ToL2Messages,
243
+ previousCheckpointOutHashes,
232
244
  );
233
-
234
- try {
235
- this.log.verbose(`Re-executing transactions in the proposal`, proposalInfo);
236
- reexecutionResult = await this.reexecuteTransactions(
237
- proposal,
238
- blockNumber,
239
- checkpointNumber,
240
- txs,
241
- l1ToL2Messages,
242
- previousCheckpointOutHashes,
243
- );
244
- } catch (error) {
245
- this.log.error(`Error reexecuting txs while processing block proposal`, error, proposalInfo);
246
- const reason = this.getReexecuteFailureReason(error);
247
- return { isValid: false, blockNumber, reason, reexecutionResult };
248
- }
245
+ } catch (error) {
246
+ this.log.error(`Error reexecuting txs while processing block proposal`, error, proposalInfo);
247
+ const reason = this.getReexecuteFailureReason(error);
248
+ return { isValid: false, blockNumber, reason, reexecutionResult };
249
249
  }
250
250
 
251
251
  // If we succeeded, push this block into the archiver (unless disabled)
@@ -254,14 +254,14 @@ export class BlockProposalHandler {
254
254
  }
255
255
 
256
256
  this.log.info(
257
- `Successfully processed block ${blockNumber} proposal at index ${proposal.indexWithinCheckpoint} on slot ${slotNumber}`,
258
- proposalInfo,
257
+ `Successfully re-executed block ${blockNumber} proposal at index ${proposal.indexWithinCheckpoint} on slot ${slotNumber}`,
258
+ { ...proposalInfo, ...pick(reexecutionResult, 'reexecutionTimeMs', 'totalManaUsed') },
259
259
  );
260
260
 
261
261
  return { isValid: true, blockNumber, reexecutionResult };
262
262
  }
263
263
 
264
- private async getParentBlock(proposal: BlockProposal): Promise<'genesis' | BlockHeader | undefined> {
264
+ private async getParentBlock(proposal: BlockProposal): Promise<'genesis' | BlockData | undefined> {
265
265
  const parentArchive = proposal.blockHeader.lastArchive.root;
266
266
  const slot = proposal.slotNumber;
267
267
  const config = this.checkpointsBuilder.getConfig();
@@ -277,12 +277,11 @@ export class BlockProposalHandler {
277
277
 
278
278
  try {
279
279
  return (
280
- (await this.blockSource.getBlockHeaderByArchive(parentArchive)) ??
280
+ (await this.blockSource.getBlockDataByArchive(parentArchive)) ??
281
281
  (timeoutDurationMs <= 0
282
282
  ? undefined
283
283
  : await retryUntil(
284
- () =>
285
- this.blockSource.syncImmediate().then(() => this.blockSource.getBlockHeaderByArchive(parentArchive)),
284
+ () => this.blockSource.syncImmediate().then(() => this.blockSource.getBlockDataByArchive(parentArchive)),
286
285
  'force archiver sync',
287
286
  timeoutDurationMs / 1000,
288
287
  0.5,
@@ -298,12 +297,12 @@ export class BlockProposalHandler {
298
297
  }
299
298
  }
300
299
 
301
- private async computeCheckpointNumber(
300
+ private computeCheckpointNumber(
302
301
  proposal: BlockProposal,
303
- parentBlockHeader: 'genesis' | BlockHeader,
302
+ parentBlock: 'genesis' | BlockData,
304
303
  proposalInfo: object,
305
- ): Promise<CheckpointComputationResult> {
306
- if (parentBlockHeader === 'genesis') {
304
+ ): CheckpointComputationResult {
305
+ if (parentBlock === 'genesis') {
307
306
  // First block is in checkpoint 1
308
307
  if (proposal.indexWithinCheckpoint !== 0) {
309
308
  this.log.warn(`First block proposal has non-zero indexWithinCheckpoint`, proposalInfo);
@@ -312,19 +311,9 @@ export class BlockProposalHandler {
312
311
  return { checkpointNumber: CheckpointNumber.INITIAL };
313
312
  }
314
313
 
315
- // Get the parent block to find its checkpoint number
316
- // TODO(palla/mbps): The block header should include the checkpoint number to avoid this lookup,
317
- // or at least the L2BlockSource should return a different struct that includes it.
318
- const parentBlockNumber = parentBlockHeader.getBlockNumber();
319
- const parentBlock = await this.blockSource.getL2Block(parentBlockNumber);
320
- if (!parentBlock) {
321
- this.log.warn(`Parent block ${parentBlockNumber} not found in archiver`, proposalInfo);
322
- return { reason: 'invalid_proposal' };
323
- }
324
-
325
314
  if (proposal.indexWithinCheckpoint === 0) {
326
315
  // If this is the first block in a new checkpoint, increment the checkpoint number
327
- if (!(proposal.blockHeader.getSlot() > parentBlockHeader.getSlot())) {
316
+ if (!(proposal.blockHeader.getSlot() > parentBlock.header.getSlot())) {
328
317
  this.log.warn(`Slot should be greater than parent block slot for first block in checkpoint`, proposalInfo);
329
318
  return { reason: 'invalid_proposal' };
330
319
  }
@@ -336,7 +325,7 @@ export class BlockProposalHandler {
336
325
  this.log.warn(`Non-sequential indexWithinCheckpoint`, proposalInfo);
337
326
  return { reason: 'invalid_proposal' };
338
327
  }
339
- if (proposal.blockHeader.getSlot() !== parentBlockHeader.getSlot()) {
328
+ if (proposal.blockHeader.getSlot() !== parentBlock.header.getSlot()) {
340
329
  this.log.warn(`Slot should be equal to parent block slot for non-first block in checkpoint`, proposalInfo);
341
330
  return { reason: 'invalid_proposal' };
342
331
  }
@@ -357,7 +346,7 @@ export class BlockProposalHandler {
357
346
  */
358
347
  private validateNonFirstBlockInCheckpoint(
359
348
  proposal: BlockProposal,
360
- parentBlock: L2Block,
349
+ parentBlock: BlockData,
361
350
  proposalInfo: object,
362
351
  ): CheckpointComputationResult | undefined {
363
352
  const proposalGlobals = proposal.blockHeader.globalVariables;
@@ -475,13 +464,15 @@ export class BlockProposalHandler {
475
464
 
476
465
  // Fork before the block to be built
477
466
  const parentBlockNumber = BlockNumber(blockNumber - 1);
478
- using fork = await this.worldState.fork(parentBlockNumber);
467
+ await this.worldState.syncImmediate(parentBlockNumber);
468
+ await using fork = await this.worldState.fork(parentBlockNumber);
479
469
 
480
- // Build checkpoint constants from proposal (excludes blockNumber and timestamp which are per-block)
470
+ // Build checkpoint constants from proposal (excludes blockNumber which is per-block)
481
471
  const constants: CheckpointGlobalVariables = {
482
472
  chainId: new Fr(config.l1ChainId),
483
473
  version: new Fr(config.rollupVersion),
484
474
  slotNumber: slot,
475
+ timestamp: blockHeader.globalVariables.timestamp,
485
476
  coinbase: blockHeader.globalVariables.coinbase,
486
477
  feeRecipient: blockHeader.globalVariables.feeRecipient,
487
478
  gasFees: blockHeader.globalVariables.gasFees,
@@ -491,26 +482,35 @@ export class BlockProposalHandler {
491
482
  const checkpointBuilder = await this.checkpointsBuilder.openCheckpoint(
492
483
  checkpointNumber,
493
484
  constants,
485
+ 0n, // only takes effect in the following checkpoint.
494
486
  l1ToL2Messages,
495
487
  previousCheckpointOutHashes,
496
488
  fork,
497
489
  priorBlocks,
490
+ this.log.getBindings(),
498
491
  );
499
492
 
500
493
  // Build the new block
501
494
  const deadline = this.getReexecutionDeadline(slot, config);
495
+ const maxBlockGas =
496
+ this.config.validateMaxL2BlockGas !== undefined || this.config.validateMaxDABlockGas !== undefined
497
+ ? new Gas(this.config.validateMaxDABlockGas ?? Infinity, this.config.validateMaxL2BlockGas ?? Infinity)
498
+ : undefined;
502
499
  const result = await checkpointBuilder.buildBlock(txs, blockNumber, blockHeader.globalVariables.timestamp, {
503
500
  deadline,
504
501
  expectedEndState: blockHeader.state,
502
+ maxTransactions: this.config.validateMaxTxsPerBlock,
503
+ maxBlockGas,
505
504
  });
506
505
 
507
506
  const { block, failedTxs } = result;
508
507
  const numFailedTxs = failedTxs.length;
509
508
 
510
- this.log.verbose(`Transaction re-execution complete for slot ${slot}`, {
509
+ this.log.verbose(`Block proposal ${blockNumber} at slot ${slot} transaction re-execution complete`, {
511
510
  numFailedTxs,
512
511
  numProposalTxs: txHashes.length,
513
512
  numProcessedTxs: block.body.txEffects.length,
513
+ blockNumber,
514
514
  slot,
515
515
  });
516
516