@@ -5,7 +5,6 @@ import { L2Block } from '@aztec/stdlib/block';
55import { Checkpoint } from '@aztec/stdlib/checkpoint' ;
66import { Gas } from '@aztec/stdlib/gas' ;
77import type {
8- BuildBlockInCheckpointResult ,
98 FullNodeBlockBuilderConfig ,
109 ICheckpointBlockBuilder ,
1110 ICheckpointsBuilder ,
@@ -15,6 +14,7 @@ import type {
1514import { CheckpointHeader } from '@aztec/stdlib/rollup' ;
1615import { makeAppendOnlyTreeSnapshot } from '@aztec/stdlib/testing' ;
1716import type { CheckpointGlobalVariables , Tx } from '@aztec/stdlib/tx' ;
17+ import type { BuildBlockInCheckpointResultWithTimer } from '@aztec/validator-client' ;
1818
1919/**
2020 * A fake CheckpointBuilder for testing that implements the same interface as the real one.
@@ -35,6 +35,8 @@ export class MockCheckpointBuilder implements ICheckpointBlockBuilder {
3535 timestamp : bigint ;
3636 opts : PublicProcessorLimits ;
3737 } > = [ ] ;
38+ /** Track all consumed transaction hashes across buildBlock calls */
39+ public consumedTxHashes : Set < string > = new Set ( ) ;
3840 public completeCheckpointCalled = false ;
3941 public getCheckpointCalled = false ;
4042
@@ -69,16 +71,16 @@ export class MockCheckpointBuilder implements ICheckpointBlockBuilder {
6971 return this . constants ;
7072 }
7173
72- buildBlock (
73- _pendingTxs : Iterable < Tx > | AsyncIterable < Tx > ,
74+ async buildBlock (
75+ pendingTxs : Iterable < Tx > | AsyncIterable < Tx > ,
7476 blockNumber : BlockNumber ,
7577 timestamp : bigint ,
7678 opts : PublicProcessorLimits ,
77- ) : Promise < BuildBlockInCheckpointResult > {
79+ ) : Promise < BuildBlockInCheckpointResultWithTimer > {
7880 this . buildBlockCalls . push ( { blockNumber, timestamp, opts } ) ;
7981
8082 if ( this . errorOnBuild ) {
81- return Promise . reject ( this . errorOnBuild ) ;
83+ throw this . errorOnBuild ;
8284 }
8385
8486 let block : L2Block ;
@@ -97,7 +99,20 @@ export class MockCheckpointBuilder implements ICheckpointBlockBuilder {
9799 this . builtBlocks . push ( block ) ;
98100 }
99101
100- return Promise . resolve ( {
102+ // Check that no pending tx has already been consumed
103+ for await ( const tx of pendingTxs ) {
104+ const hash = tx . getTxHash ( ) . toString ( ) ;
105+ if ( this . consumedTxHashes . has ( hash ) ) {
106+ throw new Error ( `Transaction ${ hash } was already consumed in a previous block` ) ;
107+ }
108+ }
109+
110+ // Add used txs to consumed set
111+ for ( const tx of usedTxs ) {
112+ this . consumedTxHashes . add ( tx . getTxHash ( ) . toString ( ) ) ;
113+ }
114+
115+ return {
101116 block,
102117 publicGas : Gas . empty ( ) ,
103118 publicProcessorDuration : 0 ,
@@ -106,7 +121,7 @@ export class MockCheckpointBuilder implements ICheckpointBlockBuilder {
106121 usedTxs,
107122 failedTxs : [ ] ,
108123 usedTxBlobFields : block ?. body ?. txEffects ?. reduce ( ( sum , tx ) => sum + tx . getNumBlobFields ( ) , 0 ) ?? 0 ,
109- } ) ;
124+ } ;
110125 }
111126
112127 completeCheckpoint ( ) : Promise < Checkpoint > {
@@ -170,6 +185,7 @@ export class MockCheckpointBuilder implements ICheckpointBlockBuilder {
170185 this . usedTxsPerBlock = [ ] ;
171186 this . blockIndex = 0 ;
172187 this . buildBlockCalls = [ ] ;
188+ this . consumedTxHashes . clear ( ) ;
173189 this . completeCheckpointCalled = false ;
174190 this . getCheckpointCalled = false ;
175191 this . errorOnBuild = undefined ;
0 commit comments