Skip to content

Commit 6d3709c

Browse files
committed
merge
2 parents 0e777c5 + f3a8f56 commit 6d3709c

File tree

5 files changed

+60
-7
lines changed

5 files changed

+60
-7
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 = "6.7.2"
3+
version = "6.8.1"
44
edition = "2021"
55

66
[dependencies]

apps/fortuna/config.sample.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ chains:
66
# Keeper configuration for the chain
77
reveal_delay_blocks: 0
88
gas_limit: 500000
9+
# Increase the transaction gas limit by 10% each time the callback fails
10+
# defaults to 100 (i.e., don't change the gas limit) if not specified.
11+
backoff_gas_multiplier_pct: 110
912
min_keeper_balance: 100000000000000000
1013

1114
# Provider configuration

apps/fortuna/src/config.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,10 @@ pub struct EthereumConfig {
134134
/// The gas limit to use for entropy callback transactions.
135135
pub gas_limit: u64,
136136

137+
/// The percentage multiplier to apply to the gas limit for each backoff.
138+
#[serde(default = "default_backoff_gas_multiplier_pct")]
139+
pub backoff_gas_multiplier_pct: u64,
140+
137141
/// The minimum percentage profit to earn as a function of the callback cost.
138142
/// For example, 20 means a profit of 20% over the cost of the callback.
139143
/// The fee will be raised if the profit is less than this number.
@@ -172,6 +176,10 @@ pub struct EthereumConfig {
172176
pub priority_fee_multiplier_pct: u64,
173177
}
174178

179+
fn default_backoff_gas_multiplier_pct() -> u64 {
180+
100
181+
}
182+
175183
/// A commitment that the provider used to generate random numbers at some point in the past.
176184
/// These historical commitments need to be stored in the configuration to support transition points where
177185
/// the commitment changes. In theory, this information is stored on the blockchain, but unfortunately it

apps/fortuna/src/keeper.rs

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ const UPDATE_COMMITMENTS_INTERVAL: Duration = Duration::from_secs(30);
5555
const UPDATE_COMMITMENTS_THRESHOLD_FACTOR: f64 = 0.95;
5656
/// Rety last N blocks
5757
const RETRY_PREVIOUS_BLOCKS: u64 = 100;
58+
/// By default, we scale the gas estimate by 25% when submitting the tx.
59+
const DEFAULT_GAS_ESTIMATE_MULTIPLIER_PCT: u64 = 125;
5860

5961
#[derive(Clone, Debug, Hash, PartialEq, Eq, EncodeLabelSet)]
6062
pub struct AccountLabel {
@@ -270,6 +272,7 @@ pub async fn run_keeper_threads(
270272
},
271273
contract.clone(),
272274
gas_limit,
275+
chain_eth_config.backoff_gas_multiplier_pct,
273276
chain_state.clone(),
274277
metrics.clone(),
275278
fulfilled_requests_cache.clone(),
@@ -295,6 +298,7 @@ pub async fn run_keeper_threads(
295298
rx,
296299
Arc::clone(&contract),
297300
gas_limit,
301+
chain_eth_config.backoff_gas_multiplier_pct,
298302
metrics.clone(),
299303
fulfilled_requests_cache.clone(),
300304
)
@@ -319,7 +323,9 @@ pub async fn run_keeper_threads(
319323
chain_state.provider_address,
320324
ADJUST_FEE_INTERVAL,
321325
chain_eth_config.legacy_tx,
322-
chain_eth_config.gas_limit,
326+
// NOTE: we adjust fees based on the maximum gas that the keeper will submit a callback with.
327+
// This number is *larger* than the configured gas limit, as we pad gas on transaction submission for reliability.
328+
(chain_eth_config.gas_limit * DEFAULT_GAS_ESTIMATE_MULTIPLIER_PCT) / 100,
323329
chain_eth_config.min_profit_pct,
324330
chain_eth_config.target_profit_pct,
325331
chain_eth_config.max_profit_pct,
@@ -388,6 +394,7 @@ pub async fn process_event_with_backoff(
388394
chain_state: BlockchainState,
389395
contract: Arc<InstrumentedSignablePythContract>,
390396
gas_limit: U256,
397+
backoff_gas_multiplier_pct: u64,
391398
metrics: Arc<KeeperMetrics>,
392399
) {
393400
let start_time = std::time::Instant::now();
@@ -403,13 +410,34 @@ pub async fn process_event_with_backoff(
403410
..Default::default()
404411
};
405412

413+
let current_multiplier = Arc::new(AtomicU64::new(DEFAULT_GAS_ESTIMATE_MULTIPLIER_PCT));
414+
406415
let success = backoff::future::retry_notify(
407416
backoff,
408417
|| async {
409-
process_event(&event, &chain_state, &contract, gas_limit, metrics.clone()).await
418+
let multiplier = current_multiplier.load(std::sync::atomic::Ordering::Relaxed);
419+
process_event(
420+
&event,
421+
&chain_state,
422+
&contract,
423+
gas_limit,
424+
multiplier,
425+
metrics.clone(),
426+
)
427+
.await
410428
},
411429
|e, dur| {
412-
tracing::error!("Error happened at {:?}: {}", dur, e);
430+
let multiplier = current_multiplier.load(std::sync::atomic::Ordering::Relaxed);
431+
tracing::error!(
432+
"Error at duration {:?} with gas multiplier {}: {}",
433+
dur,
434+
multiplier,
435+
e
436+
);
437+
current_multiplier.store(
438+
multiplier.saturating_mul(backoff_gas_multiplier_pct) / 100,
439+
std::sync::atomic::Ordering::Relaxed,
440+
);
413441
},
414442
)
415443
.await;
@@ -467,6 +495,8 @@ pub async fn process_event(
467495
chain_config: &BlockchainState,
468496
contract: &InstrumentedSignablePythContract,
469497
gas_limit: U256,
498+
// A value of 100 submits the tx with the same gas as the estimate.
499+
gas_estimate_multiplier_pct: u64,
470500
metrics: Arc<KeeperMetrics>,
471501
) -> Result<(), backoff::Error<anyhow::Error>> {
472502
// ignore requests that are not for the configured provider
@@ -497,6 +527,8 @@ pub async fn process_event(
497527
backoff::Error::transient(anyhow!("Error estimating gas for reveal: {:?}", e))
498528
})?;
499529

530+
// The gas limit on the simulated transaction is the configured gas limit on the chain,
531+
// but we are willing to pad the gas a bit to ensure reliable submission.
500532
if gas_estimate > gas_limit {
501533
return Err(backoff::Error::permanent(anyhow!(
502534
"Gas estimate for reveal with callback is higher than the gas limit {} > {}",
@@ -505,8 +537,10 @@ pub async fn process_event(
505537
)));
506538
}
507539

508-
// Pad the gas estimate by 25% after checking it against the gas limit
509-
let gas_estimate = gas_estimate.saturating_mul(5.into()) / 4;
540+
// Pad the gas estimate after checking it against the simulation gas limit, ensuring that
541+
// the padded gas estimate doesn't exceed the maximum amount of gas we are willing to use.
542+
let gas_estimate = gas_estimate.saturating_mul(gas_estimate_multiplier_pct.into()) / 100;
543+
let gas_estimate = gas_estimate.min((gas_limit * DEFAULT_GAS_ESTIMATE_MULTIPLIER_PCT) / 100);
510544

511545
let contract_call = contract
512546
.reveal_with_callback(
@@ -620,6 +654,7 @@ pub async fn process_block_range(
620654
block_range: BlockRange,
621655
contract: Arc<InstrumentedSignablePythContract>,
622656
gas_limit: U256,
657+
backoff_gas_multiplier_pct: u64,
623658
chain_state: api::BlockchainState,
624659
metrics: Arc<KeeperMetrics>,
625660
fulfilled_requests_cache: Arc<RwLock<HashSet<u64>>>,
@@ -643,6 +678,7 @@ pub async fn process_block_range(
643678
},
644679
contract.clone(),
645680
gas_limit,
681+
backoff_gas_multiplier_pct,
646682
chain_state.clone(),
647683
metrics.clone(),
648684
fulfilled_requests_cache.clone(),
@@ -665,6 +701,7 @@ pub async fn process_single_block_batch(
665701
block_range: BlockRange,
666702
contract: Arc<InstrumentedSignablePythContract>,
667703
gas_limit: U256,
704+
backoff_gas_multiplier_pct: u64,
668705
chain_state: api::BlockchainState,
669706
metrics: Arc<KeeperMetrics>,
670707
fulfilled_requests_cache: Arc<RwLock<HashSet<u64>>>,
@@ -691,6 +728,7 @@ pub async fn process_single_block_batch(
691728
chain_state.clone(),
692729
contract.clone(),
693730
gas_limit,
731+
backoff_gas_multiplier_pct,
694732
metrics.clone(),
695733
)
696734
.in_current_span(),
@@ -837,6 +875,7 @@ pub async fn process_new_blocks(
837875
mut rx: mpsc::Receiver<BlockRange>,
838876
contract: Arc<InstrumentedSignablePythContract>,
839877
gas_limit: U256,
878+
backoff_gas_multiplier_pct: u64,
840879
metrics: Arc<KeeperMetrics>,
841880
fulfilled_requests_cache: Arc<RwLock<HashSet<u64>>>,
842881
) {
@@ -847,6 +886,7 @@ pub async fn process_new_blocks(
847886
block_range,
848887
Arc::clone(&contract),
849888
gas_limit,
889+
backoff_gas_multiplier_pct,
850890
chain_state.clone(),
851891
metrics.clone(),
852892
fulfilled_requests_cache.clone(),
@@ -863,6 +903,7 @@ pub async fn process_backlog(
863903
backlog_range: BlockRange,
864904
contract: Arc<InstrumentedSignablePythContract>,
865905
gas_limit: U256,
906+
backoff_gas_multiplier_pct: u64,
866907
chain_state: BlockchainState,
867908
metrics: Arc<KeeperMetrics>,
868909
fulfilled_requests_cache: Arc<RwLock<HashSet<u64>>>,
@@ -872,6 +913,7 @@ pub async fn process_backlog(
872913
backlog_range,
873914
contract,
874915
gas_limit,
916+
backoff_gas_multiplier_pct,
875917
chain_state,
876918
metrics,
877919
fulfilled_requests_cache,

0 commit comments

Comments
 (0)