@aztec/sequencer-client 0.0.1-commit.0c875d939 → 0.0.1-commit.0dc957cde
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 +26 -6
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +49 -29
- 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 +419 -135
- 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 +40 -10
- package/dest/sequencer/checkpoint_proposal_job.d.ts.map +1 -1
- package/dest/sequencer/checkpoint_proposal_job.js +522 -212
- 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 +18 -8
- package/dest/sequencer/metrics.d.ts.map +1 -1
- package/dest/sequencer/metrics.js +85 -21
- package/dest/sequencer/sequencer.d.ts +43 -17
- package/dest/sequencer/sequencer.d.ts.map +1 -1
- package/dest/sequencer/sequencer.js +158 -97
- 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/package.json +27 -28
- package/src/client/sequencer-client.ts +81 -30
- package/src/config.ts +61 -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 +472 -193
- package/src/sequencer/README.md +83 -13
- package/src/sequencer/chain_state_overrides.ts +87 -0
- package/src/sequencer/checkpoint_proposal_job.ts +665 -234
- 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 +100 -26
- package/src/sequencer/sequencer.ts +227 -109
- 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
|
@@ -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;
|
|
@@ -40,11 +39,14 @@ export class SequencerMetrics {
|
|
|
40
39
|
private filledSlots: UpDownCounter;
|
|
41
40
|
|
|
42
41
|
private blockProposalFailed: UpDownCounter;
|
|
43
|
-
private
|
|
44
|
-
private
|
|
42
|
+
private checkpointProposalSuccess: UpDownCounter;
|
|
43
|
+
private checkpointPrecheckFailed: UpDownCounter;
|
|
44
|
+
private checkpointProposalFailed: UpDownCounter;
|
|
45
45
|
private checkpointSuccess: UpDownCounter;
|
|
46
46
|
private slashingAttempts: UpDownCounter;
|
|
47
|
-
private
|
|
47
|
+
private pipelineDepth: Gauge;
|
|
48
|
+
private pipelineDiscards: UpDownCounter;
|
|
49
|
+
private pipelineParentCheckpointMismatches: UpDownCounter;
|
|
48
50
|
|
|
49
51
|
// Fisherman fee analysis metrics
|
|
50
52
|
private fishermanWouldBeIncluded: UpDownCounter;
|
|
@@ -54,6 +56,7 @@ export class SequencerMetrics {
|
|
|
54
56
|
private fishermanPendingBlobCount: Histogram;
|
|
55
57
|
private fishermanIncludedBlobCount: Histogram;
|
|
56
58
|
private fishermanBlockBlobsFull: UpDownCounter;
|
|
59
|
+
private fishermanMaxBlobCapacity: Histogram;
|
|
57
60
|
private fishermanCalculatedPriorityFee: Histogram;
|
|
58
61
|
private fishermanPriorityFeeDelta: Histogram;
|
|
59
62
|
private fishermanEstimatedCost: Histogram;
|
|
@@ -61,6 +64,10 @@ export class SequencerMetrics {
|
|
|
61
64
|
private fishermanMinedBlobTxPriorityFee: Histogram;
|
|
62
65
|
private fishermanMinedBlobTxTotalCost: Histogram;
|
|
63
66
|
|
|
67
|
+
private blockInterBlockTime: Histogram;
|
|
68
|
+
private lastBlockBuiltTimestamp?: number;
|
|
69
|
+
private lastBlockBuiltSlot?: SlotNumber;
|
|
70
|
+
|
|
64
71
|
private lastSeenSlot?: SlotNumber;
|
|
65
72
|
|
|
66
73
|
constructor(
|
|
@@ -79,11 +86,11 @@ export class SequencerMetrics {
|
|
|
79
86
|
|
|
80
87
|
this.blockBuildManaPerSecond = this.meter.createGauge(Metrics.SEQUENCER_BLOCK_BUILD_MANA_PER_SECOND);
|
|
81
88
|
|
|
82
|
-
this.
|
|
89
|
+
this.blockInterBlockTime = this.meter.createHistogram(Metrics.SEQUENCER_BLOCK_INTER_BLOCK_TIME);
|
|
83
90
|
|
|
84
|
-
this.
|
|
91
|
+
this.stateTransitionBufferDuration = this.meter.createHistogram(Metrics.SEQUENCER_STATE_TRANSITION_BUFFER_DURATION);
|
|
85
92
|
|
|
86
|
-
this.rewards = this.meter.createGauge(Metrics.
|
|
93
|
+
this.rewards = this.meter.createGauge(Metrics.SEQUENCER_CURRENT_SLOT_REWARDS);
|
|
87
94
|
|
|
88
95
|
this.slots = createUpDownCounterWithDefault(this.meter, Metrics.SEQUENCER_SLOT_COUNT);
|
|
89
96
|
|
|
@@ -106,16 +113,16 @@ export class SequencerMetrics {
|
|
|
106
113
|
Metrics.SEQUENCER_BLOCK_PROPOSAL_FAILED_COUNT,
|
|
107
114
|
);
|
|
108
115
|
|
|
109
|
-
this.
|
|
116
|
+
this.checkpointProposalSuccess = createUpDownCounterWithDefault(
|
|
110
117
|
this.meter,
|
|
111
|
-
Metrics.
|
|
118
|
+
Metrics.SEQUENCER_CHECKPOINT_PROPOSAL_SUCCESS_COUNT,
|
|
112
119
|
);
|
|
113
120
|
|
|
114
121
|
this.checkpointSuccess = createUpDownCounterWithDefault(this.meter, Metrics.SEQUENCER_CHECKPOINT_SUCCESS_COUNT);
|
|
115
122
|
|
|
116
|
-
this.
|
|
123
|
+
this.checkpointPrecheckFailed = createUpDownCounterWithDefault(
|
|
117
124
|
this.meter,
|
|
118
|
-
Metrics.
|
|
125
|
+
Metrics.SEQUENCER_CHECKPOINT_PRECHECK_FAILED_COUNT,
|
|
119
126
|
{
|
|
120
127
|
[Attributes.ERROR_TYPE]: [
|
|
121
128
|
'slot_already_taken',
|
|
@@ -126,14 +133,37 @@ export class SequencerMetrics {
|
|
|
126
133
|
},
|
|
127
134
|
);
|
|
128
135
|
|
|
136
|
+
this.checkpointProposalFailed = createUpDownCounterWithDefault(
|
|
137
|
+
this.meter,
|
|
138
|
+
Metrics.SEQUENCER_CHECKPOINT_PROPOSAL_FAILED_COUNT,
|
|
139
|
+
);
|
|
140
|
+
|
|
129
141
|
this.slashingAttempts = createUpDownCounterWithDefault(this.meter, Metrics.SEQUENCER_SLASHING_ATTEMPTS_COUNT);
|
|
130
142
|
|
|
143
|
+
this.pipelineDepth = this.meter.createGauge(Metrics.SEQUENCER_PIPELINE_DEPTH);
|
|
144
|
+
this.pipelineDiscards = createUpDownCounterWithDefault(this.meter, Metrics.SEQUENCER_PIPELINE_DISCARDS_COUNT);
|
|
145
|
+
this.pipelineParentCheckpointMismatches = createUpDownCounterWithDefault(
|
|
146
|
+
this.meter,
|
|
147
|
+
Metrics.SEQUENCER_PIPELINE_PARENT_CHECKPOINT_MISMATCH_COUNT,
|
|
148
|
+
{
|
|
149
|
+
[Attributes.ERROR_TYPE]: [
|
|
150
|
+
'archiver-sync-timeout',
|
|
151
|
+
'parent-not-on-l1',
|
|
152
|
+
'parent-hash-mismatch',
|
|
153
|
+
'parent-invalid-attestations',
|
|
154
|
+
'unexpected-parent-appeared',
|
|
155
|
+
],
|
|
156
|
+
},
|
|
157
|
+
);
|
|
158
|
+
this.pipelineDepth.record(0);
|
|
159
|
+
|
|
131
160
|
// Fisherman fee analysis metrics
|
|
132
161
|
this.fishermanWouldBeIncluded = createUpDownCounterWithDefault(
|
|
133
162
|
this.meter,
|
|
134
163
|
Metrics.FISHERMAN_FEE_ANALYSIS_WOULD_BE_INCLUDED,
|
|
135
164
|
{
|
|
136
165
|
[Attributes.OK]: [true, false],
|
|
166
|
+
[Attributes.BLOCK_FULL]: ['true', 'false'],
|
|
137
167
|
},
|
|
138
168
|
);
|
|
139
169
|
|
|
@@ -176,6 +206,8 @@ export class SequencerMetrics {
|
|
|
176
206
|
[Attributes.OK]: [true, false],
|
|
177
207
|
},
|
|
178
208
|
);
|
|
209
|
+
|
|
210
|
+
this.fishermanMaxBlobCapacity = this.meter.createHistogram(Metrics.FISHERMAN_FEE_ANALYSIS_MAX_BLOB_CAPACITY);
|
|
179
211
|
}
|
|
180
212
|
|
|
181
213
|
public recordRequiredAttestations(requiredAttestationsCount: number, allowanceMs: number) {
|
|
@@ -187,21 +219,25 @@ export class SequencerMetrics {
|
|
|
187
219
|
this.timeToCollectAttestations.record(0);
|
|
188
220
|
}
|
|
189
221
|
|
|
190
|
-
public recordCheckpointAttestationDelay(duration: number) {
|
|
191
|
-
this.checkpointAttestationDelay.record(duration);
|
|
192
|
-
}
|
|
193
|
-
|
|
194
222
|
public recordCollectedAttestations(count: number, durationMs: number) {
|
|
195
223
|
this.collectedAttestions.record(count);
|
|
196
224
|
this.timeToCollectAttestations.record(Math.ceil(durationMs));
|
|
197
225
|
}
|
|
198
226
|
|
|
199
|
-
recordBuiltBlock(buildDurationMs: number, totalMana: number) {
|
|
227
|
+
recordBuiltBlock(buildDurationMs: number, totalMana: number, slot: SlotNumber) {
|
|
200
228
|
this.blockCounter.add(1, {
|
|
201
229
|
[Attributes.STATUS]: 'built',
|
|
202
230
|
});
|
|
203
231
|
this.blockBuildDuration.record(Math.ceil(buildDurationMs));
|
|
204
232
|
this.blockBuildManaPerSecond.record(Math.ceil((totalMana * 1000) / buildDurationMs));
|
|
233
|
+
|
|
234
|
+
// Only record inter-block time between blocks built within the same slot.
|
|
235
|
+
const now = Date.now();
|
|
236
|
+
if (this.lastBlockBuiltTimestamp !== undefined && this.lastBlockBuiltSlot === slot) {
|
|
237
|
+
this.blockInterBlockTime.record(now - this.lastBlockBuiltTimestamp);
|
|
238
|
+
}
|
|
239
|
+
this.lastBlockBuiltTimestamp = now;
|
|
240
|
+
this.lastBlockBuiltSlot = slot;
|
|
205
241
|
}
|
|
206
242
|
|
|
207
243
|
recordFailedBlock() {
|
|
@@ -216,6 +252,20 @@ export class SequencerMetrics {
|
|
|
216
252
|
});
|
|
217
253
|
}
|
|
218
254
|
|
|
255
|
+
recordPipelineDepth(depth: number) {
|
|
256
|
+
this.pipelineDepth.record(depth);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
recordPipelineDiscard(count = 1) {
|
|
260
|
+
this.pipelineDiscards.add(count);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
recordPipelineParentCheckpointMismatch(reason: string) {
|
|
264
|
+
this.pipelineParentCheckpointMismatches.add(1, {
|
|
265
|
+
[Attributes.ERROR_TYPE]: reason,
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
|
|
219
269
|
incOpenSlot(slot: SlotNumber, proposer: string) {
|
|
220
270
|
// sequencer went through the loop a second time. Noop
|
|
221
271
|
if (slot === this.lastSeenSlot) {
|
|
@@ -258,15 +308,19 @@ export class SequencerMetrics {
|
|
|
258
308
|
});
|
|
259
309
|
}
|
|
260
310
|
|
|
261
|
-
|
|
262
|
-
this.
|
|
311
|
+
recordCheckpointProposalSuccess() {
|
|
312
|
+
this.checkpointProposalSuccess.add(1);
|
|
263
313
|
}
|
|
264
314
|
|
|
265
|
-
|
|
315
|
+
recordCheckpointPrecheckFailed(
|
|
266
316
|
checkType: 'slot_already_taken' | 'rollup_contract_check_failed' | 'slot_mismatch' | 'block_number_mismatch',
|
|
267
317
|
) {
|
|
268
|
-
this.
|
|
269
|
-
|
|
318
|
+
this.checkpointPrecheckFailed.add(1, { [Attributes.ERROR_TYPE]: checkType });
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
recordCheckpointProposalFailed(reason?: string) {
|
|
322
|
+
this.checkpointProposalFailed.add(1, {
|
|
323
|
+
...(reason && { [Attributes.ERROR_TYPE]: reason }),
|
|
270
324
|
});
|
|
271
325
|
}
|
|
272
326
|
|
|
@@ -342,13 +396,21 @@ export class SequencerMetrics {
|
|
|
342
396
|
this.fishermanBlockBlobsFull.add(1, { ...strategyAttributes, [Attributes.OK]: false });
|
|
343
397
|
}
|
|
344
398
|
|
|
399
|
+
// Record the max blob capacity for this block
|
|
400
|
+
this.fishermanMaxBlobCapacity.record(analysis.analysis.maxBlobCapacity, strategyAttributes);
|
|
401
|
+
|
|
345
402
|
// Record strategy-specific inclusion result
|
|
346
403
|
if (strategyResult.wouldBeIncluded !== undefined) {
|
|
404
|
+
const inclusionAttributes = {
|
|
405
|
+
...strategyAttributes,
|
|
406
|
+
[Attributes.BLOCK_FULL]: analysis.analysis.blockBlobsFull ? 'true' : 'false',
|
|
407
|
+
};
|
|
408
|
+
|
|
347
409
|
if (strategyResult.wouldBeIncluded) {
|
|
348
|
-
this.fishermanWouldBeIncluded.add(1, { ...
|
|
410
|
+
this.fishermanWouldBeIncluded.add(1, { ...inclusionAttributes, [Attributes.OK]: true });
|
|
349
411
|
} else {
|
|
350
412
|
this.fishermanWouldBeIncluded.add(1, {
|
|
351
|
-
...
|
|
413
|
+
...inclusionAttributes,
|
|
352
414
|
[Attributes.OK]: false,
|
|
353
415
|
...(strategyResult.exclusionReason && { [Attributes.ERROR_TYPE]: strategyResult.exclusionReason }),
|
|
354
416
|
});
|
|
@@ -358,17 +420,29 @@ export class SequencerMetrics {
|
|
|
358
420
|
// Record strategy-specific priority fee delta
|
|
359
421
|
if (strategyResult.priorityFeeDelta !== undefined) {
|
|
360
422
|
const priorityFeeDeltaGwei = Number(strategyResult.priorityFeeDelta) / 1e9;
|
|
361
|
-
|
|
423
|
+
const deltaAttributes = {
|
|
424
|
+
...strategyAttributes,
|
|
425
|
+
[Attributes.BLOCK_FULL]: analysis.analysis.blockBlobsFull ? 'true' : 'false',
|
|
426
|
+
};
|
|
427
|
+
this.fishermanPriorityFeeDelta.record(priorityFeeDeltaGwei, deltaAttributes);
|
|
362
428
|
}
|
|
363
429
|
|
|
364
430
|
// Record estimated cost if available
|
|
365
431
|
if (strategyResult.estimatedCostEth !== undefined) {
|
|
366
|
-
|
|
432
|
+
const costAttributes = {
|
|
433
|
+
...strategyAttributes,
|
|
434
|
+
[Attributes.BLOCK_FULL]: analysis.analysis.blockBlobsFull ? 'true' : 'false',
|
|
435
|
+
};
|
|
436
|
+
this.fishermanEstimatedCost.record(strategyResult.estimatedCostEth, costAttributes);
|
|
367
437
|
}
|
|
368
438
|
|
|
369
439
|
// Record estimated overpayment if available
|
|
370
440
|
if (strategyResult.estimatedOverpaymentEth !== undefined) {
|
|
371
|
-
|
|
441
|
+
const overpaymentAttributes = {
|
|
442
|
+
...strategyAttributes,
|
|
443
|
+
[Attributes.BLOCK_FULL]: analysis.analysis.blockBlobsFull ? 'true' : 'false',
|
|
444
|
+
};
|
|
445
|
+
this.fishermanEstimatedOverpayment.record(strategyResult.estimatedOverpaymentEth, overpaymentAttributes);
|
|
372
446
|
}
|
|
373
447
|
}
|
|
374
448
|
}
|