@aztec/sequencer-client 0.0.1-commit.1bb068fb5 → 0.0.1-commit.1dcfe2301
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 +26 -9
- package/dest/sequencer/checkpoint_proposal_job.d.ts.map +1 -1
- package/dest/sequencer/checkpoint_proposal_job.js +372 -210
- 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 +16 -8
- package/dest/sequencer/metrics.d.ts.map +1 -1
- package/dest/sequencer/metrics.js +70 -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 +486 -231
- 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 +80 -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;
|
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,13 @@ 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;
|
|
@@ -54,6 +55,7 @@ export class SequencerMetrics {
|
|
|
54
55
|
private fishermanPendingBlobCount: Histogram;
|
|
55
56
|
private fishermanIncludedBlobCount: Histogram;
|
|
56
57
|
private fishermanBlockBlobsFull: UpDownCounter;
|
|
58
|
+
private fishermanMaxBlobCapacity: Histogram;
|
|
57
59
|
private fishermanCalculatedPriorityFee: Histogram;
|
|
58
60
|
private fishermanPriorityFeeDelta: Histogram;
|
|
59
61
|
private fishermanEstimatedCost: Histogram;
|
|
@@ -61,6 +63,10 @@ export class SequencerMetrics {
|
|
|
61
63
|
private fishermanMinedBlobTxPriorityFee: Histogram;
|
|
62
64
|
private fishermanMinedBlobTxTotalCost: Histogram;
|
|
63
65
|
|
|
66
|
+
private blockInterBlockTime: Histogram;
|
|
67
|
+
private lastBlockBuiltTimestamp?: number;
|
|
68
|
+
private lastBlockBuiltSlot?: SlotNumber;
|
|
69
|
+
|
|
64
70
|
private lastSeenSlot?: SlotNumber;
|
|
65
71
|
|
|
66
72
|
constructor(
|
|
@@ -79,11 +85,11 @@ export class SequencerMetrics {
|
|
|
79
85
|
|
|
80
86
|
this.blockBuildManaPerSecond = this.meter.createGauge(Metrics.SEQUENCER_BLOCK_BUILD_MANA_PER_SECOND);
|
|
81
87
|
|
|
82
|
-
this.
|
|
88
|
+
this.blockInterBlockTime = this.meter.createHistogram(Metrics.SEQUENCER_BLOCK_INTER_BLOCK_TIME);
|
|
83
89
|
|
|
84
|
-
this.
|
|
90
|
+
this.stateTransitionBufferDuration = this.meter.createHistogram(Metrics.SEQUENCER_STATE_TRANSITION_BUFFER_DURATION);
|
|
85
91
|
|
|
86
|
-
this.rewards = this.meter.createGauge(Metrics.
|
|
92
|
+
this.rewards = this.meter.createGauge(Metrics.SEQUENCER_CURRENT_SLOT_REWARDS);
|
|
87
93
|
|
|
88
94
|
this.slots = createUpDownCounterWithDefault(this.meter, Metrics.SEQUENCER_SLOT_COUNT);
|
|
89
95
|
|
|
@@ -106,16 +112,16 @@ export class SequencerMetrics {
|
|
|
106
112
|
Metrics.SEQUENCER_BLOCK_PROPOSAL_FAILED_COUNT,
|
|
107
113
|
);
|
|
108
114
|
|
|
109
|
-
this.
|
|
115
|
+
this.checkpointProposalSuccess = createUpDownCounterWithDefault(
|
|
110
116
|
this.meter,
|
|
111
|
-
Metrics.
|
|
117
|
+
Metrics.SEQUENCER_CHECKPOINT_PROPOSAL_SUCCESS_COUNT,
|
|
112
118
|
);
|
|
113
119
|
|
|
114
120
|
this.checkpointSuccess = createUpDownCounterWithDefault(this.meter, Metrics.SEQUENCER_CHECKPOINT_SUCCESS_COUNT);
|
|
115
121
|
|
|
116
|
-
this.
|
|
122
|
+
this.checkpointPrecheckFailed = createUpDownCounterWithDefault(
|
|
117
123
|
this.meter,
|
|
118
|
-
Metrics.
|
|
124
|
+
Metrics.SEQUENCER_CHECKPOINT_PRECHECK_FAILED_COUNT,
|
|
119
125
|
{
|
|
120
126
|
[Attributes.ERROR_TYPE]: [
|
|
121
127
|
'slot_already_taken',
|
|
@@ -126,14 +132,24 @@ export class SequencerMetrics {
|
|
|
126
132
|
},
|
|
127
133
|
);
|
|
128
134
|
|
|
135
|
+
this.checkpointProposalFailed = createUpDownCounterWithDefault(
|
|
136
|
+
this.meter,
|
|
137
|
+
Metrics.SEQUENCER_CHECKPOINT_PROPOSAL_FAILED_COUNT,
|
|
138
|
+
);
|
|
139
|
+
|
|
129
140
|
this.slashingAttempts = createUpDownCounterWithDefault(this.meter, Metrics.SEQUENCER_SLASHING_ATTEMPTS_COUNT);
|
|
130
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
|
+
|
|
131
146
|
// Fisherman fee analysis metrics
|
|
132
147
|
this.fishermanWouldBeIncluded = createUpDownCounterWithDefault(
|
|
133
148
|
this.meter,
|
|
134
149
|
Metrics.FISHERMAN_FEE_ANALYSIS_WOULD_BE_INCLUDED,
|
|
135
150
|
{
|
|
136
151
|
[Attributes.OK]: [true, false],
|
|
152
|
+
[Attributes.BLOCK_FULL]: ['true', 'false'],
|
|
137
153
|
},
|
|
138
154
|
);
|
|
139
155
|
|
|
@@ -176,6 +192,8 @@ export class SequencerMetrics {
|
|
|
176
192
|
[Attributes.OK]: [true, false],
|
|
177
193
|
},
|
|
178
194
|
);
|
|
195
|
+
|
|
196
|
+
this.fishermanMaxBlobCapacity = this.meter.createHistogram(Metrics.FISHERMAN_FEE_ANALYSIS_MAX_BLOB_CAPACITY);
|
|
179
197
|
}
|
|
180
198
|
|
|
181
199
|
public recordRequiredAttestations(requiredAttestationsCount: number, allowanceMs: number) {
|
|
@@ -187,21 +205,25 @@ export class SequencerMetrics {
|
|
|
187
205
|
this.timeToCollectAttestations.record(0);
|
|
188
206
|
}
|
|
189
207
|
|
|
190
|
-
public recordCheckpointAttestationDelay(duration: number) {
|
|
191
|
-
this.checkpointAttestationDelay.record(duration);
|
|
192
|
-
}
|
|
193
|
-
|
|
194
208
|
public recordCollectedAttestations(count: number, durationMs: number) {
|
|
195
209
|
this.collectedAttestions.record(count);
|
|
196
210
|
this.timeToCollectAttestations.record(Math.ceil(durationMs));
|
|
197
211
|
}
|
|
198
212
|
|
|
199
|
-
recordBuiltBlock(buildDurationMs: number, totalMana: number) {
|
|
213
|
+
recordBuiltBlock(buildDurationMs: number, totalMana: number, slot: SlotNumber) {
|
|
200
214
|
this.blockCounter.add(1, {
|
|
201
215
|
[Attributes.STATUS]: 'built',
|
|
202
216
|
});
|
|
203
217
|
this.blockBuildDuration.record(Math.ceil(buildDurationMs));
|
|
204
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;
|
|
205
227
|
}
|
|
206
228
|
|
|
207
229
|
recordFailedBlock() {
|
|
@@ -216,6 +238,14 @@ export class SequencerMetrics {
|
|
|
216
238
|
});
|
|
217
239
|
}
|
|
218
240
|
|
|
241
|
+
recordPipelineDepth(depth: number) {
|
|
242
|
+
this.pipelineDepth.record(depth);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
recordPipelineDiscard(count = 1) {
|
|
246
|
+
this.pipelineDiscards.add(count);
|
|
247
|
+
}
|
|
248
|
+
|
|
219
249
|
incOpenSlot(slot: SlotNumber, proposer: string) {
|
|
220
250
|
// sequencer went through the loop a second time. Noop
|
|
221
251
|
if (slot === this.lastSeenSlot) {
|
|
@@ -258,15 +288,19 @@ export class SequencerMetrics {
|
|
|
258
288
|
});
|
|
259
289
|
}
|
|
260
290
|
|
|
261
|
-
|
|
262
|
-
this.
|
|
291
|
+
recordCheckpointProposalSuccess() {
|
|
292
|
+
this.checkpointProposalSuccess.add(1);
|
|
263
293
|
}
|
|
264
294
|
|
|
265
|
-
|
|
295
|
+
recordCheckpointPrecheckFailed(
|
|
266
296
|
checkType: 'slot_already_taken' | 'rollup_contract_check_failed' | 'slot_mismatch' | 'block_number_mismatch',
|
|
267
297
|
) {
|
|
268
|
-
this.
|
|
269
|
-
|
|
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 }),
|
|
270
304
|
});
|
|
271
305
|
}
|
|
272
306
|
|
|
@@ -342,13 +376,21 @@ export class SequencerMetrics {
|
|
|
342
376
|
this.fishermanBlockBlobsFull.add(1, { ...strategyAttributes, [Attributes.OK]: false });
|
|
343
377
|
}
|
|
344
378
|
|
|
379
|
+
// Record the max blob capacity for this block
|
|
380
|
+
this.fishermanMaxBlobCapacity.record(analysis.analysis.maxBlobCapacity, strategyAttributes);
|
|
381
|
+
|
|
345
382
|
// Record strategy-specific inclusion result
|
|
346
383
|
if (strategyResult.wouldBeIncluded !== undefined) {
|
|
384
|
+
const inclusionAttributes = {
|
|
385
|
+
...strategyAttributes,
|
|
386
|
+
[Attributes.BLOCK_FULL]: analysis.analysis.blockBlobsFull ? 'true' : 'false',
|
|
387
|
+
};
|
|
388
|
+
|
|
347
389
|
if (strategyResult.wouldBeIncluded) {
|
|
348
|
-
this.fishermanWouldBeIncluded.add(1, { ...
|
|
390
|
+
this.fishermanWouldBeIncluded.add(1, { ...inclusionAttributes, [Attributes.OK]: true });
|
|
349
391
|
} else {
|
|
350
392
|
this.fishermanWouldBeIncluded.add(1, {
|
|
351
|
-
...
|
|
393
|
+
...inclusionAttributes,
|
|
352
394
|
[Attributes.OK]: false,
|
|
353
395
|
...(strategyResult.exclusionReason && { [Attributes.ERROR_TYPE]: strategyResult.exclusionReason }),
|
|
354
396
|
});
|
|
@@ -358,17 +400,29 @@ export class SequencerMetrics {
|
|
|
358
400
|
// Record strategy-specific priority fee delta
|
|
359
401
|
if (strategyResult.priorityFeeDelta !== undefined) {
|
|
360
402
|
const priorityFeeDeltaGwei = Number(strategyResult.priorityFeeDelta) / 1e9;
|
|
361
|
-
|
|
403
|
+
const deltaAttributes = {
|
|
404
|
+
...strategyAttributes,
|
|
405
|
+
[Attributes.BLOCK_FULL]: analysis.analysis.blockBlobsFull ? 'true' : 'false',
|
|
406
|
+
};
|
|
407
|
+
this.fishermanPriorityFeeDelta.record(priorityFeeDeltaGwei, deltaAttributes);
|
|
362
408
|
}
|
|
363
409
|
|
|
364
410
|
// Record estimated cost if available
|
|
365
411
|
if (strategyResult.estimatedCostEth !== undefined) {
|
|
366
|
-
|
|
412
|
+
const costAttributes = {
|
|
413
|
+
...strategyAttributes,
|
|
414
|
+
[Attributes.BLOCK_FULL]: analysis.analysis.blockBlobsFull ? 'true' : 'false',
|
|
415
|
+
};
|
|
416
|
+
this.fishermanEstimatedCost.record(strategyResult.estimatedCostEth, costAttributes);
|
|
367
417
|
}
|
|
368
418
|
|
|
369
419
|
// Record estimated overpayment if available
|
|
370
420
|
if (strategyResult.estimatedOverpaymentEth !== undefined) {
|
|
371
|
-
|
|
421
|
+
const overpaymentAttributes = {
|
|
422
|
+
...strategyAttributes,
|
|
423
|
+
[Attributes.BLOCK_FULL]: analysis.analysis.blockBlobsFull ? 'true' : 'false',
|
|
424
|
+
};
|
|
425
|
+
this.fishermanEstimatedOverpayment.record(strategyResult.estimatedOverpaymentEth, overpaymentAttributes);
|
|
372
426
|
}
|
|
373
427
|
}
|
|
374
428
|
}
|