Skip to content

Commit 42861c3

Browse files
devin-ai-integration[bot]Jayant Krishnamurthyjayantk
authored
feat(fortuna): add metrics for retry count, gas/fee multipliers, and fee estimates (#2258)
* feat(fortuna): add metrics for retry count, gas/fee multipliers, and fee estimates Added histogram metrics to track: - Number of retries for successful transactions - Final gas multiplier for successful transactions - Final fee multiplier for successful transactions - Priority fee estimate before thresholds - Estimated keeper fee before thresholds Co-Authored-By: Jayant Krishnamurthy <jayant@dourolabs.xyz> * cleanup --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: Jayant Krishnamurthy <jayant@dourolabs.xyz> Co-authored-by: Jayant Krishnamurthy <jayantkrishnamurthy@gmail.com>
1 parent a9b6b69 commit 42861c3

File tree

3 files changed

+93
-2
lines changed

3 files changed

+93
-2
lines changed

apps/fortuna/Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

apps/fortuna/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "fortuna"
3-
version = "7.2.0"
3+
version = "7.3.0"
44
edition = "2021"
55

66
[dependencies]

apps/fortuna/src/keeper.rs

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ pub struct KeeperMetrics {
6969
pub balance: Family<AccountLabel, Gauge<f64, AtomicU64>>,
7070
pub collected_fee: Family<AccountLabel, Gauge<f64, AtomicU64>>,
7171
pub current_fee: Family<AccountLabel, Gauge<f64, AtomicU64>>,
72+
pub target_provider_fee: Family<AccountLabel, Gauge<f64, AtomicU64>>,
7273
pub total_gas_spent: Family<AccountLabel, Gauge<f64, AtomicU64>>,
7374
pub total_gas_fee_spent: Family<AccountLabel, Gauge<f64, AtomicU64>>,
7475
pub requests: Family<AccountLabel, Counter>,
@@ -78,6 +79,10 @@ pub struct KeeperMetrics {
7879
pub requests_reprocessed: Family<AccountLabel, Counter>,
7980
pub reveals: Family<AccountLabel, Counter>,
8081
pub request_duration_ms: Family<AccountLabel, Histogram>,
82+
pub retry_count: Family<AccountLabel, Histogram>,
83+
pub final_gas_multiplier: Family<AccountLabel, Histogram>,
84+
pub final_fee_multiplier: Family<AccountLabel, Histogram>,
85+
pub gas_price_estimate: Family<AccountLabel, Gauge<f64, AtomicU64>>,
8186
}
8287

8388
impl Default for KeeperMetrics {
@@ -88,6 +93,7 @@ impl Default for KeeperMetrics {
8893
balance: Family::default(),
8994
collected_fee: Family::default(),
9095
current_fee: Family::default(),
96+
target_provider_fee: Family::default(),
9197
total_gas_spent: Family::default(),
9298
total_gas_fee_spent: Family::default(),
9399
requests: Family::default(),
@@ -105,6 +111,18 @@ impl Default for KeeperMetrics {
105111
.into_iter(),
106112
)
107113
}),
114+
retry_count: Family::new_with_constructor(|| {
115+
Histogram::new(vec![0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 10.0, 15.0, 20.0].into_iter())
116+
}),
117+
final_gas_multiplier: Family::new_with_constructor(|| {
118+
Histogram::new(
119+
vec![100.0, 125.0, 150.0, 200.0, 300.0, 400.0, 500.0, 600.0].into_iter(),
120+
)
121+
}),
122+
final_fee_multiplier: Family::new_with_constructor(|| {
123+
Histogram::new(vec![100.0, 110.0, 120.0, 140.0, 160.0, 180.0, 200.0].into_iter())
124+
}),
125+
gas_price_estimate: Family::default(),
108126
}
109127
}
110128
}
@@ -174,6 +192,12 @@ impl KeeperMetrics {
174192
keeper_metrics.current_fee.clone(),
175193
);
176194

195+
writable_registry.register(
196+
"target_provider_fee",
197+
"Target fee in ETH -- differs from current_fee in that this is the goal, and current_fee is the on-chain value.",
198+
keeper_metrics.target_provider_fee.clone(),
199+
);
200+
177201
writable_registry.register(
178202
"total_gas_spent",
179203
"Total gas spent revealing requests",
@@ -198,6 +222,30 @@ impl KeeperMetrics {
198222
keeper_metrics.request_duration_ms.clone(),
199223
);
200224

225+
writable_registry.register(
226+
"retry_count",
227+
"Number of retries for successful transactions",
228+
keeper_metrics.retry_count.clone(),
229+
);
230+
231+
writable_registry.register(
232+
"final_gas_multiplier",
233+
"Final gas multiplier percentage for successful transactions",
234+
keeper_metrics.final_gas_multiplier.clone(),
235+
);
236+
237+
writable_registry.register(
238+
"final_fee_multiplier",
239+
"Final fee multiplier percentage for successful transactions",
240+
keeper_metrics.final_fee_multiplier.clone(),
241+
);
242+
243+
writable_registry.register(
244+
"gas_price_estimate",
245+
"Gas price estimate for the blockchain (in gwei)",
246+
keeper_metrics.gas_price_estimate.clone(),
247+
);
248+
201249
keeper_metrics
202250
}
203251
}
@@ -327,6 +375,7 @@ pub async fn run_keeper_threads(
327375
spawn(
328376
adjust_fee_wrapper(
329377
contract.clone(),
378+
chain_state.clone(),
330379
chain_state.provider_address,
331380
ADJUST_FEE_INTERVAL,
332381
chain_eth_config.legacy_tx,
@@ -346,6 +395,7 @@ pub async fn run_keeper_threads(
346395
u64::try_from(100 + chain_eth_config.max_profit_pct)
347396
.expect("max_profit_pct must be >= -100"),
348397
chain_eth_config.fee,
398+
metrics.clone(),
349399
)
350400
.in_current_span(),
351401
);
@@ -479,6 +529,25 @@ pub async fn process_event_with_backoff(
479529
.request_duration_ms
480530
.get_or_create(&account_label)
481531
.observe(duration.as_millis() as f64);
532+
533+
// Track retry count, gas multiplier, and fee multiplier for successful transactions
534+
let num_retries = num_retries.load(std::sync::atomic::Ordering::Relaxed);
535+
metrics
536+
.retry_count
537+
.get_or_create(&account_label)
538+
.observe(num_retries as f64);
539+
540+
let gas_multiplier = escalation_policy.get_gas_multiplier_pct(num_retries);
541+
metrics
542+
.final_gas_multiplier
543+
.get_or_create(&account_label)
544+
.observe(gas_multiplier as f64);
545+
546+
let fee_multiplier = escalation_policy.get_fee_multiplier_pct(num_retries);
547+
metrics
548+
.final_fee_multiplier
549+
.get_or_create(&account_label)
550+
.observe(fee_multiplier as f64);
482551
}
483552
Err(e) => {
484553
// In case the callback did not succeed, we double-check that the request is still on-chain.
@@ -1133,6 +1202,7 @@ pub async fn send_and_confirm(contract_call: PythContractCall) -> Result<()> {
11331202
#[allow(clippy::too_many_arguments)]
11341203
pub async fn adjust_fee_wrapper(
11351204
contract: Arc<InstrumentedSignablePythContract>,
1205+
chain_state: BlockchainState,
11361206
provider_address: Address,
11371207
poll_interval: Duration,
11381208
legacy_tx: bool,
@@ -1141,6 +1211,7 @@ pub async fn adjust_fee_wrapper(
11411211
target_profit_pct: u64,
11421212
max_profit_pct: u64,
11431213
min_fee_wei: u128,
1214+
metrics: Arc<KeeperMetrics>,
11441215
) {
11451216
// The maximum balance of accrued fees + provider wallet balance. None if we haven't observed a value yet.
11461217
let mut high_water_pnl: Option<U256> = None;
@@ -1149,6 +1220,7 @@ pub async fn adjust_fee_wrapper(
11491220
loop {
11501221
if let Err(e) = adjust_fee_if_necessary(
11511222
contract.clone(),
1223+
chain_state.id.clone(),
11521224
provider_address,
11531225
legacy_tx,
11541226
gas_limit,
@@ -1158,6 +1230,7 @@ pub async fn adjust_fee_wrapper(
11581230
min_fee_wei,
11591231
&mut high_water_pnl,
11601232
&mut sequence_number_of_last_fee_update,
1233+
metrics.clone(),
11611234
)
11621235
.in_current_span()
11631236
.await
@@ -1232,6 +1305,7 @@ pub async fn update_commitments_if_necessary(
12321305
#[allow(clippy::too_many_arguments)]
12331306
pub async fn adjust_fee_if_necessary(
12341307
contract: Arc<InstrumentedSignablePythContract>,
1308+
chain_id: ChainId,
12351309
provider_address: Address,
12361310
legacy_tx: bool,
12371311
gas_limit: u64,
@@ -1241,6 +1315,7 @@ pub async fn adjust_fee_if_necessary(
12411315
min_fee_wei: u128,
12421316
high_water_pnl: &mut Option<U256>,
12431317
sequence_number_of_last_fee_update: &mut Option<u64>,
1318+
metrics: Arc<KeeperMetrics>,
12441319
) -> Result<()> {
12451320
let provider_info = contract
12461321
.get_provider_info(provider_address)
@@ -1256,6 +1331,17 @@ pub async fn adjust_fee_if_necessary(
12561331
let max_callback_cost: u128 = estimate_tx_cost(contract.clone(), legacy_tx, gas_limit.into())
12571332
.await
12581333
.map_err(|e| anyhow!("Could not estimate transaction cost. error {:?}", e))?;
1334+
1335+
let account_label = AccountLabel {
1336+
chain_id: chain_id.clone(),
1337+
address: provider_address.to_string(),
1338+
};
1339+
1340+
metrics
1341+
.gas_price_estimate
1342+
.get_or_create(&account_label)
1343+
.set((max_callback_cost / u128::from(gas_limit)) as f64 / 1e9);
1344+
12591345
let target_fee_min = std::cmp::max(
12601346
(max_callback_cost * u128::from(min_profit_pct)) / 100,
12611347
min_fee_wei,
@@ -1264,6 +1350,11 @@ pub async fn adjust_fee_if_necessary(
12641350
(max_callback_cost * u128::from(target_profit_pct)) / 100,
12651351
min_fee_wei,
12661352
);
1353+
metrics
1354+
.target_provider_fee
1355+
.get_or_create(&account_label)
1356+
.set(((max_callback_cost * u128::from(target_profit_pct)) / 100) as f64 / 1e18);
1357+
12671358
let target_fee_max = std::cmp::max(
12681359
(max_callback_cost * u128::from(max_profit_pct)) / 100,
12691360
min_fee_wei,

0 commit comments

Comments
 (0)