@@ -15,7 +15,9 @@ import { StatefulTestContract } from '@aztec/noir-test-contracts.js/StatefulTest
1515import { TestContract } from '@aztec/noir-test-contracts.js/Test' ;
1616import type { SequencerClient } from '@aztec/sequencer-client' ;
1717import type { TestSequencerClient } from '@aztec/sequencer-client/test' ;
18+ import { getAllFunctionAbis } from '@aztec/stdlib/abi' ;
1819import { getProofSubmissionDeadlineEpoch } from '@aztec/stdlib/epoch-helpers' ;
20+ import { GasFees } from '@aztec/stdlib/gas' ;
1921import { computeSiloedPrivateLogFirstField } from '@aztec/stdlib/hash' ;
2022import type { AztecNodeAdmin } from '@aztec/stdlib/interfaces/client' ;
2123import { TX_ERROR_EXISTING_NULLIFIER } from '@aztec/stdlib/tx' ;
@@ -72,36 +74,53 @@ describe('e2e_block_building', () => {
7274 } ) ;
7375
7476 afterEach ( async ( ) => {
75- await aztecNodeAdmin . setConfig ( { minTxsPerBlock : 1 } ) ;
77+ await aztecNodeAdmin . setConfig ( {
78+ fakeProcessingDelayPerTxMs : 0 ,
79+ minTxsPerBlock : 1 ,
80+ maxTxsPerBlock : undefined , // reset to default
81+ enforceTimeTable : false , // reset to false (as it is in setup())
82+ } ) ;
7683 // Clean up any mocks
7784 jest . restoreAllMocks ( ) ;
7885 } ) ;
7986
8087 afterAll ( ( ) => teardown ( ) ) ;
8188
8289 it ( 'processes txs until hitting timetable' , async ( ) => {
83- // We send enough txs so they are spread across multiple blocks, but not
84- // so many so that we don't end up hitting a reorg or timing out the tx wait().
85- const TX_COUNT = 16 ;
90+ const DEADLINE_S = 0.5 ; // half a second of building per block
91+ const DEADLINE_MS = DEADLINE_S * 1000 ;
92+ const MAX_TXS_FIT_IN_DEADLINE = 5 ; // via deadline and fake delay, we force this maximum to be true
93+ const FAKE_DELAY_PER_TX_MS = DEADLINE_MS / MAX_TXS_FIT_IN_DEADLINE ; // e.g. 100ms if 5 txs per 0.5s
94+
95+ // the minimum number of blocks we want to see
96+ const EXPECTED_BLOCKS = 3 ;
97+ // choose a tx count should ensure that we use EXPECTED_BLOCKS or more
98+ // Note that we don't need to ensure that last block is _full_
99+ const TX_COUNT = MAX_TXS_FIT_IN_DEADLINE * ( EXPECTED_BLOCKS - 1 ) + 1 ;
100+
101+ // print out the test parameters
102+ logger . info ( `multi-block timetable test parameters:` ) ;
103+ logger . info ( ` Deadline per block: ${ DEADLINE_MS } ms` ) ;
104+ logger . info ( ` Fake delay per tx: ${ FAKE_DELAY_PER_TX_MS } ms` ) ;
105+ logger . info ( ` Max txs that should fit in deadline: ${ MAX_TXS_FIT_IN_DEADLINE } ` ) ;
106+ logger . info ( ` Total txs to send: ${ TX_COUNT } ` ) ;
107+ logger . info ( ` Expected minimum blocks: ${ EXPECTED_BLOCKS } ` ) ;
86108
87109 const contract = await StatefulTestContract . deploy ( wallet , ownerAddress , 1 ) . send ( { from : ownerAddress } ) ;
88110 logger . info ( `Deployed stateful test contract at ${ contract . address } ` ) ;
89111
90- // We add a delay to every public tx processing
91- logger . info ( `Updating aztec node config` ) ;
112+ // Configure sequencer with a small delay per tx and enforce timetable
92113 await aztecNodeAdmin . setConfig ( {
93- fakeProcessingDelayPerTxMs : 300 ,
114+ fakeProcessingDelayPerTxMs : FAKE_DELAY_PER_TX_MS , // ensure that each tx takes at least this long
94115 minTxsPerBlock : 1 ,
95- maxTxsPerBlock : TX_COUNT ,
116+ maxTxsPerBlock : TX_COUNT , // intentionally large because we want to flex deadline, not this max
117+ enforceTimeTable : true ,
96118 } ) ;
97119
98- // We also cheat the sequencer's timetable so it allocates little time to processing.
99- // This will leave the sequencer with just a few seconds to build the block, so it shouldn't
100- // be able to squeeze in more than a few txs in each. This is sensitive to the time it takes
101- // to pick up and validate the txs, so we may need to bump it to work on CI.
120+ // Mock the timetable to limit time for block building.
102121 jest . spyOn ( sequencer . sequencer . timetable , 'canStartNextBlock' ) . mockImplementation ( ( secondsIntoSlot : number ) => ( {
103122 canStart : true ,
104- deadline : secondsIntoSlot + 1 , // Give only 1 second for building
123+ deadline : secondsIntoSlot + DEADLINE_S , // limit block- building time
105124 isLastBlock : true ,
106125 } ) ) ;
107126
@@ -118,7 +137,7 @@ describe('e2e_block_building', () => {
118137 const receipts = await Promise . all ( txHashes . map ( txHash => waitForTx ( aztecNode , txHash ) ) ) ;
119138 const blockNumbers = receipts . map ( r => r . blockNumber ! ) . sort ( ( a , b ) => a - b ) ;
120139 logger . info ( `Txs mined on blocks: ${ unique ( blockNumbers ) } ` ) ;
121- expect ( blockNumbers . at ( - 1 ) ! - blockNumbers [ 0 ] ) . toBeGreaterThan ( 1 ) ;
140+ expect ( blockNumbers . at ( - 1 ) ! - blockNumbers [ 0 ] ) . toBeGreaterThan ( EXPECTED_BLOCKS - 1 ) ;
122141 } ) ;
123142
124143 it ( 'assembles a block with multiple txs' , async ( ) => {
@@ -225,7 +244,8 @@ describe('e2e_block_building', () => {
225244 logger . info ( `Txs sent` ) ;
226245 } ) ;
227246
228- it . skip ( 'can call public function from different tx in same block as deployed' , async ( ) => {
247+ // Uses priority fees to guarantee the deploy tx is ordered before the call tx within the same block.
248+ it ( 'can call public function from different tx in same block as deployed' , async ( ) => {
229249 // Ensure both txs will land on the same block
230250 await aztecNodeAdmin . setConfig ( { minTxsPerBlock : 2 } ) ;
231251
@@ -239,13 +259,29 @@ describe('e2e_block_building', () => {
239259 const callInteraction = new ContractFunctionInteraction (
240260 wallet ,
241261 deployerInstance . address ,
242- TokenContract . artifact . functions . find ( x => x . name === 'set_minter' ) ! ,
262+ getAllFunctionAbis ( TokenContract . artifact ) . find ( x => x . name === 'set_minter' ) ! ,
243263 [ minterAddress , true ] ,
244264 ) ;
245265
266+ // Use priority fees to guarantee ordering: deploy tx gets higher priority so the
267+ // sequencer places it before the call tx in the block.
268+ const highPriority = new GasFees ( 100 , 100 ) ;
269+ const lowPriority = new GasFees ( 1 , 1 ) ;
270+
271+ const deployTxHash = await deployMethod . send ( {
272+ from : ownerAddress ,
273+ fee : { gasSettings : { maxPriorityFeesPerGas : highPriority } } ,
274+ wait : NO_WAIT ,
275+ } ) ;
276+ const callTxHash = await callInteraction . send ( {
277+ from : ownerAddress ,
278+ fee : { gasSettings : { maxPriorityFeesPerGas : lowPriority } } ,
279+ wait : NO_WAIT ,
280+ } ) ;
281+
246282 const [ deployTxReceipt , callTxReceipt ] = await Promise . all ( [
247- deployMethod . send ( { from : ownerAddress , wait : { returnReceipt : true } } ) ,
248- callInteraction . send ( { from : ownerAddress } ) ,
283+ waitForTx ( aztecNode , deployTxHash ) ,
284+ waitForTx ( aztecNode , callTxHash ) ,
249285 ] ) ;
250286
251287 expect ( deployTxReceipt . blockNumber ) . toEqual ( callTxReceipt . blockNumber ) ;
0 commit comments