@aztec/sequencer-client 2.1.9 → 2.1.11
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/publisher/sequencer-publisher.d.ts +15 -0
- package/dest/publisher/sequencer-publisher.d.ts.map +1 -1
- package/dest/publisher/sequencer-publisher.js +51 -0
- package/dest/sequencer/metrics.d.ts +16 -0
- package/dest/sequencer/metrics.d.ts.map +1 -1
- package/dest/sequencer/metrics.js +136 -0
- package/dest/sequencer/sequencer.d.ts +6 -0
- package/dest/sequencer/sequencer.d.ts.map +1 -1
- package/dest/sequencer/sequencer.js +46 -4
- package/package.json +27 -27
- package/src/publisher/sequencer-publisher.ts +76 -0
- package/src/sequencer/metrics.ts +180 -0
- package/src/sequencer/sequencer.ts +52 -2
|
@@ -2,6 +2,7 @@ import type { L2Block } from '@aztec/aztec.js';
|
|
|
2
2
|
import { type BlobSinkClientInterface } from '@aztec/blob-sink/client';
|
|
3
3
|
import type { EpochCache } from '@aztec/epoch-cache';
|
|
4
4
|
import { type EmpireSlashingProposerContract, FormattedViemError, type GovernanceProposerContract, type L1BlobInputs, type L1ContractsConfig, type L1TxConfig, type L1TxRequest, RollupContract, type TallySlashingProposerContract, type TransactionStats } from '@aztec/ethereum';
|
|
5
|
+
import { type L1FeeAnalysisResult, L1FeeAnalyzer } from '@aztec/ethereum/l1-fee-analysis';
|
|
5
6
|
import type { L1TxUtilsWithBlobs } from '@aztec/ethereum/l1-tx-utils-with-blobs';
|
|
6
7
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
7
8
|
import { Signature } from '@aztec/foundation/eth-signature';
|
|
@@ -51,6 +52,8 @@ export declare class SequencerPublisher {
|
|
|
51
52
|
private blobSinkClient;
|
|
52
53
|
/** Address to use for simulations in fisherman mode (actual proposer's address) */
|
|
53
54
|
private proposerAddressForSimulation?;
|
|
55
|
+
/** L1 fee analyzer for fisherman mode */
|
|
56
|
+
private l1FeeAnalyzer?;
|
|
54
57
|
static PROPOSE_GAS_GUESS: bigint;
|
|
55
58
|
static MULTICALL_OVERHEAD_GAS_GUESS: bigint;
|
|
56
59
|
static VOTE_GAS_GUESS: bigint;
|
|
@@ -76,6 +79,10 @@ export declare class SequencerPublisher {
|
|
|
76
79
|
});
|
|
77
80
|
getRollupContract(): RollupContract;
|
|
78
81
|
getSenderAddress(): EthAddress;
|
|
82
|
+
/**
|
|
83
|
+
* Gets the L1 fee analyzer instance (only available in fisherman mode)
|
|
84
|
+
*/
|
|
85
|
+
getL1FeeAnalyzer(): L1FeeAnalyzer | undefined;
|
|
79
86
|
/**
|
|
80
87
|
* Sets the proposer address to use for simulations in fisherman mode.
|
|
81
88
|
* @param proposerAddress - The actual proposer's address to use for balance lookups in simulations
|
|
@@ -87,6 +94,14 @@ export declare class SequencerPublisher {
|
|
|
87
94
|
* Clears all pending requests without sending them.
|
|
88
95
|
*/
|
|
89
96
|
clearPendingRequests(): void;
|
|
97
|
+
/**
|
|
98
|
+
* Analyzes L1 fees for the pending requests without sending them.
|
|
99
|
+
* This is used in fisherman mode to validate fee calculations.
|
|
100
|
+
* @param l2SlotNumber - The L2 slot number for this analysis
|
|
101
|
+
* @param onComplete - Optional callback to invoke when analysis completes (after block is mined)
|
|
102
|
+
* @returns The analysis result (incomplete until block mines), or undefined if no requests
|
|
103
|
+
*/
|
|
104
|
+
analyzeL1Fees(l2SlotNumber: bigint, onComplete?: (analysis: L1FeeAnalysisResult) => void): Promise<L1FeeAnalysisResult | undefined>;
|
|
90
105
|
/**
|
|
91
106
|
* Sends all requests that are still valid.
|
|
92
107
|
* @returns one of:
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sequencer-publisher.d.ts","sourceRoot":"","sources":["../../src/publisher/sequencer-publisher.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAE/C,OAAO,EAAE,KAAK,uBAAuB,EAAwB,MAAM,yBAAyB,CAAC;AAC7F,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EACL,KAAK,8BAA8B,EACnC,kBAAkB,EAClB,KAAK,0BAA0B,EAE/B,KAAK,YAAY,EACjB,KAAK,iBAAiB,EACtB,KAAK,UAAU,EACf,KAAK,WAAW,EAGhB,cAAc,EACd,KAAK,6BAA6B,EAClC,KAAK,gBAAgB,EAOtB,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wCAAwC,CAAC;AAGjF,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAC3D,OAAO,EAAE,SAAS,EAAsB,MAAM,iCAAiC,CAAC;AAChF,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,0BAA0B,CAAC;AACnD,OAAO,EAAE,KAAK,MAAM,EAAgB,MAAM,uBAAuB,CAAC;AAElE,OAAO,EAAE,YAAY,EAAS,MAAM,yBAAyB,CAAC;AAE9D,OAAO,EAAE,KAAK,mBAAmB,EAA6B,MAAM,gBAAgB,CAAC;AACrF,OAAO,EAAwB,+BAA+B,EAAE,KAAK,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AACtH,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAElE,OAAO,EAAE,KAAK,mBAAmB,EAAkB,MAAM,kBAAkB,CAAC;AAC5E,OAAO,EAAE,KAAK,eAAe,EAAsB,MAAM,yBAAyB,CAAC;AAEnF,OAAO,EAAsB,KAAK,kBAAkB,EAAE,KAAK,mBAAmB,EAA6B,MAAM,MAAM,CAAC;AAExH,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AACnE,OAAO,EAAE,yBAAyB,EAAE,MAAM,kCAAkC,CAAC;AAkB7E,eAAO,MAAM,OAAO,0OAUV,CAAC;AAEX,MAAM,MAAM,MAAM,GAAG,CAAC,OAAO,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC;AAK9C,eAAO,MAAM,cAAc,GAAI,GAAG,MAAM,EAAE,GAAG,MAAM,WAA4C,CAAC;AAEhG,MAAM,MAAM,sBAAsB,GAAG;IACnC,OAAO,EAAE,WAAW,CAAC;IACrB,MAAM,EAAE,qBAAqB,GAAG,2BAA2B,CAAC;IAC5D,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,uBAAuB,EAAE,MAAM,CAAC;CACjC,CAAC;AAEF,UAAU,iBAAiB;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,WAAW,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,IAAI,CAAC,UAAU,EAAE,aAAa,GAAG,UAAU,CAAC,CAAC;IACzD,UAAU,CAAC,EAAE,YAAY,CAAC;IAC1B,YAAY,EAAE,CACZ,OAAO,EAAE,WAAW,EACpB,MAAM,CAAC,EAAE;QAAE,OAAO,EAAE,kBAAkB,CAAC;QAAC,KAAK,CAAC,EAAE,gBAAgB,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,KAClF,OAAO,CAAC;CACd;AAED,qBAAa,kBAAkB;
|
|
1
|
+
{"version":3,"file":"sequencer-publisher.d.ts","sourceRoot":"","sources":["../../src/publisher/sequencer-publisher.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Blob } from '@aztec/blob-lib';
|
|
2
2
|
import { createBlobSinkClient } from '@aztec/blob-sink/client';
|
|
3
3
|
import { FormattedViemError, MULTI_CALL_3_ADDRESS, Multicall3, RollupContract, WEI_CONST, formatViemError, tryExtractEvent } from '@aztec/ethereum';
|
|
4
|
+
import { L1FeeAnalyzer } from '@aztec/ethereum/l1-fee-analysis';
|
|
4
5
|
import { sumBigint } from '@aztec/foundation/bigint';
|
|
5
6
|
import { toHex as toPaddedHex } from '@aztec/foundation/bigint-buffer';
|
|
6
7
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
@@ -39,6 +40,7 @@ export class SequencerPublisher {
|
|
|
39
40
|
ethereumSlotDuration;
|
|
40
41
|
blobSinkClient;
|
|
41
42
|
/** Address to use for simulations in fisherman mode (actual proposer's address) */ proposerAddressForSimulation;
|
|
43
|
+
/** L1 fee analyzer for fisherman mode */ l1FeeAnalyzer;
|
|
42
44
|
// @note - with blobs, the below estimate seems too large.
|
|
43
45
|
// Total used for full block from int_l1_pub e2e test: 1m (of which 86k is 1x blob)
|
|
44
46
|
// Total used for emptier block from above test: 429k (of which 84k is 1x blob)
|
|
@@ -79,6 +81,10 @@ export class SequencerPublisher {
|
|
|
79
81
|
this.slashingProposerContract = newSlashingProposer;
|
|
80
82
|
});
|
|
81
83
|
this.slashFactoryContract = deps.slashFactoryContract;
|
|
84
|
+
// Initialize L1 fee analyzer for fisherman mode
|
|
85
|
+
if (config.fishermanMode) {
|
|
86
|
+
this.l1FeeAnalyzer = new L1FeeAnalyzer(this.l1TxUtils.client, deps.dateProvider, createLogger('sequencer:publisher:fee-analyzer'));
|
|
87
|
+
}
|
|
82
88
|
}
|
|
83
89
|
getRollupContract() {
|
|
84
90
|
return this.rollupContract;
|
|
@@ -87,6 +93,11 @@ export class SequencerPublisher {
|
|
|
87
93
|
return this.l1TxUtils.getSenderAddress();
|
|
88
94
|
}
|
|
89
95
|
/**
|
|
96
|
+
* Gets the L1 fee analyzer instance (only available in fisherman mode)
|
|
97
|
+
*/ getL1FeeAnalyzer() {
|
|
98
|
+
return this.l1FeeAnalyzer;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
90
101
|
* Sets the proposer address to use for simulations in fisherman mode.
|
|
91
102
|
* @param proposerAddress - The actual proposer's address to use for balance lookups in simulations
|
|
92
103
|
*/ setProposerAddressForSimulation(proposerAddress) {
|
|
@@ -108,6 +119,46 @@ export class SequencerPublisher {
|
|
|
108
119
|
}
|
|
109
120
|
}
|
|
110
121
|
/**
|
|
122
|
+
* Analyzes L1 fees for the pending requests without sending them.
|
|
123
|
+
* This is used in fisherman mode to validate fee calculations.
|
|
124
|
+
* @param l2SlotNumber - The L2 slot number for this analysis
|
|
125
|
+
* @param onComplete - Optional callback to invoke when analysis completes (after block is mined)
|
|
126
|
+
* @returns The analysis result (incomplete until block mines), or undefined if no requests
|
|
127
|
+
*/ async analyzeL1Fees(l2SlotNumber, onComplete) {
|
|
128
|
+
if (!this.l1FeeAnalyzer) {
|
|
129
|
+
this.log.warn('L1 fee analyzer not available (not in fisherman mode)');
|
|
130
|
+
return undefined;
|
|
131
|
+
}
|
|
132
|
+
const requestsToAnalyze = [
|
|
133
|
+
...this.requests
|
|
134
|
+
];
|
|
135
|
+
if (requestsToAnalyze.length === 0) {
|
|
136
|
+
this.log.debug('No requests to analyze for L1 fees');
|
|
137
|
+
return undefined;
|
|
138
|
+
}
|
|
139
|
+
// Extract blob config from requests (if any)
|
|
140
|
+
const blobConfigs = requestsToAnalyze.filter((request)=>request.blobConfig).map((request)=>request.blobConfig);
|
|
141
|
+
const blobConfig = blobConfigs[0];
|
|
142
|
+
// Get gas configs
|
|
143
|
+
const gasConfigs = requestsToAnalyze.filter((request)=>request.gasConfig).map((request)=>request.gasConfig);
|
|
144
|
+
const gasLimits = gasConfigs.map((g)=>g?.gasLimit).filter((g)=>g !== undefined);
|
|
145
|
+
const gasLimit = gasLimits.length > 0 ? gasLimits.reduce((sum, g)=>sum + g, 0n) : 0n;
|
|
146
|
+
// Get the transaction requests
|
|
147
|
+
const l1Requests = requestsToAnalyze.map((r)=>r.request);
|
|
148
|
+
// Start the analysis
|
|
149
|
+
const analysisId = await this.l1FeeAnalyzer.startAnalysis(l2SlotNumber, gasLimit > 0n ? gasLimit : SequencerPublisher.PROPOSE_GAS_GUESS, l1Requests, blobConfig, onComplete);
|
|
150
|
+
this.log.info('Started L1 fee analysis', {
|
|
151
|
+
analysisId,
|
|
152
|
+
l2SlotNumber: l2SlotNumber.toString(),
|
|
153
|
+
requestCount: requestsToAnalyze.length,
|
|
154
|
+
hasBlobConfig: !!blobConfig,
|
|
155
|
+
gasLimit: gasLimit.toString(),
|
|
156
|
+
actions: requestsToAnalyze.map((r)=>r.action)
|
|
157
|
+
});
|
|
158
|
+
// Return the analysis result (will be incomplete until block mines)
|
|
159
|
+
return this.l1FeeAnalyzer.getAnalysis(analysisId);
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
111
162
|
* Sends all requests that are still valid.
|
|
112
163
|
* @returns one of:
|
|
113
164
|
* - A receipt and stats if the tx succeeded
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { EthAddress } from '@aztec/aztec.js';
|
|
2
2
|
import type { RollupContract } from '@aztec/ethereum';
|
|
3
|
+
import type { L1FeeAnalysisResult } from '@aztec/ethereum/l1-fee-analysis';
|
|
3
4
|
import { type TelemetryClient, type Tracer } from '@aztec/telemetry-client';
|
|
4
5
|
import { type Hex } from 'viem';
|
|
5
6
|
import type { SequencerState } from './utils.js';
|
|
@@ -23,6 +24,16 @@ export declare class SequencerMetrics {
|
|
|
23
24
|
private blockProposalPrecheckFailed;
|
|
24
25
|
private slashingAttempts;
|
|
25
26
|
private lastSeenSlot?;
|
|
27
|
+
private fishermanWouldBeIncluded;
|
|
28
|
+
private fishermanTimeBeforeBlock;
|
|
29
|
+
private fishermanPendingBlobTxCount;
|
|
30
|
+
private fishermanIncludedBlobTxCount;
|
|
31
|
+
private fishermanCalculatedPriorityFee;
|
|
32
|
+
private fishermanPriorityFeeDelta;
|
|
33
|
+
private fishermanEstimatedCost;
|
|
34
|
+
private fishermanEstimatedOverpayment;
|
|
35
|
+
private fishermanMinedBlobTxPriorityFee;
|
|
36
|
+
private fishermanMinedBlobTxTotalCost;
|
|
26
37
|
constructor(client: TelemetryClient, rollup: RollupContract, name?: string);
|
|
27
38
|
recordRequiredAttestations(requiredAttestationsCount: number, allowanceMs: number): void;
|
|
28
39
|
recordCollectedAttestations(count: number, durationMs: number): void;
|
|
@@ -35,5 +46,10 @@ export declare class SequencerMetrics {
|
|
|
35
46
|
recordBlockProposalSuccess(): void;
|
|
36
47
|
recordBlockProposalPrecheckFailed(checkType: string): void;
|
|
37
48
|
recordSlashingAttempt(actionCount: number): void;
|
|
49
|
+
/**
|
|
50
|
+
* Records metrics for a completed fisherman fee analysis
|
|
51
|
+
* @param analysis - The completed fee analysis result
|
|
52
|
+
*/
|
|
53
|
+
recordFishermanFeeAnalysis(analysis: L1FeeAnalysisResult): void;
|
|
38
54
|
}
|
|
39
55
|
//# sourceMappingURL=metrics.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metrics.d.ts","sourceRoot":"","sources":["../../src/sequencer/metrics.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EAML,KAAK,eAAe,EACpB,KAAK,MAAM,EAGZ,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EAAE,KAAK,GAAG,EAAe,MAAM,MAAM,CAAC;AAE7C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,qBAAa,gBAAgB;
|
|
1
|
+
{"version":3,"file":"metrics.d.ts","sourceRoot":"","sources":["../../src/sequencer/metrics.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AAC3E,OAAO,EAML,KAAK,eAAe,EACpB,KAAK,MAAM,EAGZ,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EAAE,KAAK,GAAG,EAAe,MAAM,MAAM,CAAC;AAE7C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,qBAAa,gBAAgB;IAyCzB,OAAO,CAAC,MAAM;IAxChB,SAAgB,MAAM,EAAE,MAAM,CAAC;IAC/B,OAAO,CAAC,KAAK,CAAQ;IAErB,OAAO,CAAC,YAAY,CAAgB;IACpC,OAAO,CAAC,kBAAkB,CAAY;IACtC,OAAO,CAAC,uBAAuB,CAAQ;IACvC,OAAO,CAAC,6BAA6B,CAAY;IAGjD,OAAO,CAAC,yBAAyB,CAAQ;IACzC,OAAO,CAAC,8BAA8B,CAAQ;IAC9C,OAAO,CAAC,kBAAkB,CAAQ;IAClC,OAAO,CAAC,mBAAmB,CAAQ;IAEnC,OAAO,CAAC,OAAO,CAAQ;IAEvB,OAAO,CAAC,KAAK,CAAgB;IAC7B,OAAO,CAAC,WAAW,CAAgB;IAEnC,OAAO,CAAC,mBAAmB,CAAgB;IAC3C,OAAO,CAAC,oBAAoB,CAAgB;IAC5C,OAAO,CAAC,2BAA2B,CAAgB;IACnD,OAAO,CAAC,gBAAgB,CAAgB;IAExC,OAAO,CAAC,YAAY,CAAC,CAAS;IAG9B,OAAO,CAAC,wBAAwB,CAAgB;IAChD,OAAO,CAAC,wBAAwB,CAAY;IAC5C,OAAO,CAAC,2BAA2B,CAAY;IAC/C,OAAO,CAAC,4BAA4B,CAAY;IAChD,OAAO,CAAC,8BAA8B,CAAY;IAClD,OAAO,CAAC,yBAAyB,CAAY;IAC7C,OAAO,CAAC,sBAAsB,CAAY;IAC1C,OAAO,CAAC,6BAA6B,CAAY;IACjD,OAAO,CAAC,+BAA+B,CAAY;IACnD,OAAO,CAAC,6BAA6B,CAAY;gBAG/C,MAAM,EAAE,eAAe,EACf,MAAM,EAAE,cAAc,EAC9B,IAAI,SAAc;IAqLb,0BAA0B,CAAC,yBAAyB,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM;IASjF,2BAA2B,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM;IAKpE,gBAAgB,CAAC,eAAe,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;IAQ3D,iBAAiB;IAMjB,6BAA6B,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,cAAc;IAMvE,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;IAapC,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,GAAG,UAAU,GAAG,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAmB5F,yBAAyB,CAAC,MAAM,CAAC,EAAE,MAAM;IAMzC,0BAA0B;IAI1B,iCAAiC,CAAC,SAAS,EAAE,MAAM;IAMnD,qBAAqB,CAAC,WAAW,EAAE,MAAM;IAIzC;;;OAGG;IACH,0BAA0B,CAAC,QAAQ,EAAE,mBAAmB;CAsFzD"}
|
|
@@ -21,6 +21,17 @@ export class SequencerMetrics {
|
|
|
21
21
|
blockProposalPrecheckFailed;
|
|
22
22
|
slashingAttempts;
|
|
23
23
|
lastSeenSlot;
|
|
24
|
+
// Fisherman fee analysis metrics
|
|
25
|
+
fishermanWouldBeIncluded;
|
|
26
|
+
fishermanTimeBeforeBlock;
|
|
27
|
+
fishermanPendingBlobTxCount;
|
|
28
|
+
fishermanIncludedBlobTxCount;
|
|
29
|
+
fishermanCalculatedPriorityFee;
|
|
30
|
+
fishermanPriorityFeeDelta;
|
|
31
|
+
fishermanEstimatedCost;
|
|
32
|
+
fishermanEstimatedOverpayment;
|
|
33
|
+
fishermanMinedBlobTxPriorityFee;
|
|
34
|
+
fishermanMinedBlobTxTotalCost;
|
|
24
35
|
constructor(client, rollup, name = 'Sequencer'){
|
|
25
36
|
this.rollup = rollup;
|
|
26
37
|
this.meter = client.getMeter(name);
|
|
@@ -97,6 +108,54 @@ export class SequencerMetrics {
|
|
|
97
108
|
valueType: ValueType.INT,
|
|
98
109
|
description: 'The number of slashing action attempts'
|
|
99
110
|
});
|
|
111
|
+
// Fisherman fee analysis metrics
|
|
112
|
+
this.fishermanWouldBeIncluded = this.meter.createUpDownCounter(Metrics.FISHERMAN_FEE_ANALYSIS_WOULD_BE_INCLUDED, {
|
|
113
|
+
valueType: ValueType.INT,
|
|
114
|
+
description: 'Whether the transaction would have been included in the block'
|
|
115
|
+
});
|
|
116
|
+
this.fishermanTimeBeforeBlock = this.meter.createHistogram(Metrics.FISHERMAN_FEE_ANALYSIS_TIME_BEFORE_BLOCK, {
|
|
117
|
+
unit: 'ms',
|
|
118
|
+
description: 'Time in ms between fee analysis and block being mined',
|
|
119
|
+
valueType: ValueType.INT
|
|
120
|
+
});
|
|
121
|
+
this.fishermanPendingBlobTxCount = this.meter.createHistogram(Metrics.FISHERMAN_FEE_ANALYSIS_PENDING_BLOB_TX_COUNT, {
|
|
122
|
+
description: 'Number of blob transactions seen in the pending block',
|
|
123
|
+
valueType: ValueType.INT
|
|
124
|
+
});
|
|
125
|
+
this.fishermanIncludedBlobTxCount = this.meter.createHistogram(Metrics.FISHERMAN_FEE_ANALYSIS_INCLUDED_BLOB_TX_COUNT, {
|
|
126
|
+
description: 'Number of blob transactions that got included in the mined block',
|
|
127
|
+
valueType: ValueType.INT
|
|
128
|
+
});
|
|
129
|
+
this.fishermanCalculatedPriorityFee = this.meter.createHistogram(Metrics.FISHERMAN_FEE_ANALYSIS_CALCULATED_PRIORITY_FEE, {
|
|
130
|
+
unit: 'gwei',
|
|
131
|
+
description: 'Priority fee calculated by each strategy',
|
|
132
|
+
valueType: ValueType.DOUBLE
|
|
133
|
+
});
|
|
134
|
+
this.fishermanPriorityFeeDelta = this.meter.createHistogram(Metrics.FISHERMAN_FEE_ANALYSIS_PRIORITY_FEE_DELTA, {
|
|
135
|
+
unit: 'gwei',
|
|
136
|
+
description: 'Difference between our priority fee and minimum included priority fee',
|
|
137
|
+
valueType: ValueType.DOUBLE
|
|
138
|
+
});
|
|
139
|
+
this.fishermanEstimatedCost = this.meter.createHistogram(Metrics.FISHERMAN_FEE_ANALYSIS_ESTIMATED_COST, {
|
|
140
|
+
unit: 'eth',
|
|
141
|
+
description: 'Estimated total cost in ETH for the transaction with this strategy',
|
|
142
|
+
valueType: ValueType.DOUBLE
|
|
143
|
+
});
|
|
144
|
+
this.fishermanEstimatedOverpayment = this.meter.createHistogram(Metrics.FISHERMAN_FEE_ANALYSIS_ESTIMATED_OVERPAYMENT, {
|
|
145
|
+
unit: 'eth',
|
|
146
|
+
description: 'Estimated overpayment in ETH vs minimum required for inclusion',
|
|
147
|
+
valueType: ValueType.DOUBLE
|
|
148
|
+
});
|
|
149
|
+
this.fishermanMinedBlobTxPriorityFee = this.meter.createHistogram(Metrics.FISHERMAN_FEE_ANALYSIS_MINED_BLOB_TX_PRIORITY_FEE, {
|
|
150
|
+
unit: 'gwei',
|
|
151
|
+
description: 'Priority fee per gas for blob transactions in mined blocks',
|
|
152
|
+
valueType: ValueType.DOUBLE
|
|
153
|
+
});
|
|
154
|
+
this.fishermanMinedBlobTxTotalCost = this.meter.createHistogram(Metrics.FISHERMAN_FEE_ANALYSIS_MINED_BLOB_TX_TOTAL_COST, {
|
|
155
|
+
unit: 'eth',
|
|
156
|
+
description: 'Total cost in ETH for blob transactions in mined blocks',
|
|
157
|
+
valueType: ValueType.DOUBLE
|
|
158
|
+
});
|
|
100
159
|
}
|
|
101
160
|
recordRequiredAttestations(requiredAttestationsCount, allowanceMs) {
|
|
102
161
|
this.requiredAttestions.record(requiredAttestationsCount);
|
|
@@ -171,4 +230,81 @@ export class SequencerMetrics {
|
|
|
171
230
|
recordSlashingAttempt(actionCount) {
|
|
172
231
|
this.slashingAttempts.add(actionCount);
|
|
173
232
|
}
|
|
233
|
+
/**
|
|
234
|
+
* Records metrics for a completed fisherman fee analysis
|
|
235
|
+
* @param analysis - The completed fee analysis result
|
|
236
|
+
*/ recordFishermanFeeAnalysis(analysis) {
|
|
237
|
+
// In fisherman mode, we should always have strategy results
|
|
238
|
+
if (!analysis.computedPrices.strategyResults || analysis.computedPrices.strategyResults.length === 0) {
|
|
239
|
+
// This should never happen in fisherman mode - log an error
|
|
240
|
+
// We don't record metrics without strategy IDs as that defeats the purpose
|
|
241
|
+
throw new Error(`No strategy results found in fisherman fee analysis ${analysis.id}. This indicates a bug in the fee analysis.`);
|
|
242
|
+
}
|
|
243
|
+
// Record metrics for each strategy separately
|
|
244
|
+
for (const strategyResult of analysis.computedPrices.strategyResults){
|
|
245
|
+
const strategyAttributes = {
|
|
246
|
+
[Attributes.FISHERMAN_FEE_STRATEGY_ID]: strategyResult.strategyId
|
|
247
|
+
};
|
|
248
|
+
// Record pending block snapshot data (once per strategy for comparison)
|
|
249
|
+
this.fishermanPendingBlobTxCount.record(analysis.pendingSnapshot.pendingBlobTxCount, strategyAttributes);
|
|
250
|
+
// Record mined block data if available
|
|
251
|
+
if (analysis.minedBlock) {
|
|
252
|
+
this.fishermanIncludedBlobTxCount.record(analysis.minedBlock.includedBlobTxCount, strategyAttributes);
|
|
253
|
+
// Record actual fees from blob transactions in the mined block
|
|
254
|
+
for (const blobTx of analysis.minedBlock.includedBlobTxs){
|
|
255
|
+
// Record priority fee per gas in Gwei
|
|
256
|
+
const priorityFeeGwei = Number(blobTx.maxPriorityFeePerGas) / 1e9;
|
|
257
|
+
this.fishermanMinedBlobTxPriorityFee.record(priorityFeeGwei, strategyAttributes);
|
|
258
|
+
// Calculate total cost in ETH
|
|
259
|
+
// Cost = (gas * (baseFee + priorityFee)) + (blobCount * blobGasPerBlob * blobBaseFee)
|
|
260
|
+
const baseFee = analysis.minedBlock.baseFeePerGas;
|
|
261
|
+
const effectiveGasPrice = baseFee + blobTx.maxPriorityFeePerGas;
|
|
262
|
+
// Calculate execution cost using actual gas limit from the transaction
|
|
263
|
+
const executionCost = blobTx.gas * effectiveGasPrice;
|
|
264
|
+
// Calculate blob cost using maxFeePerBlobGas * blobCount * GAS_PER_BLOB
|
|
265
|
+
const blobCost = blobTx.maxFeePerBlobGas * BigInt(blobTx.blobCount) * 131072n; // 128KB per blob
|
|
266
|
+
const totalCostWei = executionCost + blobCost;
|
|
267
|
+
const totalCostEth = Number(totalCostWei) / 1e18;
|
|
268
|
+
this.fishermanMinedBlobTxTotalCost.record(totalCostEth, strategyAttributes);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
// Record the calculated priority fee for this strategy
|
|
272
|
+
const calculatedPriorityFeeGwei = Number(strategyResult.calculatedPriorityFee) / 1e9;
|
|
273
|
+
this.fishermanCalculatedPriorityFee.record(calculatedPriorityFeeGwei, strategyAttributes);
|
|
274
|
+
// Record analysis results if available
|
|
275
|
+
if (analysis.analysis) {
|
|
276
|
+
this.fishermanTimeBeforeBlock.record(Math.ceil(analysis.analysis.timeBeforeBlockMs), strategyAttributes);
|
|
277
|
+
// Record strategy-specific inclusion result
|
|
278
|
+
if (strategyResult.wouldBeIncluded !== undefined) {
|
|
279
|
+
if (strategyResult.wouldBeIncluded) {
|
|
280
|
+
this.fishermanWouldBeIncluded.add(1, {
|
|
281
|
+
...strategyAttributes,
|
|
282
|
+
[Attributes.OK]: true
|
|
283
|
+
});
|
|
284
|
+
} else {
|
|
285
|
+
this.fishermanWouldBeIncluded.add(1, {
|
|
286
|
+
...strategyAttributes,
|
|
287
|
+
[Attributes.OK]: false,
|
|
288
|
+
...strategyResult.exclusionReason && {
|
|
289
|
+
[Attributes.ERROR_TYPE]: strategyResult.exclusionReason
|
|
290
|
+
}
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
// Record strategy-specific priority fee delta
|
|
295
|
+
if (strategyResult.priorityFeeDelta !== undefined) {
|
|
296
|
+
const priorityFeeDeltaGwei = Number(strategyResult.priorityFeeDelta) / 1e9;
|
|
297
|
+
this.fishermanPriorityFeeDelta.record(priorityFeeDeltaGwei, strategyAttributes);
|
|
298
|
+
}
|
|
299
|
+
// Record estimated cost if available
|
|
300
|
+
if (strategyResult.estimatedCostEth !== undefined) {
|
|
301
|
+
this.fishermanEstimatedCost.record(strategyResult.estimatedCostEth, strategyAttributes);
|
|
302
|
+
}
|
|
303
|
+
// Record estimated overpayment if available
|
|
304
|
+
if (strategyResult.estimatedOverpaymentEth !== undefined) {
|
|
305
|
+
this.fishermanEstimatedOverpayment.record(strategyResult.estimatedOverpaymentEth, strategyAttributes);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
174
310
|
}
|
|
@@ -93,6 +93,8 @@ export declare class Sequencer extends Sequencer_base {
|
|
|
93
93
|
private lastSlotForVoteWhenSyncFailed;
|
|
94
94
|
/** The last slot for which we built a validation block in fisherman mode, to prevent duplicate attempts. */
|
|
95
95
|
private lastSlotForValidationBlock;
|
|
96
|
+
/** The last epoch for which we logged strategy comparison in fisherman mode. */
|
|
97
|
+
private lastEpochForStrategyComparison;
|
|
96
98
|
/** The maximum number of seconds that the sequencer can be into a slot to transition to a particular state. */
|
|
97
99
|
protected timetable: SequencerTimetable;
|
|
98
100
|
protected enforceTimeTable: boolean;
|
|
@@ -216,6 +218,10 @@ export declare class Sequencer extends Sequencer_base {
|
|
|
216
218
|
protected considerInvalidatingBlock(syncedTo: NonNullable<Awaited<ReturnType<Sequencer['checkSync']>>>, currentSlot: bigint): Promise<void>;
|
|
217
219
|
private getSlotStartBuildTimestamp;
|
|
218
220
|
private getSecondsIntoSlot;
|
|
221
|
+
/**
|
|
222
|
+
* Logs strategy comparison statistics at the end of each epoch in fisherman mode
|
|
223
|
+
*/
|
|
224
|
+
private logStrategyComparison;
|
|
219
225
|
get aztecSlotDuration(): number;
|
|
220
226
|
get maxL2BlockGas(): number | undefined;
|
|
221
227
|
getSlasherClient(): SlasherClientInterface | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sequencer.d.ts","sourceRoot":"","sources":["../../src/sequencer/sequencer.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"sequencer.d.ts","sourceRoot":"","sources":["../../src/sequencer/sequencer.ts"],"names":[],"mappings":"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"}
|
|
@@ -69,6 +69,7 @@ export { SequencerState };
|
|
|
69
69
|
governanceProposerPayload;
|
|
70
70
|
/** The last slot for which we attempted to vote when sync failed, to prevent duplicate attempts. */ lastSlotForVoteWhenSyncFailed;
|
|
71
71
|
/** The last slot for which we built a validation block in fisherman mode, to prevent duplicate attempts. */ lastSlotForValidationBlock;
|
|
72
|
+
/** The last epoch for which we logged strategy comparison in fisherman mode. */ lastEpochForStrategyComparison;
|
|
72
73
|
/** The maximum number of seconds that the sequencer can be into a slot to transition to a particular state. */ timetable;
|
|
73
74
|
enforceTimeTable;
|
|
74
75
|
// This shouldn't be here as this gets re-created each time we build/propose a block.
|
|
@@ -318,16 +319,28 @@ export { SequencerState };
|
|
|
318
319
|
const block = await this.tryBuildBlockAndEnqueuePublish(slot, proposer, newBlockNumber, publisher, newGlobalVariables, chainTipArchive, invalidateBlock);
|
|
319
320
|
// Wait until the voting promises have resolved, so all requests are enqueued
|
|
320
321
|
await Promise.all(votesPromises);
|
|
321
|
-
// In fisherman mode, we don't publish to L1
|
|
322
|
+
// In fisherman mode, we don't publish to L1 but analyze the fees
|
|
322
323
|
if (this.config.fishermanMode) {
|
|
323
|
-
//
|
|
324
|
+
// Perform L1 fee analysis before clearing requests
|
|
325
|
+
// The callback is invoked asynchronously after the next block is mined
|
|
326
|
+
const feeAnalysis = await publisher.analyzeL1Fees(BigInt(slot), (analysis)=>{
|
|
327
|
+
this.metrics.recordFishermanFeeAnalysis(analysis);
|
|
328
|
+
});
|
|
329
|
+
// Check if we've moved to a new epoch and log strategy comparison
|
|
330
|
+
const currentEpoch = this.epochCache.getEpochAndSlotNow().epoch;
|
|
331
|
+
if (this.lastEpochForStrategyComparison === undefined || currentEpoch > this.lastEpochForStrategyComparison) {
|
|
332
|
+
this.logStrategyComparison(currentEpoch, publisher);
|
|
333
|
+
this.lastEpochForStrategyComparison = currentEpoch;
|
|
334
|
+
}
|
|
335
|
+
// Clear pending requests (we're not sending them)
|
|
324
336
|
publisher.clearPendingRequests();
|
|
325
337
|
if (block) {
|
|
326
338
|
this.log.info(`Validation block building SUCCEEDED for slot ${slot}`, {
|
|
327
339
|
blockNumber: newBlockNumber,
|
|
328
340
|
slot: Number(slot),
|
|
329
341
|
archive: block.archive.toString(),
|
|
330
|
-
txCount: block.body.txEffects.length
|
|
342
|
+
txCount: block.body.txEffects.length,
|
|
343
|
+
feeAnalysisId: feeAnalysis?.id
|
|
331
344
|
});
|
|
332
345
|
this.lastBlockPublished = block;
|
|
333
346
|
this.metrics.recordBlockProposalSuccess();
|
|
@@ -335,7 +348,8 @@ export { SequencerState };
|
|
|
335
348
|
// Block building failed in fisherman mode
|
|
336
349
|
this.log.warn(`Validation block building FAILED for slot ${slot}`, {
|
|
337
350
|
blockNumber: newBlockNumber,
|
|
338
|
-
slot: Number(slot)
|
|
351
|
+
slot: Number(slot),
|
|
352
|
+
feeAnalysisId: feeAnalysis?.id
|
|
339
353
|
});
|
|
340
354
|
this.metrics.recordBlockProposalFailed('block_build_failed');
|
|
341
355
|
}
|
|
@@ -941,6 +955,34 @@ export { SequencerState };
|
|
|
941
955
|
const slotStartTimestamp = this.getSlotStartBuildTimestamp(slotNumber);
|
|
942
956
|
return Number((this.dateProvider.now() / 1000 - slotStartTimestamp).toFixed(3));
|
|
943
957
|
}
|
|
958
|
+
/**
|
|
959
|
+
* Logs strategy comparison statistics at the end of each epoch in fisherman mode
|
|
960
|
+
*/ logStrategyComparison(epoch, publisher) {
|
|
961
|
+
const feeAnalyzer = publisher.getL1FeeAnalyzer();
|
|
962
|
+
if (!feeAnalyzer) {
|
|
963
|
+
return;
|
|
964
|
+
}
|
|
965
|
+
const comparison = feeAnalyzer.getStrategyComparison();
|
|
966
|
+
if (comparison.length === 0) {
|
|
967
|
+
this.log.debug(`No strategy data available yet for epoch ${epoch}`);
|
|
968
|
+
return;
|
|
969
|
+
}
|
|
970
|
+
this.log.info(`L1 Fee Strategy Performance Report - End of Epoch ${epoch}`, {
|
|
971
|
+
epoch: Number(epoch),
|
|
972
|
+
totalAnalyses: comparison[0]?.totalAnalyses,
|
|
973
|
+
strategies: comparison.map((s)=>({
|
|
974
|
+
id: s.strategyId,
|
|
975
|
+
name: s.strategyName,
|
|
976
|
+
inclusionRate: `${(s.inclusionRate * 100).toFixed(1)}%`,
|
|
977
|
+
inclusionCount: `${s.inclusionCount}/${s.totalAnalyses}`,
|
|
978
|
+
avgCostEth: s.avgEstimatedCostEth.toFixed(6),
|
|
979
|
+
totalCostEth: s.totalEstimatedCostEth.toFixed(6),
|
|
980
|
+
avgOverpaymentEth: s.avgOverpaymentEth.toFixed(6),
|
|
981
|
+
totalOverpaymentEth: s.totalOverpaymentEth.toFixed(6),
|
|
982
|
+
avgPriorityFeeDeltaGwei: s.avgPriorityFeeDeltaGwei.toFixed(2)
|
|
983
|
+
}))
|
|
984
|
+
});
|
|
985
|
+
}
|
|
944
986
|
get aztecSlotDuration() {
|
|
945
987
|
return this.l1Constants.slotDuration;
|
|
946
988
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aztec/sequencer-client",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.11",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./dest/index.js",
|
|
@@ -26,37 +26,37 @@
|
|
|
26
26
|
"test:integration:run": "NODE_NO_WARNINGS=1 node --experimental-vm-modules $(yarn bin jest) --no-cache --config jest.integration.config.json"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@aztec/aztec.js": "2.1.
|
|
30
|
-
"@aztec/bb-prover": "2.1.
|
|
31
|
-
"@aztec/blob-lib": "2.1.
|
|
32
|
-
"@aztec/blob-sink": "2.1.
|
|
33
|
-
"@aztec/constants": "2.1.
|
|
34
|
-
"@aztec/epoch-cache": "2.1.
|
|
35
|
-
"@aztec/ethereum": "2.1.
|
|
36
|
-
"@aztec/foundation": "2.1.
|
|
37
|
-
"@aztec/l1-artifacts": "2.1.
|
|
38
|
-
"@aztec/merkle-tree": "2.1.
|
|
39
|
-
"@aztec/node-keystore": "2.1.
|
|
40
|
-
"@aztec/noir-acvm_js": "2.1.
|
|
41
|
-
"@aztec/noir-contracts.js": "2.1.
|
|
42
|
-
"@aztec/noir-protocol-circuits-types": "2.1.
|
|
43
|
-
"@aztec/noir-types": "2.1.
|
|
44
|
-
"@aztec/p2p": "2.1.
|
|
45
|
-
"@aztec/protocol-contracts": "2.1.
|
|
46
|
-
"@aztec/prover-client": "2.1.
|
|
47
|
-
"@aztec/simulator": "2.1.
|
|
48
|
-
"@aztec/slasher": "2.1.
|
|
49
|
-
"@aztec/stdlib": "2.1.
|
|
50
|
-
"@aztec/telemetry-client": "2.1.
|
|
51
|
-
"@aztec/validator-client": "2.1.
|
|
52
|
-
"@aztec/world-state": "2.1.
|
|
29
|
+
"@aztec/aztec.js": "2.1.11",
|
|
30
|
+
"@aztec/bb-prover": "2.1.11",
|
|
31
|
+
"@aztec/blob-lib": "2.1.11",
|
|
32
|
+
"@aztec/blob-sink": "2.1.11",
|
|
33
|
+
"@aztec/constants": "2.1.11",
|
|
34
|
+
"@aztec/epoch-cache": "2.1.11",
|
|
35
|
+
"@aztec/ethereum": "2.1.11",
|
|
36
|
+
"@aztec/foundation": "2.1.11",
|
|
37
|
+
"@aztec/l1-artifacts": "2.1.11",
|
|
38
|
+
"@aztec/merkle-tree": "2.1.11",
|
|
39
|
+
"@aztec/node-keystore": "2.1.11",
|
|
40
|
+
"@aztec/noir-acvm_js": "2.1.11",
|
|
41
|
+
"@aztec/noir-contracts.js": "2.1.11",
|
|
42
|
+
"@aztec/noir-protocol-circuits-types": "2.1.11",
|
|
43
|
+
"@aztec/noir-types": "2.1.11",
|
|
44
|
+
"@aztec/p2p": "2.1.11",
|
|
45
|
+
"@aztec/protocol-contracts": "2.1.11",
|
|
46
|
+
"@aztec/prover-client": "2.1.11",
|
|
47
|
+
"@aztec/simulator": "2.1.11",
|
|
48
|
+
"@aztec/slasher": "2.1.11",
|
|
49
|
+
"@aztec/stdlib": "2.1.11",
|
|
50
|
+
"@aztec/telemetry-client": "2.1.11",
|
|
51
|
+
"@aztec/validator-client": "2.1.11",
|
|
52
|
+
"@aztec/world-state": "2.1.11",
|
|
53
53
|
"lodash.chunk": "^4.2.0",
|
|
54
54
|
"tslib": "^2.4.0",
|
|
55
55
|
"viem": "npm:@aztec/viem@2.38.2"
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
58
|
-
"@aztec/archiver": "2.1.
|
|
59
|
-
"@aztec/kv-store": "2.1.
|
|
58
|
+
"@aztec/archiver": "2.1.11",
|
|
59
|
+
"@aztec/kv-store": "2.1.11",
|
|
60
60
|
"@jest/globals": "^30.0.0",
|
|
61
61
|
"@types/jest": "^30.0.0",
|
|
62
62
|
"@types/lodash.chunk": "^4.2.7",
|
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
formatViemError,
|
|
24
24
|
tryExtractEvent,
|
|
25
25
|
} from '@aztec/ethereum';
|
|
26
|
+
import { type L1FeeAnalysisResult, L1FeeAnalyzer } from '@aztec/ethereum/l1-fee-analysis';
|
|
26
27
|
import type { L1TxUtilsWithBlobs } from '@aztec/ethereum/l1-tx-utils-with-blobs';
|
|
27
28
|
import { sumBigint } from '@aztec/foundation/bigint';
|
|
28
29
|
import { toHex as toPaddedHex } from '@aztec/foundation/bigint-buffer';
|
|
@@ -117,6 +118,9 @@ export class SequencerPublisher {
|
|
|
117
118
|
|
|
118
119
|
/** Address to use for simulations in fisherman mode (actual proposer's address) */
|
|
119
120
|
private proposerAddressForSimulation?: EthAddress;
|
|
121
|
+
|
|
122
|
+
/** L1 fee analyzer for fisherman mode */
|
|
123
|
+
private l1FeeAnalyzer?: L1FeeAnalyzer;
|
|
120
124
|
// @note - with blobs, the below estimate seems too large.
|
|
121
125
|
// Total used for full block from int_l1_pub e2e test: 1m (of which 86k is 1x blob)
|
|
122
126
|
// Total used for emptier block from above test: 429k (of which 84k is 1x blob)
|
|
@@ -176,6 +180,15 @@ export class SequencerPublisher {
|
|
|
176
180
|
this.slashingProposerContract = newSlashingProposer;
|
|
177
181
|
});
|
|
178
182
|
this.slashFactoryContract = deps.slashFactoryContract;
|
|
183
|
+
|
|
184
|
+
// Initialize L1 fee analyzer for fisherman mode
|
|
185
|
+
if (config.fishermanMode) {
|
|
186
|
+
this.l1FeeAnalyzer = new L1FeeAnalyzer(
|
|
187
|
+
this.l1TxUtils.client,
|
|
188
|
+
deps.dateProvider,
|
|
189
|
+
createLogger('sequencer:publisher:fee-analyzer'),
|
|
190
|
+
);
|
|
191
|
+
}
|
|
179
192
|
}
|
|
180
193
|
|
|
181
194
|
public getRollupContract(): RollupContract {
|
|
@@ -186,6 +199,13 @@ export class SequencerPublisher {
|
|
|
186
199
|
return this.l1TxUtils.getSenderAddress();
|
|
187
200
|
}
|
|
188
201
|
|
|
202
|
+
/**
|
|
203
|
+
* Gets the L1 fee analyzer instance (only available in fisherman mode)
|
|
204
|
+
*/
|
|
205
|
+
public getL1FeeAnalyzer(): L1FeeAnalyzer | undefined {
|
|
206
|
+
return this.l1FeeAnalyzer;
|
|
207
|
+
}
|
|
208
|
+
|
|
189
209
|
/**
|
|
190
210
|
* Sets the proposer address to use for simulations in fisherman mode.
|
|
191
211
|
* @param proposerAddress - The actual proposer's address to use for balance lookups in simulations
|
|
@@ -213,6 +233,62 @@ export class SequencerPublisher {
|
|
|
213
233
|
}
|
|
214
234
|
}
|
|
215
235
|
|
|
236
|
+
/**
|
|
237
|
+
* Analyzes L1 fees for the pending requests without sending them.
|
|
238
|
+
* This is used in fisherman mode to validate fee calculations.
|
|
239
|
+
* @param l2SlotNumber - The L2 slot number for this analysis
|
|
240
|
+
* @param onComplete - Optional callback to invoke when analysis completes (after block is mined)
|
|
241
|
+
* @returns The analysis result (incomplete until block mines), or undefined if no requests
|
|
242
|
+
*/
|
|
243
|
+
public async analyzeL1Fees(
|
|
244
|
+
l2SlotNumber: bigint,
|
|
245
|
+
onComplete?: (analysis: L1FeeAnalysisResult) => void,
|
|
246
|
+
): Promise<L1FeeAnalysisResult | undefined> {
|
|
247
|
+
if (!this.l1FeeAnalyzer) {
|
|
248
|
+
this.log.warn('L1 fee analyzer not available (not in fisherman mode)');
|
|
249
|
+
return undefined;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
const requestsToAnalyze = [...this.requests];
|
|
253
|
+
if (requestsToAnalyze.length === 0) {
|
|
254
|
+
this.log.debug('No requests to analyze for L1 fees');
|
|
255
|
+
return undefined;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Extract blob config from requests (if any)
|
|
259
|
+
const blobConfigs = requestsToAnalyze.filter(request => request.blobConfig).map(request => request.blobConfig);
|
|
260
|
+
const blobConfig = blobConfigs[0];
|
|
261
|
+
|
|
262
|
+
// Get gas configs
|
|
263
|
+
const gasConfigs = requestsToAnalyze.filter(request => request.gasConfig).map(request => request.gasConfig);
|
|
264
|
+
const gasLimits = gasConfigs.map(g => g?.gasLimit).filter((g): g is bigint => g !== undefined);
|
|
265
|
+
const gasLimit = gasLimits.length > 0 ? gasLimits.reduce((sum, g) => sum + g, 0n) : 0n;
|
|
266
|
+
|
|
267
|
+
// Get the transaction requests
|
|
268
|
+
const l1Requests = requestsToAnalyze.map(r => r.request);
|
|
269
|
+
|
|
270
|
+
// Start the analysis
|
|
271
|
+
const analysisId = await this.l1FeeAnalyzer.startAnalysis(
|
|
272
|
+
l2SlotNumber,
|
|
273
|
+
gasLimit > 0n ? gasLimit : SequencerPublisher.PROPOSE_GAS_GUESS,
|
|
274
|
+
l1Requests,
|
|
275
|
+
blobConfig,
|
|
276
|
+
onComplete,
|
|
277
|
+
);
|
|
278
|
+
|
|
279
|
+
this.log.info('Started L1 fee analysis', {
|
|
280
|
+
analysisId,
|
|
281
|
+
l2SlotNumber: l2SlotNumber.toString(),
|
|
282
|
+
requestCount: requestsToAnalyze.length,
|
|
283
|
+
hasBlobConfig: !!blobConfig,
|
|
284
|
+
gasLimit: gasLimit.toString(),
|
|
285
|
+
actions: requestsToAnalyze.map(r => r.action),
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
// Return the analysis result (will be incomplete until block mines)
|
|
289
|
+
return this.l1FeeAnalyzer.getAnalysis(analysisId);
|
|
290
|
+
}
|
|
291
|
+
|
|
216
292
|
/**
|
|
217
293
|
* Sends all requests that are still valid.
|
|
218
294
|
* @returns one of:
|
package/src/sequencer/metrics.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { EthAddress } from '@aztec/aztec.js';
|
|
2
2
|
import type { RollupContract } from '@aztec/ethereum';
|
|
3
|
+
import type { L1FeeAnalysisResult } from '@aztec/ethereum/l1-fee-analysis';
|
|
3
4
|
import {
|
|
4
5
|
Attributes,
|
|
5
6
|
type Gauge,
|
|
@@ -43,6 +44,18 @@ export class SequencerMetrics {
|
|
|
43
44
|
|
|
44
45
|
private lastSeenSlot?: bigint;
|
|
45
46
|
|
|
47
|
+
// Fisherman fee analysis metrics
|
|
48
|
+
private fishermanWouldBeIncluded: UpDownCounter;
|
|
49
|
+
private fishermanTimeBeforeBlock: Histogram;
|
|
50
|
+
private fishermanPendingBlobTxCount: Histogram;
|
|
51
|
+
private fishermanIncludedBlobTxCount: Histogram;
|
|
52
|
+
private fishermanCalculatedPriorityFee: Histogram;
|
|
53
|
+
private fishermanPriorityFeeDelta: Histogram;
|
|
54
|
+
private fishermanEstimatedCost: Histogram;
|
|
55
|
+
private fishermanEstimatedOverpayment: Histogram;
|
|
56
|
+
private fishermanMinedBlobTxPriorityFee: Histogram;
|
|
57
|
+
private fishermanMinedBlobTxTotalCost: Histogram;
|
|
58
|
+
|
|
46
59
|
constructor(
|
|
47
60
|
client: TelemetryClient,
|
|
48
61
|
private rollup: RollupContract,
|
|
@@ -149,6 +162,82 @@ export class SequencerMetrics {
|
|
|
149
162
|
valueType: ValueType.INT,
|
|
150
163
|
description: 'The number of slashing action attempts',
|
|
151
164
|
});
|
|
165
|
+
|
|
166
|
+
// Fisherman fee analysis metrics
|
|
167
|
+
this.fishermanWouldBeIncluded = this.meter.createUpDownCounter(Metrics.FISHERMAN_FEE_ANALYSIS_WOULD_BE_INCLUDED, {
|
|
168
|
+
valueType: ValueType.INT,
|
|
169
|
+
description: 'Whether the transaction would have been included in the block',
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
this.fishermanTimeBeforeBlock = this.meter.createHistogram(Metrics.FISHERMAN_FEE_ANALYSIS_TIME_BEFORE_BLOCK, {
|
|
173
|
+
unit: 'ms',
|
|
174
|
+
description: 'Time in ms between fee analysis and block being mined',
|
|
175
|
+
valueType: ValueType.INT,
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
this.fishermanPendingBlobTxCount = this.meter.createHistogram(
|
|
179
|
+
Metrics.FISHERMAN_FEE_ANALYSIS_PENDING_BLOB_TX_COUNT,
|
|
180
|
+
{
|
|
181
|
+
description: 'Number of blob transactions seen in the pending block',
|
|
182
|
+
valueType: ValueType.INT,
|
|
183
|
+
},
|
|
184
|
+
);
|
|
185
|
+
|
|
186
|
+
this.fishermanIncludedBlobTxCount = this.meter.createHistogram(
|
|
187
|
+
Metrics.FISHERMAN_FEE_ANALYSIS_INCLUDED_BLOB_TX_COUNT,
|
|
188
|
+
{
|
|
189
|
+
description: 'Number of blob transactions that got included in the mined block',
|
|
190
|
+
valueType: ValueType.INT,
|
|
191
|
+
},
|
|
192
|
+
);
|
|
193
|
+
|
|
194
|
+
this.fishermanCalculatedPriorityFee = this.meter.createHistogram(
|
|
195
|
+
Metrics.FISHERMAN_FEE_ANALYSIS_CALCULATED_PRIORITY_FEE,
|
|
196
|
+
{
|
|
197
|
+
unit: 'gwei',
|
|
198
|
+
description: 'Priority fee calculated by each strategy',
|
|
199
|
+
valueType: ValueType.DOUBLE,
|
|
200
|
+
},
|
|
201
|
+
);
|
|
202
|
+
|
|
203
|
+
this.fishermanPriorityFeeDelta = this.meter.createHistogram(Metrics.FISHERMAN_FEE_ANALYSIS_PRIORITY_FEE_DELTA, {
|
|
204
|
+
unit: 'gwei',
|
|
205
|
+
description: 'Difference between our priority fee and minimum included priority fee',
|
|
206
|
+
valueType: ValueType.DOUBLE,
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
this.fishermanEstimatedCost = this.meter.createHistogram(Metrics.FISHERMAN_FEE_ANALYSIS_ESTIMATED_COST, {
|
|
210
|
+
unit: 'eth',
|
|
211
|
+
description: 'Estimated total cost in ETH for the transaction with this strategy',
|
|
212
|
+
valueType: ValueType.DOUBLE,
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
this.fishermanEstimatedOverpayment = this.meter.createHistogram(
|
|
216
|
+
Metrics.FISHERMAN_FEE_ANALYSIS_ESTIMATED_OVERPAYMENT,
|
|
217
|
+
{
|
|
218
|
+
unit: 'eth',
|
|
219
|
+
description: 'Estimated overpayment in ETH vs minimum required for inclusion',
|
|
220
|
+
valueType: ValueType.DOUBLE,
|
|
221
|
+
},
|
|
222
|
+
);
|
|
223
|
+
|
|
224
|
+
this.fishermanMinedBlobTxPriorityFee = this.meter.createHistogram(
|
|
225
|
+
Metrics.FISHERMAN_FEE_ANALYSIS_MINED_BLOB_TX_PRIORITY_FEE,
|
|
226
|
+
{
|
|
227
|
+
unit: 'gwei',
|
|
228
|
+
description: 'Priority fee per gas for blob transactions in mined blocks',
|
|
229
|
+
valueType: ValueType.DOUBLE,
|
|
230
|
+
},
|
|
231
|
+
);
|
|
232
|
+
|
|
233
|
+
this.fishermanMinedBlobTxTotalCost = this.meter.createHistogram(
|
|
234
|
+
Metrics.FISHERMAN_FEE_ANALYSIS_MINED_BLOB_TX_TOTAL_COST,
|
|
235
|
+
{
|
|
236
|
+
unit: 'eth',
|
|
237
|
+
description: 'Total cost in ETH for blob transactions in mined blocks',
|
|
238
|
+
valueType: ValueType.DOUBLE,
|
|
239
|
+
},
|
|
240
|
+
);
|
|
152
241
|
}
|
|
153
242
|
|
|
154
243
|
public recordRequiredAttestations(requiredAttestationsCount: number, allowanceMs: number) {
|
|
@@ -236,4 +325,95 @@ export class SequencerMetrics {
|
|
|
236
325
|
recordSlashingAttempt(actionCount: number) {
|
|
237
326
|
this.slashingAttempts.add(actionCount);
|
|
238
327
|
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Records metrics for a completed fisherman fee analysis
|
|
331
|
+
* @param analysis - The completed fee analysis result
|
|
332
|
+
*/
|
|
333
|
+
recordFishermanFeeAnalysis(analysis: L1FeeAnalysisResult) {
|
|
334
|
+
// In fisherman mode, we should always have strategy results
|
|
335
|
+
if (!analysis.computedPrices.strategyResults || analysis.computedPrices.strategyResults.length === 0) {
|
|
336
|
+
// This should never happen in fisherman mode - log an error
|
|
337
|
+
// We don't record metrics without strategy IDs as that defeats the purpose
|
|
338
|
+
throw new Error(
|
|
339
|
+
`No strategy results found in fisherman fee analysis ${analysis.id}. This indicates a bug in the fee analysis.`,
|
|
340
|
+
);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// Record metrics for each strategy separately
|
|
344
|
+
for (const strategyResult of analysis.computedPrices.strategyResults) {
|
|
345
|
+
const strategyAttributes = {
|
|
346
|
+
[Attributes.FISHERMAN_FEE_STRATEGY_ID]: strategyResult.strategyId,
|
|
347
|
+
};
|
|
348
|
+
|
|
349
|
+
// Record pending block snapshot data (once per strategy for comparison)
|
|
350
|
+
this.fishermanPendingBlobTxCount.record(analysis.pendingSnapshot.pendingBlobTxCount, strategyAttributes);
|
|
351
|
+
|
|
352
|
+
// Record mined block data if available
|
|
353
|
+
if (analysis.minedBlock) {
|
|
354
|
+
this.fishermanIncludedBlobTxCount.record(analysis.minedBlock.includedBlobTxCount, strategyAttributes);
|
|
355
|
+
|
|
356
|
+
// Record actual fees from blob transactions in the mined block
|
|
357
|
+
for (const blobTx of analysis.minedBlock.includedBlobTxs) {
|
|
358
|
+
// Record priority fee per gas in Gwei
|
|
359
|
+
const priorityFeeGwei = Number(blobTx.maxPriorityFeePerGas) / 1e9;
|
|
360
|
+
this.fishermanMinedBlobTxPriorityFee.record(priorityFeeGwei, strategyAttributes);
|
|
361
|
+
|
|
362
|
+
// Calculate total cost in ETH
|
|
363
|
+
// Cost = (gas * (baseFee + priorityFee)) + (blobCount * blobGasPerBlob * blobBaseFee)
|
|
364
|
+
const baseFee = analysis.minedBlock.baseFeePerGas;
|
|
365
|
+
const effectiveGasPrice = baseFee + blobTx.maxPriorityFeePerGas;
|
|
366
|
+
|
|
367
|
+
// Calculate execution cost using actual gas limit from the transaction
|
|
368
|
+
const executionCost = blobTx.gas * effectiveGasPrice;
|
|
369
|
+
|
|
370
|
+
// Calculate blob cost using maxFeePerBlobGas * blobCount * GAS_PER_BLOB
|
|
371
|
+
const blobCost = blobTx.maxFeePerBlobGas * BigInt(blobTx.blobCount) * 131072n; // 128KB per blob
|
|
372
|
+
|
|
373
|
+
const totalCostWei = executionCost + blobCost;
|
|
374
|
+
const totalCostEth = Number(totalCostWei) / 1e18;
|
|
375
|
+
|
|
376
|
+
this.fishermanMinedBlobTxTotalCost.record(totalCostEth, strategyAttributes);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
// Record the calculated priority fee for this strategy
|
|
381
|
+
const calculatedPriorityFeeGwei = Number(strategyResult.calculatedPriorityFee) / 1e9;
|
|
382
|
+
this.fishermanCalculatedPriorityFee.record(calculatedPriorityFeeGwei, strategyAttributes);
|
|
383
|
+
|
|
384
|
+
// Record analysis results if available
|
|
385
|
+
if (analysis.analysis) {
|
|
386
|
+
this.fishermanTimeBeforeBlock.record(Math.ceil(analysis.analysis.timeBeforeBlockMs), strategyAttributes);
|
|
387
|
+
|
|
388
|
+
// Record strategy-specific inclusion result
|
|
389
|
+
if (strategyResult.wouldBeIncluded !== undefined) {
|
|
390
|
+
if (strategyResult.wouldBeIncluded) {
|
|
391
|
+
this.fishermanWouldBeIncluded.add(1, { ...strategyAttributes, [Attributes.OK]: true });
|
|
392
|
+
} else {
|
|
393
|
+
this.fishermanWouldBeIncluded.add(1, {
|
|
394
|
+
...strategyAttributes,
|
|
395
|
+
[Attributes.OK]: false,
|
|
396
|
+
...(strategyResult.exclusionReason && { [Attributes.ERROR_TYPE]: strategyResult.exclusionReason }),
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
// Record strategy-specific priority fee delta
|
|
402
|
+
if (strategyResult.priorityFeeDelta !== undefined) {
|
|
403
|
+
const priorityFeeDeltaGwei = Number(strategyResult.priorityFeeDelta) / 1e9;
|
|
404
|
+
this.fishermanPriorityFeeDelta.record(priorityFeeDeltaGwei, strategyAttributes);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// Record estimated cost if available
|
|
408
|
+
if (strategyResult.estimatedCostEth !== undefined) {
|
|
409
|
+
this.fishermanEstimatedCost.record(strategyResult.estimatedCostEth, strategyAttributes);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
// Record estimated overpayment if available
|
|
413
|
+
if (strategyResult.estimatedOverpaymentEth !== undefined) {
|
|
414
|
+
this.fishermanEstimatedOverpayment.record(strategyResult.estimatedOverpaymentEth, strategyAttributes);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
}
|
|
239
419
|
}
|
|
@@ -103,6 +103,9 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
103
103
|
/** The last slot for which we built a validation block in fisherman mode, to prevent duplicate attempts. */
|
|
104
104
|
private lastSlotForValidationBlock: bigint | undefined;
|
|
105
105
|
|
|
106
|
+
/** The last epoch for which we logged strategy comparison in fisherman mode. */
|
|
107
|
+
private lastEpochForStrategyComparison: bigint | undefined;
|
|
108
|
+
|
|
106
109
|
/** The maximum number of seconds that the sequencer can be into a slot to transition to a particular state. */
|
|
107
110
|
protected timetable!: SequencerTimetable;
|
|
108
111
|
protected enforceTimeTable: boolean = false;
|
|
@@ -422,9 +425,22 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
422
425
|
// Wait until the voting promises have resolved, so all requests are enqueued
|
|
423
426
|
await Promise.all(votesPromises);
|
|
424
427
|
|
|
425
|
-
// In fisherman mode, we don't publish to L1
|
|
428
|
+
// In fisherman mode, we don't publish to L1 but analyze the fees
|
|
426
429
|
if (this.config.fishermanMode) {
|
|
427
|
-
//
|
|
430
|
+
// Perform L1 fee analysis before clearing requests
|
|
431
|
+
// The callback is invoked asynchronously after the next block is mined
|
|
432
|
+
const feeAnalysis = await publisher.analyzeL1Fees(BigInt(slot), analysis => {
|
|
433
|
+
this.metrics.recordFishermanFeeAnalysis(analysis);
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
// Check if we've moved to a new epoch and log strategy comparison
|
|
437
|
+
const currentEpoch = this.epochCache.getEpochAndSlotNow().epoch;
|
|
438
|
+
if (this.lastEpochForStrategyComparison === undefined || currentEpoch > this.lastEpochForStrategyComparison) {
|
|
439
|
+
this.logStrategyComparison(currentEpoch, publisher);
|
|
440
|
+
this.lastEpochForStrategyComparison = currentEpoch;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
// Clear pending requests (we're not sending them)
|
|
428
444
|
publisher.clearPendingRequests();
|
|
429
445
|
|
|
430
446
|
if (block) {
|
|
@@ -433,6 +449,7 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
433
449
|
slot: Number(slot),
|
|
434
450
|
archive: block.archive.toString(),
|
|
435
451
|
txCount: block.body.txEffects.length,
|
|
452
|
+
feeAnalysisId: feeAnalysis?.id,
|
|
436
453
|
});
|
|
437
454
|
this.lastBlockPublished = block;
|
|
438
455
|
this.metrics.recordBlockProposalSuccess();
|
|
@@ -441,6 +458,7 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
441
458
|
this.log.warn(`Validation block building FAILED for slot ${slot}`, {
|
|
442
459
|
blockNumber: newBlockNumber,
|
|
443
460
|
slot: Number(slot),
|
|
461
|
+
feeAnalysisId: feeAnalysis?.id,
|
|
444
462
|
});
|
|
445
463
|
this.metrics.recordBlockProposalFailed('block_build_failed');
|
|
446
464
|
}
|
|
@@ -1234,6 +1252,38 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
1234
1252
|
return Number((this.dateProvider.now() / 1000 - slotStartTimestamp).toFixed(3));
|
|
1235
1253
|
}
|
|
1236
1254
|
|
|
1255
|
+
/**
|
|
1256
|
+
* Logs strategy comparison statistics at the end of each epoch in fisherman mode
|
|
1257
|
+
*/
|
|
1258
|
+
private logStrategyComparison(epoch: bigint, publisher: SequencerPublisher): void {
|
|
1259
|
+
const feeAnalyzer = publisher.getL1FeeAnalyzer();
|
|
1260
|
+
if (!feeAnalyzer) {
|
|
1261
|
+
return;
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
const comparison = feeAnalyzer.getStrategyComparison();
|
|
1265
|
+
if (comparison.length === 0) {
|
|
1266
|
+
this.log.debug(`No strategy data available yet for epoch ${epoch}`);
|
|
1267
|
+
return;
|
|
1268
|
+
}
|
|
1269
|
+
|
|
1270
|
+
this.log.info(`L1 Fee Strategy Performance Report - End of Epoch ${epoch}`, {
|
|
1271
|
+
epoch: Number(epoch),
|
|
1272
|
+
totalAnalyses: comparison[0]?.totalAnalyses,
|
|
1273
|
+
strategies: comparison.map(s => ({
|
|
1274
|
+
id: s.strategyId,
|
|
1275
|
+
name: s.strategyName,
|
|
1276
|
+
inclusionRate: `${(s.inclusionRate * 100).toFixed(1)}%`,
|
|
1277
|
+
inclusionCount: `${s.inclusionCount}/${s.totalAnalyses}`,
|
|
1278
|
+
avgCostEth: s.avgEstimatedCostEth.toFixed(6),
|
|
1279
|
+
totalCostEth: s.totalEstimatedCostEth.toFixed(6),
|
|
1280
|
+
avgOverpaymentEth: s.avgOverpaymentEth.toFixed(6),
|
|
1281
|
+
totalOverpaymentEth: s.totalOverpaymentEth.toFixed(6),
|
|
1282
|
+
avgPriorityFeeDeltaGwei: s.avgPriorityFeeDeltaGwei.toFixed(2),
|
|
1283
|
+
})),
|
|
1284
|
+
});
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1237
1287
|
get aztecSlotDuration() {
|
|
1238
1288
|
return this.l1Constants.slotDuration;
|
|
1239
1289
|
}
|