Skip to content

Commit 8326189

Browse files
authored
Merge pull request #725 from onflow/mpeter/eth-estimate-gas-track-iterations
Add metric to count iterations taken for `eth_estimateGas`
2 parents e250f39 + b49b795 commit 8326189

File tree

3 files changed

+53
-26
lines changed

3 files changed

+53
-26
lines changed

metrics/collector.go

Lines changed: 33 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -19,22 +19,24 @@ type Collector interface {
1919
MeasureRequestDuration(start time.Time, method string)
2020
OperatorBalance(account *flow.Account)
2121
AvailableSigningKeys(count int)
22+
GasEstimationIterations(count int)
2223
}
2324

2425
var _ Collector = &DefaultCollector{}
2526

2627
type DefaultCollector struct {
2728
// TODO: for now we cannot differentiate which api request failed number of times
28-
apiErrorsCounter prometheus.Counter
29-
serverPanicsCounters *prometheus.CounterVec
30-
cadenceBlockHeight prometheus.Gauge
31-
evmBlockHeight prometheus.Gauge
32-
evmBlockIndexedCounter prometheus.Counter
33-
evmTxIndexedCounter prometheus.Counter
34-
operatorBalance prometheus.Gauge
35-
evmAccountCallCounters *prometheus.CounterVec
36-
requestDurations *prometheus.HistogramVec
37-
availableSigningkeys prometheus.Gauge
29+
apiErrorsCounter prometheus.Counter
30+
serverPanicsCounters *prometheus.CounterVec
31+
cadenceBlockHeight prometheus.Gauge
32+
evmBlockHeight prometheus.Gauge
33+
evmBlockIndexedCounter prometheus.Counter
34+
evmTxIndexedCounter prometheus.Counter
35+
operatorBalance prometheus.Gauge
36+
evmAccountCallCounters *prometheus.CounterVec
37+
requestDurations *prometheus.HistogramVec
38+
availableSigningkeys prometheus.Gauge
39+
gasEstimationIterations prometheus.Gauge
3840
}
3941

4042
func NewCollector(logger zerolog.Logger) Collector {
@@ -90,6 +92,11 @@ func NewCollector(logger zerolog.Logger) Collector {
9092
Help: "Number of keys available for transaction signing",
9193
})
9294

95+
gasEstimationIterations := prometheus.NewGauge(prometheus.GaugeOpts{
96+
Name: prefixedName("gas_estimation_iterations"),
97+
Help: "Number of iterations taken to estimate the gas of a EVM call/tx",
98+
})
99+
93100
metrics := []prometheus.Collector{
94101
apiErrors,
95102
serverPanicsCounters,
@@ -101,23 +108,25 @@ func NewCollector(logger zerolog.Logger) Collector {
101108
evmAccountCallCounters,
102109
requestDurations,
103110
availableSigningKeys,
111+
gasEstimationIterations,
104112
}
105113
if err := registerMetrics(logger, metrics...); err != nil {
106114
logger.Info().Msg("using noop collector as metric register failed")
107115
return NopCollector
108116
}
109117

110118
return &DefaultCollector{
111-
apiErrorsCounter: apiErrors,
112-
serverPanicsCounters: serverPanicsCounters,
113-
cadenceBlockHeight: cadenceBlockHeight,
114-
evmBlockHeight: evmBlockHeight,
115-
evmBlockIndexedCounter: evmBlockIndexedCounter,
116-
evmTxIndexedCounter: evmTxIndexedCounter,
117-
evmAccountCallCounters: evmAccountCallCounters,
118-
requestDurations: requestDurations,
119-
operatorBalance: operatorBalance,
120-
availableSigningkeys: availableSigningKeys,
119+
apiErrorsCounter: apiErrors,
120+
serverPanicsCounters: serverPanicsCounters,
121+
cadenceBlockHeight: cadenceBlockHeight,
122+
evmBlockHeight: evmBlockHeight,
123+
evmBlockIndexedCounter: evmBlockIndexedCounter,
124+
evmTxIndexedCounter: evmTxIndexedCounter,
125+
evmAccountCallCounters: evmAccountCallCounters,
126+
requestDurations: requestDurations,
127+
operatorBalance: operatorBalance,
128+
availableSigningkeys: availableSigningKeys,
129+
gasEstimationIterations: gasEstimationIterations,
121130
}
122131
}
123132

@@ -172,6 +181,10 @@ func (c *DefaultCollector) AvailableSigningKeys(count int) {
172181
c.availableSigningkeys.Set(float64(count))
173182
}
174183

184+
func (c *DefaultCollector) GasEstimationIterations(count int) {
185+
c.gasEstimationIterations.Set(float64(count))
186+
}
187+
175188
func prefixedName(name string) string {
176189
return fmt.Sprintf("evm_gateway_%s", name)
177190
}

metrics/nop.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,4 @@ func (c *nopCollector) EVMAccountInteraction(string) {}
2121
func (c *nopCollector) MeasureRequestDuration(time.Time, string) {}
2222
func (c *nopCollector) OperatorBalance(*flow.Account) {}
2323
func (c *nopCollector) AvailableSigningKeys(count int) {}
24+
func (c *nopCollector) GasEstimationIterations(count int) {}

services/requester/requester.go

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,15 @@ func (e *EVM) EstimateGas(
310310
height uint64,
311311
stateOverrides *ethTypes.StateOverride,
312312
) (uint64, error) {
313+
iterations := 0
314+
315+
dryRun := func(gasLimit uint64) (*evmTypes.Result, error) {
316+
tx.Gas = gasLimit
317+
result, err := e.dryRunTx(tx, from, height, stateOverrides, nil)
318+
iterations += 1
319+
return result, err
320+
}
321+
313322
// Note: The following algorithm, is largely inspired from
314323
// https://github.com/onflow/go-ethereum/blob/master/eth/gasestimator/gasestimator.go#L49-L192,
315324
// and adapted to fit our use-case.
@@ -323,10 +332,10 @@ func (e *EVM) EstimateGas(
323332
if tx.Gas >= gethParams.TxGas {
324333
passingGasLimit = tx.Gas
325334
}
326-
tx.Gas = passingGasLimit
335+
327336
// We first execute the transaction at the highest allowable gas limit,
328337
// since if this fails we can return the error immediately.
329-
result, err := e.dryRunTx(tx, from, height, stateOverrides, nil)
338+
result, err := dryRun(passingGasLimit)
330339
if err != nil {
331340
return 0, err
332341
}
@@ -338,6 +347,12 @@ func (e *EVM) EstimateGas(
338347
return 0, errs.NewFailedTransactionError(resultSummary.ErrorMessage)
339348
}
340349

350+
// We do not want to report iterations for calls/transactions
351+
// that errored out or had their execution reverted.
352+
defer func() {
353+
e.collector.GasEstimationIterations(iterations)
354+
}()
355+
341356
// For almost any transaction, the gas consumed by the unconstrained execution
342357
// above lower-bounds the gas limit required for it to succeed. One exception
343358
// is those that explicitly check gas remaining in order to execute within a
@@ -350,8 +365,7 @@ func (e *EVM) EstimateGas(
350365
// Explicitly check that gas amount and use as a limit for the binary search.
351366
optimisticGasLimit := (result.GasConsumed + result.GasRefund + gethParams.CallStipend) * 64 / 63
352367
if optimisticGasLimit < passingGasLimit {
353-
tx.Gas = optimisticGasLimit
354-
result, err = e.dryRunTx(tx, from, height, stateOverrides, nil)
368+
result, err := dryRun(optimisticGasLimit)
355369
if err != nil {
356370
// This should not happen under normal conditions since if we make it this far the
357371
// transaction had run without error at least once before.
@@ -380,8 +394,7 @@ func (e *EVM) EstimateGas(
380394
// range here is skewed to favor the low side.
381395
mid = failingGasLimit * 2
382396
}
383-
tx.Gas = mid
384-
result, err = e.dryRunTx(tx, from, height, stateOverrides, nil)
397+
result, err := dryRun(mid)
385398
if err != nil {
386399
return 0, err
387400
}

0 commit comments

Comments
 (0)