@aztec/sequencer-client 0.0.1-commit.0c875d939 → 0.0.1-commit.0ec55a70b
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 +17 -7
- package/dest/client/sequencer-client.d.ts.map +1 -1
- package/dest/client/sequencer-client.js +63 -30
- package/dest/config.d.ts +27 -6
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +55 -30
- package/dest/global_variable_builder/fee_predictor.d.ts +37 -0
- package/dest/global_variable_builder/fee_predictor.d.ts.map +1 -0
- package/dest/global_variable_builder/fee_predictor.js +128 -0
- package/dest/global_variable_builder/fee_provider.d.ts +21 -0
- package/dest/global_variable_builder/fee_provider.d.ts.map +1 -0
- package/dest/global_variable_builder/fee_provider.js +58 -0
- package/dest/global_variable_builder/global_builder.d.ts +15 -16
- package/dest/global_variable_builder/global_builder.d.ts.map +1 -1
- package/dest/global_variable_builder/global_builder.js +16 -50
- package/dest/global_variable_builder/index.d.ts +4 -2
- package/dest/global_variable_builder/index.d.ts.map +1 -1
- package/dest/global_variable_builder/index.js +2 -0
- package/dest/publisher/config.d.ts +47 -17
- package/dest/publisher/config.d.ts.map +1 -1
- package/dest/publisher/config.js +121 -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 +58 -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 -5
- package/dest/publisher/sequencer-publisher-factory.d.ts.map +1 -1
- package/dest/publisher/sequencer-publisher-factory.js +27 -3
- package/dest/publisher/sequencer-publisher.d.ts +68 -48
- package/dest/publisher/sequencer-publisher.d.ts.map +1 -1
- package/dest/publisher/sequencer-publisher.js +421 -137
- package/dest/sequencer/chain_state_overrides.d.ts +25 -0
- package/dest/sequencer/chain_state_overrides.d.ts.map +1 -0
- package/dest/sequencer/chain_state_overrides.js +39 -0
- package/dest/sequencer/checkpoint_proposal_job.d.ts +46 -10
- package/dest/sequencer/checkpoint_proposal_job.d.ts.map +1 -1
- package/dest/sequencer/checkpoint_proposal_job.js +700 -220
- package/dest/sequencer/checkpoint_proposal_job_metrics.d.ts +34 -0
- package/dest/sequencer/checkpoint_proposal_job_metrics.d.ts.map +1 -0
- package/dest/sequencer/checkpoint_proposal_job_metrics.js +72 -0
- package/dest/sequencer/checkpoint_voter.d.ts +1 -2
- package/dest/sequencer/checkpoint_voter.d.ts.map +1 -1
- package/dest/sequencer/checkpoint_voter.js +2 -5
- package/dest/sequencer/events.d.ts +7 -1
- package/dest/sequencer/events.d.ts.map +1 -1
- package/dest/sequencer/metrics.d.ts +20 -8
- package/dest/sequencer/metrics.d.ts.map +1 -1
- package/dest/sequencer/metrics.js +92 -21
- package/dest/sequencer/sequencer.d.ts +53 -19
- package/dest/sequencer/sequencer.d.ts.map +1 -1
- package/dest/sequencer/sequencer.js +188 -102
- package/dest/sequencer/timetable.d.ts +17 -3
- package/dest/sequencer/timetable.d.ts.map +1 -1
- package/dest/sequencer/timetable.js +51 -43
- package/dest/sequencer/types.d.ts +2 -2
- package/dest/sequencer/types.d.ts.map +1 -1
- 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 +7 -9
- package/dest/test/mock_checkpoint_builder.d.ts.map +1 -1
- package/dest/test/mock_checkpoint_builder.js +39 -30
- package/dest/test/utils.d.ts +1 -1
- package/dest/test/utils.d.ts.map +1 -1
- package/dest/test/utils.js +7 -6
- package/package.json +27 -28
- package/src/client/sequencer-client.ts +81 -30
- package/src/config.ts +68 -35
- package/src/global_variable_builder/README.md +44 -0
- package/src/global_variable_builder/fee_predictor.ts +172 -0
- package/src/global_variable_builder/fee_provider.ts +75 -0
- package/src/global_variable_builder/global_builder.ts +27 -63
- package/src/global_variable_builder/index.ts +3 -1
- package/src/publisher/config.ts +157 -45
- 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 +57 -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 +38 -9
- package/src/publisher/sequencer-publisher.ts +474 -197
- package/src/sequencer/README.md +82 -13
- package/src/sequencer/chain_state_overrides.ts +87 -0
- package/src/sequencer/checkpoint_proposal_job.ts +866 -241
- package/src/sequencer/checkpoint_proposal_job_metrics.ts +128 -0
- package/src/sequencer/checkpoint_voter.ts +1 -12
- package/src/sequencer/events.ts +6 -1
- package/src/sequencer/metrics.ts +108 -25
- package/src/sequencer/sequencer.ts +262 -116
- package/src/sequencer/timetable.ts +64 -52
- package/src/sequencer/types.ts +1 -1
- package/src/test/index.ts +2 -4
- package/src/test/mock_checkpoint_builder.ts +51 -48
- package/src/test/utils.ts +28 -10
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Attributes,
|
|
3
|
+
type Gauge,
|
|
4
|
+
type Histogram,
|
|
5
|
+
type Meter,
|
|
6
|
+
Metrics,
|
|
7
|
+
type TelemetryClient,
|
|
8
|
+
} from '@aztec/telemetry-client';
|
|
9
|
+
|
|
10
|
+
type CheckpointProposalJobInstruments = {
|
|
11
|
+
checkpointAttestationDelay: Histogram;
|
|
12
|
+
checkpointBuildDuration: Histogram;
|
|
13
|
+
checkpointStartToFirstBlockDuration: Histogram;
|
|
14
|
+
checkpointLastBlockToBroadcastDuration: Histogram;
|
|
15
|
+
pipelinedCheckpointBuildStartOffsetFromSlotBoundary: Histogram;
|
|
16
|
+
checkpointBlockCount: Gauge;
|
|
17
|
+
checkpointTxCount: Gauge;
|
|
18
|
+
checkpointTotalMana: Gauge;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Per-job recording surface used by {@link CheckpointProposalJob}.
|
|
23
|
+
*
|
|
24
|
+
* Ownership split:
|
|
25
|
+
* - {@link CheckpointProposalJobMetrics} owns the OpenTelemetry meter and instruments and should live for the
|
|
26
|
+
* lifetime of the sequencer process.
|
|
27
|
+
* - A recorder owns only mutable timing state for one checkpoint proposal job so overlapping jobs cannot
|
|
28
|
+
* overwrite each other's timing markers.
|
|
29
|
+
*/
|
|
30
|
+
export interface CheckpointProposalJobMetricsRecorder {
|
|
31
|
+
recordCheckpointAttestationDelay(durationMs: number): void;
|
|
32
|
+
recordCheckpointBuild(durationMs: number, blockCount: number, txCount: number, totalMana: number): void;
|
|
33
|
+
recordPipelinedCheckpointBuildStartOffsetFromSlotBoundary(offsetMs: number): void;
|
|
34
|
+
startCheckpointTiming(nowMs: number): void;
|
|
35
|
+
noteCheckpointBlockBuilt(nowMs: number, opts: { isFirstBlock: boolean; isLastBlock: boolean }): void;
|
|
36
|
+
noteCheckpointBroadcast(nowMs: number): void;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Concrete per-job recorder.
|
|
41
|
+
*
|
|
42
|
+
* This class should be short-lived: create one recorder per checkpoint proposal job and discard it when the job
|
|
43
|
+
* completes. It intentionally does not create instruments; it only holds the job-local timestamps needed to derive
|
|
44
|
+
* timing metrics safely.
|
|
45
|
+
*/
|
|
46
|
+
class CheckpointProposalJobMetricsRecorderImpl implements CheckpointProposalJobMetricsRecorder {
|
|
47
|
+
private checkpointStartedAt?: number;
|
|
48
|
+
private checkpointLastBlockBuiltAt?: number;
|
|
49
|
+
|
|
50
|
+
constructor(private readonly instruments: CheckpointProposalJobInstruments) {}
|
|
51
|
+
|
|
52
|
+
public recordCheckpointAttestationDelay(durationMs: number) {
|
|
53
|
+
this.instruments.checkpointAttestationDelay.record(Math.ceil(durationMs));
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
public recordCheckpointBuild(durationMs: number, blockCount: number, txCount: number, totalMana: number) {
|
|
57
|
+
this.instruments.checkpointBuildDuration.record(Math.ceil(durationMs));
|
|
58
|
+
this.instruments.checkpointBlockCount.record(blockCount);
|
|
59
|
+
this.instruments.checkpointTxCount.record(txCount);
|
|
60
|
+
this.instruments.checkpointTotalMana.record(totalMana);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
public recordPipelinedCheckpointBuildStartOffsetFromSlotBoundary(offsetMs: number) {
|
|
64
|
+
this.instruments.pipelinedCheckpointBuildStartOffsetFromSlotBoundary.record(Math.ceil(Math.abs(offsetMs)), {
|
|
65
|
+
[Attributes.SLOT_BOUNDARY_SIDE]: offsetMs < 0 ? 'before' : 'after',
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
public startCheckpointTiming(nowMs: number) {
|
|
70
|
+
this.checkpointStartedAt = nowMs;
|
|
71
|
+
this.checkpointLastBlockBuiltAt = undefined;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
public noteCheckpointBlockBuilt(nowMs: number, opts: { isFirstBlock: boolean; isLastBlock: boolean }) {
|
|
75
|
+
if (opts.isFirstBlock && this.checkpointStartedAt !== undefined) {
|
|
76
|
+
this.instruments.checkpointStartToFirstBlockDuration.record(Math.ceil(nowMs - this.checkpointStartedAt));
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (opts.isLastBlock) {
|
|
80
|
+
this.checkpointLastBlockBuiltAt = nowMs;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
public noteCheckpointBroadcast(nowMs: number) {
|
|
85
|
+
if (this.checkpointLastBlockBuiltAt !== undefined) {
|
|
86
|
+
this.instruments.checkpointLastBlockToBroadcastDuration.record(
|
|
87
|
+
Math.ceil(nowMs - this.checkpointLastBlockBuiltAt),
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
this.checkpointLastBlockBuiltAt = undefined;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Long-lived owner of checkpoint proposal job telemetry instruments.
|
|
97
|
+
*
|
|
98
|
+
* The sequencer should construct this once and reuse it across jobs. Each call to {@link createRecorder} returns a
|
|
99
|
+
* lightweight recorder with isolated mutable state for a single checkpoint proposal job.
|
|
100
|
+
*/
|
|
101
|
+
export class CheckpointProposalJobMetrics {
|
|
102
|
+
private readonly meter: Meter;
|
|
103
|
+
private readonly instruments: CheckpointProposalJobInstruments;
|
|
104
|
+
|
|
105
|
+
constructor(client: TelemetryClient, name = 'CheckpointProposalJob') {
|
|
106
|
+
this.meter = client.getMeter(name);
|
|
107
|
+
this.instruments = {
|
|
108
|
+
checkpointAttestationDelay: this.meter.createHistogram(Metrics.SEQUENCER_CHECKPOINT_ATTESTATION_DELAY),
|
|
109
|
+
checkpointBuildDuration: this.meter.createHistogram(Metrics.SEQUENCER_CHECKPOINT_BUILD_DURATION),
|
|
110
|
+
checkpointStartToFirstBlockDuration: this.meter.createHistogram(
|
|
111
|
+
Metrics.SEQUENCER_CHECKPOINT_START_TO_FIRST_BLOCK_DURATION,
|
|
112
|
+
),
|
|
113
|
+
checkpointLastBlockToBroadcastDuration: this.meter.createHistogram(
|
|
114
|
+
Metrics.SEQUENCER_CHECKPOINT_LAST_BLOCK_TO_BROADCAST_DURATION,
|
|
115
|
+
),
|
|
116
|
+
pipelinedCheckpointBuildStartOffsetFromSlotBoundary: this.meter.createHistogram(
|
|
117
|
+
Metrics.SEQUENCER_PIPELINED_CHECKPOINT_BUILD_START_OFFSET_FROM_SLOT_BOUNDARY,
|
|
118
|
+
),
|
|
119
|
+
checkpointBlockCount: this.meter.createGauge(Metrics.SEQUENCER_CHECKPOINT_BLOCK_COUNT),
|
|
120
|
+
checkpointTxCount: this.meter.createGauge(Metrics.SEQUENCER_CHECKPOINT_TX_COUNT),
|
|
121
|
+
checkpointTotalMana: this.meter.createGauge(Metrics.SEQUENCER_CHECKPOINT_TOTAL_MANA),
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
public createRecorder(): CheckpointProposalJobMetricsRecorder {
|
|
126
|
+
return new CheckpointProposalJobMetricsRecorderImpl(this.instruments);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
@@ -2,7 +2,6 @@ import type { SlotNumber } from '@aztec/foundation/branded-types';
|
|
|
2
2
|
import type { EthAddress } from '@aztec/foundation/eth-address';
|
|
3
3
|
import type { Logger } from '@aztec/foundation/log';
|
|
4
4
|
import type { SlasherClientInterface } from '@aztec/slasher';
|
|
5
|
-
import { getTimestampForSlot } from '@aztec/stdlib/epoch-helpers';
|
|
6
5
|
import type { ResolvedSequencerConfig } from '@aztec/stdlib/interfaces/server';
|
|
7
6
|
import type { ValidatorClient } from '@aztec/validator-client';
|
|
8
7
|
import { DutyAlreadySignedError } from '@aztec/validator-ha-signer/errors';
|
|
@@ -18,7 +17,6 @@ import type { SequencerRollupConstants } from './types.js';
|
|
|
18
17
|
* Handles governance and slashing voting for a given slot.
|
|
19
18
|
*/
|
|
20
19
|
export class CheckpointVoter {
|
|
21
|
-
private slotTimestamp: bigint;
|
|
22
20
|
private governanceSigner: (msg: TypedDataDefinition) => Promise<`0x${string}`>;
|
|
23
21
|
private slashingSigner: (msg: TypedDataDefinition) => Promise<`0x${string}`>;
|
|
24
22
|
|
|
@@ -33,8 +31,6 @@ export class CheckpointVoter {
|
|
|
33
31
|
private readonly metrics: SequencerMetrics,
|
|
34
32
|
private readonly log: Logger,
|
|
35
33
|
) {
|
|
36
|
-
this.slotTimestamp = getTimestampForSlot(this.slot, this.l1Constants);
|
|
37
|
-
|
|
38
34
|
// Create separate signers with appropriate duty contexts for governance and slashing votes
|
|
39
35
|
// These use HA protection to ensure only one node signs per slot/duty
|
|
40
36
|
const governanceContext: SigningContext = { slot: this.slot, dutyType: DutyType.GOVERNANCE_VOTE };
|
|
@@ -77,7 +73,6 @@ export class CheckpointVoter {
|
|
|
77
73
|
return await this.publisher.enqueueGovernanceCastSignal(
|
|
78
74
|
governanceProposerPayload,
|
|
79
75
|
this.slot,
|
|
80
|
-
this.slotTimestamp,
|
|
81
76
|
this.attestorAddress,
|
|
82
77
|
this.governanceSigner,
|
|
83
78
|
);
|
|
@@ -108,13 +103,7 @@ export class CheckpointVoter {
|
|
|
108
103
|
|
|
109
104
|
this.metrics.recordSlashingAttempt(actions.length);
|
|
110
105
|
|
|
111
|
-
return await this.publisher.enqueueSlashingActions(
|
|
112
|
-
actions,
|
|
113
|
-
this.slot,
|
|
114
|
-
this.slotTimestamp,
|
|
115
|
-
this.attestorAddress,
|
|
116
|
-
this.slashingSigner,
|
|
117
|
-
);
|
|
106
|
+
return await this.publisher.enqueueSlashingActions(actions, this.slot, this.attestorAddress, this.slashingSigner);
|
|
118
107
|
} catch (err) {
|
|
119
108
|
if (err instanceof DutyAlreadySignedError) {
|
|
120
109
|
this.log.info(`Slashing vote already signed by another node`, {
|
package/src/sequencer/events.ts
CHANGED
|
@@ -13,7 +13,7 @@ export type SequencerEvents = {
|
|
|
13
13
|
['proposer-rollup-check-failed']: (args: { reason: string; slot: SlotNumber }) => void;
|
|
14
14
|
['block-tx-count-check-failed']: (args: { minTxs: number; availableTxs: number; slot: SlotNumber }) => void;
|
|
15
15
|
['block-build-failed']: (args: { reason: string; slot: SlotNumber }) => void;
|
|
16
|
-
['block-proposed']: (args: { blockNumber: BlockNumber; slot: SlotNumber }) => void;
|
|
16
|
+
['block-proposed']: (args: { blockNumber: BlockNumber; slot: SlotNumber; buildSlot: SlotNumber }) => void;
|
|
17
17
|
['checkpoint-empty']: (args: { slot: SlotNumber }) => void;
|
|
18
18
|
['checkpoint-publish-failed']: (args: {
|
|
19
19
|
slot: SlotNumber;
|
|
@@ -24,4 +24,9 @@ export type SequencerEvents = {
|
|
|
24
24
|
}) => void;
|
|
25
25
|
['checkpoint-published']: (args: { checkpoint: CheckpointNumber; slot: SlotNumber }) => void;
|
|
26
26
|
['checkpoint-error']: (args: { error: Error }) => void;
|
|
27
|
+
['pipelined-checkpoint-discarded']: (args: {
|
|
28
|
+
slot: SlotNumber;
|
|
29
|
+
checkpointNumber: CheckpointNumber;
|
|
30
|
+
reason: string;
|
|
31
|
+
}) => void;
|
|
27
32
|
};
|
package/src/sequencer/metrics.ts
CHANGED
|
@@ -18,7 +18,6 @@ import { type Hex, formatUnits } from 'viem';
|
|
|
18
18
|
|
|
19
19
|
import type { SequencerState } from './utils.js';
|
|
20
20
|
|
|
21
|
-
// TODO(palla/mbps): Review all metrics and add any missing ones per checkpoint
|
|
22
21
|
export class SequencerMetrics {
|
|
23
22
|
public readonly tracer: Tracer;
|
|
24
23
|
private meter: Meter;
|
|
@@ -27,6 +26,7 @@ export class SequencerMetrics {
|
|
|
27
26
|
private blockBuildDuration: Histogram;
|
|
28
27
|
private blockBuildManaPerSecond: Gauge;
|
|
29
28
|
private stateTransitionBufferDuration: Histogram;
|
|
29
|
+
private stateDuration: Histogram;
|
|
30
30
|
|
|
31
31
|
// these are gauges because for individual sequencers building a block is not something that happens often enough to warrant a histogram
|
|
32
32
|
private timeToCollectAttestations: Gauge;
|
|
@@ -40,11 +40,14 @@ export class SequencerMetrics {
|
|
|
40
40
|
private filledSlots: UpDownCounter;
|
|
41
41
|
|
|
42
42
|
private blockProposalFailed: UpDownCounter;
|
|
43
|
-
private
|
|
44
|
-
private
|
|
43
|
+
private checkpointProposalSuccess: UpDownCounter;
|
|
44
|
+
private checkpointPrecheckFailed: UpDownCounter;
|
|
45
|
+
private checkpointProposalFailed: UpDownCounter;
|
|
45
46
|
private checkpointSuccess: UpDownCounter;
|
|
46
47
|
private slashingAttempts: UpDownCounter;
|
|
47
|
-
private
|
|
48
|
+
private pipelineDepth: Gauge;
|
|
49
|
+
private pipelineDiscards: UpDownCounter;
|
|
50
|
+
private pipelineParentCheckpointMismatches: UpDownCounter;
|
|
48
51
|
|
|
49
52
|
// Fisherman fee analysis metrics
|
|
50
53
|
private fishermanWouldBeIncluded: UpDownCounter;
|
|
@@ -54,6 +57,7 @@ export class SequencerMetrics {
|
|
|
54
57
|
private fishermanPendingBlobCount: Histogram;
|
|
55
58
|
private fishermanIncludedBlobCount: Histogram;
|
|
56
59
|
private fishermanBlockBlobsFull: UpDownCounter;
|
|
60
|
+
private fishermanMaxBlobCapacity: Histogram;
|
|
57
61
|
private fishermanCalculatedPriorityFee: Histogram;
|
|
58
62
|
private fishermanPriorityFeeDelta: Histogram;
|
|
59
63
|
private fishermanEstimatedCost: Histogram;
|
|
@@ -61,6 +65,10 @@ export class SequencerMetrics {
|
|
|
61
65
|
private fishermanMinedBlobTxPriorityFee: Histogram;
|
|
62
66
|
private fishermanMinedBlobTxTotalCost: Histogram;
|
|
63
67
|
|
|
68
|
+
private blockInterBlockTime: Histogram;
|
|
69
|
+
private lastBlockBuiltTimestamp?: number;
|
|
70
|
+
private lastBlockBuiltSlot?: SlotNumber;
|
|
71
|
+
|
|
64
72
|
private lastSeenSlot?: SlotNumber;
|
|
65
73
|
|
|
66
74
|
constructor(
|
|
@@ -79,11 +87,13 @@ export class SequencerMetrics {
|
|
|
79
87
|
|
|
80
88
|
this.blockBuildManaPerSecond = this.meter.createGauge(Metrics.SEQUENCER_BLOCK_BUILD_MANA_PER_SECOND);
|
|
81
89
|
|
|
90
|
+
this.blockInterBlockTime = this.meter.createHistogram(Metrics.SEQUENCER_BLOCK_INTER_BLOCK_TIME);
|
|
91
|
+
|
|
82
92
|
this.stateTransitionBufferDuration = this.meter.createHistogram(Metrics.SEQUENCER_STATE_TRANSITION_BUFFER_DURATION);
|
|
83
93
|
|
|
84
|
-
this.
|
|
94
|
+
this.stateDuration = this.meter.createHistogram(Metrics.SEQUENCER_STATE_DURATION);
|
|
85
95
|
|
|
86
|
-
this.rewards = this.meter.createGauge(Metrics.
|
|
96
|
+
this.rewards = this.meter.createGauge(Metrics.SEQUENCER_CURRENT_SLOT_REWARDS);
|
|
87
97
|
|
|
88
98
|
this.slots = createUpDownCounterWithDefault(this.meter, Metrics.SEQUENCER_SLOT_COUNT);
|
|
89
99
|
|
|
@@ -106,16 +116,16 @@ export class SequencerMetrics {
|
|
|
106
116
|
Metrics.SEQUENCER_BLOCK_PROPOSAL_FAILED_COUNT,
|
|
107
117
|
);
|
|
108
118
|
|
|
109
|
-
this.
|
|
119
|
+
this.checkpointProposalSuccess = createUpDownCounterWithDefault(
|
|
110
120
|
this.meter,
|
|
111
|
-
Metrics.
|
|
121
|
+
Metrics.SEQUENCER_CHECKPOINT_PROPOSAL_SUCCESS_COUNT,
|
|
112
122
|
);
|
|
113
123
|
|
|
114
124
|
this.checkpointSuccess = createUpDownCounterWithDefault(this.meter, Metrics.SEQUENCER_CHECKPOINT_SUCCESS_COUNT);
|
|
115
125
|
|
|
116
|
-
this.
|
|
126
|
+
this.checkpointPrecheckFailed = createUpDownCounterWithDefault(
|
|
117
127
|
this.meter,
|
|
118
|
-
Metrics.
|
|
128
|
+
Metrics.SEQUENCER_CHECKPOINT_PRECHECK_FAILED_COUNT,
|
|
119
129
|
{
|
|
120
130
|
[Attributes.ERROR_TYPE]: [
|
|
121
131
|
'slot_already_taken',
|
|
@@ -126,14 +136,37 @@ export class SequencerMetrics {
|
|
|
126
136
|
},
|
|
127
137
|
);
|
|
128
138
|
|
|
139
|
+
this.checkpointProposalFailed = createUpDownCounterWithDefault(
|
|
140
|
+
this.meter,
|
|
141
|
+
Metrics.SEQUENCER_CHECKPOINT_PROPOSAL_FAILED_COUNT,
|
|
142
|
+
);
|
|
143
|
+
|
|
129
144
|
this.slashingAttempts = createUpDownCounterWithDefault(this.meter, Metrics.SEQUENCER_SLASHING_ATTEMPTS_COUNT);
|
|
130
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
|
+
|
|
131
163
|
// Fisherman fee analysis metrics
|
|
132
164
|
this.fishermanWouldBeIncluded = createUpDownCounterWithDefault(
|
|
133
165
|
this.meter,
|
|
134
166
|
Metrics.FISHERMAN_FEE_ANALYSIS_WOULD_BE_INCLUDED,
|
|
135
167
|
{
|
|
136
168
|
[Attributes.OK]: [true, false],
|
|
169
|
+
[Attributes.BLOCK_FULL]: ['true', 'false'],
|
|
137
170
|
},
|
|
138
171
|
);
|
|
139
172
|
|
|
@@ -176,6 +209,8 @@ export class SequencerMetrics {
|
|
|
176
209
|
[Attributes.OK]: [true, false],
|
|
177
210
|
},
|
|
178
211
|
);
|
|
212
|
+
|
|
213
|
+
this.fishermanMaxBlobCapacity = this.meter.createHistogram(Metrics.FISHERMAN_FEE_ANALYSIS_MAX_BLOB_CAPACITY);
|
|
179
214
|
}
|
|
180
215
|
|
|
181
216
|
public recordRequiredAttestations(requiredAttestationsCount: number, allowanceMs: number) {
|
|
@@ -187,21 +222,25 @@ export class SequencerMetrics {
|
|
|
187
222
|
this.timeToCollectAttestations.record(0);
|
|
188
223
|
}
|
|
189
224
|
|
|
190
|
-
public recordCheckpointAttestationDelay(duration: number) {
|
|
191
|
-
this.checkpointAttestationDelay.record(duration);
|
|
192
|
-
}
|
|
193
|
-
|
|
194
225
|
public recordCollectedAttestations(count: number, durationMs: number) {
|
|
195
226
|
this.collectedAttestions.record(count);
|
|
196
227
|
this.timeToCollectAttestations.record(Math.ceil(durationMs));
|
|
197
228
|
}
|
|
198
229
|
|
|
199
|
-
recordBuiltBlock(buildDurationMs: number, totalMana: number) {
|
|
230
|
+
recordBuiltBlock(buildDurationMs: number, totalMana: number, slot: SlotNumber) {
|
|
200
231
|
this.blockCounter.add(1, {
|
|
201
232
|
[Attributes.STATUS]: 'built',
|
|
202
233
|
});
|
|
203
234
|
this.blockBuildDuration.record(Math.ceil(buildDurationMs));
|
|
204
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;
|
|
205
244
|
}
|
|
206
245
|
|
|
207
246
|
recordFailedBlock() {
|
|
@@ -216,6 +255,26 @@ export class SequencerMetrics {
|
|
|
216
255
|
});
|
|
217
256
|
}
|
|
218
257
|
|
|
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
|
+
|
|
219
278
|
incOpenSlot(slot: SlotNumber, proposer: string) {
|
|
220
279
|
// sequencer went through the loop a second time. Noop
|
|
221
280
|
if (slot === this.lastSeenSlot) {
|
|
@@ -258,15 +317,19 @@ export class SequencerMetrics {
|
|
|
258
317
|
});
|
|
259
318
|
}
|
|
260
319
|
|
|
261
|
-
|
|
262
|
-
this.
|
|
320
|
+
recordCheckpointProposalSuccess() {
|
|
321
|
+
this.checkpointProposalSuccess.add(1);
|
|
263
322
|
}
|
|
264
323
|
|
|
265
|
-
|
|
324
|
+
recordCheckpointPrecheckFailed(
|
|
266
325
|
checkType: 'slot_already_taken' | 'rollup_contract_check_failed' | 'slot_mismatch' | 'block_number_mismatch',
|
|
267
326
|
) {
|
|
268
|
-
this.
|
|
269
|
-
|
|
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 }),
|
|
270
333
|
});
|
|
271
334
|
}
|
|
272
335
|
|
|
@@ -342,13 +405,21 @@ export class SequencerMetrics {
|
|
|
342
405
|
this.fishermanBlockBlobsFull.add(1, { ...strategyAttributes, [Attributes.OK]: false });
|
|
343
406
|
}
|
|
344
407
|
|
|
408
|
+
// Record the max blob capacity for this block
|
|
409
|
+
this.fishermanMaxBlobCapacity.record(analysis.analysis.maxBlobCapacity, strategyAttributes);
|
|
410
|
+
|
|
345
411
|
// Record strategy-specific inclusion result
|
|
346
412
|
if (strategyResult.wouldBeIncluded !== undefined) {
|
|
413
|
+
const inclusionAttributes = {
|
|
414
|
+
...strategyAttributes,
|
|
415
|
+
[Attributes.BLOCK_FULL]: analysis.analysis.blockBlobsFull ? 'true' : 'false',
|
|
416
|
+
};
|
|
417
|
+
|
|
347
418
|
if (strategyResult.wouldBeIncluded) {
|
|
348
|
-
this.fishermanWouldBeIncluded.add(1, { ...
|
|
419
|
+
this.fishermanWouldBeIncluded.add(1, { ...inclusionAttributes, [Attributes.OK]: true });
|
|
349
420
|
} else {
|
|
350
421
|
this.fishermanWouldBeIncluded.add(1, {
|
|
351
|
-
...
|
|
422
|
+
...inclusionAttributes,
|
|
352
423
|
[Attributes.OK]: false,
|
|
353
424
|
...(strategyResult.exclusionReason && { [Attributes.ERROR_TYPE]: strategyResult.exclusionReason }),
|
|
354
425
|
});
|
|
@@ -358,17 +429,29 @@ export class SequencerMetrics {
|
|
|
358
429
|
// Record strategy-specific priority fee delta
|
|
359
430
|
if (strategyResult.priorityFeeDelta !== undefined) {
|
|
360
431
|
const priorityFeeDeltaGwei = Number(strategyResult.priorityFeeDelta) / 1e9;
|
|
361
|
-
|
|
432
|
+
const deltaAttributes = {
|
|
433
|
+
...strategyAttributes,
|
|
434
|
+
[Attributes.BLOCK_FULL]: analysis.analysis.blockBlobsFull ? 'true' : 'false',
|
|
435
|
+
};
|
|
436
|
+
this.fishermanPriorityFeeDelta.record(priorityFeeDeltaGwei, deltaAttributes);
|
|
362
437
|
}
|
|
363
438
|
|
|
364
439
|
// Record estimated cost if available
|
|
365
440
|
if (strategyResult.estimatedCostEth !== undefined) {
|
|
366
|
-
|
|
441
|
+
const costAttributes = {
|
|
442
|
+
...strategyAttributes,
|
|
443
|
+
[Attributes.BLOCK_FULL]: analysis.analysis.blockBlobsFull ? 'true' : 'false',
|
|
444
|
+
};
|
|
445
|
+
this.fishermanEstimatedCost.record(strategyResult.estimatedCostEth, costAttributes);
|
|
367
446
|
}
|
|
368
447
|
|
|
369
448
|
// Record estimated overpayment if available
|
|
370
449
|
if (strategyResult.estimatedOverpaymentEth !== undefined) {
|
|
371
|
-
|
|
450
|
+
const overpaymentAttributes = {
|
|
451
|
+
...strategyAttributes,
|
|
452
|
+
[Attributes.BLOCK_FULL]: analysis.analysis.blockBlobsFull ? 'true' : 'false',
|
|
453
|
+
};
|
|
454
|
+
this.fishermanEstimatedOverpayment.record(strategyResult.estimatedOverpaymentEth, overpaymentAttributes);
|
|
372
455
|
}
|
|
373
456
|
}
|
|
374
457
|
}
|