@aztec/sequencer-client 0.61.0 → 0.63.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 (40) hide show
  1. package/dest/block_builder/light.d.ts.map +1 -1
  2. package/dest/block_builder/light.js +3 -5
  3. package/dest/client/sequencer-client.d.ts +1 -1
  4. package/dest/client/sequencer-client.d.ts.map +1 -1
  5. package/dest/client/sequencer-client.js +9 -4
  6. package/dest/config.d.ts +2 -2
  7. package/dest/config.d.ts.map +1 -1
  8. package/dest/config.js +14 -10
  9. package/dest/global_variable_builder/global_builder.d.ts +3 -2
  10. package/dest/global_variable_builder/global_builder.d.ts.map +1 -1
  11. package/dest/global_variable_builder/global_builder.js +4 -3
  12. package/dest/publisher/l1-publisher.d.ts +6 -4
  13. package/dest/publisher/l1-publisher.d.ts.map +1 -1
  14. package/dest/publisher/l1-publisher.js +28 -20
  15. package/dest/sequencer/metrics.d.ts +3 -2
  16. package/dest/sequencer/metrics.d.ts.map +1 -1
  17. package/dest/sequencer/metrics.js +16 -2
  18. package/dest/sequencer/sequencer.d.ts +23 -38
  19. package/dest/sequencer/sequencer.d.ts.map +1 -1
  20. package/dest/sequencer/sequencer.js +105 -95
  21. package/dest/sequencer/utils.d.ts +52 -0
  22. package/dest/sequencer/utils.d.ts.map +1 -0
  23. package/dest/sequencer/utils.js +70 -0
  24. package/dest/tx_validator/gas_validator.d.ts.map +1 -1
  25. package/dest/tx_validator/gas_validator.js +5 -5
  26. package/dest/tx_validator/phases_validator.d.ts.map +1 -1
  27. package/dest/tx_validator/phases_validator.js +4 -4
  28. package/dest/tx_validator/test_utils.js +9 -7
  29. package/package.json +19 -19
  30. package/src/block_builder/light.ts +1 -4
  31. package/src/client/sequencer-client.ts +10 -2
  32. package/src/config.ts +24 -10
  33. package/src/global_variable_builder/global_builder.ts +7 -10
  34. package/src/publisher/l1-publisher.ts +35 -23
  35. package/src/sequencer/metrics.ts +18 -2
  36. package/src/sequencer/sequencer.ts +135 -101
  37. package/src/sequencer/utils.ts +78 -0
  38. package/src/tx_validator/gas_validator.ts +4 -4
  39. package/src/tx_validator/phases_validator.ts +3 -3
  40. package/src/tx_validator/test_utils.ts +9 -7
@@ -1,5 +1,4 @@
1
1
  import {
2
- type BlockAttestation,
3
2
  type EpochProofQuote,
4
3
  type L1ToL2MessageSource,
5
4
  type L2Block,
@@ -10,11 +9,7 @@ import {
10
9
  type TxValidator,
11
10
  type WorldStateSynchronizer,
12
11
  } from '@aztec/circuit-types';
13
- import {
14
- type AllowedElement,
15
- BlockProofError,
16
- type WorldStateSynchronizerStatus,
17
- } from '@aztec/circuit-types/interfaces';
12
+ import type { AllowedElement, Signature, WorldStateSynchronizerStatus } from '@aztec/circuit-types/interfaces';
18
13
  import { type L2BlockBuiltStats } from '@aztec/circuit-types/stats';
19
14
  import {
20
15
  AppendOnlyTreeSnapshot,
@@ -25,7 +20,6 @@ import {
25
20
  } from '@aztec/circuits.js';
26
21
  import { AztecAddress } from '@aztec/foundation/aztec-address';
27
22
  import { EthAddress } from '@aztec/foundation/eth-address';
28
- import { Signature } from '@aztec/foundation/eth-signature';
29
23
  import { Fr } from '@aztec/foundation/fields';
30
24
  import { createDebugLogger } from '@aztec/foundation/log';
31
25
  import { RunningPromise } from '@aztec/foundation/running-promise';
@@ -44,6 +38,7 @@ import { prettyLogViemErrorMsg } from '../publisher/utils.js';
44
38
  import { type TxValidatorFactory } from '../tx_validator/tx_validator_factory.js';
45
39
  import { type SequencerConfig } from './config.js';
46
40
  import { SequencerMetrics } from './metrics.js';
41
+ import { SequencerState, getSecondsIntoSlot, orderAttestations } from './utils.js';
47
42
 
48
43
  export type ShouldProposeArgs = {
49
44
  pendingTxsCount?: number;
@@ -51,6 +46,20 @@ export type ShouldProposeArgs = {
51
46
  processedTxsCount?: number;
52
47
  };
53
48
 
49
+ export class SequencerTooSlowError extends Error {
50
+ constructor(
51
+ public readonly currentState: SequencerState,
52
+ public readonly proposedState: SequencerState,
53
+ public readonly maxAllowedTime: number,
54
+ public readonly currentTime: number,
55
+ ) {
56
+ super(
57
+ `Too far into slot to transition to ${proposedState}. max allowed: ${maxAllowedTime}s, time into slot: ${currentTime}s`,
58
+ );
59
+ this.name = 'SequencerTooSlowError';
60
+ }
61
+ }
62
+
54
63
  /**
55
64
  * Sequencer client
56
65
  * - Wins a period of time to become the sequencer (depending on finalized protocol).
@@ -72,11 +81,17 @@ export class Sequencer {
72
81
  private _feeRecipient = AztecAddress.ZERO;
73
82
  private state = SequencerState.STOPPED;
74
83
  private allowedInSetup: AllowedElement[] = [];
75
- private allowedInTeardown: AllowedElement[] = [];
76
84
  private maxBlockSizeInBytes: number = 1024 * 1024;
77
85
  private metrics: SequencerMetrics;
78
86
  private isFlushing: boolean = false;
79
87
 
88
+ /**
89
+ * The maximum number of seconds that the sequencer can be into a slot to transition to a particular state.
90
+ * For example, in order to transition into WAITING_FOR_ATTESTATIONS, the sequencer can be at most 3 seconds into the slot.
91
+ */
92
+ protected timeTable!: Record<SequencerState, number>;
93
+ protected enforceTimeTable: boolean = false;
94
+
80
95
  constructor(
81
96
  private publisher: L1Publisher,
82
97
  private validatorClient: ValidatorClient | undefined, // During migration the validator client can be inactive
@@ -88,6 +103,8 @@ export class Sequencer {
88
103
  private l1ToL2MessageSource: L1ToL2MessageSource,
89
104
  private publicProcessorFactory: PublicProcessorFactory,
90
105
  private txValidatorFactory: TxValidatorFactory,
106
+ protected l1GenesisTime: number,
107
+ private aztecSlotDuration: number,
91
108
  telemetry: TelemetryClient,
92
109
  private config: SequencerConfig = {},
93
110
  private log = createDebugLogger('aztec:sequencer'),
@@ -133,25 +150,42 @@ export class Sequencer {
133
150
  if (config.maxBlockSizeInBytes !== undefined) {
134
151
  this.maxBlockSizeInBytes = config.maxBlockSizeInBytes;
135
152
  }
136
- // TODO(#5917) remove this. it is no longer needed since we don't need to whitelist functions in teardown
137
- if (config.allowedInTeardown) {
138
- this.allowedInTeardown = config.allowedInTeardown;
139
- }
140
- if (config.gerousiaPayload) {
141
- this.publisher.setPayload(config.gerousiaPayload);
153
+ if (config.governanceProposerPayload) {
154
+ this.publisher.setPayload(config.governanceProposerPayload);
142
155
  }
156
+ this.enforceTimeTable = config.enforceTimeTable === true;
157
+
158
+ this.setTimeTable();
143
159
 
144
160
  // TODO: Just read everything from the config object as needed instead of copying everything into local vars.
145
161
  this.config = config;
146
162
  }
147
163
 
164
+ private setTimeTable() {
165
+ const newTimeTable: Record<SequencerState, number> = {
166
+ [SequencerState.STOPPED]: this.aztecSlotDuration,
167
+ [SequencerState.IDLE]: this.aztecSlotDuration,
168
+ [SequencerState.SYNCHRONIZING]: this.aztecSlotDuration,
169
+ [SequencerState.PROPOSER_CHECK]: this.aztecSlotDuration, // We always want to allow the full slot to check if we are the proposer
170
+ [SequencerState.WAITING_FOR_TXS]: 3,
171
+ [SequencerState.CREATING_BLOCK]: 5,
172
+ [SequencerState.PUBLISHING_BLOCK_TO_PEERS]: 5 + this.maxTxsPerBlock * 2, // if we take 5 seconds to create block, then 4 transactions at 2 seconds each
173
+ [SequencerState.WAITING_FOR_ATTESTATIONS]: 5 + this.maxTxsPerBlock * 2 + 3, // it shouldn't take 3 seconds to publish to peers
174
+ [SequencerState.PUBLISHING_BLOCK]: 5 + this.maxTxsPerBlock * 2 + 3 + 5, // wait 5 seconds for attestations
175
+ };
176
+ if (this.enforceTimeTable && newTimeTable[SequencerState.PUBLISHING_BLOCK] > this.aztecSlotDuration) {
177
+ throw new Error('Sequencer cannot publish block in less than a slot');
178
+ }
179
+ this.timeTable = newTimeTable;
180
+ }
181
+
148
182
  /**
149
- * Starts the sequencer and moves to IDLE state. Blocks until the initial sync is complete.
183
+ * Starts the sequencer and moves to IDLE state.
150
184
  */
151
185
  public start() {
152
186
  this.runningPromise = new RunningPromise(this.work.bind(this), this.pollingIntervalMs);
153
187
  this.runningPromise.start();
154
- this.state = SequencerState.IDLE;
188
+ this.setState(SequencerState.IDLE, true /** force */);
155
189
  this.log.info('Sequencer started');
156
190
  return Promise.resolve();
157
191
  }
@@ -163,7 +197,7 @@ export class Sequencer {
163
197
  this.log.debug(`Stopping sequencer`);
164
198
  await this.runningPromise?.stop();
165
199
  this.publisher.interrupt();
166
- this.state = SequencerState.STOPPED;
200
+ this.setState(SequencerState.STOPPED, true /** force */);
167
201
  this.log.info('Stopped sequencer');
168
202
  }
169
203
 
@@ -174,7 +208,7 @@ export class Sequencer {
174
208
  this.log.info('Restarting sequencer');
175
209
  this.publisher.restart();
176
210
  this.runningPromise!.start();
177
- this.state = SequencerState.IDLE;
211
+ this.setState(SequencerState.IDLE, true /** force */);
178
212
  }
179
213
 
180
214
  /**
@@ -193,7 +227,8 @@ export class Sequencer {
193
227
  * - Submit block
194
228
  * - If our block for some reason is not included, revert the state
195
229
  */
196
- protected async work() {
230
+ protected async doRealWork() {
231
+ this.setState(SequencerState.SYNCHRONIZING);
197
232
  // Update state when the previous block has been synced
198
233
  const prevBlockSynced = await this.isBlockSynced();
199
234
  // Do not go forward with new block if the previous one has not been mined and processed
@@ -202,10 +237,9 @@ export class Sequencer {
202
237
  return;
203
238
  }
204
239
 
205
- if (prevBlockSynced && this.state === SequencerState.PUBLISHING_BLOCK) {
206
- this.log.debug(`Block has been synced`);
207
- this.state = SequencerState.IDLE;
208
- }
240
+ this.log.debug('Previous block has been mined and processed');
241
+
242
+ this.setState(SequencerState.PROPOSER_CHECK);
209
243
 
210
244
  const chainTip = await this.l2BlockSource.getBlock(-1);
211
245
  const historicalHeader = chainTip?.header;
@@ -240,7 +274,7 @@ export class Sequencer {
240
274
  return;
241
275
  }
242
276
 
243
- this.state = SequencerState.WAITING_FOR_TXS;
277
+ this.setState(SequencerState.WAITING_FOR_TXS);
244
278
 
245
279
  // Get txs to build the new block.
246
280
  const pendingTxs = this.p2pClient.getTxs('pending');
@@ -283,13 +317,24 @@ export class Sequencer {
283
317
  // be in for a world of pain.
284
318
  await this.buildBlockAndAttemptToPublish(validTxs, proposalHeader, historicalHeader);
285
319
  } catch (err) {
286
- if (BlockProofError.isBlockProofError(err)) {
287
- const txHashes = err.txHashes.filter(h => !h.isZero());
288
- this.log.warn(`Proving block failed, removing ${txHashes.length} txs from pool`);
289
- await this.p2pClient.deleteTxs(txHashes);
290
- }
291
320
  this.log.error(`Error assembling block`, (err as any).stack);
292
321
  }
322
+ this.setState(SequencerState.IDLE);
323
+ }
324
+
325
+ protected async work() {
326
+ try {
327
+ await this.doRealWork();
328
+ } catch (err) {
329
+ if (err instanceof SequencerTooSlowError) {
330
+ this.log.warn(err.message);
331
+ } else {
332
+ // Re-throw other errors
333
+ throw err;
334
+ }
335
+ } finally {
336
+ this.setState(SequencerState.IDLE);
337
+ }
293
338
  }
294
339
 
295
340
  /** Whether to skip the check of min txs per block if more than maxSecondsBetweenBlocks has passed since the previous block. */
@@ -312,7 +357,7 @@ export class Sequencer {
312
357
  throw new Error(msg);
313
358
  }
314
359
 
315
- this.log.debug(`Can propose block ${proposalBlockNumber} at slot ${slot}`);
360
+ this.log.verbose(`Can propose block ${proposalBlockNumber} at slot ${slot}`);
316
361
  return slot;
317
362
  } catch (err) {
318
363
  const msg = prettyLogViemErrorMsg(err);
@@ -323,6 +368,44 @@ export class Sequencer {
323
368
  }
324
369
  }
325
370
 
371
+ doIHaveEnoughTimeLeft(proposedState: SequencerState, secondsIntoSlot: number): boolean {
372
+ if (!this.enforceTimeTable) {
373
+ return true;
374
+ }
375
+
376
+ if (this.timeTable[proposedState] === this.aztecSlotDuration) {
377
+ return true;
378
+ }
379
+
380
+ const bufferSeconds = this.timeTable[proposedState] - secondsIntoSlot;
381
+ this.metrics.recordStateTransitionBufferMs(bufferSeconds * 1000, proposedState);
382
+
383
+ if (bufferSeconds < 0) {
384
+ this.log.warn(
385
+ `Too far into slot to transition to ${proposedState}. max allowed: ${this.timeTable[proposedState]}s, time into slot: ${secondsIntoSlot}s`,
386
+ );
387
+ return false;
388
+ }
389
+ this.log.debug(
390
+ `Enough time to transition to ${proposedState}, max allowed: ${this.timeTable[proposedState]}s, time into slot: ${secondsIntoSlot}s`,
391
+ );
392
+ return true;
393
+ }
394
+
395
+ setState(proposedState: SequencerState, force: boolean = false) {
396
+ if (this.state === SequencerState.STOPPED && force !== true) {
397
+ this.log.warn(
398
+ `Cannot set sequencer from ${this.state} to ${proposedState} as it is stopped. Set force=true to override.`,
399
+ );
400
+ return;
401
+ }
402
+ const secondsIntoSlot = getSecondsIntoSlot(this.l1GenesisTime, this.aztecSlotDuration);
403
+ if (!this.doIHaveEnoughTimeLeft(proposedState, secondsIntoSlot)) {
404
+ throw new SequencerTooSlowError(this.state, proposedState, this.timeTable[proposedState], secondsIntoSlot);
405
+ }
406
+ this.state = proposedState;
407
+ }
408
+
326
409
  shouldProposeBlock(historicalHeader: Header | undefined, args: ShouldProposeArgs): boolean {
327
410
  if (this.isFlushing) {
328
411
  this.log.verbose(`Flushing all pending txs in new block`);
@@ -413,8 +496,12 @@ export class Sequencer {
413
496
 
414
497
  this.metrics.recordNewBlock(newGlobalVariables.blockNumber.toNumber(), validTxs.length);
415
498
  const workTimer = new Timer();
416
- this.state = SequencerState.CREATING_BLOCK;
417
- this.log.info(`Building block ${newGlobalVariables.blockNumber.toNumber()} with ${validTxs.length} transactions`);
499
+ this.setState(SequencerState.CREATING_BLOCK);
500
+ this.log.info(
501
+ `Building blockNumber=${newGlobalVariables.blockNumber.toNumber()} txCount=${
502
+ validTxs.length
503
+ } slotNumber=${newGlobalVariables.slotNumber.toNumber()}`,
504
+ );
418
505
 
419
506
  // Get l1 to l2 messages from the contract
420
507
  this.log.debug('Requesting L1 to L2 messages from contract');
@@ -426,16 +513,23 @@ export class Sequencer {
426
513
  const numRealTxs = validTxs.length;
427
514
  const blockSize = Math.max(2, numRealTxs);
428
515
 
429
- const fork = await this.worldState.fork();
516
+ // NB: separating the dbs because both should update the state
517
+ const publicProcessorFork = await this.worldState.fork();
518
+ const orchestratorFork = await this.worldState.fork();
430
519
  try {
431
520
  // We create a fresh processor each time to reset any cached state (eg storage writes)
432
- const processor = this.publicProcessorFactory.create(fork, historicalHeader, newGlobalVariables);
521
+ const processor = this.publicProcessorFactory.create(publicProcessorFork, historicalHeader, newGlobalVariables);
433
522
  const blockBuildingTimer = new Timer();
434
- const blockBuilder = this.blockBuilderFactory.create(fork);
523
+ const blockBuilder = this.blockBuilderFactory.create(orchestratorFork);
435
524
  await blockBuilder.startNewBlock(blockSize, newGlobalVariables, l1ToL2Messages);
436
525
 
437
526
  const [publicProcessorDuration, [processedTxs, failedTxs]] = await elapsed(() =>
438
- processor.process(validTxs, blockSize, blockBuilder, this.txValidatorFactory.validatorForProcessedTxs(fork)),
527
+ processor.process(
528
+ validTxs,
529
+ blockSize,
530
+ blockBuilder,
531
+ this.txValidatorFactory.validatorForProcessedTxs(publicProcessorFork),
532
+ ),
439
533
  );
440
534
  if (failedTxs.length > 0) {
441
535
  const failedTxData = failedTxs.map(fail => fail.tx);
@@ -506,7 +600,8 @@ export class Sequencer {
506
600
  throw err;
507
601
  }
508
602
  } finally {
509
- await fork.close();
603
+ await publicProcessorFork.close();
604
+ await orchestratorFork.close();
510
605
  }
511
606
  }
512
607
 
@@ -541,11 +636,11 @@ export class Sequencer {
541
636
  this.log.verbose('Creating block proposal');
542
637
  const proposal = await this.validatorClient.createBlockProposal(block.header, block.archive.root, txHashes);
543
638
 
544
- this.state = SequencerState.PUBLISHING_BLOCK_TO_PEERS;
639
+ this.setState(SequencerState.PUBLISHING_BLOCK_TO_PEERS);
545
640
  this.log.verbose('Broadcasting block proposal to validators');
546
641
  this.validatorClient.broadcastBlockProposal(proposal);
547
642
 
548
- this.state = SequencerState.WAITING_FOR_ATTESTATIONS;
643
+ this.setState(SequencerState.WAITING_FOR_ATTESTATIONS);
549
644
  const attestations = await this.validatorClient.collectAttestations(proposal, numberOfRequiredAttestations);
550
645
  this.log.verbose(`Collected attestations from validators, number of attestations: ${attestations.length}`);
551
646
 
@@ -603,7 +698,7 @@ export class Sequencer {
603
698
  proofQuote?: EpochProofQuote,
604
699
  ) {
605
700
  // Publishes new block to the network and awaits the tx to be mined
606
- this.state = SequencerState.PUBLISHING_BLOCK;
701
+ this.setState(SequencerState.PUBLISHING_BLOCK);
607
702
 
608
703
  const publishedL2Block = await this.publisher.proposeL2Block(block, attestations, txHashes, proofQuote);
609
704
  if (!publishedL2Block) {
@@ -689,64 +784,3 @@ export class Sequencer {
689
784
  /**
690
785
  * State of the sequencer.
691
786
  */
692
- export enum SequencerState {
693
- /**
694
- * Will move to WAITING_FOR_TXS after a configured amount of time.
695
- */
696
- IDLE,
697
- /**
698
- * Polling the P2P module for txs to include in a block. Will move to CREATING_BLOCK if there are valid txs to include, or back to IDLE otherwise.
699
- */
700
- WAITING_FOR_TXS,
701
- /**
702
- * Creating a new L2 block. Includes processing public function calls and running rollup circuits. Will move to PUBLISHING_CONTRACT_DATA.
703
- */
704
- CREATING_BLOCK,
705
- /**
706
- * Publishing blocks to validator peers. Will move to WAITING_FOR_ATTESTATIONS.
707
- */
708
- PUBLISHING_BLOCK_TO_PEERS,
709
- /**
710
- * The block has been published to peers, and we are waiting for attestations. Will move to PUBLISHING_CONTRACT_DATA.
711
- */
712
- WAITING_FOR_ATTESTATIONS,
713
- /**
714
- * Sending the tx to L1 with encrypted logs and awaiting it to be mined. Will move back to PUBLISHING_BLOCK once finished.
715
- */
716
- PUBLISHING_CONTRACT_DATA,
717
- /**
718
- * Sending the tx to L1 with the L2 block data and awaiting it to be mined. Will move to IDLE.
719
- */
720
- PUBLISHING_BLOCK,
721
- /**
722
- * Sequencer is stopped and not processing any txs from the pool.
723
- */
724
- STOPPED,
725
- }
726
-
727
- /** Order Attestations
728
- *
729
- * Returns attestation signatures in the order of a series of provided ethereum addresses
730
- * The rollup smart contract expects attestations to appear in the order of the committee
731
- *
732
- * @todo: perform this logic within the memory attestation store instead?
733
- */
734
- function orderAttestations(attestations: BlockAttestation[], orderAddresses: EthAddress[]): Signature[] {
735
- // Create a map of sender addresses to BlockAttestations
736
- const attestationMap = new Map<string, BlockAttestation>();
737
-
738
- for (const attestation of attestations) {
739
- const sender = attestation.getSender();
740
- if (sender) {
741
- attestationMap.set(sender.toString(), attestation);
742
- }
743
- }
744
-
745
- // Create the ordered array based on the orderAddresses, else return an empty signature
746
- const orderedAttestations = orderAddresses.map(address => {
747
- const addressString = address.toString();
748
- return attestationMap.get(addressString)?.signature || Signature.empty();
749
- });
750
-
751
- return orderedAttestations;
752
- }
@@ -0,0 +1,78 @@
1
+ import type { BlockAttestation, EthAddress } from '@aztec/circuit-types';
2
+ import { Signature } from '@aztec/foundation/eth-signature';
3
+
4
+ export enum SequencerState {
5
+ /**
6
+ * Sequencer is stopped and not processing any txs from the pool.
7
+ */
8
+ STOPPED = 'STOPPED',
9
+ /**
10
+ * Sequencer is awaiting the next call to work().
11
+ */
12
+ IDLE = 'IDLE',
13
+ /**
14
+ * Synchronizing with the L2 chain.
15
+ */
16
+ SYNCHRONIZING = 'SYNCHRONIZING',
17
+ /**
18
+ * Checking if we are the proposer for the current slot.
19
+ */
20
+ PROPOSER_CHECK = 'PROPOSER_CHECK',
21
+ /**
22
+ * Polling the P2P module for txs to include in a block. Will move to CREATING_BLOCK if there are valid txs to include, or back to SYNCHRONIZING otherwise.
23
+ */
24
+ WAITING_FOR_TXS = 'WAITING_FOR_TXS',
25
+ /**
26
+ * Creating a new L2 block. Includes processing public function calls and running rollup circuits. Will move to PUBLISHING_CONTRACT_DATA.
27
+ */
28
+ CREATING_BLOCK = 'CREATING_BLOCK',
29
+ /**
30
+ * Publishing blocks to validator peers. Will move to WAITING_FOR_ATTESTATIONS.
31
+ */
32
+ PUBLISHING_BLOCK_TO_PEERS = 'PUBLISHING_BLOCK_TO_PEERS',
33
+ /**
34
+ * The block has been published to peers, and we are waiting for attestations. Will move to PUBLISHING_CONTRACT_DATA.
35
+ */
36
+ WAITING_FOR_ATTESTATIONS = 'WAITING_FOR_ATTESTATIONS',
37
+ /**
38
+ * Sending the tx to L1 with the L2 block data and awaiting it to be mined. Will move to SYNCHRONIZING.
39
+ */
40
+ PUBLISHING_BLOCK = 'PUBLISHING_BLOCK',
41
+ }
42
+
43
+ export type SequencerStateCallback = () => SequencerState;
44
+
45
+ export function sequencerStateToNumber(state: SequencerState): number {
46
+ return Object.values(SequencerState).indexOf(state);
47
+ }
48
+
49
+ /** Order Attestations
50
+ *
51
+ * Returns attestation signatures in the order of a series of provided ethereum addresses
52
+ * The rollup smart contract expects attestations to appear in the order of the committee
53
+ *
54
+ * @todo: perform this logic within the memory attestation store instead?
55
+ */
56
+ export function orderAttestations(attestations: BlockAttestation[], orderAddresses: EthAddress[]): Signature[] {
57
+ // Create a map of sender addresses to BlockAttestations
58
+ const attestationMap = new Map<string, BlockAttestation>();
59
+
60
+ for (const attestation of attestations) {
61
+ const sender = attestation.getSender();
62
+ if (sender) {
63
+ attestationMap.set(sender.toString(), attestation);
64
+ }
65
+ }
66
+
67
+ // Create the ordered array based on the orderAddresses, else return an empty signature
68
+ const orderedAttestations = orderAddresses.map(address => {
69
+ const addressString = address.toString();
70
+ return attestationMap.get(addressString)?.signature || Signature.empty();
71
+ });
72
+
73
+ return orderedAttestations;
74
+ }
75
+
76
+ export function getSecondsIntoSlot(l1GenesisTime: number, aztecSlotDuration: number): number {
77
+ return (Date.now() / 1000 - l1GenesisTime) % aztecSlotDuration;
78
+ }
@@ -1,7 +1,7 @@
1
- import { PublicKernelPhase, type Tx, type TxValidator } from '@aztec/circuit-types';
1
+ import { type Tx, TxExecutionPhase, type TxValidator } from '@aztec/circuit-types';
2
2
  import { type AztecAddress, type Fr, FunctionSelector } from '@aztec/circuits.js';
3
3
  import { createDebugLogger } from '@aztec/foundation/log';
4
- import { EnqueuedCallsProcessor, computeFeePayerBalanceStorageSlot } from '@aztec/simulator';
4
+ import { computeFeePayerBalanceStorageSlot, getExecutionRequestsByPhase } from '@aztec/simulator';
5
5
 
6
6
  /** Provides a view into public contract state */
7
7
  export interface PublicStateSource {
@@ -58,7 +58,7 @@ export class GasTxValidator implements TxValidator<Tx> {
58
58
  );
59
59
 
60
60
  // If there is a claim in this tx that increases the fee payer balance in Fee Juice, add it to balance
61
- const setupFns = EnqueuedCallsProcessor.getExecutionRequestsByPhase(tx, PublicKernelPhase.SETUP);
61
+ const setupFns = getExecutionRequestsByPhase(tx, TxExecutionPhase.SETUP);
62
62
  const claimFunctionCall = setupFns.find(
63
63
  fn =>
64
64
  fn.callContext.contractAddress.equals(this.#feeJuiceAddress) &&
@@ -66,7 +66,7 @@ export class GasTxValidator implements TxValidator<Tx> {
66
66
  fn.args.length > 2 &&
67
67
  // Public functions get routed through the dispatch function, whose first argument is the target function selector.
68
68
  fn.args[0].equals(FunctionSelector.fromSignature('_increase_public_balance((Field),Field)').toField()) &&
69
- fn.args[1].equals(feePayer) &&
69
+ fn.args[1].equals(feePayer.toField()) &&
70
70
  !fn.callContext.isStaticCall,
71
71
  );
72
72
 
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  type AllowedElement,
3
3
  type PublicExecutionRequest,
4
- PublicKernelPhase,
5
4
  Tx,
5
+ TxExecutionPhase,
6
6
  type TxValidator,
7
7
  } from '@aztec/circuit-types';
8
8
  import { type ContractDataSource } from '@aztec/circuits.js';
9
9
  import { createDebugLogger } from '@aztec/foundation/log';
10
- import { ContractsDataSourcePublicDB, EnqueuedCallsProcessor } from '@aztec/simulator';
10
+ import { ContractsDataSourcePublicDB, getExecutionRequestsByPhase } from '@aztec/simulator';
11
11
 
12
12
  export class PhasesTxValidator implements TxValidator<Tx> {
13
13
  #log = createDebugLogger('aztec:sequencer:tx_validator:tx_phases');
@@ -45,7 +45,7 @@ export class PhasesTxValidator implements TxValidator<Tx> {
45
45
  return true;
46
46
  }
47
47
 
48
- const setupFns = EnqueuedCallsProcessor.getExecutionRequestsByPhase(tx, PublicKernelPhase.SETUP);
48
+ const setupFns = getExecutionRequestsByPhase(tx, TxExecutionPhase.SETUP);
49
49
  for (const setupFn of setupFns) {
50
50
  if (!(await this.isOnAllowList(setupFn, this.setupAllowList))) {
51
51
  this.#log.warn(
@@ -7,7 +7,7 @@ export function patchNonRevertibleFn(
7
7
  index: number,
8
8
  overrides: { address?: AztecAddress; selector: FunctionSelector; args?: Fr[]; msgSender?: AztecAddress },
9
9
  ): { address: AztecAddress; selector: FunctionSelector } {
10
- return patchFn('endNonRevertibleData', tx, index, overrides);
10
+ return patchFn('nonRevertibleAccumulatedData', tx, index, overrides);
11
11
  }
12
12
 
13
13
  export function patchRevertibleFn(
@@ -15,11 +15,11 @@ export function patchRevertibleFn(
15
15
  index: number,
16
16
  overrides: { address?: AztecAddress; selector: FunctionSelector; args?: Fr[]; msgSender?: AztecAddress },
17
17
  ): { address: AztecAddress; selector: FunctionSelector } {
18
- return patchFn('end', tx, index, overrides);
18
+ return patchFn('revertibleAccumulatedData', tx, index, overrides);
19
19
  }
20
20
 
21
21
  function patchFn(
22
- where: 'end' | 'endNonRevertibleData',
22
+ where: 'revertibleAccumulatedData' | 'nonRevertibleAccumulatedData',
23
23
  tx: Tx,
24
24
  index: number,
25
25
  overrides: { address?: AztecAddress; selector: FunctionSelector; args?: Fr[]; msgSender?: AztecAddress },
@@ -31,11 +31,13 @@ function patchFn(
31
31
  fn.callContext.msgSender = overrides.msgSender ?? fn.callContext.msgSender;
32
32
  tx.enqueuedPublicFunctionCalls[index] = fn;
33
33
 
34
- const request = tx.data.forPublic![where].publicCallStack[index];
35
- request.callContext.contractAddress = fn.callContext.contractAddress;
36
- request.callContext = fn.callContext;
34
+ const request = tx.data.forPublic![where].publicCallRequests[index];
35
+ request.contractAddress = fn.callContext.contractAddress;
36
+ request.msgSender = fn.callContext.msgSender;
37
+ request.functionSelector = fn.callContext.functionSelector;
38
+ request.isStaticCall = fn.callContext.isStaticCall;
37
39
  request.argsHash = computeVarArgsHash(fn.args);
38
- tx.data.forPublic![where].publicCallStack[index] = request;
40
+ tx.data.forPublic![where].publicCallRequests[index] = request;
39
41
 
40
42
  return {
41
43
  address: fn.callContext.contractAddress,