@aztec-labs/sequencer-client 6.0.0-nightly.20260829

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 (165) hide show
  1. package/README.md +307 -0
  2. package/dest/client/index.d.ts +2 -0
  3. package/dest/client/index.d.ts.map +1 -0
  4. package/dest/client/index.js +1 -0
  5. package/dest/client/sequencer-client.d.ts +94 -0
  6. package/dest/client/sequencer-client.d.ts.map +1 -0
  7. package/dest/client/sequencer-client.js +177 -0
  8. package/dest/config.d.ts +56 -0
  9. package/dest/config.d.ts.map +1 -0
  10. package/dest/config.js +251 -0
  11. package/dest/global_variable_builder/fee_predictor.d.ts +49 -0
  12. package/dest/global_variable_builder/fee_predictor.d.ts.map +1 -0
  13. package/dest/global_variable_builder/fee_predictor.js +127 -0
  14. package/dest/global_variable_builder/fee_provider.d.ts +28 -0
  15. package/dest/global_variable_builder/fee_provider.d.ts.map +1 -0
  16. package/dest/global_variable_builder/fee_provider.js +87 -0
  17. package/dest/global_variable_builder/global_builder.d.ts +28 -0
  18. package/dest/global_variable_builder/global_builder.d.ts.map +1 -0
  19. package/dest/global_variable_builder/global_builder.js +40 -0
  20. package/dest/global_variable_builder/index.d.ts +4 -0
  21. package/dest/global_variable_builder/index.d.ts.map +1 -0
  22. package/dest/global_variable_builder/index.js +3 -0
  23. package/dest/index.d.ts +7 -0
  24. package/dest/index.d.ts.map +1 -0
  25. package/dest/index.js +8 -0
  26. package/dest/publisher/config.d.ts +68 -0
  27. package/dest/publisher/config.d.ts.map +1 -0
  28. package/dest/publisher/config.js +137 -0
  29. package/dest/publisher/index.d.ts +5 -0
  30. package/dest/publisher/index.d.ts.map +1 -0
  31. package/dest/publisher/index.js +4 -0
  32. package/dest/publisher/l1_to_l2_messaging.d.ts +21 -0
  33. package/dest/publisher/l1_to_l2_messaging.d.ts.map +1 -0
  34. package/dest/publisher/l1_to_l2_messaging.js +70 -0
  35. package/dest/publisher/l1_tx_failed_store/factory.d.ts +11 -0
  36. package/dest/publisher/l1_tx_failed_store/factory.d.ts.map +1 -0
  37. package/dest/publisher/l1_tx_failed_store/factory.js +22 -0
  38. package/dest/publisher/l1_tx_failed_store/failed_tx_store.d.ts +101 -0
  39. package/dest/publisher/l1_tx_failed_store/failed_tx_store.d.ts.map +1 -0
  40. package/dest/publisher/l1_tx_failed_store/failed_tx_store.js +68 -0
  41. package/dest/publisher/l1_tx_failed_store/file_store_failed_tx_store.d.ts +15 -0
  42. package/dest/publisher/l1_tx_failed_store/file_store_failed_tx_store.d.ts.map +1 -0
  43. package/dest/publisher/l1_tx_failed_store/file_store_failed_tx_store.js +36 -0
  44. package/dest/publisher/l1_tx_failed_store/index.d.ts +4 -0
  45. package/dest/publisher/l1_tx_failed_store/index.d.ts.map +1 -0
  46. package/dest/publisher/l1_tx_failed_store/index.js +3 -0
  47. package/dest/publisher/sequencer-bundle-simulator.d.ts +96 -0
  48. package/dest/publisher/sequencer-bundle-simulator.d.ts.map +1 -0
  49. package/dest/publisher/sequencer-bundle-simulator.js +198 -0
  50. package/dest/publisher/sequencer-publisher-factory.d.ts +50 -0
  51. package/dest/publisher/sequencer-publisher-factory.d.ts.map +1 -0
  52. package/dest/publisher/sequencer-publisher-factory.js +75 -0
  53. package/dest/publisher/sequencer-publisher-metrics.d.ts +26 -0
  54. package/dest/publisher/sequencer-publisher-metrics.d.ts.map +1 -0
  55. package/dest/publisher/sequencer-publisher-metrics.js +101 -0
  56. package/dest/publisher/sequencer-publisher.d.ts +254 -0
  57. package/dest/publisher/sequencer-publisher.d.ts.map +1 -0
  58. package/dest/publisher/sequencer-publisher.js +1784 -0
  59. package/dest/publisher/write_json.d.ts +11 -0
  60. package/dest/publisher/write_json.d.ts.map +1 -0
  61. package/dest/publisher/write_json.js +57 -0
  62. package/dest/sequencer/automine/automine_factory.d.ts +56 -0
  63. package/dest/sequencer/automine/automine_factory.d.ts.map +1 -0
  64. package/dest/sequencer/automine/automine_factory.js +85 -0
  65. package/dest/sequencer/automine/automine_sequencer.d.ts +189 -0
  66. package/dest/sequencer/automine/automine_sequencer.d.ts.map +1 -0
  67. package/dest/sequencer/automine/automine_sequencer.js +732 -0
  68. package/dest/sequencer/automine/index.d.ts +3 -0
  69. package/dest/sequencer/automine/index.d.ts.map +1 -0
  70. package/dest/sequencer/automine/index.js +2 -0
  71. package/dest/sequencer/checkpoint_proposal_job.d.ts +169 -0
  72. package/dest/sequencer/checkpoint_proposal_job.d.ts.map +1 -0
  73. package/dest/sequencer/checkpoint_proposal_job.js +1961 -0
  74. package/dest/sequencer/checkpoint_proposal_job_metrics.d.ts +34 -0
  75. package/dest/sequencer/checkpoint_proposal_job_metrics.d.ts.map +1 -0
  76. package/dest/sequencer/checkpoint_proposal_job_metrics.js +72 -0
  77. package/dest/sequencer/checkpoint_voter.d.ts +34 -0
  78. package/dest/sequencer/checkpoint_voter.d.ts.map +1 -0
  79. package/dest/sequencer/checkpoint_voter.js +106 -0
  80. package/dest/sequencer/config.d.ts +8 -0
  81. package/dest/sequencer/config.d.ts.map +1 -0
  82. package/dest/sequencer/config.js +1 -0
  83. package/dest/sequencer/errors.d.ts +11 -0
  84. package/dest/sequencer/errors.d.ts.map +1 -0
  85. package/dest/sequencer/errors.js +15 -0
  86. package/dest/sequencer/events.d.ts +103 -0
  87. package/dest/sequencer/events.d.ts.map +1 -0
  88. package/dest/sequencer/events.js +1 -0
  89. package/dest/sequencer/inbox_bucket_selector.d.ts +88 -0
  90. package/dest/sequencer/inbox_bucket_selector.d.ts.map +1 -0
  91. package/dest/sequencer/inbox_bucket_selector.js +80 -0
  92. package/dest/sequencer/index.d.ts +6 -0
  93. package/dest/sequencer/index.d.ts.map +1 -0
  94. package/dest/sequencer/index.js +5 -0
  95. package/dest/sequencer/metrics.d.ts +75 -0
  96. package/dest/sequencer/metrics.d.ts.map +1 -0
  97. package/dest/sequencer/metrics.js +343 -0
  98. package/dest/sequencer/missing_committee.d.ts +72 -0
  99. package/dest/sequencer/missing_committee.d.ts.map +1 -0
  100. package/dest/sequencer/missing_committee.js +139 -0
  101. package/dest/sequencer/requests_tracker.d.ts +22 -0
  102. package/dest/sequencer/requests_tracker.d.ts.map +1 -0
  103. package/dest/sequencer/requests_tracker.js +33 -0
  104. package/dest/sequencer/sequencer.d.ts +326 -0
  105. package/dest/sequencer/sequencer.d.ts.map +1 -0
  106. package/dest/sequencer/sequencer.js +1495 -0
  107. package/dest/sequencer/types.d.ts +3 -0
  108. package/dest/sequencer/types.d.ts.map +1 -0
  109. package/dest/sequencer/types.js +1 -0
  110. package/dest/sequencer/utils.d.ts +30 -0
  111. package/dest/sequencer/utils.d.ts.map +1 -0
  112. package/dest/sequencer/utils.js +18 -0
  113. package/dest/test/index.d.ts +23 -0
  114. package/dest/test/index.d.ts.map +1 -0
  115. package/dest/test/index.js +6 -0
  116. package/dest/test/mock_checkpoint_builder.d.ts +95 -0
  117. package/dest/test/mock_checkpoint_builder.d.ts.map +1 -0
  118. package/dest/test/mock_checkpoint_builder.js +230 -0
  119. package/dest/test/utils.d.ts +67 -0
  120. package/dest/test/utils.d.ts.map +1 -0
  121. package/dest/test/utils.js +121 -0
  122. package/package.json +118 -0
  123. package/src/client/index.ts +1 -0
  124. package/src/client/sequencer-client.ts +281 -0
  125. package/src/config.ts +309 -0
  126. package/src/global_variable_builder/README.md +44 -0
  127. package/src/global_variable_builder/fee_predictor.ts +176 -0
  128. package/src/global_variable_builder/fee_provider.ts +104 -0
  129. package/src/global_variable_builder/global_builder.ts +68 -0
  130. package/src/global_variable_builder/index.ts +3 -0
  131. package/src/index.ts +15 -0
  132. package/src/publisher/config.ts +220 -0
  133. package/src/publisher/index.ts +8 -0
  134. package/src/publisher/l1_to_l2_messaging.ts +85 -0
  135. package/src/publisher/l1_tx_failed_store/factory.ts +32 -0
  136. package/src/publisher/l1_tx_failed_store/failed_tx_store.ts +166 -0
  137. package/src/publisher/l1_tx_failed_store/file_store_failed_tx_store.ts +47 -0
  138. package/src/publisher/l1_tx_failed_store/index.ts +3 -0
  139. package/src/publisher/sequencer-bundle-simulator.ts +253 -0
  140. package/src/publisher/sequencer-publisher-factory.ts +121 -0
  141. package/src/publisher/sequencer-publisher-metrics.ts +145 -0
  142. package/src/publisher/sequencer-publisher.ts +1719 -0
  143. package/src/publisher/write_json.ts +77 -0
  144. package/src/sequencer/README.md +243 -0
  145. package/src/sequencer/automine/README.md +60 -0
  146. package/src/sequencer/automine/automine_factory.ts +156 -0
  147. package/src/sequencer/automine/automine_sequencer.ts +841 -0
  148. package/src/sequencer/automine/index.ts +6 -0
  149. package/src/sequencer/checkpoint_proposal_job.ts +1889 -0
  150. package/src/sequencer/checkpoint_proposal_job_metrics.ts +128 -0
  151. package/src/sequencer/checkpoint_voter.ts +118 -0
  152. package/src/sequencer/config.ts +9 -0
  153. package/src/sequencer/errors.ts +21 -0
  154. package/src/sequencer/events.ts +93 -0
  155. package/src/sequencer/inbox_bucket_selector.ts +160 -0
  156. package/src/sequencer/index.ts +5 -0
  157. package/src/sequencer/metrics.ts +463 -0
  158. package/src/sequencer/missing_committee.ts +192 -0
  159. package/src/sequencer/requests_tracker.ts +43 -0
  160. package/src/sequencer/sequencer.ts +1401 -0
  161. package/src/sequencer/types.ts +6 -0
  162. package/src/sequencer/utils.ts +42 -0
  163. package/src/test/index.ts +26 -0
  164. package/src/test/mock_checkpoint_builder.ts +324 -0
  165. package/src/test/utils.ts +215 -0
@@ -0,0 +1,34 @@
1
+ import { type TelemetryClient } from '@aztec-labs/telemetry-client';
2
+ /**
3
+ * Per-job recording surface used by {@link CheckpointProposalJob}.
4
+ *
5
+ * Ownership split:
6
+ * - {@link CheckpointProposalJobMetrics} owns the OpenTelemetry meter and instruments and should live for the
7
+ * lifetime of the sequencer process.
8
+ * - A recorder owns only mutable timing state for one checkpoint proposal job so overlapping jobs cannot
9
+ * overwrite each other's timing markers.
10
+ */
11
+ export interface CheckpointProposalJobMetricsRecorder {
12
+ recordCheckpointAttestationDelay(durationMs: number): void;
13
+ recordCheckpointBuild(durationMs: number, blockCount: number, txCount: number, totalMana: number): void;
14
+ recordPipelinedCheckpointBuildStartOffsetFromSlotBoundary(offsetMs: number): void;
15
+ startCheckpointTiming(nowMs: number): void;
16
+ noteCheckpointBlockBuilt(nowMs: number, opts: {
17
+ isFirstBlock: boolean;
18
+ isLastBlock: boolean;
19
+ }): void;
20
+ noteCheckpointBroadcast(nowMs: number): void;
21
+ }
22
+ /**
23
+ * Long-lived owner of checkpoint proposal job telemetry instruments.
24
+ *
25
+ * The sequencer should construct this once and reuse it across jobs. Each call to {@link createRecorder} returns a
26
+ * lightweight recorder with isolated mutable state for a single checkpoint proposal job.
27
+ */
28
+ export declare class CheckpointProposalJobMetrics {
29
+ private readonly meter;
30
+ private readonly instruments;
31
+ constructor(client: TelemetryClient, name?: string);
32
+ createRecorder(): CheckpointProposalJobMetricsRecorder;
33
+ }
34
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2hlY2twb2ludF9wcm9wb3NhbF9qb2JfbWV0cmljcy5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3NlcXVlbmNlci9jaGVja3BvaW50X3Byb3Bvc2FsX2pvYl9tZXRyaWNzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFNTCxLQUFLLGVBQWUsRUFDckIsTUFBTSw4QkFBOEIsQ0FBQztBQWF0Qzs7Ozs7Ozs7R0FRRztBQUNILE1BQU0sV0FBVyxvQ0FBb0M7SUFDbkQsZ0NBQWdDLENBQUMsVUFBVSxFQUFFLE1BQU0sR0FBRyxJQUFJLENBQUM7SUFDM0QscUJBQXFCLENBQUMsVUFBVSxFQUFFLE1BQU0sRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFLE9BQU8sRUFBRSxNQUFNLEVBQUUsU0FBUyxFQUFFLE1BQU0sR0FBRyxJQUFJLENBQUM7SUFDeEcseURBQXlELENBQUMsUUFBUSxFQUFFLE1BQU0sR0FBRyxJQUFJLENBQUM7SUFDbEYscUJBQXFCLENBQUMsS0FBSyxFQUFFLE1BQU0sR0FBRyxJQUFJLENBQUM7SUFDM0Msd0JBQXdCLENBQUMsS0FBSyxFQUFFLE1BQU0sRUFBRSxJQUFJLEVBQUU7UUFBRSxZQUFZLEVBQUUsT0FBTyxDQUFDO1FBQUMsV0FBVyxFQUFFLE9BQU8sQ0FBQTtLQUFFLEdBQUcsSUFBSSxDQUFDO0lBQ3JHLHVCQUF1QixDQUFDLEtBQUssRUFBRSxNQUFNLEdBQUcsSUFBSSxDQUFDO0NBQzlDO0FBMEREOzs7OztHQUtHO0FBQ0gscUJBQWEsNEJBQTRCO0lBQ3ZDLE9BQU8sQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFRO0lBQzlCLE9BQU8sQ0FBQyxRQUFRLENBQUMsV0FBVyxDQUFtQztJQUUvRCxZQUFZLE1BQU0sRUFBRSxlQUFlLEVBQUUsSUFBSSxTQUEwQixFQWtCbEU7SUFFTSxjQUFjLElBQUksb0NBQW9DLENBRTVEO0NBQ0YifQ==
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checkpoint_proposal_job_metrics.d.ts","sourceRoot":"","sources":["../../src/sequencer/checkpoint_proposal_job_metrics.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,eAAe,EACrB,MAAM,8BAA8B,CAAC;AAatC;;;;;;;;GAQG;AACH,MAAM,WAAW,oCAAoC;IACnD,gCAAgC,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3D,qBAAqB,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACxG,yDAAyD,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IAClF,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3C,wBAAwB,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE;QAAE,YAAY,EAAE,OAAO,CAAC;QAAC,WAAW,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC;IACrG,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9C;AA0DD;;;;;GAKG;AACH,qBAAa,4BAA4B;IACvC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAQ;IAC9B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAmC;IAE/D,YAAY,MAAM,EAAE,eAAe,EAAE,IAAI,SAA0B,EAkBlE;IAEM,cAAc,IAAI,oCAAoC,CAE5D;CACF"}
@@ -0,0 +1,72 @@
1
+ import { Attributes, Metrics } from '@aztec-labs/telemetry-client';
2
+ /**
3
+ * Concrete per-job recorder.
4
+ *
5
+ * This class should be short-lived: create one recorder per checkpoint proposal job and discard it when the job
6
+ * completes. It intentionally does not create instruments; it only holds the job-local timestamps needed to derive
7
+ * timing metrics safely.
8
+ */ class CheckpointProposalJobMetricsRecorderImpl {
9
+ instruments;
10
+ checkpointStartedAt;
11
+ checkpointLastBlockBuiltAt;
12
+ constructor(instruments){
13
+ this.instruments = instruments;
14
+ }
15
+ recordCheckpointAttestationDelay(durationMs) {
16
+ this.instruments.checkpointAttestationDelay.record(Math.ceil(durationMs));
17
+ }
18
+ recordCheckpointBuild(durationMs, blockCount, txCount, totalMana) {
19
+ this.instruments.checkpointBuildDuration.record(Math.ceil(durationMs));
20
+ this.instruments.checkpointBlockCount.record(blockCount);
21
+ this.instruments.checkpointTxCount.record(txCount);
22
+ this.instruments.checkpointTotalMana.record(totalMana);
23
+ }
24
+ recordPipelinedCheckpointBuildStartOffsetFromSlotBoundary(offsetMs) {
25
+ this.instruments.pipelinedCheckpointBuildStartOffsetFromSlotBoundary.record(Math.ceil(Math.abs(offsetMs)), {
26
+ [Attributes.SLOT_BOUNDARY_SIDE]: offsetMs < 0 ? 'before' : 'after'
27
+ });
28
+ }
29
+ startCheckpointTiming(nowMs) {
30
+ this.checkpointStartedAt = nowMs;
31
+ this.checkpointLastBlockBuiltAt = undefined;
32
+ }
33
+ noteCheckpointBlockBuilt(nowMs, opts) {
34
+ if (opts.isFirstBlock && this.checkpointStartedAt !== undefined) {
35
+ this.instruments.checkpointStartToFirstBlockDuration.record(Math.ceil(nowMs - this.checkpointStartedAt));
36
+ }
37
+ if (opts.isLastBlock) {
38
+ this.checkpointLastBlockBuiltAt = nowMs;
39
+ }
40
+ }
41
+ noteCheckpointBroadcast(nowMs) {
42
+ if (this.checkpointLastBlockBuiltAt !== undefined) {
43
+ this.instruments.checkpointLastBlockToBroadcastDuration.record(Math.ceil(nowMs - this.checkpointLastBlockBuiltAt));
44
+ }
45
+ this.checkpointLastBlockBuiltAt = undefined;
46
+ }
47
+ }
48
+ /**
49
+ * Long-lived owner of checkpoint proposal job telemetry instruments.
50
+ *
51
+ * The sequencer should construct this once and reuse it across jobs. Each call to {@link createRecorder} returns a
52
+ * lightweight recorder with isolated mutable state for a single checkpoint proposal job.
53
+ */ export class CheckpointProposalJobMetrics {
54
+ meter;
55
+ instruments;
56
+ constructor(client, name = 'CheckpointProposalJob'){
57
+ this.meter = client.getMeter(name);
58
+ this.instruments = {
59
+ checkpointAttestationDelay: this.meter.createHistogram(Metrics.SEQUENCER_CHECKPOINT_ATTESTATION_DELAY),
60
+ checkpointBuildDuration: this.meter.createHistogram(Metrics.SEQUENCER_CHECKPOINT_BUILD_DURATION),
61
+ checkpointStartToFirstBlockDuration: this.meter.createHistogram(Metrics.SEQUENCER_CHECKPOINT_START_TO_FIRST_BLOCK_DURATION),
62
+ checkpointLastBlockToBroadcastDuration: this.meter.createHistogram(Metrics.SEQUENCER_CHECKPOINT_LAST_BLOCK_TO_BROADCAST_DURATION),
63
+ pipelinedCheckpointBuildStartOffsetFromSlotBoundary: this.meter.createHistogram(Metrics.SEQUENCER_PIPELINED_CHECKPOINT_BUILD_START_OFFSET_FROM_SLOT_BOUNDARY),
64
+ checkpointBlockCount: this.meter.createGauge(Metrics.SEQUENCER_CHECKPOINT_BLOCK_COUNT),
65
+ checkpointTxCount: this.meter.createGauge(Metrics.SEQUENCER_CHECKPOINT_TX_COUNT),
66
+ checkpointTotalMana: this.meter.createGauge(Metrics.SEQUENCER_CHECKPOINT_TOTAL_MANA)
67
+ };
68
+ }
69
+ createRecorder() {
70
+ return new CheckpointProposalJobMetricsRecorderImpl(this.instruments);
71
+ }
72
+ }
@@ -0,0 +1,34 @@
1
+ import type { SlotNumber } from '@aztec-labs/foundation/branded-types';
2
+ import type { EthAddress } from '@aztec-labs/foundation/eth-address';
3
+ import type { Logger } from '@aztec-labs/foundation/log';
4
+ import type { SlasherClientInterface } from '@aztec-labs/slasher';
5
+ import type { ResolvedSequencerConfig } from '@aztec-labs/stdlib/interfaces/server';
6
+ import type { ValidatorClient } from '@aztec-labs/validator-client';
7
+ import type { SequencerPublisher } from '../publisher/sequencer-publisher.js';
8
+ import type { SequencerMetrics } from './metrics.js';
9
+ import type { SequencerRollupConstants } from './types.js';
10
+ /**
11
+ * Handles governance and slashing voting for a given slot.
12
+ */
13
+ export declare class CheckpointVoter {
14
+ private readonly slot;
15
+ private readonly publisher;
16
+ private readonly attestorAddress;
17
+ private readonly validatorClient;
18
+ private readonly slasherClient;
19
+ private readonly l1Constants;
20
+ private readonly config;
21
+ private readonly metrics;
22
+ private readonly log;
23
+ private governanceSigner;
24
+ private slashingSigner;
25
+ constructor(slot: SlotNumber, publisher: SequencerPublisher, attestorAddress: EthAddress, validatorClient: ValidatorClient, slasherClient: SlasherClientInterface | undefined, l1Constants: SequencerRollupConstants, config: ResolvedSequencerConfig, metrics: SequencerMetrics, log: Logger);
26
+ /**
27
+ * Enqueues governance and slashing votes with the publisher.
28
+ * Returns a tuple of promises that resolve to whether each vote was successfully enqueued.
29
+ */
30
+ enqueueVotes(): [Promise<boolean | undefined>, Promise<boolean | undefined>];
31
+ private enqueueGovernanceVote;
32
+ private enqueueSlashingVote;
33
+ }
34
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2hlY2twb2ludF92b3Rlci5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3NlcXVlbmNlci9jaGVja3BvaW50X3ZvdGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxFQUFFLFVBQVUsRUFBRSxNQUFNLHNDQUFzQyxDQUFDO0FBQ3ZFLE9BQU8sS0FBSyxFQUFFLFVBQVUsRUFBRSxNQUFNLG9DQUFvQyxDQUFDO0FBQ3JFLE9BQU8sS0FBSyxFQUFFLE1BQU0sRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBQ3pELE9BQU8sS0FBSyxFQUFFLHNCQUFzQixFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDbEUsT0FBTyxLQUFLLEVBQUUsdUJBQXVCLEVBQUUsTUFBTSxzQ0FBc0MsQ0FBQztBQUNwRixPQUFPLEtBQUssRUFBRSxlQUFlLEVBQUUsTUFBTSw4QkFBOEIsQ0FBQztBQUtwRSxPQUFPLEtBQUssRUFBRSxrQkFBa0IsRUFBRSxNQUFNLHFDQUFxQyxDQUFDO0FBQzlFLE9BQU8sS0FBSyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sY0FBYyxDQUFDO0FBQ3JELE9BQU8sS0FBSyxFQUFFLHdCQUF3QixFQUFFLE1BQU0sWUFBWSxDQUFDO0FBRTNEOztHQUVHO0FBQ0gscUJBQWEsZUFBZTtJQUt4QixPQUFPLENBQUMsUUFBUSxDQUFDLElBQUk7SUFDckIsT0FBTyxDQUFDLFFBQVEsQ0FBQyxTQUFTO0lBQzFCLE9BQU8sQ0FBQyxRQUFRLENBQUMsZUFBZTtJQUNoQyxPQUFPLENBQUMsUUFBUSxDQUFDLGVBQWU7SUFDaEMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxhQUFhO0lBQzlCLE9BQU8sQ0FBQyxRQUFRLENBQUMsV0FBVztJQUM1QixPQUFPLENBQUMsUUFBUSxDQUFDLE1BQU07SUFDdkIsT0FBTyxDQUFDLFFBQVEsQ0FBQyxPQUFPO0lBQ3hCLE9BQU8sQ0FBQyxRQUFRLENBQUMsR0FBRztJQVp0QixPQUFPLENBQUMsZ0JBQWdCLENBQXVEO0lBQy9FLE9BQU8sQ0FBQyxjQUFjLENBQXVEO0lBRTdFLFlBQ21CLElBQUksRUFBRSxVQUFVLEVBQ2hCLFNBQVMsRUFBRSxrQkFBa0IsRUFDN0IsZUFBZSxFQUFFLFVBQVUsRUFDM0IsZUFBZSxFQUFFLGVBQWUsRUFDaEMsYUFBYSxFQUFFLHNCQUFzQixHQUFHLFNBQVMsRUFDakQsV0FBVyxFQUFFLHdCQUF3QixFQUNyQyxNQUFNLEVBQUUsdUJBQXVCLEVBQy9CLE9BQU8sRUFBRSxnQkFBZ0IsRUFDekIsR0FBRyxFQUFFLE1BQU0sRUFXN0I7SUFFRDs7O09BR0c7SUFDSCxZQUFZLElBQUksQ0FBQyxPQUFPLENBQUMsT0FBTyxHQUFHLFNBQVMsQ0FBQyxFQUFFLE9BQU8sQ0FBQyxPQUFPLEdBQUcsU0FBUyxDQUFDLENBQUMsQ0FVM0U7WUFFYSxxQkFBcUI7WUErQnJCLG1CQUFtQjtDQTJCbEMifQ==
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checkpoint_voter.d.ts","sourceRoot":"","sources":["../../src/sequencer/checkpoint_voter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sCAAsC,CAAC;AACvE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oCAAoC,CAAC;AACrE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AACzD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAClE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,sCAAsC,CAAC;AACpF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAKpE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AAC9E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAE3D;;GAEG;AACH,qBAAa,eAAe;IAKxB,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,eAAe;IAChC,OAAO,CAAC,QAAQ,CAAC,eAAe;IAChC,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,GAAG;IAZtB,OAAO,CAAC,gBAAgB,CAAuD;IAC/E,OAAO,CAAC,cAAc,CAAuD;IAE7E,YACmB,IAAI,EAAE,UAAU,EAChB,SAAS,EAAE,kBAAkB,EAC7B,eAAe,EAAE,UAAU,EAC3B,eAAe,EAAE,eAAe,EAChC,aAAa,EAAE,sBAAsB,GAAG,SAAS,EACjD,WAAW,EAAE,wBAAwB,EACrC,MAAM,EAAE,uBAAuB,EAC/B,OAAO,EAAE,gBAAgB,EACzB,GAAG,EAAE,MAAM,EAW7B;IAED;;;OAGG;IACH,YAAY,IAAI,CAAC,OAAO,CAAC,OAAO,GAAG,SAAS,CAAC,EAAE,OAAO,CAAC,OAAO,GAAG,SAAS,CAAC,CAAC,CAU3E;YAEa,qBAAqB;YA+BrB,mBAAmB;CA2BlC"}
@@ -0,0 +1,106 @@
1
+ import { DutyAlreadySignedError } from '@aztec-labs/validator-ha-signer/errors';
2
+ import { DutyType } from '@aztec-labs/validator-ha-signer/types';
3
+ /**
4
+ * Handles governance and slashing voting for a given slot.
5
+ */ export class CheckpointVoter {
6
+ slot;
7
+ publisher;
8
+ attestorAddress;
9
+ validatorClient;
10
+ slasherClient;
11
+ l1Constants;
12
+ config;
13
+ metrics;
14
+ log;
15
+ governanceSigner;
16
+ slashingSigner;
17
+ constructor(slot, publisher, attestorAddress, validatorClient, slasherClient, l1Constants, config, metrics, log){
18
+ this.slot = slot;
19
+ this.publisher = publisher;
20
+ this.attestorAddress = attestorAddress;
21
+ this.validatorClient = validatorClient;
22
+ this.slasherClient = slasherClient;
23
+ this.l1Constants = l1Constants;
24
+ this.config = config;
25
+ this.metrics = metrics;
26
+ this.log = log;
27
+ // Create separate signers with appropriate duty contexts for governance and slashing votes
28
+ // These use HA protection to ensure only one node signs per slot/duty
29
+ const governanceContext = {
30
+ slot: this.slot,
31
+ dutyType: DutyType.GOVERNANCE_VOTE
32
+ };
33
+ this.governanceSigner = (msg)=>this.validatorClient.signWithAddress(this.attestorAddress, msg, governanceContext).then((s)=>s.toString());
34
+ const slashingContext = {
35
+ slot: this.slot,
36
+ dutyType: DutyType.SLASHING_VOTE
37
+ };
38
+ this.slashingSigner = (msg)=>this.validatorClient.signWithAddress(this.attestorAddress, msg, slashingContext).then((s)=>s.toString());
39
+ }
40
+ /**
41
+ * Enqueues governance and slashing votes with the publisher.
42
+ * Returns a tuple of promises that resolve to whether each vote was successfully enqueued.
43
+ */ enqueueVotes() {
44
+ try {
45
+ const enqueueGovernancePromise = this.enqueueGovernanceVote();
46
+ const enqueueSlashingPromise = this.enqueueSlashingVote();
47
+ return [
48
+ enqueueGovernancePromise,
49
+ enqueueSlashingPromise
50
+ ];
51
+ } catch (err) {
52
+ this.log.error(`Error enqueueing governance and slashing votes`, err);
53
+ return [
54
+ Promise.resolve(false),
55
+ Promise.resolve(false)
56
+ ];
57
+ }
58
+ }
59
+ async enqueueGovernanceVote() {
60
+ const governanceProposerPayload = this.config.governanceProposerPayload;
61
+ if (!governanceProposerPayload || governanceProposerPayload.isZero()) {
62
+ return undefined;
63
+ }
64
+ this.log.info(`Enqueuing vote for ${governanceProposerPayload} governance for slot ${this.slot}`, {
65
+ slot: this.slot,
66
+ governanceProposerPayload: governanceProposerPayload.toString()
67
+ });
68
+ try {
69
+ return await this.publisher.enqueueGovernanceCastSignal(governanceProposerPayload, this.slot, this.attestorAddress, this.governanceSigner);
70
+ } catch (err) {
71
+ if (err instanceof DutyAlreadySignedError) {
72
+ this.log.info(`Governance vote already signed by another node`, {
73
+ slot: this.slot,
74
+ signedByNode: err.signedByNode
75
+ });
76
+ } else {
77
+ this.log.error(`Error enqueueing governance vote`, err);
78
+ }
79
+ return false;
80
+ }
81
+ }
82
+ async enqueueSlashingVote() {
83
+ try {
84
+ const actions = await this.slasherClient?.getProposerActions(this.slot);
85
+ if (!actions || actions.length === 0) {
86
+ return undefined;
87
+ }
88
+ this.log.info(`Enqueuing vote for ${actions.length} slashing actions for slot ${this.slot}`, {
89
+ slot: this.slot,
90
+ actionCount: actions.length
91
+ });
92
+ this.metrics.recordSlashingAttempt(actions.length);
93
+ return await this.publisher.enqueueSlashingActions(actions, this.slot, this.attestorAddress, this.slashingSigner);
94
+ } catch (err) {
95
+ if (err instanceof DutyAlreadySignedError) {
96
+ this.log.info(`Slashing vote already signed by another node`, {
97
+ slot: this.slot,
98
+ signedByNode: err.signedByNode
99
+ });
100
+ } else {
101
+ this.log.error(`Error enqueueing slashing vote`, err);
102
+ }
103
+ return false;
104
+ }
105
+ }
106
+ }
@@ -0,0 +1,8 @@
1
+ import type { GovernanceProposerContract } from '@aztec-labs/ethereum/contracts';
2
+ import type { RollupContract } from '@aztec-labs/ethereum/contracts/rollup';
3
+ export { type SequencerConfig } from '@aztec-labs/stdlib/config';
4
+ export type SequencerContracts = {
5
+ rollupContract: RollupContract;
6
+ governanceProposerContract: GovernanceProposerContract;
7
+ };
8
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uZmlnLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc2VxdWVuY2VyL2NvbmZpZy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssRUFBRSwwQkFBMEIsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBQ2pGLE9BQU8sS0FBSyxFQUFFLGNBQWMsRUFBRSxNQUFNLHVDQUF1QyxDQUFDO0FBRTVFLE9BQU8sRUFBRSxLQUFLLGVBQWUsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBRWpFLE1BQU0sTUFBTSxrQkFBa0IsR0FBRztJQUMvQixjQUFjLEVBQUUsY0FBYyxDQUFDO0lBQy9CLDBCQUEwQixFQUFFLDBCQUEwQixDQUFDO0NBQ3hELENBQUMifQ==
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/sequencer/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,gCAAgC,CAAC;AACjF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAE5E,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAEjE,MAAM,MAAM,kBAAkB,GAAG;IAC/B,cAAc,EAAE,cAAc,CAAC;IAC/B,0BAA0B,EAAE,0BAA0B,CAAC;CACxD,CAAC"}
@@ -0,0 +1 @@
1
+ export { };
@@ -0,0 +1,11 @@
1
+ import type { SequencerState } from './utils.js';
2
+ export declare class SequencerTooSlowError extends Error {
3
+ readonly proposedState: SequencerState;
4
+ readonly maxAllowedTime: number;
5
+ readonly currentTime: number;
6
+ constructor(proposedState: SequencerState, maxAllowedTime: number, currentTime: number);
7
+ }
8
+ export declare class SequencerInterruptedError extends Error {
9
+ constructor();
10
+ }
11
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXJyb3JzLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc2VxdWVuY2VyL2Vycm9ycy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssRUFBRSxjQUFjLEVBQUUsTUFBTSxZQUFZLENBQUM7QUFFakQscUJBQWEscUJBQXNCLFNBQVEsS0FBSzthQUU1QixhQUFhLEVBQUUsY0FBYzthQUM3QixjQUFjLEVBQUUsTUFBTTthQUN0QixXQUFXLEVBQUUsTUFBTTtJQUhyQyxZQUNrQixhQUFhLEVBQUUsY0FBYyxFQUM3QixjQUFjLEVBQUUsTUFBTSxFQUN0QixXQUFXLEVBQUUsTUFBTSxFQU1wQztDQUNGO0FBRUQscUJBQWEseUJBQTBCLFNBQVEsS0FBSztJQUNsRCxjQUdDO0NBQ0YifQ==
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/sequencer/errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,qBAAa,qBAAsB,SAAQ,KAAK;aAE5B,aAAa,EAAE,cAAc;aAC7B,cAAc,EAAE,MAAM;aACtB,WAAW,EAAE,MAAM;IAHrC,YACkB,aAAa,EAAE,cAAc,EAC7B,cAAc,EAAE,MAAM,EACtB,WAAW,EAAE,MAAM,EAMpC;CACF;AAED,qBAAa,yBAA0B,SAAQ,KAAK;IAClD,cAGC;CACF"}
@@ -0,0 +1,15 @@
1
+ export class SequencerTooSlowError extends Error {
2
+ proposedState;
3
+ maxAllowedTime;
4
+ currentTime;
5
+ constructor(proposedState, maxAllowedTime, currentTime){
6
+ super(`Too far into slot for ${proposedState} (time into slot ${currentTime}s greater than ${maxAllowedTime}s allowance)`), this.proposedState = proposedState, this.maxAllowedTime = maxAllowedTime, this.currentTime = currentTime;
7
+ this.name = 'SequencerTooSlowError';
8
+ }
9
+ }
10
+ export class SequencerInterruptedError extends Error {
11
+ constructor(){
12
+ super(`Sequencer was interrupted`);
13
+ this.name = 'SequencerInterruptedError';
14
+ }
15
+ }
@@ -0,0 +1,103 @@
1
+ import type { BlockNumber, CheckpointNumber, IndexWithinCheckpoint, SlotNumber } from '@aztec-labs/foundation/branded-types';
2
+ import type { BlockHash } from '@aztec-labs/stdlib/block';
3
+ import type { Action } from '../publisher/sequencer-publisher.js';
4
+ import type { SequencerState } from './utils.js';
5
+ export type SequencerEvents = {
6
+ /**
7
+ * Emitted on every sequencer state transition (including no-op transitions to the same state). The
8
+ * timing fields are anchored to the build frame of the slot being proposed for, not to wall-clock
9
+ * slot boundaries, because the proposer builds for `targetSlot` during the previous (build) slot.
10
+ *
11
+ * - `oldState` / `newState` are the previous and new {@link SequencerState}.
12
+ * - `secondsIntoBuildFrame` is the wall-clock seconds elapsed since the build-frame start of
13
+ * `targetSlot` (`now − getBuildFrameStart(targetSlot)`). Undefined for lifecycle states with no
14
+ * associated slot (e.g. IDLE/STOPPING). It can be negative if the transition happens before the
15
+ * build frame opens.
16
+ * - `targetSlot` is the slot the checkpoint is being proposed for (the submission slot, one ahead of
17
+ * the wall-clock build slot under pipelining). Undefined for lifecycle states with no slot.
18
+ */
19
+ ['state-changed']: (args: {
20
+ oldState: SequencerState;
21
+ newState: SequencerState;
22
+ secondsIntoBuildFrame?: number;
23
+ targetSlot?: SlotNumber;
24
+ }) => void;
25
+ /**
26
+ * Emitted by the sequencer once it has decided it is going to attempt to build a
27
+ * checkpoint for `targetSlot`, after computing the L1 simulation overrides used by
28
+ * `canProposeAt`. Fired BEFORE the L1 simulation is run, so consumers can observe the
29
+ * decision regardless of whether the propose ultimately lands.
30
+ *
31
+ * - `hadProposedParent` indicates whether the build saw a proposed (pipelined) parent
32
+ * checkpoint that hasn't landed on L1 yet.
33
+ * - `provenOverride` is the assumed proven checkpoint number pinned for the L1
34
+ * simulation. The plan always pins both chain tips to short-circuit `canPruneAtTime`,
35
+ * so this is populated whenever a simulation plan was built — the value either
36
+ * matches the on-chain proven snapshot (defensive pin) or the assumed-proven
37
+ * checkpoint when building optimistically across a pruning boundary.
38
+ * - `simulatedPending` is the pending checkpoint passed to L1 simulation. The plan
39
+ * always pins both chain tips to short-circuit `canPruneAtTime`, so this reflects
40
+ * either the pipelined/invalidated tip or the on-chain pending snapshot.
41
+ */
42
+ ['preparing-checkpoint']: (args: {
43
+ targetSlot: SlotNumber;
44
+ checkpointNumber: CheckpointNumber;
45
+ hadProposedParent: boolean;
46
+ provenOverride: CheckpointNumber | undefined;
47
+ simulatedPending: CheckpointNumber | undefined;
48
+ }) => void;
49
+ ['proposer-rollup-check-failed']: (args: {
50
+ reason: string;
51
+ slot: SlotNumber;
52
+ }) => void;
53
+ ['block-tx-count-check-failed']: (args: {
54
+ minTxs: number;
55
+ slot: SlotNumber;
56
+ }) => void;
57
+ ['block-build-failed']: (args: {
58
+ reason: string;
59
+ slot: SlotNumber;
60
+ }) => void;
61
+ ['block-proposed']: (args: {
62
+ blockNumber: BlockNumber;
63
+ blockHash: BlockHash;
64
+ checkpointNumber: CheckpointNumber;
65
+ indexWithinCheckpoint: IndexWithinCheckpoint;
66
+ slot: SlotNumber;
67
+ buildSlot: SlotNumber;
68
+ }) => void;
69
+ ['checkpoint-empty']: (args: {
70
+ slot: SlotNumber;
71
+ }) => void;
72
+ /**
73
+ * Emitted when the proposer's pre-broadcast `validateCheckpointHeader` simulation fails. This is a
74
+ * last-chance check before we gossip a checkpoint proposal: a failure here means the header
75
+ * would not be accepted by L1 (e.g. archive mismatch, stale chain tip, or some other state
76
+ * drift between when we built the checkpoint and when we are about to broadcast it).
77
+ */
78
+ ['header-validation-failed']: (args: {
79
+ slot: SlotNumber;
80
+ checkpointNumber: CheckpointNumber;
81
+ reason: string;
82
+ }) => void;
83
+ ['checkpoint-publish-failed']: (args: {
84
+ slot: SlotNumber;
85
+ successfulActions?: Action[];
86
+ failedActions?: Action[];
87
+ sentActions?: Action[];
88
+ expiredActions?: Action[];
89
+ }) => void;
90
+ ['checkpoint-published']: (args: {
91
+ checkpoint: CheckpointNumber;
92
+ slot: SlotNumber;
93
+ }) => void;
94
+ ['checkpoint-error']: (args: {
95
+ error: Error;
96
+ }) => void;
97
+ ['pipelined-checkpoint-discarded']: (args: {
98
+ slot: SlotNumber;
99
+ checkpointNumber: CheckpointNumber;
100
+ reason: string;
101
+ }) => void;
102
+ };
103
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXZlbnRzLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc2VxdWVuY2VyL2V2ZW50cy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssRUFDVixXQUFXLEVBQ1gsZ0JBQWdCLEVBQ2hCLHFCQUFxQixFQUNyQixVQUFVLEVBQ1gsTUFBTSxzQ0FBc0MsQ0FBQztBQUM5QyxPQUFPLEtBQUssRUFBRSxTQUFTLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUUxRCxPQUFPLEtBQUssRUFBRSxNQUFNLEVBQUUsTUFBTSxxQ0FBcUMsQ0FBQztBQUNsRSxPQUFPLEtBQUssRUFBRSxjQUFjLEVBQUUsTUFBTSxZQUFZLENBQUM7QUFFakQsTUFBTSxNQUFNLGVBQWUsR0FBRztJQUM1Qjs7Ozs7Ozs7Ozs7O09BWUc7SUFDSCxDQUFDLGVBQWUsQ0FBQyxFQUFFLENBQUMsSUFBSSxFQUFFO1FBQ3hCLFFBQVEsRUFBRSxjQUFjLENBQUM7UUFDekIsUUFBUSxFQUFFLGNBQWMsQ0FBQztRQUN6QixxQkFBcUIsQ0FBQyxFQUFFLE1BQU0sQ0FBQztRQUMvQixVQUFVLENBQUMsRUFBRSxVQUFVLENBQUM7S0FDekIsS0FBSyxJQUFJLENBQUM7SUFDWDs7Ozs7Ozs7Ozs7Ozs7OztPQWdCRztJQUNILENBQUMsc0JBQXNCLENBQUMsRUFBRSxDQUFDLElBQUksRUFBRTtRQUMvQixVQUFVLEVBQUUsVUFBVSxDQUFDO1FBQ3ZCLGdCQUFnQixFQUFFLGdCQUFnQixDQUFDO1FBQ25DLGlCQUFpQixFQUFFLE9BQU8sQ0FBQztRQUMzQixjQUFjLEVBQUUsZ0JBQWdCLEdBQUcsU0FBUyxDQUFDO1FBQzdDLGdCQUFnQixFQUFFLGdCQUFnQixHQUFHLFNBQVMsQ0FBQztLQUNoRCxLQUFLLElBQUksQ0FBQztJQUNYLENBQUMsOEJBQThCLENBQUMsRUFBRSxDQUFDLElBQUksRUFBRTtRQUFFLE1BQU0sRUFBRSxNQUFNLENBQUM7UUFBQyxJQUFJLEVBQUUsVUFBVSxDQUFBO0tBQUUsS0FBSyxJQUFJLENBQUM7SUFDdkYsQ0FBQyw2QkFBNkIsQ0FBQyxFQUFFLENBQUMsSUFBSSxFQUFFO1FBQUUsTUFBTSxFQUFFLE1BQU0sQ0FBQztRQUFDLElBQUksRUFBRSxVQUFVLENBQUE7S0FBRSxLQUFLLElBQUksQ0FBQztJQUN0RixDQUFDLG9CQUFvQixDQUFDLEVBQUUsQ0FBQyxJQUFJLEVBQUU7UUFBRSxNQUFNLEVBQUUsTUFBTSxDQUFDO1FBQUMsSUFBSSxFQUFFLFVBQVUsQ0FBQTtLQUFFLEtBQUssSUFBSSxDQUFDO0lBQzdFLENBQUMsZ0JBQWdCLENBQUMsRUFBRSxDQUFDLElBQUksRUFBRTtRQUN6QixXQUFXLEVBQUUsV0FBVyxDQUFDO1FBQ3pCLFNBQVMsRUFBRSxTQUFTLENBQUM7UUFDckIsZ0JBQWdCLEVBQUUsZ0JBQWdCLENBQUM7UUFDbkMscUJBQXFCLEVBQUUscUJBQXFCLENBQUM7UUFDN0MsSUFBSSxFQUFFLFVBQVUsQ0FBQztRQUNqQixTQUFTLEVBQUUsVUFBVSxDQUFDO0tBQ3ZCLEtBQUssSUFBSSxDQUFDO0lBQ1gsQ0FBQyxrQkFBa0IsQ0FBQyxFQUFFLENBQUMsSUFBSSxFQUFFO1FBQUUsSUFBSSxFQUFFLFVBQVUsQ0FBQTtLQUFFLEtBQUssSUFBSSxDQUFDO0lBQzNEOzs7OztPQUtHO0lBQ0gsQ0FBQywwQkFBMEIsQ0FBQyxFQUFFLENBQUMsSUFBSSxFQUFFO1FBQ25DLElBQUksRUFBRSxVQUFVLENBQUM7UUFDakIsZ0JBQWdCLEVBQUUsZ0JBQWdCLENBQUM7UUFDbkMsTUFBTSxFQUFFLE1BQU0sQ0FBQztLQUNoQixLQUFLLElBQUksQ0FBQztJQUNYLENBQUMsMkJBQTJCLENBQUMsRUFBRSxDQUFDLElBQUksRUFBRTtRQUNwQyxJQUFJLEVBQUUsVUFBVSxDQUFDO1FBQ2pCLGlCQUFpQixDQUFDLEVBQUUsTUFBTSxFQUFFLENBQUM7UUFDN0IsYUFBYSxDQUFDLEVBQUUsTUFBTSxFQUFFLENBQUM7UUFDekIsV0FBVyxDQUFDLEVBQUUsTUFBTSxFQUFFLENBQUM7UUFDdkIsY0FBYyxDQUFDLEVBQUUsTUFBTSxFQUFFLENBQUM7S0FDM0IsS0FBSyxJQUFJLENBQUM7SUFDWCxDQUFDLHNCQUFzQixDQUFDLEVBQUUsQ0FBQyxJQUFJLEVBQUU7UUFBRSxVQUFVLEVBQUUsZ0JBQWdCLENBQUM7UUFBQyxJQUFJLEVBQUUsVUFBVSxDQUFBO0tBQUUsS0FBSyxJQUFJLENBQUM7SUFDN0YsQ0FBQyxrQkFBa0IsQ0FBQyxFQUFFLENBQUMsSUFBSSxFQUFFO1FBQUUsS0FBSyxFQUFFLEtBQUssQ0FBQTtLQUFFLEtBQUssSUFBSSxDQUFDO0lBQ3ZELENBQUMsZ0NBQWdDLENBQUMsRUFBRSxDQUFDLElBQUksRUFBRTtRQUN6QyxJQUFJLEVBQUUsVUFBVSxDQUFDO1FBQ2pCLGdCQUFnQixFQUFFLGdCQUFnQixDQUFDO1FBQ25DLE1BQU0sRUFBRSxNQUFNLENBQUM7S0FDaEIsS0FBSyxJQUFJLENBQUM7Q0FDWixDQUFDIn0=
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../src/sequencer/events.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,WAAW,EACX,gBAAgB,EAChB,qBAAqB,EACrB,UAAU,EACX,MAAM,sCAAsC,CAAC;AAC9C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAE1D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qCAAqC,CAAC;AAClE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,MAAM,MAAM,eAAe,GAAG;IAC5B;;;;;;;;;;;;OAYG;IACH,CAAC,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE;QACxB,QAAQ,EAAE,cAAc,CAAC;QACzB,QAAQ,EAAE,cAAc,CAAC;QACzB,qBAAqB,CAAC,EAAE,MAAM,CAAC;QAC/B,UAAU,CAAC,EAAE,UAAU,CAAC;KACzB,KAAK,IAAI,CAAC;IACX;;;;;;;;;;;;;;;;OAgBG;IACH,CAAC,sBAAsB,CAAC,EAAE,CAAC,IAAI,EAAE;QAC/B,UAAU,EAAE,UAAU,CAAC;QACvB,gBAAgB,EAAE,gBAAgB,CAAC;QACnC,iBAAiB,EAAE,OAAO,CAAC;QAC3B,cAAc,EAAE,gBAAgB,GAAG,SAAS,CAAC;QAC7C,gBAAgB,EAAE,gBAAgB,GAAG,SAAS,CAAC;KAChD,KAAK,IAAI,CAAC;IACX,CAAC,8BAA8B,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,UAAU,CAAA;KAAE,KAAK,IAAI,CAAC;IACvF,CAAC,6BAA6B,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,UAAU,CAAA;KAAE,KAAK,IAAI,CAAC;IACtF,CAAC,oBAAoB,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,UAAU,CAAA;KAAE,KAAK,IAAI,CAAC;IAC7E,CAAC,gBAAgB,CAAC,EAAE,CAAC,IAAI,EAAE;QACzB,WAAW,EAAE,WAAW,CAAC;QACzB,SAAS,EAAE,SAAS,CAAC;QACrB,gBAAgB,EAAE,gBAAgB,CAAC;QACnC,qBAAqB,EAAE,qBAAqB,CAAC;QAC7C,IAAI,EAAE,UAAU,CAAC;QACjB,SAAS,EAAE,UAAU,CAAC;KACvB,KAAK,IAAI,CAAC;IACX,CAAC,kBAAkB,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,UAAU,CAAA;KAAE,KAAK,IAAI,CAAC;IAC3D;;;;;OAKG;IACH,CAAC,0BAA0B,CAAC,EAAE,CAAC,IAAI,EAAE;QACnC,IAAI,EAAE,UAAU,CAAC;QACjB,gBAAgB,EAAE,gBAAgB,CAAC;QACnC,MAAM,EAAE,MAAM,CAAC;KAChB,KAAK,IAAI,CAAC;IACX,CAAC,2BAA2B,CAAC,EAAE,CAAC,IAAI,EAAE;QACpC,IAAI,EAAE,UAAU,CAAC;QACjB,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;QAC7B,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;QACzB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;QACvB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;KAC3B,KAAK,IAAI,CAAC;IACX,CAAC,sBAAsB,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,UAAU,EAAE,gBAAgB,CAAC;QAAC,IAAI,EAAE,UAAU,CAAA;KAAE,KAAK,IAAI,CAAC;IAC7F,CAAC,kBAAkB,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,KAAK,CAAA;KAAE,KAAK,IAAI,CAAC;IACvD,CAAC,gCAAgC,CAAC,EAAE,CAAC,IAAI,EAAE;QACzC,IAAI,EAAE,UAAU,CAAC;QACjB,gBAAgB,EAAE,gBAAgB,CAAC;QACnC,MAAM,EAAE,MAAM,CAAC;KAChB,KAAK,IAAI,CAAC;CACZ,CAAC"}
@@ -0,0 +1 @@
1
+ export { };
@@ -0,0 +1,88 @@
1
+ import type { Fr } from '@aztec-labs/foundation/curves/bn254';
2
+ import { type InboxBucket, type L1ToL2MessageSource } from '@aztec-labs/stdlib/messaging';
3
+ /** The subset of the archiver's Inbox-bucket queries the selector needs. */
4
+ export type InboxBucketSource = Pick<L1ToL2MessageSource, 'getInboxBucket' | 'getLatestInboxBucketAtOrBefore' | 'getL1ToL2MessagesBetweenBuckets'>;
5
+ /**
6
+ * The last-consumed Inbox bucket a block streams from. Only the sequence number and cumulative message count are
7
+ * needed: the sequence number bounds the derived bundle, and the count is the per-block/per-checkpoint cap origin.
8
+ * At a checkpoint's first block this is the parent checkpoint's last-consumed bucket; the genesis base case is
9
+ * `{ seq: 0, totalMsgCount: 0 }` (bundles derive from the start of the Inbox).
10
+ */
11
+ export type ConsumedBucketCursor = Pick<InboxBucket, 'seq' | 'totalMsgCount'>;
12
+ /** Inputs to a single block's streaming Inbox-bucket selection. */
13
+ export type SelectInboxBucketInput = {
14
+ /** Archiver Inbox-bucket queries. */
15
+ messageSource: InboxBucketSource;
16
+ /** Wall-clock time of this sub-slot, in seconds; the lag-eligibility anchor. */
17
+ now: bigint;
18
+ /**
19
+ * Minimum bucket age in seconds for a bucket to be lag-eligible this sub-slot: one configured Ethereum slot, the
20
+ * same value the validator's acceptance check applies (which documents why age in seconds is only a proxy for the
21
+ * L1 reorg depth this really guards against).
22
+ */
23
+ minBucketAgeSeconds: bigint;
24
+ /** The last bucket consumed by this checkpoint so far (parent checkpoint's at the first block). */
25
+ parent: ConsumedBucketCursor;
26
+ /** Cumulative Inbox message count consumed as of the parent checkpoint; the per-checkpoint cap origin. */
27
+ checkpointStartTotalMsgCount: bigint;
28
+ /** Maximum number of messages this block may consume. */
29
+ perBlockCap: number;
30
+ /** Maximum number of messages the checkpoint may consume in total. */
31
+ perCheckpointCap: number;
32
+ /** True on the checkpoint's final block, where the censorship cutoff becomes a consumption floor. */
33
+ isLastBlock: boolean;
34
+ /**
35
+ * Censorship cutoff timestamp from `getInboxCutoffTimestamp` (mirrors `ProposeLib.validateInboxConsumption`).
36
+ * Buckets opened at or before it are mandatory to consume by the checkpoint's last block.
37
+ */
38
+ cutoffTimestamp: bigint;
39
+ };
40
+ /** Whether and through which bucket a block consumes. */
41
+ type InboxBucketConsumption = {
42
+ /** The block consumes messages, advancing to `bucket`. */
43
+ consume: true;
44
+ /** The newest bucket this block consumes through. */
45
+ bucket: InboxBucket;
46
+ /** The message leaves consumed this block, in insertion order (may be empty for an empty bucket). */
47
+ bundle: Fr[];
48
+ } | {
49
+ /** The block consumes nothing; it reuses the parent bucket reference. */
50
+ consume: false;
51
+ };
52
+ /** Result of a block's streaming Inbox-bucket selection. */
53
+ export type InboxBucketSelection = InboxBucketConsumption & {
54
+ /**
55
+ * Set on the checkpoint's final block when the selected position still leaves a mandatory bucket unconsumed, so no
56
+ * checkpoint ending on this block can satisfy the censorship floor. The consumption fields still describe the best
57
+ * reachable prefix, but proposing it would produce a checkpoint every honest validator refuses to attest and that
58
+ * L1 `propose` would revert, so the caller is expected to abandon the checkpoint rather than build on it.
59
+ */
60
+ insufficientFinalBlockCapacity?: true;
61
+ };
62
+ /**
63
+ * Selects the newest Inbox bucket a block streams from, mirroring the L1 consumption predicate in
64
+ * `ProposeLib.validateInboxConsumption`. The policy, per block:
65
+ *
66
+ * 1. Pick the newest lag-eligible bucket: the newest bucket opened at or before `now - minBucketAgeSeconds`. On the
67
+ * checkpoint's last block, also consider the cutoff bucket (newest opened at or before `cutoffTimestamp`) and take
68
+ * whichever is newer, so the checkpoint reaches the censorship floor even if the sub-slot lag preferred less.
69
+ * 2. If nothing is newer than the parent bucket, consume nothing.
70
+ * 3. Otherwise walk back from the candidate to the newest bucket whose consumption fits both the per-block cap
71
+ * (`bucket.totalMsgCount - parent.totalMsgCount`) and the per-checkpoint cap
72
+ * (`bucket.totalMsgCount - checkpointStartTotalMsgCount`). If even the first bucket past the parent overshoots the
73
+ * per-checkpoint cap, consume nothing — the L1 cap-escape (`ProposeLib` allows leaving a bucket unconsumed when
74
+ * consuming through it would exceed the per-checkpoint cap).
75
+ * 4. On the last block only, check the resulting position against the censorship floor with the shared
76
+ * `isInboxConsumptionSufficient` predicate. Because buckets are indivisible, the walk-back in step 3 can be forced
77
+ * onto a prefix that still leaves a mandatory bucket behind; that is reported as
78
+ * `insufficientFinalBlockCapacity` rather than passed off as a usable selection.
79
+ *
80
+ * The `<=` comparisons make a bucket exactly `minBucketAgeSeconds` old lag-eligible and a bucket exactly at the cutoff
81
+ * mandatory, matching the strict `>` "past cutoff" test on L1 (`next.timestamp > cutoff` leaves it optional).
82
+ *
83
+ * A single bucket never exceeds the per-block cap by construction (the Inbox bucket size is at most the per-block cap),
84
+ * so per-block walk-back always lands on at least one bucket; only the per-checkpoint cap can force consuming nothing.
85
+ */
86
+ export declare function selectInboxBucketForBlock(input: SelectInboxBucketInput): Promise<InboxBucketSelection>;
87
+ export {};
88
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5ib3hfYnVja2V0X3NlbGVjdG9yLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc2VxdWVuY2VyL2luYm94X2J1Y2tldF9zZWxlY3Rvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssRUFBRSxFQUFFLEVBQUUsTUFBTSxxQ0FBcUMsQ0FBQztBQUM5RCxPQUFPLEVBQUUsS0FBSyxXQUFXLEVBQUUsS0FBSyxtQkFBbUIsRUFBZ0MsTUFBTSw4QkFBOEIsQ0FBQztBQUV4SCw0RUFBNEU7QUFDNUUsTUFBTSxNQUFNLGlCQUFpQixHQUFHLElBQUksQ0FDbEMsbUJBQW1CLEVBQ25CLGdCQUFnQixHQUFHLGdDQUFnQyxHQUFHLGlDQUFpQyxDQUN4RixDQUFDO0FBRUY7Ozs7O0dBS0c7QUFDSCxNQUFNLE1BQU0sb0JBQW9CLEdBQUcsSUFBSSxDQUFDLFdBQVcsRUFBRSxLQUFLLEdBQUcsZUFBZSxDQUFDLENBQUM7QUFFOUUsbUVBQW1FO0FBQ25FLE1BQU0sTUFBTSxzQkFBc0IsR0FBRztJQUNuQyxxQ0FBcUM7SUFDckMsYUFBYSxFQUFFLGlCQUFpQixDQUFDO0lBQ2pDLGdGQUFnRjtJQUNoRixHQUFHLEVBQUUsTUFBTSxDQUFDO0lBQ1o7Ozs7T0FJRztJQUNILG1CQUFtQixFQUFFLE1BQU0sQ0FBQztJQUM1QixtR0FBbUc7SUFDbkcsTUFBTSxFQUFFLG9CQUFvQixDQUFDO0lBQzdCLDBHQUEwRztJQUMxRyw0QkFBNEIsRUFBRSxNQUFNLENBQUM7SUFDckMseURBQXlEO0lBQ3pELFdBQVcsRUFBRSxNQUFNLENBQUM7SUFDcEIsc0VBQXNFO0lBQ3RFLGdCQUFnQixFQUFFLE1BQU0sQ0FBQztJQUN6QixxR0FBcUc7SUFDckcsV0FBVyxFQUFFLE9BQU8sQ0FBQztJQUNyQjs7O09BR0c7SUFDSCxlQUFlLEVBQUUsTUFBTSxDQUFDO0NBQ3pCLENBQUM7QUFFRix5REFBeUQ7QUFDekQsS0FBSyxzQkFBc0IsR0FDdkI7SUFDRSwwREFBMEQ7SUFDMUQsT0FBTyxFQUFFLElBQUksQ0FBQztJQUNkLHFEQUFxRDtJQUNyRCxNQUFNLEVBQUUsV0FBVyxDQUFDO0lBQ3BCLHFHQUFxRztJQUNyRyxNQUFNLEVBQUUsRUFBRSxFQUFFLENBQUM7Q0FDZCxHQUNEO0lBQ0UseUVBQXlFO0lBQ3pFLE9BQU8sRUFBRSxLQUFLLENBQUM7Q0FDaEIsQ0FBQztBQUVOLDREQUE0RDtBQUM1RCxNQUFNLE1BQU0sb0JBQW9CLEdBQUcsc0JBQXNCLEdBQUc7SUFDMUQ7Ozs7O09BS0c7SUFDSCw4QkFBOEIsQ0FBQyxFQUFFLElBQUksQ0FBQztDQUN2QyxDQUFDO0FBRUY7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBdUJHO0FBQ0gsd0JBQXNCLHlCQUF5QixDQUFDLEtBQUssRUFBRSxzQkFBc0IsR0FBRyxPQUFPLENBQUMsb0JBQW9CLENBQUMsQ0FnQjVHIn0=
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inbox_bucket_selector.d.ts","sourceRoot":"","sources":["../../src/sequencer/inbox_bucket_selector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,qCAAqC,CAAC;AAC9D,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,mBAAmB,EAAgC,MAAM,8BAA8B,CAAC;AAExH,4EAA4E;AAC5E,MAAM,MAAM,iBAAiB,GAAG,IAAI,CAClC,mBAAmB,EACnB,gBAAgB,GAAG,gCAAgC,GAAG,iCAAiC,CACxF,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,oBAAoB,GAAG,IAAI,CAAC,WAAW,EAAE,KAAK,GAAG,eAAe,CAAC,CAAC;AAE9E,mEAAmE;AACnE,MAAM,MAAM,sBAAsB,GAAG;IACnC,qCAAqC;IACrC,aAAa,EAAE,iBAAiB,CAAC;IACjC,gFAAgF;IAChF,GAAG,EAAE,MAAM,CAAC;IACZ;;;;OAIG;IACH,mBAAmB,EAAE,MAAM,CAAC;IAC5B,mGAAmG;IACnG,MAAM,EAAE,oBAAoB,CAAC;IAC7B,0GAA0G;IAC1G,4BAA4B,EAAE,MAAM,CAAC;IACrC,yDAAyD;IACzD,WAAW,EAAE,MAAM,CAAC;IACpB,sEAAsE;IACtE,gBAAgB,EAAE,MAAM,CAAC;IACzB,qGAAqG;IACrG,WAAW,EAAE,OAAO,CAAC;IACrB;;;OAGG;IACH,eAAe,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,yDAAyD;AACzD,KAAK,sBAAsB,GACvB;IACE,0DAA0D;IAC1D,OAAO,EAAE,IAAI,CAAC;IACd,qDAAqD;IACrD,MAAM,EAAE,WAAW,CAAC;IACpB,qGAAqG;IACrG,MAAM,EAAE,EAAE,EAAE,CAAC;CACd,GACD;IACE,yEAAyE;IACzE,OAAO,EAAE,KAAK,CAAC;CAChB,CAAC;AAEN,4DAA4D;AAC5D,MAAM,MAAM,oBAAoB,GAAG,sBAAsB,GAAG;IAC1D;;;;;OAKG;IACH,8BAA8B,CAAC,EAAE,IAAI,CAAC;CACvC,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAsB,yBAAyB,CAAC,KAAK,EAAE,sBAAsB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAgB5G"}
@@ -0,0 +1,80 @@
1
+ import { isInboxConsumptionSufficient } from '@aztec-labs/stdlib/messaging';
2
+ /**
3
+ * Selects the newest Inbox bucket a block streams from, mirroring the L1 consumption predicate in
4
+ * `ProposeLib.validateInboxConsumption`. The policy, per block:
5
+ *
6
+ * 1. Pick the newest lag-eligible bucket: the newest bucket opened at or before `now - minBucketAgeSeconds`. On the
7
+ * checkpoint's last block, also consider the cutoff bucket (newest opened at or before `cutoffTimestamp`) and take
8
+ * whichever is newer, so the checkpoint reaches the censorship floor even if the sub-slot lag preferred less.
9
+ * 2. If nothing is newer than the parent bucket, consume nothing.
10
+ * 3. Otherwise walk back from the candidate to the newest bucket whose consumption fits both the per-block cap
11
+ * (`bucket.totalMsgCount - parent.totalMsgCount`) and the per-checkpoint cap
12
+ * (`bucket.totalMsgCount - checkpointStartTotalMsgCount`). If even the first bucket past the parent overshoots the
13
+ * per-checkpoint cap, consume nothing — the L1 cap-escape (`ProposeLib` allows leaving a bucket unconsumed when
14
+ * consuming through it would exceed the per-checkpoint cap).
15
+ * 4. On the last block only, check the resulting position against the censorship floor with the shared
16
+ * `isInboxConsumptionSufficient` predicate. Because buckets are indivisible, the walk-back in step 3 can be forced
17
+ * onto a prefix that still leaves a mandatory bucket behind; that is reported as
18
+ * `insufficientFinalBlockCapacity` rather than passed off as a usable selection.
19
+ *
20
+ * The `<=` comparisons make a bucket exactly `minBucketAgeSeconds` old lag-eligible and a bucket exactly at the cutoff
21
+ * mandatory, matching the strict `>` "past cutoff" test on L1 (`next.timestamp > cutoff` leaves it optional).
22
+ *
23
+ * A single bucket never exceeds the per-block cap by construction (the Inbox bucket size is at most the per-block cap),
24
+ * so per-block walk-back always lands on at least one bucket; only the per-checkpoint cap can force consuming nothing.
25
+ */ export async function selectInboxBucketForBlock(input) {
26
+ const consumption = await selectConsumption(input);
27
+ if (!input.isLastBlock) {
28
+ return consumption;
29
+ }
30
+ const { messageSource, parent, checkpointStartTotalMsgCount, perCheckpointCap, cutoffTimestamp } = input;
31
+ const finalSeq = consumption.consume ? consumption.bucket.seq : parent.seq;
32
+ const nextBucket = await messageSource.getInboxBucket(finalSeq + 1n);
33
+ const sufficient = isInboxConsumptionSufficient({
34
+ nextBucket,
35
+ cutoffTimestamp,
36
+ checkpointStartTotalMsgCount,
37
+ perCheckpointCap
38
+ });
39
+ return sufficient ? consumption : {
40
+ ...consumption,
41
+ insufficientFinalBlockCapacity: true
42
+ };
43
+ }
44
+ /** Steps 1 to 3 of {@link selectInboxBucketForBlock}: the cap-bounded walk back from the newest eligible bucket. */ async function selectConsumption(input) {
45
+ const { messageSource, now, minBucketAgeSeconds, parent, checkpointStartTotalMsgCount, perBlockCap, perCheckpointCap, isLastBlock, cutoffTimestamp } = input;
46
+ let candidate = await messageSource.getLatestInboxBucketAtOrBefore(now - minBucketAgeSeconds);
47
+ if (isLastBlock) {
48
+ const cutoffBucket = await messageSource.getLatestInboxBucketAtOrBefore(cutoffTimestamp);
49
+ if (cutoffBucket !== undefined && (candidate === undefined || cutoffBucket.seq > candidate.seq)) {
50
+ candidate = cutoffBucket;
51
+ }
52
+ }
53
+ if (candidate === undefined || candidate.seq <= parent.seq) {
54
+ return {
55
+ consume: false
56
+ };
57
+ }
58
+ const perBlockCapBig = BigInt(perBlockCap);
59
+ const perCheckpointCapBig = BigInt(perCheckpointCap);
60
+ let selected = candidate;
61
+ while(selected !== undefined && selected.seq > parent.seq){
62
+ const blockCount = selected.totalMsgCount - parent.totalMsgCount;
63
+ const checkpointCount = selected.totalMsgCount - checkpointStartTotalMsgCount;
64
+ if (blockCount <= perBlockCapBig && checkpointCount <= perCheckpointCapBig) {
65
+ const bundle = await messageSource.getL1ToL2MessagesBetweenBuckets(parent.seq, selected.seq);
66
+ return {
67
+ consume: true,
68
+ bucket: selected,
69
+ bundle
70
+ };
71
+ }
72
+ if (selected.seq - 1n <= parent.seq) {
73
+ break;
74
+ }
75
+ selected = await messageSource.getInboxBucket(selected.seq - 1n);
76
+ }
77
+ return {
78
+ consume: false
79
+ };
80
+ }
@@ -0,0 +1,6 @@
1
+ export * from './checkpoint_proposal_job.js';
2
+ export * from './checkpoint_voter.js';
3
+ export * from './config.js';
4
+ export * from './events.js';
5
+ export * from './sequencer.js';
6
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9zZXF1ZW5jZXIvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsY0FBYyw4QkFBOEIsQ0FBQztBQUM3QyxjQUFjLHVCQUF1QixDQUFDO0FBQ3RDLGNBQWMsYUFBYSxDQUFDO0FBQzVCLGNBQWMsYUFBYSxDQUFDO0FBQzVCLGNBQWMsZ0JBQWdCLENBQUMifQ==
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sequencer/index.ts"],"names":[],"mappings":"AAAA,cAAc,8BAA8B,CAAC;AAC7C,cAAc,uBAAuB,CAAC;AACtC,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC"}
@@ -0,0 +1,5 @@
1
+ export * from './checkpoint_proposal_job.js';
2
+ export * from './checkpoint_voter.js';
3
+ export * from './config.js';
4
+ export * from './events.js';
5
+ export * from './sequencer.js';