@aztec/sequencer-client 0.62.0 → 0.63.1

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 +22 -18
  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 +104 -94
  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 +29 -21
  35. package/src/sequencer/metrics.ts +18 -2
  36. package/src/sequencer/sequencer.ts +130 -100
  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,7 +496,7 @@ 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;
499
+ this.setState(SequencerState.CREATING_BLOCK);
417
500
  this.log.info(
418
501
  `Building blockNumber=${newGlobalVariables.blockNumber.toNumber()} txCount=${
419
502
  validTxs.length
@@ -430,16 +513,23 @@ export class Sequencer {
430
513
  const numRealTxs = validTxs.length;
431
514
  const blockSize = Math.max(2, numRealTxs);
432
515
 
433
- 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();
434
519
  try {
435
520
  // We create a fresh processor each time to reset any cached state (eg storage writes)
436
- const processor = this.publicProcessorFactory.create(fork, historicalHeader, newGlobalVariables);
521
+ const processor = this.publicProcessorFactory.create(publicProcessorFork, historicalHeader, newGlobalVariables);
437
522
  const blockBuildingTimer = new Timer();
438
- const blockBuilder = this.blockBuilderFactory.create(fork);
523
+ const blockBuilder = this.blockBuilderFactory.create(orchestratorFork);
439
524
  await blockBuilder.startNewBlock(blockSize, newGlobalVariables, l1ToL2Messages);
440
525
 
441
526
  const [publicProcessorDuration, [processedTxs, failedTxs]] = await elapsed(() =>
442
- processor.process(validTxs, blockSize, blockBuilder, this.txValidatorFactory.validatorForProcessedTxs(fork)),
527
+ processor.process(
528
+ validTxs,
529
+ blockSize,
530
+ blockBuilder,
531
+ this.txValidatorFactory.validatorForProcessedTxs(publicProcessorFork),
532
+ ),
443
533
  );
444
534
  if (failedTxs.length > 0) {
445
535
  const failedTxData = failedTxs.map(fail => fail.tx);
@@ -510,7 +600,8 @@ export class Sequencer {
510
600
  throw err;
511
601
  }
512
602
  } finally {
513
- await fork.close();
603
+ await publicProcessorFork.close();
604
+ await orchestratorFork.close();
514
605
  }
515
606
  }
516
607
 
@@ -545,11 +636,11 @@ export class Sequencer {
545
636
  this.log.verbose('Creating block proposal');
546
637
  const proposal = await this.validatorClient.createBlockProposal(block.header, block.archive.root, txHashes);
547
638
 
548
- this.state = SequencerState.PUBLISHING_BLOCK_TO_PEERS;
639
+ this.setState(SequencerState.PUBLISHING_BLOCK_TO_PEERS);
549
640
  this.log.verbose('Broadcasting block proposal to validators');
550
641
  this.validatorClient.broadcastBlockProposal(proposal);
551
642
 
552
- this.state = SequencerState.WAITING_FOR_ATTESTATIONS;
643
+ this.setState(SequencerState.WAITING_FOR_ATTESTATIONS);
553
644
  const attestations = await this.validatorClient.collectAttestations(proposal, numberOfRequiredAttestations);
554
645
  this.log.verbose(`Collected attestations from validators, number of attestations: ${attestations.length}`);
555
646
 
@@ -607,7 +698,7 @@ export class Sequencer {
607
698
  proofQuote?: EpochProofQuote,
608
699
  ) {
609
700
  // Publishes new block to the network and awaits the tx to be mined
610
- this.state = SequencerState.PUBLISHING_BLOCK;
701
+ this.setState(SequencerState.PUBLISHING_BLOCK);
611
702
 
612
703
  const publishedL2Block = await this.publisher.proposeL2Block(block, attestations, txHashes, proofQuote);
613
704
  if (!publishedL2Block) {
@@ -693,64 +784,3 @@ export class Sequencer {
693
784
  /**
694
785
  * State of the sequencer.
695
786
  */
696
- export enum SequencerState {
697
- /**
698
- * Will move to WAITING_FOR_TXS after a configured amount of time.
699
- */
700
- IDLE,
701
- /**
702
- * 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.
703
- */
704
- WAITING_FOR_TXS,
705
- /**
706
- * Creating a new L2 block. Includes processing public function calls and running rollup circuits. Will move to PUBLISHING_CONTRACT_DATA.
707
- */
708
- CREATING_BLOCK,
709
- /**
710
- * Publishing blocks to validator peers. Will move to WAITING_FOR_ATTESTATIONS.
711
- */
712
- PUBLISHING_BLOCK_TO_PEERS,
713
- /**
714
- * The block has been published to peers, and we are waiting for attestations. Will move to PUBLISHING_CONTRACT_DATA.
715
- */
716
- WAITING_FOR_ATTESTATIONS,
717
- /**
718
- * Sending the tx to L1 with encrypted logs and awaiting it to be mined. Will move back to PUBLISHING_BLOCK once finished.
719
- */
720
- PUBLISHING_CONTRACT_DATA,
721
- /**
722
- * Sending the tx to L1 with the L2 block data and awaiting it to be mined. Will move to IDLE.
723
- */
724
- PUBLISHING_BLOCK,
725
- /**
726
- * Sequencer is stopped and not processing any txs from the pool.
727
- */
728
- STOPPED,
729
- }
730
-
731
- /** Order Attestations
732
- *
733
- * Returns attestation signatures in the order of a series of provided ethereum addresses
734
- * The rollup smart contract expects attestations to appear in the order of the committee
735
- *
736
- * @todo: perform this logic within the memory attestation store instead?
737
- */
738
- function orderAttestations(attestations: BlockAttestation[], orderAddresses: EthAddress[]): Signature[] {
739
- // Create a map of sender addresses to BlockAttestations
740
- const attestationMap = new Map<string, BlockAttestation>();
741
-
742
- for (const attestation of attestations) {
743
- const sender = attestation.getSender();
744
- if (sender) {
745
- attestationMap.set(sender.toString(), attestation);
746
- }
747
- }
748
-
749
- // Create the ordered array based on the orderAddresses, else return an empty signature
750
- const orderedAttestations = orderAddresses.map(address => {
751
- const addressString = address.toString();
752
- return attestationMap.get(addressString)?.signature || Signature.empty();
753
- });
754
-
755
- return orderedAttestations;
756
- }
@@ -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,