@aztec/sequencer-client 0.0.0-test.1 → 0.0.1-commit.017a351

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 (185) hide show
  1. package/README.md +281 -21
  2. package/dest/client/index.d.ts +1 -1
  3. package/dest/client/sequencer-client.d.ts +43 -33
  4. package/dest/client/sequencer-client.d.ts.map +1 -1
  5. package/dest/client/sequencer-client.js +117 -62
  6. package/dest/config.d.ts +38 -17
  7. package/dest/config.d.ts.map +1 -1
  8. package/dest/config.js +172 -85
  9. package/dest/global_variable_builder/fee_predictor.d.ts +37 -0
  10. package/dest/global_variable_builder/fee_predictor.d.ts.map +1 -0
  11. package/dest/global_variable_builder/fee_predictor.js +128 -0
  12. package/dest/global_variable_builder/fee_provider.d.ts +21 -0
  13. package/dest/global_variable_builder/fee_provider.d.ts.map +1 -0
  14. package/dest/global_variable_builder/fee_provider.js +58 -0
  15. package/dest/global_variable_builder/global_builder.d.ts +26 -17
  16. package/dest/global_variable_builder/global_builder.d.ts.map +1 -1
  17. package/dest/global_variable_builder/global_builder.js +45 -61
  18. package/dest/global_variable_builder/index.d.ts +4 -2
  19. package/dest/global_variable_builder/index.d.ts.map +1 -1
  20. package/dest/global_variable_builder/index.js +2 -0
  21. package/dest/index.d.ts +2 -4
  22. package/dest/index.d.ts.map +1 -1
  23. package/dest/index.js +1 -3
  24. package/dest/publisher/config.d.ts +60 -27
  25. package/dest/publisher/config.d.ts.map +1 -1
  26. package/dest/publisher/config.js +124 -32
  27. package/dest/publisher/index.d.ts +4 -1
  28. package/dest/publisher/index.d.ts.map +1 -1
  29. package/dest/publisher/index.js +3 -0
  30. package/dest/publisher/l1_tx_failed_store/factory.d.ts +11 -0
  31. package/dest/publisher/l1_tx_failed_store/factory.d.ts.map +1 -0
  32. package/dest/publisher/l1_tx_failed_store/factory.js +22 -0
  33. package/dest/publisher/l1_tx_failed_store/failed_tx_store.d.ts +58 -0
  34. package/dest/publisher/l1_tx_failed_store/failed_tx_store.d.ts.map +1 -0
  35. package/dest/publisher/l1_tx_failed_store/failed_tx_store.js +1 -0
  36. package/dest/publisher/l1_tx_failed_store/file_store_failed_tx_store.d.ts +15 -0
  37. package/dest/publisher/l1_tx_failed_store/file_store_failed_tx_store.d.ts.map +1 -0
  38. package/dest/publisher/l1_tx_failed_store/file_store_failed_tx_store.js +34 -0
  39. package/dest/publisher/l1_tx_failed_store/index.d.ts +4 -0
  40. package/dest/publisher/l1_tx_failed_store/index.d.ts.map +1 -0
  41. package/dest/publisher/l1_tx_failed_store/index.js +2 -0
  42. package/dest/publisher/sequencer-bundle-simulator.d.ts +96 -0
  43. package/dest/publisher/sequencer-bundle-simulator.d.ts.map +1 -0
  44. package/dest/publisher/sequencer-bundle-simulator.js +198 -0
  45. package/dest/publisher/sequencer-publisher-factory.d.ts +50 -0
  46. package/dest/publisher/sequencer-publisher-factory.d.ts.map +1 -0
  47. package/dest/publisher/sequencer-publisher-factory.js +75 -0
  48. package/dest/publisher/sequencer-publisher-metrics.d.ts +5 -4
  49. package/dest/publisher/sequencer-publisher-metrics.d.ts.map +1 -1
  50. package/dest/publisher/sequencer-publisher-metrics.js +34 -62
  51. package/dest/publisher/sequencer-publisher.d.ts +170 -97
  52. package/dest/publisher/sequencer-publisher.d.ts.map +1 -1
  53. package/dest/publisher/sequencer-publisher.js +1255 -276
  54. package/dest/sequencer/automine/automine_factory.d.ts +54 -0
  55. package/dest/sequencer/automine/automine_factory.d.ts.map +1 -0
  56. package/dest/sequencer/automine/automine_factory.js +84 -0
  57. package/dest/sequencer/automine/automine_sequencer.d.ts +151 -0
  58. package/dest/sequencer/automine/automine_sequencer.d.ts.map +1 -0
  59. package/dest/sequencer/automine/automine_sequencer.js +509 -0
  60. package/dest/sequencer/chain_state_overrides.d.ts +61 -0
  61. package/dest/sequencer/chain_state_overrides.d.ts.map +1 -0
  62. package/dest/sequencer/chain_state_overrides.js +98 -0
  63. package/dest/sequencer/checkpoint_proposal_job.d.ts +150 -0
  64. package/dest/sequencer/checkpoint_proposal_job.d.ts.map +1 -0
  65. package/dest/sequencer/checkpoint_proposal_job.js +1792 -0
  66. package/dest/sequencer/checkpoint_proposal_job_metrics.d.ts +34 -0
  67. package/dest/sequencer/checkpoint_proposal_job_metrics.d.ts.map +1 -0
  68. package/dest/sequencer/checkpoint_proposal_job_metrics.js +72 -0
  69. package/dest/sequencer/checkpoint_voter.d.ts +34 -0
  70. package/dest/sequencer/checkpoint_voter.d.ts.map +1 -0
  71. package/dest/sequencer/checkpoint_voter.js +106 -0
  72. package/dest/sequencer/config.d.ts +7 -1
  73. package/dest/sequencer/config.d.ts.map +1 -1
  74. package/dest/sequencer/errors.d.ts +11 -0
  75. package/dest/sequencer/errors.d.ts.map +1 -0
  76. package/dest/sequencer/errors.js +15 -0
  77. package/dest/sequencer/events.d.ts +92 -0
  78. package/dest/sequencer/events.d.ts.map +1 -0
  79. package/dest/sequencer/events.js +1 -0
  80. package/dest/sequencer/index.d.ts +6 -2
  81. package/dest/sequencer/index.d.ts.map +1 -1
  82. package/dest/sequencer/index.js +5 -1
  83. package/dest/sequencer/metrics.d.ts +64 -13
  84. package/dest/sequencer/metrics.d.ts.map +1 -1
  85. package/dest/sequencer/metrics.js +309 -68
  86. package/dest/sequencer/sequencer.d.ts +205 -135
  87. package/dest/sequencer/sequencer.d.ts.map +1 -1
  88. package/dest/sequencer/sequencer.js +1208 -523
  89. package/dest/sequencer/timetable.d.ts +85 -25
  90. package/dest/sequencer/timetable.d.ts.map +1 -1
  91. package/dest/sequencer/timetable.js +177 -60
  92. package/dest/sequencer/types.d.ts +3 -0
  93. package/dest/sequencer/types.d.ts.map +1 -0
  94. package/dest/sequencer/types.js +1 -0
  95. package/dest/sequencer/utils.d.ts +20 -38
  96. package/dest/sequencer/utils.d.ts.map +1 -1
  97. package/dest/sequencer/utils.js +12 -47
  98. package/dest/test/index.d.ts +9 -3
  99. package/dest/test/index.d.ts.map +1 -1
  100. package/dest/test/index.js +0 -4
  101. package/dest/test/mock_checkpoint_builder.d.ts +95 -0
  102. package/dest/test/mock_checkpoint_builder.d.ts.map +1 -0
  103. package/dest/test/mock_checkpoint_builder.js +231 -0
  104. package/dest/test/utils.d.ts +53 -0
  105. package/dest/test/utils.d.ts.map +1 -0
  106. package/dest/test/utils.js +105 -0
  107. package/package.json +46 -45
  108. package/src/client/sequencer-client.ts +158 -103
  109. package/src/config.ts +201 -99
  110. package/src/global_variable_builder/README.md +44 -0
  111. package/src/global_variable_builder/fee_predictor.ts +172 -0
  112. package/src/global_variable_builder/fee_provider.ts +75 -0
  113. package/src/global_variable_builder/global_builder.ts +68 -76
  114. package/src/global_variable_builder/index.ts +3 -1
  115. package/src/index.ts +10 -3
  116. package/src/publisher/config.ts +184 -59
  117. package/src/publisher/index.ts +7 -0
  118. package/src/publisher/l1_tx_failed_store/factory.ts +32 -0
  119. package/src/publisher/l1_tx_failed_store/failed_tx_store.ts +57 -0
  120. package/src/publisher/l1_tx_failed_store/file_store_failed_tx_store.ts +46 -0
  121. package/src/publisher/l1_tx_failed_store/index.ts +3 -0
  122. package/src/publisher/sequencer-bundle-simulator.ts +254 -0
  123. package/src/publisher/sequencer-publisher-factory.ts +121 -0
  124. package/src/publisher/sequencer-publisher-metrics.ts +33 -63
  125. package/src/publisher/sequencer-publisher.ts +1101 -350
  126. package/src/sequencer/README.md +243 -0
  127. package/src/sequencer/automine/README.md +46 -0
  128. package/src/sequencer/automine/automine_factory.ts +145 -0
  129. package/src/sequencer/automine/automine_sequencer.ts +595 -0
  130. package/src/sequencer/chain_state_overrides.ts +162 -0
  131. package/src/sequencer/checkpoint_proposal_job.ts +1632 -0
  132. package/src/sequencer/checkpoint_proposal_job_metrics.ts +128 -0
  133. package/src/sequencer/checkpoint_voter.ts +119 -0
  134. package/src/sequencer/config.ts +8 -0
  135. package/src/sequencer/errors.ts +21 -0
  136. package/src/sequencer/events.ts +76 -0
  137. package/src/sequencer/index.ts +5 -1
  138. package/src/sequencer/metrics.ts +397 -75
  139. package/src/sequencer/sequencer.ts +1013 -579
  140. package/src/sequencer/timetable.ts +225 -60
  141. package/src/sequencer/types.ts +6 -0
  142. package/src/sequencer/utils.ts +28 -60
  143. package/src/test/index.ts +11 -5
  144. package/src/test/mock_checkpoint_builder.ts +323 -0
  145. package/src/test/utils.ts +185 -0
  146. package/dest/sequencer/allowed.d.ts +0 -3
  147. package/dest/sequencer/allowed.d.ts.map +0 -1
  148. package/dest/sequencer/allowed.js +0 -27
  149. package/dest/slasher/factory.d.ts +0 -7
  150. package/dest/slasher/factory.d.ts.map +0 -1
  151. package/dest/slasher/factory.js +0 -8
  152. package/dest/slasher/index.d.ts +0 -3
  153. package/dest/slasher/index.d.ts.map +0 -1
  154. package/dest/slasher/index.js +0 -2
  155. package/dest/slasher/slasher_client.d.ts +0 -75
  156. package/dest/slasher/slasher_client.d.ts.map +0 -1
  157. package/dest/slasher/slasher_client.js +0 -132
  158. package/dest/tx_validator/archive_cache.d.ts +0 -14
  159. package/dest/tx_validator/archive_cache.d.ts.map +0 -1
  160. package/dest/tx_validator/archive_cache.js +0 -22
  161. package/dest/tx_validator/gas_validator.d.ts +0 -14
  162. package/dest/tx_validator/gas_validator.d.ts.map +0 -1
  163. package/dest/tx_validator/gas_validator.js +0 -78
  164. package/dest/tx_validator/nullifier_cache.d.ts +0 -16
  165. package/dest/tx_validator/nullifier_cache.d.ts.map +0 -1
  166. package/dest/tx_validator/nullifier_cache.js +0 -24
  167. package/dest/tx_validator/phases_validator.d.ts +0 -12
  168. package/dest/tx_validator/phases_validator.d.ts.map +0 -1
  169. package/dest/tx_validator/phases_validator.js +0 -80
  170. package/dest/tx_validator/test_utils.d.ts +0 -23
  171. package/dest/tx_validator/test_utils.d.ts.map +0 -1
  172. package/dest/tx_validator/test_utils.js +0 -26
  173. package/dest/tx_validator/tx_validator_factory.d.ts +0 -18
  174. package/dest/tx_validator/tx_validator_factory.d.ts.map +0 -1
  175. package/dest/tx_validator/tx_validator_factory.js +0 -50
  176. package/src/sequencer/allowed.ts +0 -36
  177. package/src/slasher/factory.ts +0 -15
  178. package/src/slasher/index.ts +0 -2
  179. package/src/slasher/slasher_client.ts +0 -193
  180. package/src/tx_validator/archive_cache.ts +0 -28
  181. package/src/tx_validator/gas_validator.ts +0 -101
  182. package/src/tx_validator/nullifier_cache.ts +0 -30
  183. package/src/tx_validator/phases_validator.ts +0 -98
  184. package/src/tx_validator/test_utils.ts +0 -48
  185. package/src/tx_validator/tx_validator_factory.ts +0 -120
@@ -1,127 +1,252 @@
1
+ import { EthAddress } from '@aztec/aztec.js/addresses';
2
+ import type { RollupContract } from '@aztec/ethereum/contracts';
3
+ import type { L1FeeAnalysisResult } from '@aztec/ethereum/l1-fee-analysis';
4
+ import type { SlotNumber } from '@aztec/foundation/branded-types';
1
5
  import {
2
6
  Attributes,
3
7
  type Gauge,
4
8
  type Histogram,
9
+ type Meter,
5
10
  Metrics,
6
11
  type TelemetryClient,
7
12
  type Tracer,
8
13
  type UpDownCounter,
9
- ValueType,
14
+ createUpDownCounterWithDefault,
10
15
  } from '@aztec/telemetry-client';
11
16
 
12
- import { type SequencerState, type SequencerStateCallback, sequencerStateToNumber } from './utils.js';
17
+ import { type Hex, formatUnits } from 'viem';
18
+
19
+ import type { SequencerState } from './utils.js';
13
20
 
14
21
  export class SequencerMetrics {
15
22
  public readonly tracer: Tracer;
23
+ private meter: Meter;
16
24
 
17
25
  private blockCounter: UpDownCounter;
18
26
  private blockBuildDuration: Histogram;
19
27
  private blockBuildManaPerSecond: Gauge;
20
28
  private stateTransitionBufferDuration: Histogram;
21
- private currentBlockNumber: Gauge;
22
- private currentBlockSize: Gauge;
23
- private blockBuilderInsertions: Histogram;
29
+ private stateDuration: Histogram;
24
30
 
31
+ // these are gauges because for individual sequencers building a block is not something that happens often enough to warrant a histogram
25
32
  private timeToCollectAttestations: Gauge;
33
+ private allowanceToCollectAttestations: Gauge;
34
+ private requiredAttestions: Gauge;
35
+ private collectedAttestions: Gauge;
26
36
 
27
- constructor(client: TelemetryClient, getState: SequencerStateCallback, name = 'Sequencer') {
28
- const meter = client.getMeter(name);
29
- this.tracer = client.getTracer(name);
37
+ private rewards: Gauge;
30
38
 
31
- this.blockCounter = meter.createUpDownCounter(Metrics.SEQUENCER_BLOCK_COUNT);
39
+ private slots: UpDownCounter;
40
+ private filledSlots: UpDownCounter;
32
41
 
33
- this.blockBuildDuration = meter.createHistogram(Metrics.SEQUENCER_BLOCK_BUILD_DURATION, {
34
- unit: 'ms',
35
- description: 'Duration to build a block',
36
- valueType: ValueType.INT,
37
- });
42
+ private blockProposalFailed: UpDownCounter;
43
+ private checkpointProposalSuccess: UpDownCounter;
44
+ private checkpointPrecheckFailed: UpDownCounter;
45
+ private checkpointProposalFailed: UpDownCounter;
46
+ private checkpointSuccess: UpDownCounter;
47
+ private slashingAttempts: UpDownCounter;
48
+ private pipelineDepth: Gauge;
49
+ private pipelineDiscards: UpDownCounter;
50
+ private pipelineParentCheckpointMismatches: UpDownCounter;
38
51
 
39
- this.blockBuildManaPerSecond = meter.createGauge(Metrics.SEQUENCER_BLOCK_BUILD_MANA_PER_SECOND, {
40
- unit: 'mana/s',
41
- description: 'Mana per second when building a block',
42
- valueType: ValueType.INT,
43
- });
52
+ // Fisherman fee analysis metrics
53
+ private fishermanWouldBeIncluded: UpDownCounter;
54
+ private fishermanTimeBeforeBlock: Histogram;
55
+ private fishermanPendingBlobTxCount: Histogram;
56
+ private fishermanIncludedBlobTxCount: Histogram;
57
+ private fishermanPendingBlobCount: Histogram;
58
+ private fishermanIncludedBlobCount: Histogram;
59
+ private fishermanBlockBlobsFull: UpDownCounter;
60
+ private fishermanMaxBlobCapacity: Histogram;
61
+ private fishermanCalculatedPriorityFee: Histogram;
62
+ private fishermanPriorityFeeDelta: Histogram;
63
+ private fishermanEstimatedCost: Histogram;
64
+ private fishermanEstimatedOverpayment: Histogram;
65
+ private fishermanMinedBlobTxPriorityFee: Histogram;
66
+ private fishermanMinedBlobTxTotalCost: Histogram;
44
67
 
45
- this.stateTransitionBufferDuration = meter.createHistogram(Metrics.SEQUENCER_STATE_TRANSITION_BUFFER_DURATION, {
46
- unit: 'ms',
47
- description:
48
- 'The time difference between when the sequencer needed to transition to a new state and when it actually did.',
49
- valueType: ValueType.INT,
50
- });
68
+ private blockInterBlockTime: Histogram;
69
+ private lastBlockBuiltTimestamp?: number;
70
+ private lastBlockBuiltSlot?: SlotNumber;
51
71
 
52
- const currentState = meter.createObservableGauge(Metrics.SEQUENCER_CURRENT_STATE, {
53
- description: 'Current state of the sequencer',
54
- });
72
+ private lastSeenSlot?: SlotNumber;
55
73
 
56
- currentState.addCallback(observer => {
57
- observer.observe(sequencerStateToNumber(getState()));
58
- });
74
+ constructor(
75
+ client: TelemetryClient,
76
+ private rollup: RollupContract,
77
+ name = 'Sequencer',
78
+ ) {
79
+ this.meter = client.getMeter(name);
80
+ this.tracer = client.getTracer(name);
59
81
 
60
- this.currentBlockNumber = meter.createGauge(Metrics.SEQUENCER_CURRENT_BLOCK_NUMBER, {
61
- description: 'Current block number',
62
- valueType: ValueType.INT,
82
+ this.blockCounter = createUpDownCounterWithDefault(this.meter, Metrics.SEQUENCER_BLOCK_COUNT, {
83
+ [Attributes.STATUS]: ['failed', 'built'],
63
84
  });
64
85
 
65
- this.currentBlockSize = meter.createGauge(Metrics.SEQUENCER_CURRENT_BLOCK_SIZE, {
66
- description: 'Current block size',
67
- valueType: ValueType.INT,
68
- });
86
+ this.blockBuildDuration = this.meter.createHistogram(Metrics.SEQUENCER_BLOCK_BUILD_DURATION);
69
87
 
70
- this.timeToCollectAttestations = meter.createGauge(Metrics.SEQUENCER_TIME_TO_COLLECT_ATTESTATIONS, {
71
- description: 'The time spent collecting attestations from committee members',
72
- valueType: ValueType.INT,
73
- });
88
+ this.blockBuildManaPerSecond = this.meter.createGauge(Metrics.SEQUENCER_BLOCK_BUILD_MANA_PER_SECOND);
74
89
 
75
- this.blockBuilderInsertions = meter.createHistogram(Metrics.SEQUENCER_BLOCK_BUILD_INSERTION_TIME, {
76
- description: 'Timer for tree insertions performed by the block builder',
77
- unit: 'us',
78
- valueType: ValueType.INT,
79
- });
90
+ this.blockInterBlockTime = this.meter.createHistogram(Metrics.SEQUENCER_BLOCK_INTER_BLOCK_TIME);
80
91
 
81
- this.setCurrentBlock(0, 0);
82
- }
92
+ this.stateTransitionBufferDuration = this.meter.createHistogram(Metrics.SEQUENCER_STATE_TRANSITION_BUFFER_DURATION);
83
93
 
84
- startCollectingAttestationsTimer(): () => void {
85
- const startTime = Date.now();
86
- const stop = () => {
87
- const duration = Date.now() - startTime;
88
- this.recordTimeToCollectAttestations(duration);
89
- };
90
- return stop.bind(this);
91
- }
94
+ this.stateDuration = this.meter.createHistogram(Metrics.SEQUENCER_STATE_DURATION);
95
+
96
+ this.rewards = this.meter.createGauge(Metrics.SEQUENCER_CURRENT_SLOT_REWARDS);
97
+
98
+ this.slots = createUpDownCounterWithDefault(this.meter, Metrics.SEQUENCER_SLOT_COUNT);
99
+
100
+ /**
101
+ * NOTE: we do not track missed slots as a separate metric. That would be difficult to determine
102
+ * Instead, use a computed metric, `slots - filledSlots` to get the number of slots a sequencer has missed.
103
+ */
104
+ this.filledSlots = createUpDownCounterWithDefault(this.meter, Metrics.SEQUENCER_FILLED_SLOT_COUNT);
105
+
106
+ this.timeToCollectAttestations = this.meter.createGauge(Metrics.SEQUENCER_COLLECT_ATTESTATIONS_DURATION);
107
+
108
+ this.allowanceToCollectAttestations = this.meter.createGauge(Metrics.SEQUENCER_COLLECT_ATTESTATIONS_TIME_ALLOWANCE);
109
+
110
+ this.requiredAttestions = this.meter.createGauge(Metrics.SEQUENCER_REQUIRED_ATTESTATIONS_COUNT);
111
+
112
+ this.collectedAttestions = this.meter.createGauge(Metrics.SEQUENCER_COLLECTED_ATTESTATIONS_COUNT);
113
+
114
+ this.blockProposalFailed = createUpDownCounterWithDefault(
115
+ this.meter,
116
+ Metrics.SEQUENCER_BLOCK_PROPOSAL_FAILED_COUNT,
117
+ );
118
+
119
+ this.checkpointProposalSuccess = createUpDownCounterWithDefault(
120
+ this.meter,
121
+ Metrics.SEQUENCER_CHECKPOINT_PROPOSAL_SUCCESS_COUNT,
122
+ );
123
+
124
+ this.checkpointSuccess = createUpDownCounterWithDefault(this.meter, Metrics.SEQUENCER_CHECKPOINT_SUCCESS_COUNT);
125
+
126
+ this.checkpointPrecheckFailed = createUpDownCounterWithDefault(
127
+ this.meter,
128
+ Metrics.SEQUENCER_CHECKPOINT_PRECHECK_FAILED_COUNT,
129
+ {
130
+ [Attributes.ERROR_TYPE]: [
131
+ 'slot_already_taken',
132
+ 'rollup_contract_check_failed',
133
+ 'slot_mismatch',
134
+ 'block_number_mismatch',
135
+ ],
136
+ },
137
+ );
138
+
139
+ this.checkpointProposalFailed = createUpDownCounterWithDefault(
140
+ this.meter,
141
+ Metrics.SEQUENCER_CHECKPOINT_PROPOSAL_FAILED_COUNT,
142
+ );
92
143
 
93
- recordTimeToCollectAttestations(time: number) {
94
- this.timeToCollectAttestations.record(time);
144
+ this.slashingAttempts = createUpDownCounterWithDefault(this.meter, Metrics.SEQUENCER_SLASHING_ATTEMPTS_COUNT);
145
+
146
+ this.pipelineDepth = this.meter.createGauge(Metrics.SEQUENCER_PIPELINE_DEPTH);
147
+ this.pipelineDiscards = createUpDownCounterWithDefault(this.meter, Metrics.SEQUENCER_PIPELINE_DISCARDS_COUNT);
148
+ this.pipelineParentCheckpointMismatches = createUpDownCounterWithDefault(
149
+ this.meter,
150
+ Metrics.SEQUENCER_PIPELINE_PARENT_CHECKPOINT_MISMATCH_COUNT,
151
+ {
152
+ [Attributes.ERROR_TYPE]: [
153
+ 'archiver-sync-timeout',
154
+ 'parent-not-on-l1',
155
+ 'parent-hash-mismatch',
156
+ 'parent-invalid-attestations',
157
+ 'unexpected-parent-appeared',
158
+ ],
159
+ },
160
+ );
161
+ this.pipelineDepth.record(0);
162
+
163
+ // Fisherman fee analysis metrics
164
+ this.fishermanWouldBeIncluded = createUpDownCounterWithDefault(
165
+ this.meter,
166
+ Metrics.FISHERMAN_FEE_ANALYSIS_WOULD_BE_INCLUDED,
167
+ {
168
+ [Attributes.OK]: [true, false],
169
+ [Attributes.BLOCK_FULL]: ['true', 'false'],
170
+ },
171
+ );
172
+
173
+ this.fishermanTimeBeforeBlock = this.meter.createHistogram(Metrics.FISHERMAN_FEE_ANALYSIS_TIME_BEFORE_BLOCK);
174
+
175
+ this.fishermanPendingBlobTxCount = this.meter.createHistogram(Metrics.FISHERMAN_FEE_ANALYSIS_PENDING_BLOB_TX_COUNT);
176
+
177
+ this.fishermanIncludedBlobTxCount = this.meter.createHistogram(
178
+ Metrics.FISHERMAN_FEE_ANALYSIS_INCLUDED_BLOB_TX_COUNT,
179
+ );
180
+
181
+ this.fishermanCalculatedPriorityFee = this.meter.createHistogram(
182
+ Metrics.FISHERMAN_FEE_ANALYSIS_CALCULATED_PRIORITY_FEE,
183
+ );
184
+
185
+ this.fishermanPriorityFeeDelta = this.meter.createHistogram(Metrics.FISHERMAN_FEE_ANALYSIS_PRIORITY_FEE_DELTA);
186
+
187
+ this.fishermanEstimatedCost = this.meter.createHistogram(Metrics.FISHERMAN_FEE_ANALYSIS_ESTIMATED_COST);
188
+
189
+ this.fishermanEstimatedOverpayment = this.meter.createHistogram(
190
+ Metrics.FISHERMAN_FEE_ANALYSIS_ESTIMATED_OVERPAYMENT,
191
+ );
192
+
193
+ this.fishermanMinedBlobTxPriorityFee = this.meter.createHistogram(
194
+ Metrics.FISHERMAN_FEE_ANALYSIS_MINED_BLOB_TX_PRIORITY_FEE,
195
+ );
196
+
197
+ this.fishermanMinedBlobTxTotalCost = this.meter.createHistogram(
198
+ Metrics.FISHERMAN_FEE_ANALYSIS_MINED_BLOB_TX_TOTAL_COST,
199
+ );
200
+
201
+ this.fishermanPendingBlobCount = this.meter.createHistogram(Metrics.FISHERMAN_FEE_ANALYSIS_PENDING_BLOB_COUNT);
202
+
203
+ this.fishermanIncludedBlobCount = this.meter.createHistogram(Metrics.FISHERMAN_FEE_ANALYSIS_INCLUDED_BLOB_COUNT);
204
+
205
+ this.fishermanBlockBlobsFull = createUpDownCounterWithDefault(
206
+ this.meter,
207
+ Metrics.FISHERMAN_FEE_ANALYSIS_BLOCK_BLOBS_FULL,
208
+ {
209
+ [Attributes.OK]: [true, false],
210
+ },
211
+ );
212
+
213
+ this.fishermanMaxBlobCapacity = this.meter.createHistogram(Metrics.FISHERMAN_FEE_ANALYSIS_MAX_BLOB_CAPACITY);
95
214
  }
96
215
 
97
- recordBlockBuilderTreeInsertions(timeUs: number) {
98
- this.blockBuilderInsertions.record(Math.ceil(timeUs));
216
+ public recordRequiredAttestations(requiredAttestationsCount: number, allowanceMs: number) {
217
+ this.requiredAttestions.record(requiredAttestationsCount);
218
+ this.allowanceToCollectAttestations.record(Math.ceil(allowanceMs));
219
+
220
+ // reset
221
+ this.collectedAttestions.record(0);
222
+ this.timeToCollectAttestations.record(0);
99
223
  }
100
224
 
101
- recordCancelledBlock() {
102
- this.blockCounter.add(1, {
103
- [Attributes.STATUS]: 'cancelled',
104
- });
105
- this.setCurrentBlock(0, 0);
225
+ public recordCollectedAttestations(count: number, durationMs: number) {
226
+ this.collectedAttestions.record(count);
227
+ this.timeToCollectAttestations.record(Math.ceil(durationMs));
106
228
  }
107
229
 
108
- recordBuiltBlock(buildDurationMs: number, totalMana: number) {
230
+ recordBuiltBlock(buildDurationMs: number, totalMana: number, slot: SlotNumber) {
109
231
  this.blockCounter.add(1, {
110
232
  [Attributes.STATUS]: 'built',
111
233
  });
112
234
  this.blockBuildDuration.record(Math.ceil(buildDurationMs));
113
235
  this.blockBuildManaPerSecond.record(Math.ceil((totalMana * 1000) / buildDurationMs));
236
+
237
+ // Only record inter-block time between blocks built within the same slot.
238
+ const now = Date.now();
239
+ if (this.lastBlockBuiltTimestamp !== undefined && this.lastBlockBuiltSlot === slot) {
240
+ this.blockInterBlockTime.record(now - this.lastBlockBuiltTimestamp);
241
+ }
242
+ this.lastBlockBuiltTimestamp = now;
243
+ this.lastBlockBuiltSlot = slot;
114
244
  }
115
245
 
116
246
  recordFailedBlock() {
117
247
  this.blockCounter.add(1, {
118
248
  [Attributes.STATUS]: 'failed',
119
249
  });
120
- this.setCurrentBlock(0, 0);
121
- }
122
-
123
- recordNewBlock(blockNumber: number, txCount: number) {
124
- this.setCurrentBlock(blockNumber, txCount);
125
250
  }
126
251
 
127
252
  recordStateTransitionBufferMs(durationMs: number, state: SequencerState) {
@@ -130,8 +255,205 @@ export class SequencerMetrics {
130
255
  });
131
256
  }
132
257
 
133
- private setCurrentBlock(blockNumber: number, txCount: number) {
134
- this.currentBlockNumber.record(blockNumber);
135
- this.currentBlockSize.record(txCount);
258
+ recordStateDuration(durationMs: number, state: SequencerState) {
259
+ this.stateDuration.record(Math.ceil(durationMs), {
260
+ [Attributes.SEQUENCER_STATE]: state,
261
+ });
262
+ }
263
+
264
+ recordPipelineDepth(depth: number) {
265
+ this.pipelineDepth.record(depth);
266
+ }
267
+
268
+ recordPipelineDiscard(count = 1) {
269
+ this.pipelineDiscards.add(count);
270
+ }
271
+
272
+ recordPipelineParentCheckpointMismatch(reason: string) {
273
+ this.pipelineParentCheckpointMismatches.add(1, {
274
+ [Attributes.ERROR_TYPE]: reason,
275
+ });
276
+ }
277
+
278
+ incOpenSlot(slot: SlotNumber, proposer: string) {
279
+ // sequencer went through the loop a second time. Noop
280
+ if (slot === this.lastSeenSlot) {
281
+ return;
282
+ }
283
+
284
+ this.slots.add(1, {
285
+ [Attributes.BLOCK_PROPOSER]: proposer,
286
+ });
287
+
288
+ this.lastSeenSlot = slot;
289
+ }
290
+
291
+ async incFilledSlot(proposer: string, coinbase: Hex | EthAddress | undefined): Promise<void> {
292
+ this.filledSlots.add(1, {
293
+ [Attributes.BLOCK_PROPOSER]: proposer,
294
+ });
295
+ this.lastSeenSlot = undefined;
296
+
297
+ if (coinbase) {
298
+ try {
299
+ const rewards = await this.rollup.getSequencerRewards(coinbase);
300
+ const fmt = parseFloat(formatUnits(rewards, 18));
301
+ this.rewards.record(fmt, {
302
+ [Attributes.COINBASE]: coinbase.toString(),
303
+ });
304
+ } catch {
305
+ // no-op
306
+ }
307
+ }
308
+ }
309
+
310
+ recordCheckpointSuccess() {
311
+ this.checkpointSuccess.add(1);
312
+ }
313
+
314
+ recordBlockProposalFailed(reason?: string) {
315
+ this.blockProposalFailed.add(1, {
316
+ ...(reason && { [Attributes.ERROR_TYPE]: reason }),
317
+ });
318
+ }
319
+
320
+ recordCheckpointProposalSuccess() {
321
+ this.checkpointProposalSuccess.add(1);
322
+ }
323
+
324
+ recordCheckpointPrecheckFailed(
325
+ checkType: 'slot_already_taken' | 'rollup_contract_check_failed' | 'slot_mismatch' | 'block_number_mismatch',
326
+ ) {
327
+ this.checkpointPrecheckFailed.add(1, { [Attributes.ERROR_TYPE]: checkType });
328
+ }
329
+
330
+ recordCheckpointProposalFailed(reason?: string) {
331
+ this.checkpointProposalFailed.add(1, {
332
+ ...(reason && { [Attributes.ERROR_TYPE]: reason }),
333
+ });
334
+ }
335
+
336
+ recordSlashingAttempt(actionCount: number) {
337
+ this.slashingAttempts.add(actionCount);
338
+ }
339
+
340
+ /**
341
+ * Records metrics for a completed fisherman fee analysis
342
+ * @param analysis - The completed fee analysis result
343
+ */
344
+ recordFishermanFeeAnalysis(analysis: L1FeeAnalysisResult) {
345
+ // In fisherman mode, we should always have strategy results
346
+ if (!analysis.computedPrices.strategyResults || analysis.computedPrices.strategyResults.length === 0) {
347
+ // This should never happen in fisherman mode - log an error
348
+ // We don't record metrics without strategy IDs as that defeats the purpose
349
+ throw new Error(
350
+ `No strategy results found in fisherman fee analysis ${analysis.id}. This indicates a bug in the fee analysis.`,
351
+ );
352
+ }
353
+
354
+ // Record metrics for each strategy separately
355
+ for (const strategyResult of analysis.computedPrices.strategyResults) {
356
+ const strategyAttributes = {
357
+ [Attributes.FISHERMAN_FEE_STRATEGY_ID]: strategyResult.strategyId,
358
+ };
359
+
360
+ // Record pending block snapshot data (once per strategy for comparison)
361
+ this.fishermanPendingBlobTxCount.record(analysis.pendingSnapshot.pendingBlobTxCount, strategyAttributes);
362
+ this.fishermanPendingBlobCount.record(analysis.pendingSnapshot.pendingBlobCount, strategyAttributes);
363
+
364
+ // Record mined block data if available
365
+ if (analysis.minedBlock) {
366
+ this.fishermanIncludedBlobTxCount.record(analysis.minedBlock.includedBlobTxCount, strategyAttributes);
367
+ this.fishermanIncludedBlobCount.record(analysis.minedBlock.includedBlobCount, strategyAttributes);
368
+
369
+ // Record actual fees from blob transactions in the mined block
370
+ for (const blobTx of analysis.minedBlock.includedBlobTxs) {
371
+ // Record priority fee per gas in Gwei
372
+ const priorityFeeGwei = Number(blobTx.maxPriorityFeePerGas) / 1e9;
373
+ this.fishermanMinedBlobTxPriorityFee.record(priorityFeeGwei, strategyAttributes);
374
+
375
+ // Calculate total cost in ETH
376
+ // Cost = (gas * (baseFee + priorityFee)) + (blobCount * blobGasPerBlob * blobBaseFee)
377
+ const baseFee = analysis.minedBlock.baseFeePerGas;
378
+ const effectiveGasPrice = baseFee + blobTx.maxPriorityFeePerGas;
379
+
380
+ // Calculate execution cost using actual gas limit from the transaction
381
+ const executionCost = blobTx.gas * effectiveGasPrice;
382
+
383
+ // Calculate blob cost using maxFeePerBlobGas * blobCount * GAS_PER_BLOB
384
+ const blobCost = blobTx.maxFeePerBlobGas * BigInt(blobTx.blobCount) * 131072n; // 128KB per blob
385
+
386
+ const totalCostWei = executionCost + blobCost;
387
+ const totalCostEth = Number(totalCostWei) / 1e18;
388
+
389
+ this.fishermanMinedBlobTxTotalCost.record(totalCostEth, strategyAttributes);
390
+ }
391
+ }
392
+
393
+ // Record the calculated priority fee for this strategy
394
+ const calculatedPriorityFeeGwei = Number(strategyResult.calculatedPriorityFee) / 1e9;
395
+ this.fishermanCalculatedPriorityFee.record(calculatedPriorityFeeGwei, strategyAttributes);
396
+
397
+ // Record analysis results if available
398
+ if (analysis.analysis) {
399
+ this.fishermanTimeBeforeBlock.record(Math.ceil(analysis.analysis.timeBeforeBlockMs), strategyAttributes);
400
+
401
+ // Record whether the block reached 100% blob capacity
402
+ if (analysis.analysis.blockBlobsFull) {
403
+ this.fishermanBlockBlobsFull.add(1, { ...strategyAttributes, [Attributes.OK]: true });
404
+ } else {
405
+ this.fishermanBlockBlobsFull.add(1, { ...strategyAttributes, [Attributes.OK]: false });
406
+ }
407
+
408
+ // Record the max blob capacity for this block
409
+ this.fishermanMaxBlobCapacity.record(analysis.analysis.maxBlobCapacity, strategyAttributes);
410
+
411
+ // Record strategy-specific inclusion result
412
+ if (strategyResult.wouldBeIncluded !== undefined) {
413
+ const inclusionAttributes = {
414
+ ...strategyAttributes,
415
+ [Attributes.BLOCK_FULL]: analysis.analysis.blockBlobsFull ? 'true' : 'false',
416
+ };
417
+
418
+ if (strategyResult.wouldBeIncluded) {
419
+ this.fishermanWouldBeIncluded.add(1, { ...inclusionAttributes, [Attributes.OK]: true });
420
+ } else {
421
+ this.fishermanWouldBeIncluded.add(1, {
422
+ ...inclusionAttributes,
423
+ [Attributes.OK]: false,
424
+ ...(strategyResult.exclusionReason && { [Attributes.ERROR_TYPE]: strategyResult.exclusionReason }),
425
+ });
426
+ }
427
+ }
428
+
429
+ // Record strategy-specific priority fee delta
430
+ if (strategyResult.priorityFeeDelta !== undefined) {
431
+ const priorityFeeDeltaGwei = Number(strategyResult.priorityFeeDelta) / 1e9;
432
+ const deltaAttributes = {
433
+ ...strategyAttributes,
434
+ [Attributes.BLOCK_FULL]: analysis.analysis.blockBlobsFull ? 'true' : 'false',
435
+ };
436
+ this.fishermanPriorityFeeDelta.record(priorityFeeDeltaGwei, deltaAttributes);
437
+ }
438
+
439
+ // Record estimated cost if available
440
+ if (strategyResult.estimatedCostEth !== undefined) {
441
+ const costAttributes = {
442
+ ...strategyAttributes,
443
+ [Attributes.BLOCK_FULL]: analysis.analysis.blockBlobsFull ? 'true' : 'false',
444
+ };
445
+ this.fishermanEstimatedCost.record(strategyResult.estimatedCostEth, costAttributes);
446
+ }
447
+
448
+ // Record estimated overpayment if available
449
+ if (strategyResult.estimatedOverpaymentEth !== undefined) {
450
+ const overpaymentAttributes = {
451
+ ...strategyAttributes,
452
+ [Attributes.BLOCK_FULL]: analysis.analysis.blockBlobsFull ? 'true' : 'false',
453
+ };
454
+ this.fishermanEstimatedOverpayment.record(strategyResult.estimatedOverpaymentEth, overpaymentAttributes);
455
+ }
456
+ }
457
+ }
136
458
  }
137
459
  }