@aztec/sequencer-client 0.0.1-commit.96bb3f7 → 0.0.1-commit.96dac018d
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.
- package/dest/client/sequencer-client.d.ts +12 -7
- package/dest/client/sequencer-client.d.ts.map +1 -1
- package/dest/client/sequencer-client.js +15 -4
- package/dest/config.d.ts +3 -4
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +17 -14
- package/dest/global_variable_builder/global_builder.d.ts +2 -4
- package/dest/global_variable_builder/global_builder.d.ts.map +1 -1
- package/dest/global_variable_builder/global_builder.js +2 -2
- package/dest/index.d.ts +2 -2
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +1 -1
- package/dest/publisher/config.d.ts +35 -17
- package/dest/publisher/config.d.ts.map +1 -1
- package/dest/publisher/config.js +106 -42
- package/dest/publisher/index.d.ts +2 -1
- package/dest/publisher/index.d.ts.map +1 -1
- package/dest/publisher/l1_tx_failed_store/factory.d.ts +11 -0
- package/dest/publisher/l1_tx_failed_store/factory.d.ts.map +1 -0
- package/dest/publisher/l1_tx_failed_store/factory.js +22 -0
- package/dest/publisher/l1_tx_failed_store/failed_tx_store.d.ts +59 -0
- package/dest/publisher/l1_tx_failed_store/failed_tx_store.d.ts.map +1 -0
- package/dest/publisher/l1_tx_failed_store/failed_tx_store.js +1 -0
- package/dest/publisher/l1_tx_failed_store/file_store_failed_tx_store.d.ts +15 -0
- package/dest/publisher/l1_tx_failed_store/file_store_failed_tx_store.d.ts.map +1 -0
- package/dest/publisher/l1_tx_failed_store/file_store_failed_tx_store.js +34 -0
- package/dest/publisher/l1_tx_failed_store/index.d.ts +4 -0
- package/dest/publisher/l1_tx_failed_store/index.d.ts.map +1 -0
- package/dest/publisher/l1_tx_failed_store/index.js +2 -0
- package/dest/publisher/sequencer-publisher-factory.d.ts +11 -3
- package/dest/publisher/sequencer-publisher-factory.d.ts.map +1 -1
- package/dest/publisher/sequencer-publisher-factory.js +13 -2
- package/dest/publisher/sequencer-publisher-metrics.d.ts +1 -1
- package/dest/publisher/sequencer-publisher-metrics.d.ts.map +1 -1
- package/dest/publisher/sequencer-publisher-metrics.js +12 -4
- package/dest/publisher/sequencer-publisher.d.ts +22 -8
- package/dest/publisher/sequencer-publisher.d.ts.map +1 -1
- package/dest/publisher/sequencer-publisher.js +297 -47
- package/dest/sequencer/checkpoint_proposal_job.d.ts +34 -9
- package/dest/sequencer/checkpoint_proposal_job.d.ts.map +1 -1
- package/dest/sequencer/checkpoint_proposal_job.js +171 -41
- package/dest/sequencer/checkpoint_voter.d.ts +3 -2
- package/dest/sequencer/checkpoint_voter.d.ts.map +1 -1
- package/dest/sequencer/checkpoint_voter.js +34 -10
- package/dest/sequencer/index.d.ts +1 -2
- package/dest/sequencer/index.d.ts.map +1 -1
- package/dest/sequencer/index.js +0 -1
- package/dest/sequencer/metrics.d.ts +17 -5
- package/dest/sequencer/metrics.d.ts.map +1 -1
- package/dest/sequencer/metrics.js +111 -30
- package/dest/sequencer/sequencer.d.ts +31 -13
- package/dest/sequencer/sequencer.d.ts.map +1 -1
- package/dest/sequencer/sequencer.js +95 -36
- package/dest/sequencer/timetable.d.ts +1 -4
- package/dest/sequencer/timetable.d.ts.map +1 -1
- package/dest/sequencer/timetable.js +1 -4
- package/dest/test/index.d.ts +3 -5
- package/dest/test/index.d.ts.map +1 -1
- package/dest/test/mock_checkpoint_builder.d.ts +19 -13
- package/dest/test/mock_checkpoint_builder.d.ts.map +1 -1
- package/dest/test/mock_checkpoint_builder.js +31 -11
- package/dest/test/utils.d.ts +8 -8
- package/dest/test/utils.d.ts.map +1 -1
- package/dest/test/utils.js +12 -11
- package/package.json +30 -28
- package/src/client/sequencer-client.ts +25 -7
- package/src/config.ts +27 -22
- package/src/global_variable_builder/global_builder.ts +3 -3
- package/src/index.ts +1 -6
- package/src/publisher/config.ts +121 -43
- package/src/publisher/index.ts +3 -0
- package/src/publisher/l1_tx_failed_store/factory.ts +32 -0
- package/src/publisher/l1_tx_failed_store/failed_tx_store.ts +55 -0
- package/src/publisher/l1_tx_failed_store/file_store_failed_tx_store.ts +46 -0
- package/src/publisher/l1_tx_failed_store/index.ts +3 -0
- package/src/publisher/sequencer-publisher-factory.ts +23 -6
- package/src/publisher/sequencer-publisher-metrics.ts +7 -3
- package/src/publisher/sequencer-publisher.ts +274 -53
- package/src/sequencer/checkpoint_proposal_job.ts +243 -59
- package/src/sequencer/checkpoint_voter.ts +32 -7
- package/src/sequencer/index.ts +0 -1
- package/src/sequencer/metrics.ts +124 -32
- package/src/sequencer/sequencer.ts +118 -38
- package/src/sequencer/timetable.ts +6 -5
- package/src/test/index.ts +2 -4
- package/src/test/mock_checkpoint_builder.ts +75 -34
- package/src/test/utils.ts +24 -14
- package/dest/sequencer/block_builder.d.ts +0 -26
- package/dest/sequencer/block_builder.d.ts.map +0 -1
- package/dest/sequencer/block_builder.js +0 -129
- package/src/sequencer/block_builder.ts +0 -216
package/src/sequencer/metrics.ts
CHANGED
|
@@ -11,13 +11,13 @@ import {
|
|
|
11
11
|
type TelemetryClient,
|
|
12
12
|
type Tracer,
|
|
13
13
|
type UpDownCounter,
|
|
14
|
+
createUpDownCounterWithDefault,
|
|
14
15
|
} from '@aztec/telemetry-client';
|
|
15
16
|
|
|
16
17
|
import { type Hex, formatUnits } from 'viem';
|
|
17
18
|
|
|
18
19
|
import type { SequencerState } from './utils.js';
|
|
19
20
|
|
|
20
|
-
// TODO(palla/mbps): Review all metrics and add any missing ones per checkpoint
|
|
21
21
|
export class SequencerMetrics {
|
|
22
22
|
public readonly tracer: Tracer;
|
|
23
23
|
private meter: Meter;
|
|
@@ -39,17 +39,26 @@ export class SequencerMetrics {
|
|
|
39
39
|
private filledSlots: UpDownCounter;
|
|
40
40
|
|
|
41
41
|
private blockProposalFailed: UpDownCounter;
|
|
42
|
-
private
|
|
43
|
-
private
|
|
42
|
+
private checkpointProposalSuccess: UpDownCounter;
|
|
43
|
+
private checkpointPrecheckFailed: UpDownCounter;
|
|
44
|
+
private checkpointProposalFailed: UpDownCounter;
|
|
44
45
|
private checkpointSuccess: UpDownCounter;
|
|
45
46
|
private slashingAttempts: UpDownCounter;
|
|
46
47
|
private checkpointAttestationDelay: Histogram;
|
|
48
|
+
private checkpointBuildDuration: Histogram;
|
|
49
|
+
private checkpointBlockCount: Gauge;
|
|
50
|
+
private checkpointTxCount: Gauge;
|
|
51
|
+
private checkpointTotalMana: Gauge;
|
|
47
52
|
|
|
48
53
|
// Fisherman fee analysis metrics
|
|
49
54
|
private fishermanWouldBeIncluded: UpDownCounter;
|
|
50
55
|
private fishermanTimeBeforeBlock: Histogram;
|
|
51
56
|
private fishermanPendingBlobTxCount: Histogram;
|
|
52
57
|
private fishermanIncludedBlobTxCount: Histogram;
|
|
58
|
+
private fishermanPendingBlobCount: Histogram;
|
|
59
|
+
private fishermanIncludedBlobCount: Histogram;
|
|
60
|
+
private fishermanBlockBlobsFull: UpDownCounter;
|
|
61
|
+
private fishermanMaxBlobCapacity: Histogram;
|
|
53
62
|
private fishermanCalculatedPriorityFee: Histogram;
|
|
54
63
|
private fishermanPriorityFeeDelta: Histogram;
|
|
55
64
|
private fishermanEstimatedCost: Histogram;
|
|
@@ -67,7 +76,9 @@ export class SequencerMetrics {
|
|
|
67
76
|
this.meter = client.getMeter(name);
|
|
68
77
|
this.tracer = client.getTracer(name);
|
|
69
78
|
|
|
70
|
-
this.blockCounter = this.meter
|
|
79
|
+
this.blockCounter = createUpDownCounterWithDefault(this.meter, Metrics.SEQUENCER_BLOCK_COUNT, {
|
|
80
|
+
[Attributes.STATUS]: ['failed', 'built'],
|
|
81
|
+
});
|
|
71
82
|
|
|
72
83
|
this.blockBuildDuration = this.meter.createHistogram(Metrics.SEQUENCER_BLOCK_BUILD_DURATION);
|
|
73
84
|
|
|
@@ -77,23 +88,15 @@ export class SequencerMetrics {
|
|
|
77
88
|
|
|
78
89
|
this.checkpointAttestationDelay = this.meter.createHistogram(Metrics.SEQUENCER_CHECKPOINT_ATTESTATION_DELAY);
|
|
79
90
|
|
|
80
|
-
|
|
81
|
-
this.blockCounter.add(0, {
|
|
82
|
-
[Attributes.STATUS]: 'failed',
|
|
83
|
-
});
|
|
84
|
-
this.blockCounter.add(0, {
|
|
85
|
-
[Attributes.STATUS]: 'built',
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
this.rewards = this.meter.createGauge(Metrics.SEQUENCER_CURRENT_BLOCK_REWARDS);
|
|
91
|
+
this.rewards = this.meter.createGauge(Metrics.SEQUENCER_CURRENT_SLOT_REWARDS);
|
|
89
92
|
|
|
90
|
-
this.slots = this.meter
|
|
93
|
+
this.slots = createUpDownCounterWithDefault(this.meter, Metrics.SEQUENCER_SLOT_COUNT);
|
|
91
94
|
|
|
92
95
|
/**
|
|
93
96
|
* NOTE: we do not track missed slots as a separate metric. That would be difficult to determine
|
|
94
97
|
* Instead, use a computed metric, `slots - filledSlots` to get the number of slots a sequencer has missed.
|
|
95
98
|
*/
|
|
96
|
-
this.filledSlots = this.meter
|
|
99
|
+
this.filledSlots = createUpDownCounterWithDefault(this.meter, Metrics.SEQUENCER_FILLED_SLOT_COUNT);
|
|
97
100
|
|
|
98
101
|
this.timeToCollectAttestations = this.meter.createGauge(Metrics.SEQUENCER_COLLECT_ATTESTATIONS_DURATION);
|
|
99
102
|
|
|
@@ -103,20 +106,52 @@ export class SequencerMetrics {
|
|
|
103
106
|
|
|
104
107
|
this.collectedAttestions = this.meter.createGauge(Metrics.SEQUENCER_COLLECTED_ATTESTATIONS_COUNT);
|
|
105
108
|
|
|
106
|
-
this.blockProposalFailed =
|
|
109
|
+
this.blockProposalFailed = createUpDownCounterWithDefault(
|
|
110
|
+
this.meter,
|
|
111
|
+
Metrics.SEQUENCER_BLOCK_PROPOSAL_FAILED_COUNT,
|
|
112
|
+
);
|
|
107
113
|
|
|
108
|
-
this.
|
|
114
|
+
this.checkpointProposalSuccess = createUpDownCounterWithDefault(
|
|
115
|
+
this.meter,
|
|
116
|
+
Metrics.SEQUENCER_CHECKPOINT_PROPOSAL_SUCCESS_COUNT,
|
|
117
|
+
);
|
|
109
118
|
|
|
110
|
-
this.checkpointSuccess = this.meter
|
|
119
|
+
this.checkpointSuccess = createUpDownCounterWithDefault(this.meter, Metrics.SEQUENCER_CHECKPOINT_SUCCESS_COUNT);
|
|
120
|
+
|
|
121
|
+
this.checkpointPrecheckFailed = createUpDownCounterWithDefault(
|
|
122
|
+
this.meter,
|
|
123
|
+
Metrics.SEQUENCER_CHECKPOINT_PRECHECK_FAILED_COUNT,
|
|
124
|
+
{
|
|
125
|
+
[Attributes.ERROR_TYPE]: [
|
|
126
|
+
'slot_already_taken',
|
|
127
|
+
'rollup_contract_check_failed',
|
|
128
|
+
'slot_mismatch',
|
|
129
|
+
'block_number_mismatch',
|
|
130
|
+
],
|
|
131
|
+
},
|
|
132
|
+
);
|
|
111
133
|
|
|
112
|
-
this.
|
|
113
|
-
|
|
134
|
+
this.checkpointProposalFailed = createUpDownCounterWithDefault(
|
|
135
|
+
this.meter,
|
|
136
|
+
Metrics.SEQUENCER_CHECKPOINT_PROPOSAL_FAILED_COUNT,
|
|
114
137
|
);
|
|
115
138
|
|
|
116
|
-
this.
|
|
139
|
+
this.checkpointBuildDuration = this.meter.createHistogram(Metrics.SEQUENCER_CHECKPOINT_BUILD_DURATION);
|
|
140
|
+
this.checkpointBlockCount = this.meter.createGauge(Metrics.SEQUENCER_CHECKPOINT_BLOCK_COUNT);
|
|
141
|
+
this.checkpointTxCount = this.meter.createGauge(Metrics.SEQUENCER_CHECKPOINT_TX_COUNT);
|
|
142
|
+
this.checkpointTotalMana = this.meter.createGauge(Metrics.SEQUENCER_CHECKPOINT_TOTAL_MANA);
|
|
143
|
+
|
|
144
|
+
this.slashingAttempts = createUpDownCounterWithDefault(this.meter, Metrics.SEQUENCER_SLASHING_ATTEMPTS_COUNT);
|
|
117
145
|
|
|
118
146
|
// Fisherman fee analysis metrics
|
|
119
|
-
this.fishermanWouldBeIncluded =
|
|
147
|
+
this.fishermanWouldBeIncluded = createUpDownCounterWithDefault(
|
|
148
|
+
this.meter,
|
|
149
|
+
Metrics.FISHERMAN_FEE_ANALYSIS_WOULD_BE_INCLUDED,
|
|
150
|
+
{
|
|
151
|
+
[Attributes.OK]: [true, false],
|
|
152
|
+
[Attributes.BLOCK_FULL]: ['true', 'false'],
|
|
153
|
+
},
|
|
154
|
+
);
|
|
120
155
|
|
|
121
156
|
this.fishermanTimeBeforeBlock = this.meter.createHistogram(Metrics.FISHERMAN_FEE_ANALYSIS_TIME_BEFORE_BLOCK);
|
|
122
157
|
|
|
@@ -145,6 +180,20 @@ export class SequencerMetrics {
|
|
|
145
180
|
this.fishermanMinedBlobTxTotalCost = this.meter.createHistogram(
|
|
146
181
|
Metrics.FISHERMAN_FEE_ANALYSIS_MINED_BLOB_TX_TOTAL_COST,
|
|
147
182
|
);
|
|
183
|
+
|
|
184
|
+
this.fishermanPendingBlobCount = this.meter.createHistogram(Metrics.FISHERMAN_FEE_ANALYSIS_PENDING_BLOB_COUNT);
|
|
185
|
+
|
|
186
|
+
this.fishermanIncludedBlobCount = this.meter.createHistogram(Metrics.FISHERMAN_FEE_ANALYSIS_INCLUDED_BLOB_COUNT);
|
|
187
|
+
|
|
188
|
+
this.fishermanBlockBlobsFull = createUpDownCounterWithDefault(
|
|
189
|
+
this.meter,
|
|
190
|
+
Metrics.FISHERMAN_FEE_ANALYSIS_BLOCK_BLOBS_FULL,
|
|
191
|
+
{
|
|
192
|
+
[Attributes.OK]: [true, false],
|
|
193
|
+
},
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
this.fishermanMaxBlobCapacity = this.meter.createHistogram(Metrics.FISHERMAN_FEE_ANALYSIS_MAX_BLOB_CAPACITY);
|
|
148
197
|
}
|
|
149
198
|
|
|
150
199
|
public recordRequiredAttestations(requiredAttestationsCount: number, allowanceMs: number) {
|
|
@@ -227,16 +276,30 @@ export class SequencerMetrics {
|
|
|
227
276
|
});
|
|
228
277
|
}
|
|
229
278
|
|
|
230
|
-
|
|
231
|
-
this.
|
|
279
|
+
recordCheckpointProposalSuccess() {
|
|
280
|
+
this.checkpointProposalSuccess.add(1);
|
|
232
281
|
}
|
|
233
282
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
283
|
+
recordCheckpointPrecheckFailed(
|
|
284
|
+
checkType: 'slot_already_taken' | 'rollup_contract_check_failed' | 'slot_mismatch' | 'block_number_mismatch',
|
|
285
|
+
) {
|
|
286
|
+
this.checkpointPrecheckFailed.add(1, { [Attributes.ERROR_TYPE]: checkType });
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
recordCheckpointProposalFailed(reason?: string) {
|
|
290
|
+
this.checkpointProposalFailed.add(1, {
|
|
291
|
+
...(reason && { [Attributes.ERROR_TYPE]: reason }),
|
|
237
292
|
});
|
|
238
293
|
}
|
|
239
294
|
|
|
295
|
+
/** Records aggregate metrics for a completed checkpoint build. */
|
|
296
|
+
recordCheckpointBuild(durationMs: number, blockCount: number, txCount: number, totalMana: number) {
|
|
297
|
+
this.checkpointBuildDuration.record(Math.ceil(durationMs));
|
|
298
|
+
this.checkpointBlockCount.record(blockCount);
|
|
299
|
+
this.checkpointTxCount.record(txCount);
|
|
300
|
+
this.checkpointTotalMana.record(totalMana);
|
|
301
|
+
}
|
|
302
|
+
|
|
240
303
|
recordSlashingAttempt(actionCount: number) {
|
|
241
304
|
this.slashingAttempts.add(actionCount);
|
|
242
305
|
}
|
|
@@ -263,10 +326,12 @@ export class SequencerMetrics {
|
|
|
263
326
|
|
|
264
327
|
// Record pending block snapshot data (once per strategy for comparison)
|
|
265
328
|
this.fishermanPendingBlobTxCount.record(analysis.pendingSnapshot.pendingBlobTxCount, strategyAttributes);
|
|
329
|
+
this.fishermanPendingBlobCount.record(analysis.pendingSnapshot.pendingBlobCount, strategyAttributes);
|
|
266
330
|
|
|
267
331
|
// Record mined block data if available
|
|
268
332
|
if (analysis.minedBlock) {
|
|
269
333
|
this.fishermanIncludedBlobTxCount.record(analysis.minedBlock.includedBlobTxCount, strategyAttributes);
|
|
334
|
+
this.fishermanIncludedBlobCount.record(analysis.minedBlock.includedBlobCount, strategyAttributes);
|
|
270
335
|
|
|
271
336
|
// Record actual fees from blob transactions in the mined block
|
|
272
337
|
for (const blobTx of analysis.minedBlock.includedBlobTxs) {
|
|
@@ -300,13 +365,28 @@ export class SequencerMetrics {
|
|
|
300
365
|
if (analysis.analysis) {
|
|
301
366
|
this.fishermanTimeBeforeBlock.record(Math.ceil(analysis.analysis.timeBeforeBlockMs), strategyAttributes);
|
|
302
367
|
|
|
368
|
+
// Record whether the block reached 100% blob capacity
|
|
369
|
+
if (analysis.analysis.blockBlobsFull) {
|
|
370
|
+
this.fishermanBlockBlobsFull.add(1, { ...strategyAttributes, [Attributes.OK]: true });
|
|
371
|
+
} else {
|
|
372
|
+
this.fishermanBlockBlobsFull.add(1, { ...strategyAttributes, [Attributes.OK]: false });
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
// Record the max blob capacity for this block
|
|
376
|
+
this.fishermanMaxBlobCapacity.record(analysis.analysis.maxBlobCapacity, strategyAttributes);
|
|
377
|
+
|
|
303
378
|
// Record strategy-specific inclusion result
|
|
304
379
|
if (strategyResult.wouldBeIncluded !== undefined) {
|
|
380
|
+
const inclusionAttributes = {
|
|
381
|
+
...strategyAttributes,
|
|
382
|
+
[Attributes.BLOCK_FULL]: analysis.analysis.blockBlobsFull ? 'true' : 'false',
|
|
383
|
+
};
|
|
384
|
+
|
|
305
385
|
if (strategyResult.wouldBeIncluded) {
|
|
306
|
-
this.fishermanWouldBeIncluded.add(1, { ...
|
|
386
|
+
this.fishermanWouldBeIncluded.add(1, { ...inclusionAttributes, [Attributes.OK]: true });
|
|
307
387
|
} else {
|
|
308
388
|
this.fishermanWouldBeIncluded.add(1, {
|
|
309
|
-
...
|
|
389
|
+
...inclusionAttributes,
|
|
310
390
|
[Attributes.OK]: false,
|
|
311
391
|
...(strategyResult.exclusionReason && { [Attributes.ERROR_TYPE]: strategyResult.exclusionReason }),
|
|
312
392
|
});
|
|
@@ -316,17 +396,29 @@ export class SequencerMetrics {
|
|
|
316
396
|
// Record strategy-specific priority fee delta
|
|
317
397
|
if (strategyResult.priorityFeeDelta !== undefined) {
|
|
318
398
|
const priorityFeeDeltaGwei = Number(strategyResult.priorityFeeDelta) / 1e9;
|
|
319
|
-
|
|
399
|
+
const deltaAttributes = {
|
|
400
|
+
...strategyAttributes,
|
|
401
|
+
[Attributes.BLOCK_FULL]: analysis.analysis.blockBlobsFull ? 'true' : 'false',
|
|
402
|
+
};
|
|
403
|
+
this.fishermanPriorityFeeDelta.record(priorityFeeDeltaGwei, deltaAttributes);
|
|
320
404
|
}
|
|
321
405
|
|
|
322
406
|
// Record estimated cost if available
|
|
323
407
|
if (strategyResult.estimatedCostEth !== undefined) {
|
|
324
|
-
|
|
408
|
+
const costAttributes = {
|
|
409
|
+
...strategyAttributes,
|
|
410
|
+
[Attributes.BLOCK_FULL]: analysis.analysis.blockBlobsFull ? 'true' : 'false',
|
|
411
|
+
};
|
|
412
|
+
this.fishermanEstimatedCost.record(strategyResult.estimatedCostEth, costAttributes);
|
|
325
413
|
}
|
|
326
414
|
|
|
327
415
|
// Record estimated overpayment if available
|
|
328
416
|
if (strategyResult.estimatedOverpaymentEth !== undefined) {
|
|
329
|
-
|
|
417
|
+
const overpaymentAttributes = {
|
|
418
|
+
...strategyAttributes,
|
|
419
|
+
[Attributes.BLOCK_FULL]: analysis.analysis.blockBlobsFull ? 'true' : 'false',
|
|
420
|
+
};
|
|
421
|
+
this.fishermanEstimatedOverpayment.record(strategyResult.estimatedOverpaymentEth, overpaymentAttributes);
|
|
330
422
|
}
|
|
331
423
|
}
|
|
332
424
|
}
|
|
@@ -12,7 +12,7 @@ import type { DateProvider } from '@aztec/foundation/timer';
|
|
|
12
12
|
import type { TypedEventEmitter } from '@aztec/foundation/types';
|
|
13
13
|
import type { P2P } from '@aztec/p2p';
|
|
14
14
|
import type { SlasherClientInterface } from '@aztec/slasher';
|
|
15
|
-
import type {
|
|
15
|
+
import type { BlockData, L2BlockSink, L2BlockSource, ValidateCheckpointResult } from '@aztec/stdlib/block';
|
|
16
16
|
import type { Checkpoint } from '@aztec/stdlib/checkpoint';
|
|
17
17
|
import { getSlotAtTimestamp, getSlotStartBuildTimestamp } from '@aztec/stdlib/epoch-helpers';
|
|
18
18
|
import {
|
|
@@ -25,7 +25,7 @@ import type { L1ToL2MessageSource } from '@aztec/stdlib/messaging';
|
|
|
25
25
|
import { pickFromSchema } from '@aztec/stdlib/schemas';
|
|
26
26
|
import { MerkleTreeId } from '@aztec/stdlib/trees';
|
|
27
27
|
import { Attributes, type TelemetryClient, type Tracer, getTelemetryClient, trackSpan } from '@aztec/telemetry-client';
|
|
28
|
-
import { FullNodeCheckpointsBuilder, type ValidatorClient } from '@aztec/validator-client';
|
|
28
|
+
import { FullNodeCheckpointsBuilder, NodeKeystoreAdapter, type ValidatorClient } from '@aztec/validator-client';
|
|
29
29
|
|
|
30
30
|
import EventEmitter from 'node:events';
|
|
31
31
|
|
|
@@ -57,8 +57,11 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
57
57
|
private state = SequencerState.STOPPED;
|
|
58
58
|
private metrics: SequencerMetrics;
|
|
59
59
|
|
|
60
|
-
/** The last slot for which we attempted to
|
|
61
|
-
private
|
|
60
|
+
/** The last slot for which we attempted to perform our voting duties with degraded block production */
|
|
61
|
+
private lastSlotForFallbackVote: SlotNumber | undefined;
|
|
62
|
+
|
|
63
|
+
/** The last slot for which we logged "no committee" warning, to avoid spam */
|
|
64
|
+
private lastSlotForNoCommitteeWarning: SlotNumber | undefined;
|
|
62
65
|
|
|
63
66
|
/** The last slot for which we triggered a checkpoint proposal job, to prevent duplicate attempts. */
|
|
64
67
|
private lastSlotForCheckpointProposalJob: SlotNumber | undefined;
|
|
@@ -72,14 +75,6 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
72
75
|
/** The maximum number of seconds that the sequencer can be into a slot to transition to a particular state. */
|
|
73
76
|
protected timetable!: SequencerTimetable;
|
|
74
77
|
|
|
75
|
-
// This shouldn't be here as this gets re-created each time we build/propose a block.
|
|
76
|
-
// But we have a number of tests that abuse/rely on this class having a permanent publisher.
|
|
77
|
-
// As long as those tests only configure a single publisher they will continue to work.
|
|
78
|
-
// This will get re-assigned every time the sequencer goes to build a new block to a publisher that is valid
|
|
79
|
-
// for the block proposer.
|
|
80
|
-
// TODO(palla/mbps): Remove this field and fix tests
|
|
81
|
-
protected publisher: SequencerPublisher | undefined;
|
|
82
|
-
|
|
83
78
|
/** Config for the sequencer */
|
|
84
79
|
protected config: ResolvedSequencerConfig = DefaultSequencerConfig;
|
|
85
80
|
|
|
@@ -131,10 +126,9 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
131
126
|
);
|
|
132
127
|
}
|
|
133
128
|
|
|
134
|
-
/** Initializes the sequencer (precomputes tables
|
|
135
|
-
public
|
|
129
|
+
/** Initializes the sequencer (precomputes tables). Takes about 3s. */
|
|
130
|
+
public init() {
|
|
136
131
|
getKzg();
|
|
137
|
-
this.publisher = (await this.publisherFactory.create(undefined)).publisher;
|
|
138
132
|
}
|
|
139
133
|
|
|
140
134
|
/** Starts the sequencer and moves to IDLE state. */
|
|
@@ -153,7 +147,7 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
153
147
|
public async stop(): Promise<void> {
|
|
154
148
|
this.log.info(`Stopping sequencer`);
|
|
155
149
|
this.setState(SequencerState.STOPPING, undefined, { force: true });
|
|
156
|
-
this.
|
|
150
|
+
this.publisherFactory.interruptAll();
|
|
157
151
|
await this.runningPromise?.stop();
|
|
158
152
|
this.setState(SequencerState.STOPPED, undefined, { force: true });
|
|
159
153
|
this.log.info('Stopped sequencer');
|
|
@@ -166,7 +160,6 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
166
160
|
} catch (err) {
|
|
167
161
|
this.emit('checkpoint-error', { error: err as Error });
|
|
168
162
|
if (err instanceof SequencerTooSlowError) {
|
|
169
|
-
// TODO(palla/mbps): Add missing states
|
|
170
163
|
// Log as warn only if we had to abort halfway through the block proposal
|
|
171
164
|
const logLvl = [SequencerState.INITIALIZING_CHECKPOINT, SequencerState.PROPOSER_CHECK].includes(
|
|
172
165
|
err.proposedState,
|
|
@@ -202,7 +195,7 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
202
195
|
const { slot, ts, now, epoch } = this.epochCache.getEpochAndSlotInNextL1Slot();
|
|
203
196
|
|
|
204
197
|
// Check if we are synced and it's our slot, grab a publisher, check previous block invalidation, etc
|
|
205
|
-
const checkpointProposalJob = await this.prepareCheckpointProposal(slot, ts, now);
|
|
198
|
+
const checkpointProposalJob = await this.prepareCheckpointProposal(epoch, slot, ts, now);
|
|
206
199
|
if (!checkpointProposalJob) {
|
|
207
200
|
return;
|
|
208
201
|
}
|
|
@@ -234,6 +227,7 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
234
227
|
*/
|
|
235
228
|
@trackSpan('Sequencer.prepareCheckpointProposal')
|
|
236
229
|
private async prepareCheckpointProposal(
|
|
230
|
+
epoch: EpochNumber,
|
|
237
231
|
slot: SlotNumber,
|
|
238
232
|
ts: bigint,
|
|
239
233
|
now: bigint,
|
|
@@ -263,6 +257,25 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
263
257
|
return undefined;
|
|
264
258
|
}
|
|
265
259
|
|
|
260
|
+
// If escape hatch is open for this epoch, do not start checkpoint proposal work and do not attempt invalidations.
|
|
261
|
+
// Still perform governance/slashing voting (as proposer) once per slot.
|
|
262
|
+
const isEscapeHatchOpen = await this.epochCache.isEscapeHatchOpen(epoch);
|
|
263
|
+
|
|
264
|
+
if (isEscapeHatchOpen) {
|
|
265
|
+
this.setState(SequencerState.PROPOSER_CHECK, slot);
|
|
266
|
+
const [canPropose, proposer] = await this.checkCanPropose(slot);
|
|
267
|
+
if (canPropose) {
|
|
268
|
+
await this.tryVoteWhenEscapeHatchOpen({ slot, proposer });
|
|
269
|
+
} else {
|
|
270
|
+
this.log.trace(`Escape hatch open but we are not proposer, skipping vote-only actions`, {
|
|
271
|
+
slot,
|
|
272
|
+
epoch,
|
|
273
|
+
proposer,
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
return undefined;
|
|
277
|
+
}
|
|
278
|
+
|
|
266
279
|
// Next checkpoint follows from the last synced one
|
|
267
280
|
const checkpointNumber = CheckpointNumber(syncedTo.checkpointNumber + 1);
|
|
268
281
|
|
|
@@ -287,12 +300,12 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
287
300
|
}
|
|
288
301
|
|
|
289
302
|
// Check that the slot is not taken by a block already (should never happen, since only us can propose for this slot)
|
|
290
|
-
if (syncedTo.
|
|
303
|
+
if (syncedTo.blockData && syncedTo.blockData.header.getSlot() >= slot) {
|
|
291
304
|
this.log.warn(
|
|
292
305
|
`Cannot propose block at next L2 slot ${slot} since that slot was taken by block ${syncedTo.blockNumber}`,
|
|
293
|
-
{ ...logCtx, block: syncedTo.
|
|
306
|
+
{ ...logCtx, block: syncedTo.blockData.header.toInspect() },
|
|
294
307
|
);
|
|
295
|
-
this.metrics.
|
|
308
|
+
this.metrics.recordCheckpointPrecheckFailed('slot_already_taken');
|
|
296
309
|
return undefined;
|
|
297
310
|
}
|
|
298
311
|
|
|
@@ -303,7 +316,6 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
303
316
|
const proposerForPublisher = this.config.fishermanMode ? undefined : proposer;
|
|
304
317
|
const { attestorAddress, publisher } = await this.publisherFactory.create(proposerForPublisher);
|
|
305
318
|
this.log.verbose(`Created publisher at address ${publisher.getSenderAddress()} for attestor ${attestorAddress}`);
|
|
306
|
-
this.publisher = publisher;
|
|
307
319
|
|
|
308
320
|
// In fisherman mode, set the actual proposer's address for simulations
|
|
309
321
|
if (this.config.fishermanMode && proposer) {
|
|
@@ -328,7 +340,7 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
328
340
|
logCtx,
|
|
329
341
|
);
|
|
330
342
|
this.emit('proposer-rollup-check-failed', { reason: 'Rollup contract check failed', slot });
|
|
331
|
-
this.metrics.
|
|
343
|
+
this.metrics.recordCheckpointPrecheckFailed('rollup_contract_check_failed');
|
|
332
344
|
return undefined;
|
|
333
345
|
}
|
|
334
346
|
|
|
@@ -338,7 +350,7 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
338
350
|
{ ...logCtx, rollup: canProposeCheck, expectedSlot: slot },
|
|
339
351
|
);
|
|
340
352
|
this.emit('proposer-rollup-check-failed', { reason: 'Slot mismatch', slot });
|
|
341
|
-
this.metrics.
|
|
353
|
+
this.metrics.recordCheckpointPrecheckFailed('slot_mismatch');
|
|
342
354
|
return undefined;
|
|
343
355
|
}
|
|
344
356
|
|
|
@@ -348,15 +360,17 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
348
360
|
{ ...logCtx, rollup: canProposeCheck, expectedSlot: slot },
|
|
349
361
|
);
|
|
350
362
|
this.emit('proposer-rollup-check-failed', { reason: 'Block mismatch', slot });
|
|
351
|
-
this.metrics.
|
|
363
|
+
this.metrics.recordCheckpointPrecheckFailed('block_number_mismatch');
|
|
352
364
|
return undefined;
|
|
353
365
|
}
|
|
354
366
|
|
|
355
367
|
this.lastSlotForCheckpointProposalJob = slot;
|
|
368
|
+
await this.p2pClient.prepareForSlot(slot);
|
|
356
369
|
this.log.info(`Preparing checkpoint proposal ${checkpointNumber} at slot ${slot}`, { ...logCtx, proposer });
|
|
357
370
|
|
|
358
371
|
// Create and return the checkpoint proposal job
|
|
359
372
|
return this.createCheckpointProposalJob(
|
|
373
|
+
epoch,
|
|
360
374
|
slot,
|
|
361
375
|
checkpointNumber,
|
|
362
376
|
syncedTo.blockNumber,
|
|
@@ -368,6 +382,7 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
368
382
|
}
|
|
369
383
|
|
|
370
384
|
protected createCheckpointProposalJob(
|
|
385
|
+
epoch: EpochNumber,
|
|
371
386
|
slot: SlotNumber,
|
|
372
387
|
checkpointNumber: CheckpointNumber,
|
|
373
388
|
syncedToBlockNumber: BlockNumber,
|
|
@@ -377,6 +392,7 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
377
392
|
invalidateCheckpoint: InvalidateCheckpointRequest | undefined,
|
|
378
393
|
): CheckpointProposalJob {
|
|
379
394
|
return new CheckpointProposalJob(
|
|
395
|
+
epoch,
|
|
380
396
|
slot,
|
|
381
397
|
checkpointNumber,
|
|
382
398
|
syncedToBlockNumber,
|
|
@@ -389,6 +405,7 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
389
405
|
this.p2pClient,
|
|
390
406
|
this.worldState,
|
|
391
407
|
this.l1ToL2MessageSource,
|
|
408
|
+
this.l2BlockSource,
|
|
392
409
|
this.checkpointsBuilder,
|
|
393
410
|
this.l2BlockSource,
|
|
394
411
|
this.l1Constants,
|
|
@@ -400,11 +417,18 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
400
417
|
this.metrics,
|
|
401
418
|
this,
|
|
402
419
|
this.setState.bind(this),
|
|
403
|
-
this.log,
|
|
404
420
|
this.tracer,
|
|
421
|
+
this.log.getBindings(),
|
|
405
422
|
);
|
|
406
423
|
}
|
|
407
424
|
|
|
425
|
+
/**
|
|
426
|
+
* Returns the current sequencer state.
|
|
427
|
+
*/
|
|
428
|
+
public getState(): SequencerState {
|
|
429
|
+
return this.state;
|
|
430
|
+
}
|
|
431
|
+
|
|
408
432
|
/**
|
|
409
433
|
* Internal helper for setting the sequencer state and checks if we have enough time left in the slot to transition to the new state.
|
|
410
434
|
* @param proposedState - The new state to transition to.
|
|
@@ -505,18 +529,18 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
505
529
|
};
|
|
506
530
|
}
|
|
507
531
|
|
|
508
|
-
const
|
|
509
|
-
if (!
|
|
532
|
+
const blockData = await this.l2BlockSource.getBlockData(blockNumber);
|
|
533
|
+
if (!blockData) {
|
|
510
534
|
// this shouldn't really happen because a moment ago we checked that all components were in sync
|
|
511
|
-
this.log.error(`Failed to get L2 block ${blockNumber} from the archiver with all components in sync`);
|
|
535
|
+
this.log.error(`Failed to get L2 block data ${blockNumber} from the archiver with all components in sync`);
|
|
512
536
|
return undefined;
|
|
513
537
|
}
|
|
514
538
|
|
|
515
539
|
return {
|
|
516
|
-
|
|
517
|
-
blockNumber:
|
|
518
|
-
checkpointNumber:
|
|
519
|
-
archive:
|
|
540
|
+
blockData,
|
|
541
|
+
blockNumber: blockData.header.getBlockNumber(),
|
|
542
|
+
checkpointNumber: blockData.checkpointNumber,
|
|
543
|
+
archive: blockData.archive.root,
|
|
520
544
|
l1Timestamp,
|
|
521
545
|
pendingChainValidationStatus,
|
|
522
546
|
};
|
|
@@ -533,7 +557,10 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
533
557
|
proposer = await this.epochCache.getProposerAttesterAddressInSlot(slot);
|
|
534
558
|
} catch (e) {
|
|
535
559
|
if (e instanceof NoCommitteeError) {
|
|
536
|
-
this.
|
|
560
|
+
if (this.lastSlotForNoCommitteeWarning !== slot) {
|
|
561
|
+
this.lastSlotForNoCommitteeWarning = slot;
|
|
562
|
+
this.log.warn(`Cannot propose at next L2 slot ${slot} since the committee does not exist on L1`);
|
|
563
|
+
}
|
|
537
564
|
return [false, undefined];
|
|
538
565
|
}
|
|
539
566
|
this.log.error(`Error getting proposer for slot ${slot}`, e);
|
|
@@ -569,7 +596,7 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
569
596
|
const { slot } = args;
|
|
570
597
|
|
|
571
598
|
// Prevent duplicate attempts in the same slot
|
|
572
|
-
if (this.
|
|
599
|
+
if (this.lastSlotForFallbackVote === slot) {
|
|
573
600
|
this.log.trace(`Already attempted to vote in slot ${slot} (skipping)`);
|
|
574
601
|
return;
|
|
575
602
|
}
|
|
@@ -601,7 +628,7 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
601
628
|
}
|
|
602
629
|
|
|
603
630
|
// Mark this slot as attempted
|
|
604
|
-
this.
|
|
631
|
+
this.lastSlotForFallbackVote = slot;
|
|
605
632
|
|
|
606
633
|
// Get a publisher for voting
|
|
607
634
|
const { attestorAddress, publisher } = await this.publisherFactory.create(proposer);
|
|
@@ -636,7 +663,55 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
636
663
|
}
|
|
637
664
|
|
|
638
665
|
/**
|
|
639
|
-
*
|
|
666
|
+
* Tries to vote on slashing actions and governance proposals when escape hatch is open.
|
|
667
|
+
* This allows the sequencer to participate in voting without performing checkpoint proposal work.
|
|
668
|
+
*/
|
|
669
|
+
@trackSpan('Sequencer.tryVoteWhenEscapeHatchOpen', ({ slot }) => ({ [Attributes.SLOT_NUMBER]: slot }))
|
|
670
|
+
protected async tryVoteWhenEscapeHatchOpen(args: {
|
|
671
|
+
slot: SlotNumber;
|
|
672
|
+
proposer: EthAddress | undefined;
|
|
673
|
+
}): Promise<void> {
|
|
674
|
+
const { slot, proposer } = args;
|
|
675
|
+
|
|
676
|
+
// Prevent duplicate attempts in the same slot
|
|
677
|
+
if (this.lastSlotForFallbackVote === slot) {
|
|
678
|
+
this.log.trace(`Already attempted to vote in slot ${slot} (escape hatch open, skipping)`);
|
|
679
|
+
return;
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
// Mark this slot as attempted
|
|
683
|
+
this.lastSlotForFallbackVote = slot;
|
|
684
|
+
|
|
685
|
+
const { attestorAddress, publisher } = await this.publisherFactory.create(proposer);
|
|
686
|
+
|
|
687
|
+
this.log.debug(`Escape hatch open for slot ${slot}, attempting vote-only actions`, { slot, attestorAddress });
|
|
688
|
+
|
|
689
|
+
const voter = new CheckpointVoter(
|
|
690
|
+
slot,
|
|
691
|
+
publisher,
|
|
692
|
+
attestorAddress,
|
|
693
|
+
this.validatorClient,
|
|
694
|
+
this.slasherClient,
|
|
695
|
+
this.l1Constants,
|
|
696
|
+
this.config,
|
|
697
|
+
this.metrics,
|
|
698
|
+
this.log,
|
|
699
|
+
);
|
|
700
|
+
|
|
701
|
+
const votesPromises = voter.enqueueVotes();
|
|
702
|
+
const votes = await Promise.all(votesPromises);
|
|
703
|
+
|
|
704
|
+
if (votes.every(p => !p)) {
|
|
705
|
+
this.log.debug(`No votes to enqueue for slot ${slot} (escape hatch open)`);
|
|
706
|
+
return;
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
this.log.info(`Voting in slot ${slot} (escape hatch open)`, { slot });
|
|
710
|
+
await publisher.sendRequests();
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
/**
|
|
714
|
+
* Considers invalidating a block if the pending chain is invalid. Depends on how long the invalid block
|
|
640
715
|
* has been there without being invalidated and whether the sequencer is in the committee or not. We always
|
|
641
716
|
* have the proposer try to invalidate, but if they fail, the sequencers in the committee are expected to try,
|
|
642
717
|
* and if they fail, any sequencer will try as well.
|
|
@@ -788,6 +863,11 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
788
863
|
return this.validatorClient?.getValidatorAddresses();
|
|
789
864
|
}
|
|
790
865
|
|
|
866
|
+
/** Updates the publisher factory's node keystore adapter after a keystore reload. */
|
|
867
|
+
public updatePublisherNodeKeyStore(adapter: NodeKeystoreAdapter): void {
|
|
868
|
+
this.publisherFactory.updateNodeKeyStore(adapter);
|
|
869
|
+
}
|
|
870
|
+
|
|
791
871
|
public getConfig() {
|
|
792
872
|
return this.config;
|
|
793
873
|
}
|
|
@@ -798,7 +878,7 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
798
878
|
}
|
|
799
879
|
|
|
800
880
|
type SequencerSyncCheckResult = {
|
|
801
|
-
|
|
881
|
+
blockData?: BlockData;
|
|
802
882
|
checkpointNumber: CheckpointNumber;
|
|
803
883
|
blockNumber: BlockNumber;
|
|
804
884
|
archive: Fr;
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import { createLogger } from '@aztec/aztec.js/log';
|
|
2
|
+
import {
|
|
3
|
+
CHECKPOINT_ASSEMBLE_TIME,
|
|
4
|
+
CHECKPOINT_INITIALIZATION_TIME,
|
|
5
|
+
DEFAULT_P2P_PROPAGATION_TIME,
|
|
6
|
+
MIN_EXECUTION_TIME,
|
|
7
|
+
} from '@aztec/stdlib/timetable';
|
|
2
8
|
|
|
3
|
-
import { DEFAULT_ATTESTATION_PROPAGATION_TIME as DEFAULT_P2P_PROPAGATION_TIME } from '../config.js';
|
|
4
9
|
import { SequencerTooSlowError } from './errors.js';
|
|
5
10
|
import type { SequencerMetrics } from './metrics.js';
|
|
6
11
|
import { SequencerState } from './utils.js';
|
|
7
12
|
|
|
8
|
-
export const MIN_EXECUTION_TIME = 2;
|
|
9
|
-
export const CHECKPOINT_INITIALIZATION_TIME = 1;
|
|
10
|
-
export const CHECKPOINT_ASSEMBLE_TIME = 1;
|
|
11
|
-
|
|
12
13
|
export class SequencerTimetable {
|
|
13
14
|
/**
|
|
14
15
|
* How late into the slot can we be to start working. Computed as the total time needed for assembling and publishing a block,
|
package/src/test/index.ts
CHANGED
|
@@ -1,18 +1,16 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { L1TxUtils } from '@aztec/ethereum/l1-tx-utils';
|
|
2
2
|
import type { PublisherManager } from '@aztec/ethereum/publisher-manager';
|
|
3
3
|
import type { PublicProcessorFactory } from '@aztec/simulator/server';
|
|
4
4
|
import type { FullNodeCheckpointsBuilder, ValidatorClient } from '@aztec/validator-client';
|
|
5
5
|
|
|
6
6
|
import { SequencerClient } from '../client/sequencer-client.js';
|
|
7
7
|
import type { SequencerPublisherFactory } from '../publisher/sequencer-publisher-factory.js';
|
|
8
|
-
import type { SequencerPublisher } from '../publisher/sequencer-publisher.js';
|
|
9
8
|
import { Sequencer } from '../sequencer/sequencer.js';
|
|
10
9
|
import type { SequencerTimetable } from '../sequencer/timetable.js';
|
|
11
10
|
|
|
12
11
|
class TestSequencer_ extends Sequencer {
|
|
13
12
|
declare public publicProcessorFactory: PublicProcessorFactory;
|
|
14
13
|
declare public timetable: SequencerTimetable;
|
|
15
|
-
declare public publisher: SequencerPublisher;
|
|
16
14
|
declare public publisherFactory: SequencerPublisherFactory;
|
|
17
15
|
declare public validatorClient: ValidatorClient;
|
|
18
16
|
declare public checkpointsBuilder: FullNodeCheckpointsBuilder;
|
|
@@ -22,7 +20,7 @@ export type TestSequencer = TestSequencer_;
|
|
|
22
20
|
|
|
23
21
|
class TestSequencerClient_ extends SequencerClient {
|
|
24
22
|
declare public sequencer: TestSequencer;
|
|
25
|
-
declare public publisherManager: PublisherManager<
|
|
23
|
+
declare public publisherManager: PublisherManager<L1TxUtils>;
|
|
26
24
|
}
|
|
27
25
|
|
|
28
26
|
export type TestSequencerClient = TestSequencerClient_;
|