@aztec/sequencer-client 0.0.1-commit.6d63667d → 0.0.1-commit.71324e566
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 -7
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +52 -36
- 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 +75 -48
- package/dest/publisher/sequencer-publisher.d.ts.map +1 -1
- package/dest/publisher/sequencer-publisher.js +432 -139
- 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 +26 -9
- package/dest/sequencer/checkpoint_proposal_job.d.ts.map +1 -1
- package/dest/sequencer/checkpoint_proposal_job.js +377 -213
- 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 +2 -1
- package/dest/sequencer/events.d.ts.map +1 -1
- package/dest/sequencer/metrics.d.ts +19 -8
- package/dest/sequencer/metrics.d.ts.map +1 -1
- package/dest/sequencer/metrics.js +95 -21
- package/dest/sequencer/sequencer.d.ts +43 -17
- package/dest/sequencer/sequencer.d.ts.map +1 -1
- package/dest/sequencer/sequencer.js +158 -96
- package/dest/sequencer/timetable.d.ts +17 -6
- package/dest/sequencer/timetable.d.ts.map +1 -1
- package/dest/sequencer/timetable.js +51 -46
- 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 +11 -11
- package/dest/test/mock_checkpoint_builder.d.ts.map +1 -1
- package/dest/test/mock_checkpoint_builder.js +45 -34
- package/dest/test/utils.d.ts +3 -3
- package/dest/test/utils.d.ts.map +1 -1
- package/dest/test/utils.js +5 -4
- package/package.json +27 -28
- package/src/client/sequencer-client.ts +81 -30
- package/src/config.ts +70 -46
- 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 +499 -198
- package/src/sequencer/README.md +83 -13
- package/src/sequencer/chain_state_overrides.ts +87 -0
- package/src/sequencer/checkpoint_proposal_job.ts +493 -233
- package/src/sequencer/checkpoint_proposal_job_metrics.ts +128 -0
- package/src/sequencer/checkpoint_voter.ts +1 -12
- package/src/sequencer/events.ts +1 -1
- package/src/sequencer/metrics.ts +104 -26
- package/src/sequencer/sequencer.ts +227 -108
- package/src/sequencer/timetable.ts +70 -57
- package/src/sequencer/types.ts +1 -1
- package/src/test/index.ts +2 -4
- package/src/test/mock_checkpoint_builder.ts +63 -49
- package/src/test/utils.ts +5 -2
|
@@ -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;
|
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,17 +39,23 @@ 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;
|
|
48
49
|
|
|
49
50
|
// Fisherman fee analysis metrics
|
|
50
51
|
private fishermanWouldBeIncluded: UpDownCounter;
|
|
51
52
|
private fishermanTimeBeforeBlock: Histogram;
|
|
52
53
|
private fishermanPendingBlobTxCount: Histogram;
|
|
53
54
|
private fishermanIncludedBlobTxCount: Histogram;
|
|
55
|
+
private fishermanPendingBlobCount: Histogram;
|
|
56
|
+
private fishermanIncludedBlobCount: Histogram;
|
|
57
|
+
private fishermanBlockBlobsFull: UpDownCounter;
|
|
58
|
+
private fishermanMaxBlobCapacity: Histogram;
|
|
54
59
|
private fishermanCalculatedPriorityFee: Histogram;
|
|
55
60
|
private fishermanPriorityFeeDelta: Histogram;
|
|
56
61
|
private fishermanEstimatedCost: Histogram;
|
|
@@ -58,6 +63,10 @@ export class SequencerMetrics {
|
|
|
58
63
|
private fishermanMinedBlobTxPriorityFee: Histogram;
|
|
59
64
|
private fishermanMinedBlobTxTotalCost: Histogram;
|
|
60
65
|
|
|
66
|
+
private blockInterBlockTime: Histogram;
|
|
67
|
+
private lastBlockBuiltTimestamp?: number;
|
|
68
|
+
private lastBlockBuiltSlot?: SlotNumber;
|
|
69
|
+
|
|
61
70
|
private lastSeenSlot?: SlotNumber;
|
|
62
71
|
|
|
63
72
|
constructor(
|
|
@@ -76,11 +85,11 @@ export class SequencerMetrics {
|
|
|
76
85
|
|
|
77
86
|
this.blockBuildManaPerSecond = this.meter.createGauge(Metrics.SEQUENCER_BLOCK_BUILD_MANA_PER_SECOND);
|
|
78
87
|
|
|
79
|
-
this.
|
|
88
|
+
this.blockInterBlockTime = this.meter.createHistogram(Metrics.SEQUENCER_BLOCK_INTER_BLOCK_TIME);
|
|
80
89
|
|
|
81
|
-
this.
|
|
90
|
+
this.stateTransitionBufferDuration = this.meter.createHistogram(Metrics.SEQUENCER_STATE_TRANSITION_BUFFER_DURATION);
|
|
82
91
|
|
|
83
|
-
this.rewards = this.meter.createGauge(Metrics.
|
|
92
|
+
this.rewards = this.meter.createGauge(Metrics.SEQUENCER_CURRENT_SLOT_REWARDS);
|
|
84
93
|
|
|
85
94
|
this.slots = createUpDownCounterWithDefault(this.meter, Metrics.SEQUENCER_SLOT_COUNT);
|
|
86
95
|
|
|
@@ -103,16 +112,16 @@ export class SequencerMetrics {
|
|
|
103
112
|
Metrics.SEQUENCER_BLOCK_PROPOSAL_FAILED_COUNT,
|
|
104
113
|
);
|
|
105
114
|
|
|
106
|
-
this.
|
|
115
|
+
this.checkpointProposalSuccess = createUpDownCounterWithDefault(
|
|
107
116
|
this.meter,
|
|
108
|
-
Metrics.
|
|
117
|
+
Metrics.SEQUENCER_CHECKPOINT_PROPOSAL_SUCCESS_COUNT,
|
|
109
118
|
);
|
|
110
119
|
|
|
111
120
|
this.checkpointSuccess = createUpDownCounterWithDefault(this.meter, Metrics.SEQUENCER_CHECKPOINT_SUCCESS_COUNT);
|
|
112
121
|
|
|
113
|
-
this.
|
|
122
|
+
this.checkpointPrecheckFailed = createUpDownCounterWithDefault(
|
|
114
123
|
this.meter,
|
|
115
|
-
Metrics.
|
|
124
|
+
Metrics.SEQUENCER_CHECKPOINT_PRECHECK_FAILED_COUNT,
|
|
116
125
|
{
|
|
117
126
|
[Attributes.ERROR_TYPE]: [
|
|
118
127
|
'slot_already_taken',
|
|
@@ -123,14 +132,24 @@ export class SequencerMetrics {
|
|
|
123
132
|
},
|
|
124
133
|
);
|
|
125
134
|
|
|
135
|
+
this.checkpointProposalFailed = createUpDownCounterWithDefault(
|
|
136
|
+
this.meter,
|
|
137
|
+
Metrics.SEQUENCER_CHECKPOINT_PROPOSAL_FAILED_COUNT,
|
|
138
|
+
);
|
|
139
|
+
|
|
126
140
|
this.slashingAttempts = createUpDownCounterWithDefault(this.meter, Metrics.SEQUENCER_SLASHING_ATTEMPTS_COUNT);
|
|
127
141
|
|
|
142
|
+
this.pipelineDepth = this.meter.createGauge(Metrics.SEQUENCER_PIPELINE_DEPTH);
|
|
143
|
+
this.pipelineDiscards = createUpDownCounterWithDefault(this.meter, Metrics.SEQUENCER_PIPELINE_DISCARDS_COUNT);
|
|
144
|
+
this.pipelineDepth.record(0);
|
|
145
|
+
|
|
128
146
|
// Fisherman fee analysis metrics
|
|
129
147
|
this.fishermanWouldBeIncluded = createUpDownCounterWithDefault(
|
|
130
148
|
this.meter,
|
|
131
149
|
Metrics.FISHERMAN_FEE_ANALYSIS_WOULD_BE_INCLUDED,
|
|
132
150
|
{
|
|
133
151
|
[Attributes.OK]: [true, false],
|
|
152
|
+
[Attributes.BLOCK_FULL]: ['true', 'false'],
|
|
134
153
|
},
|
|
135
154
|
);
|
|
136
155
|
|
|
@@ -161,6 +180,20 @@ export class SequencerMetrics {
|
|
|
161
180
|
this.fishermanMinedBlobTxTotalCost = this.meter.createHistogram(
|
|
162
181
|
Metrics.FISHERMAN_FEE_ANALYSIS_MINED_BLOB_TX_TOTAL_COST,
|
|
163
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);
|
|
164
197
|
}
|
|
165
198
|
|
|
166
199
|
public recordRequiredAttestations(requiredAttestationsCount: number, allowanceMs: number) {
|
|
@@ -172,21 +205,25 @@ export class SequencerMetrics {
|
|
|
172
205
|
this.timeToCollectAttestations.record(0);
|
|
173
206
|
}
|
|
174
207
|
|
|
175
|
-
public recordCheckpointAttestationDelay(duration: number) {
|
|
176
|
-
this.checkpointAttestationDelay.record(duration);
|
|
177
|
-
}
|
|
178
|
-
|
|
179
208
|
public recordCollectedAttestations(count: number, durationMs: number) {
|
|
180
209
|
this.collectedAttestions.record(count);
|
|
181
210
|
this.timeToCollectAttestations.record(Math.ceil(durationMs));
|
|
182
211
|
}
|
|
183
212
|
|
|
184
|
-
recordBuiltBlock(buildDurationMs: number, totalMana: number) {
|
|
213
|
+
recordBuiltBlock(buildDurationMs: number, totalMana: number, slot: SlotNumber) {
|
|
185
214
|
this.blockCounter.add(1, {
|
|
186
215
|
[Attributes.STATUS]: 'built',
|
|
187
216
|
});
|
|
188
217
|
this.blockBuildDuration.record(Math.ceil(buildDurationMs));
|
|
189
218
|
this.blockBuildManaPerSecond.record(Math.ceil((totalMana * 1000) / buildDurationMs));
|
|
219
|
+
|
|
220
|
+
// Only record inter-block time between blocks built within the same slot.
|
|
221
|
+
const now = Date.now();
|
|
222
|
+
if (this.lastBlockBuiltTimestamp !== undefined && this.lastBlockBuiltSlot === slot) {
|
|
223
|
+
this.blockInterBlockTime.record(now - this.lastBlockBuiltTimestamp);
|
|
224
|
+
}
|
|
225
|
+
this.lastBlockBuiltTimestamp = now;
|
|
226
|
+
this.lastBlockBuiltSlot = slot;
|
|
190
227
|
}
|
|
191
228
|
|
|
192
229
|
recordFailedBlock() {
|
|
@@ -201,6 +238,14 @@ export class SequencerMetrics {
|
|
|
201
238
|
});
|
|
202
239
|
}
|
|
203
240
|
|
|
241
|
+
recordPipelineDepth(depth: number) {
|
|
242
|
+
this.pipelineDepth.record(depth);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
recordPipelineDiscard(count = 1) {
|
|
246
|
+
this.pipelineDiscards.add(count);
|
|
247
|
+
}
|
|
248
|
+
|
|
204
249
|
incOpenSlot(slot: SlotNumber, proposer: string) {
|
|
205
250
|
// sequencer went through the loop a second time. Noop
|
|
206
251
|
if (slot === this.lastSeenSlot) {
|
|
@@ -243,15 +288,19 @@ export class SequencerMetrics {
|
|
|
243
288
|
});
|
|
244
289
|
}
|
|
245
290
|
|
|
246
|
-
|
|
247
|
-
this.
|
|
291
|
+
recordCheckpointProposalSuccess() {
|
|
292
|
+
this.checkpointProposalSuccess.add(1);
|
|
248
293
|
}
|
|
249
294
|
|
|
250
|
-
|
|
295
|
+
recordCheckpointPrecheckFailed(
|
|
251
296
|
checkType: 'slot_already_taken' | 'rollup_contract_check_failed' | 'slot_mismatch' | 'block_number_mismatch',
|
|
252
297
|
) {
|
|
253
|
-
this.
|
|
254
|
-
|
|
298
|
+
this.checkpointPrecheckFailed.add(1, { [Attributes.ERROR_TYPE]: checkType });
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
recordCheckpointProposalFailed(reason?: string) {
|
|
302
|
+
this.checkpointProposalFailed.add(1, {
|
|
303
|
+
...(reason && { [Attributes.ERROR_TYPE]: reason }),
|
|
255
304
|
});
|
|
256
305
|
}
|
|
257
306
|
|
|
@@ -281,10 +330,12 @@ export class SequencerMetrics {
|
|
|
281
330
|
|
|
282
331
|
// Record pending block snapshot data (once per strategy for comparison)
|
|
283
332
|
this.fishermanPendingBlobTxCount.record(analysis.pendingSnapshot.pendingBlobTxCount, strategyAttributes);
|
|
333
|
+
this.fishermanPendingBlobCount.record(analysis.pendingSnapshot.pendingBlobCount, strategyAttributes);
|
|
284
334
|
|
|
285
335
|
// Record mined block data if available
|
|
286
336
|
if (analysis.minedBlock) {
|
|
287
337
|
this.fishermanIncludedBlobTxCount.record(analysis.minedBlock.includedBlobTxCount, strategyAttributes);
|
|
338
|
+
this.fishermanIncludedBlobCount.record(analysis.minedBlock.includedBlobCount, strategyAttributes);
|
|
288
339
|
|
|
289
340
|
// Record actual fees from blob transactions in the mined block
|
|
290
341
|
for (const blobTx of analysis.minedBlock.includedBlobTxs) {
|
|
@@ -318,13 +369,28 @@ export class SequencerMetrics {
|
|
|
318
369
|
if (analysis.analysis) {
|
|
319
370
|
this.fishermanTimeBeforeBlock.record(Math.ceil(analysis.analysis.timeBeforeBlockMs), strategyAttributes);
|
|
320
371
|
|
|
372
|
+
// Record whether the block reached 100% blob capacity
|
|
373
|
+
if (analysis.analysis.blockBlobsFull) {
|
|
374
|
+
this.fishermanBlockBlobsFull.add(1, { ...strategyAttributes, [Attributes.OK]: true });
|
|
375
|
+
} else {
|
|
376
|
+
this.fishermanBlockBlobsFull.add(1, { ...strategyAttributes, [Attributes.OK]: false });
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// Record the max blob capacity for this block
|
|
380
|
+
this.fishermanMaxBlobCapacity.record(analysis.analysis.maxBlobCapacity, strategyAttributes);
|
|
381
|
+
|
|
321
382
|
// Record strategy-specific inclusion result
|
|
322
383
|
if (strategyResult.wouldBeIncluded !== undefined) {
|
|
384
|
+
const inclusionAttributes = {
|
|
385
|
+
...strategyAttributes,
|
|
386
|
+
[Attributes.BLOCK_FULL]: analysis.analysis.blockBlobsFull ? 'true' : 'false',
|
|
387
|
+
};
|
|
388
|
+
|
|
323
389
|
if (strategyResult.wouldBeIncluded) {
|
|
324
|
-
this.fishermanWouldBeIncluded.add(1, { ...
|
|
390
|
+
this.fishermanWouldBeIncluded.add(1, { ...inclusionAttributes, [Attributes.OK]: true });
|
|
325
391
|
} else {
|
|
326
392
|
this.fishermanWouldBeIncluded.add(1, {
|
|
327
|
-
...
|
|
393
|
+
...inclusionAttributes,
|
|
328
394
|
[Attributes.OK]: false,
|
|
329
395
|
...(strategyResult.exclusionReason && { [Attributes.ERROR_TYPE]: strategyResult.exclusionReason }),
|
|
330
396
|
});
|
|
@@ -334,17 +400,29 @@ export class SequencerMetrics {
|
|
|
334
400
|
// Record strategy-specific priority fee delta
|
|
335
401
|
if (strategyResult.priorityFeeDelta !== undefined) {
|
|
336
402
|
const priorityFeeDeltaGwei = Number(strategyResult.priorityFeeDelta) / 1e9;
|
|
337
|
-
|
|
403
|
+
const deltaAttributes = {
|
|
404
|
+
...strategyAttributes,
|
|
405
|
+
[Attributes.BLOCK_FULL]: analysis.analysis.blockBlobsFull ? 'true' : 'false',
|
|
406
|
+
};
|
|
407
|
+
this.fishermanPriorityFeeDelta.record(priorityFeeDeltaGwei, deltaAttributes);
|
|
338
408
|
}
|
|
339
409
|
|
|
340
410
|
// Record estimated cost if available
|
|
341
411
|
if (strategyResult.estimatedCostEth !== undefined) {
|
|
342
|
-
|
|
412
|
+
const costAttributes = {
|
|
413
|
+
...strategyAttributes,
|
|
414
|
+
[Attributes.BLOCK_FULL]: analysis.analysis.blockBlobsFull ? 'true' : 'false',
|
|
415
|
+
};
|
|
416
|
+
this.fishermanEstimatedCost.record(strategyResult.estimatedCostEth, costAttributes);
|
|
343
417
|
}
|
|
344
418
|
|
|
345
419
|
// Record estimated overpayment if available
|
|
346
420
|
if (strategyResult.estimatedOverpaymentEth !== undefined) {
|
|
347
|
-
|
|
421
|
+
const overpaymentAttributes = {
|
|
422
|
+
...strategyAttributes,
|
|
423
|
+
[Attributes.BLOCK_FULL]: analysis.analysis.blockBlobsFull ? 'true' : 'false',
|
|
424
|
+
};
|
|
425
|
+
this.fishermanEstimatedOverpayment.record(strategyResult.estimatedOverpaymentEth, overpaymentAttributes);
|
|
348
426
|
}
|
|
349
427
|
}
|
|
350
428
|
}
|