@@ -55,6 +55,8 @@ const UPDATE_COMMITMENTS_INTERVAL: Duration = Duration::from_secs(30);
55
55
const UPDATE_COMMITMENTS_THRESHOLD_FACTOR : f64 = 0.95 ;
56
56
/// Rety last N blocks
57
57
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 ;
58
60
59
61
#[ derive( Clone , Debug , Hash , PartialEq , Eq , EncodeLabelSet ) ]
60
62
pub struct AccountLabel {
@@ -254,6 +256,7 @@ pub async fn run_keeper_threads(
254
256
} ,
255
257
contract. clone ( ) ,
256
258
gas_limit,
259
+ chain_eth_config. backoff_gas_multiplier_pct ,
257
260
chain_state. clone ( ) ,
258
261
metrics. clone ( ) ,
259
262
fulfilled_requests_cache. clone ( ) ,
@@ -279,6 +282,7 @@ pub async fn run_keeper_threads(
279
282
rx,
280
283
Arc :: clone ( & contract) ,
281
284
gas_limit,
285
+ chain_eth_config. backoff_gas_multiplier_pct ,
282
286
metrics. clone ( ) ,
283
287
fulfilled_requests_cache. clone ( ) ,
284
288
)
@@ -303,7 +307,9 @@ pub async fn run_keeper_threads(
303
307
chain_state. provider_address ,
304
308
ADJUST_FEE_INTERVAL ,
305
309
chain_eth_config. legacy_tx ,
306
- chain_eth_config. gas_limit ,
310
+ // NOTE: we adjust fees based on the maximum gas that the keeper will submit a callback with.
311
+ // This number is *larger* than the configured gas limit, as we pad gas on transaction submission for reliability.
312
+ ( chain_eth_config. gas_limit * DEFAULT_GAS_ESTIMATE_MULTIPLIER_PCT ) / 100 ,
307
313
chain_eth_config. min_profit_pct ,
308
314
chain_eth_config. target_profit_pct ,
309
315
chain_eth_config. max_profit_pct ,
@@ -372,6 +378,7 @@ pub async fn process_event_with_backoff(
372
378
chain_state : BlockchainState ,
373
379
contract : Arc < InstrumentedSignablePythContract > ,
374
380
gas_limit : U256 ,
381
+ backoff_gas_multiplier_pct : u64 ,
375
382
metrics : Arc < KeeperMetrics > ,
376
383
) {
377
384
let start_time = std:: time:: Instant :: now ( ) ;
@@ -388,13 +395,35 @@ pub async fn process_event_with_backoff(
388
395
max_elapsed_time : Some ( Duration :: from_secs ( 300 ) ) , // retry for 5 minutes
389
396
..Default :: default ( )
390
397
} ;
398
+
399
+ let current_multiplier = Arc :: new ( AtomicU64 :: new ( DEFAULT_GAS_ESTIMATE_MULTIPLIER_PCT ) ) ;
400
+
391
401
match backoff:: future:: retry_notify (
392
402
backoff,
393
403
|| async {
394
- process_event ( & event, & chain_state, & contract, gas_limit, metrics. clone ( ) ) . await
404
+ let multiplier = current_multiplier. load ( std:: sync:: atomic:: Ordering :: Relaxed ) ;
405
+ process_event (
406
+ & event,
407
+ & chain_state,
408
+ & contract,
409
+ gas_limit,
410
+ multiplier,
411
+ metrics. clone ( ) ,
412
+ )
413
+ . await
395
414
} ,
396
415
|e, dur| {
397
- tracing:: error!( "Error happened at {:?}: {}" , dur, e) ;
416
+ let multiplier = current_multiplier. load ( std:: sync:: atomic:: Ordering :: Relaxed ) ;
417
+ tracing:: error!(
418
+ "Error at duration {:?} with gas multiplier {}: {}" ,
419
+ dur,
420
+ multiplier,
421
+ e
422
+ ) ;
423
+ current_multiplier. store (
424
+ multiplier. saturating_mul ( backoff_gas_multiplier_pct) / 100 ,
425
+ std:: sync:: atomic:: Ordering :: Relaxed ,
426
+ ) ;
398
427
} ,
399
428
)
400
429
. await
@@ -436,6 +465,8 @@ pub async fn process_event(
436
465
chain_config : & BlockchainState ,
437
466
contract : & InstrumentedSignablePythContract ,
438
467
gas_limit : U256 ,
468
+ // A value of 100 submits the tx with the same gas as the estimate.
469
+ gas_estimate_multiplier_pct : u64 ,
439
470
metrics : Arc < KeeperMetrics > ,
440
471
) -> Result < ( ) , backoff:: Error < anyhow:: Error > > {
441
472
// ignore requests that are not for the configured provider
@@ -466,6 +497,8 @@ pub async fn process_event(
466
497
backoff:: Error :: transient ( anyhow ! ( "Error estimating gas for reveal: {:?}" , e) )
467
498
} ) ?;
468
499
500
+ // The gas limit on the simulated transaction is the configured gas limit on the chain,
501
+ // but we are willing to pad the gas a bit to ensure reliable submission.
469
502
if gas_estimate > gas_limit {
470
503
return Err ( backoff:: Error :: permanent ( anyhow ! (
471
504
"Gas estimate for reveal with callback is higher than the gas limit {} > {}" ,
@@ -474,8 +507,10 @@ pub async fn process_event(
474
507
) ) ) ;
475
508
}
476
509
477
- // Pad the gas estimate by 25% after checking it against the gas limit
478
- let gas_estimate = gas_estimate. saturating_mul ( 5 . into ( ) ) / 4 ;
510
+ // Pad the gas estimate after checking it against the simulation gas limit, ensuring that
511
+ // the padded gas estimate doesn't exceed the maximum amount of gas we are willing to use.
512
+ let gas_estimate = gas_estimate. saturating_mul ( gas_estimate_multiplier_pct. into ( ) ) / 100 ;
513
+ let gas_estimate = gas_estimate. min ( ( gas_limit * DEFAULT_GAS_ESTIMATE_MULTIPLIER_PCT ) / 100 ) ;
479
514
480
515
let contract_call = contract
481
516
. reveal_with_callback (
@@ -589,6 +624,7 @@ pub async fn process_block_range(
589
624
block_range : BlockRange ,
590
625
contract : Arc < InstrumentedSignablePythContract > ,
591
626
gas_limit : U256 ,
627
+ backoff_gas_multiplier_pct : u64 ,
592
628
chain_state : api:: BlockchainState ,
593
629
metrics : Arc < KeeperMetrics > ,
594
630
fulfilled_requests_cache : Arc < RwLock < HashSet < u64 > > > ,
@@ -612,6 +648,7 @@ pub async fn process_block_range(
612
648
} ,
613
649
contract. clone ( ) ,
614
650
gas_limit,
651
+ backoff_gas_multiplier_pct,
615
652
chain_state. clone ( ) ,
616
653
metrics. clone ( ) ,
617
654
fulfilled_requests_cache. clone ( ) ,
@@ -634,6 +671,7 @@ pub async fn process_single_block_batch(
634
671
block_range : BlockRange ,
635
672
contract : Arc < InstrumentedSignablePythContract > ,
636
673
gas_limit : U256 ,
674
+ backoff_gas_multiplier_pct : u64 ,
637
675
chain_state : api:: BlockchainState ,
638
676
metrics : Arc < KeeperMetrics > ,
639
677
fulfilled_requests_cache : Arc < RwLock < HashSet < u64 > > > ,
@@ -660,6 +698,7 @@ pub async fn process_single_block_batch(
660
698
chain_state. clone ( ) ,
661
699
contract. clone ( ) ,
662
700
gas_limit,
701
+ backoff_gas_multiplier_pct,
663
702
metrics. clone ( ) ,
664
703
)
665
704
. in_current_span ( ) ,
@@ -806,6 +845,7 @@ pub async fn process_new_blocks(
806
845
mut rx : mpsc:: Receiver < BlockRange > ,
807
846
contract : Arc < InstrumentedSignablePythContract > ,
808
847
gas_limit : U256 ,
848
+ backoff_gas_multiplier_pct : u64 ,
809
849
metrics : Arc < KeeperMetrics > ,
810
850
fulfilled_requests_cache : Arc < RwLock < HashSet < u64 > > > ,
811
851
) {
@@ -816,6 +856,7 @@ pub async fn process_new_blocks(
816
856
block_range,
817
857
Arc :: clone ( & contract) ,
818
858
gas_limit,
859
+ backoff_gas_multiplier_pct,
819
860
chain_state. clone ( ) ,
820
861
metrics. clone ( ) ,
821
862
fulfilled_requests_cache. clone ( ) ,
@@ -832,6 +873,7 @@ pub async fn process_backlog(
832
873
backlog_range : BlockRange ,
833
874
contract : Arc < InstrumentedSignablePythContract > ,
834
875
gas_limit : U256 ,
876
+ backoff_gas_multiplier_pct : u64 ,
835
877
chain_state : BlockchainState ,
836
878
metrics : Arc < KeeperMetrics > ,
837
879
fulfilled_requests_cache : Arc < RwLock < HashSet < u64 > > > ,
@@ -841,6 +883,7 @@ pub async fn process_backlog(
841
883
backlog_range,
842
884
contract,
843
885
gas_limit,
886
+ backoff_gas_multiplier_pct,
844
887
chain_state,
845
888
metrics,
846
889
fulfilled_requests_cache,
0 commit comments