Skip to content

Commit db9439b

Browse files
devin-ai-integration[bot]Jayant Krishnamurthy
andcommitted
refactor: move block delays to EthereumConfig and support multiple delays
Co-Authored-By: Jayant Krishnamurthy <[email protected]>
1 parent 71e1a2f commit db9439b

File tree

3 files changed

+44
-93
lines changed

3 files changed

+44
-93
lines changed

apps/fortuna/config.sample.yaml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@ chains:
3939
target_profit_pct: 20
4040
max_profit_pct: 100
4141

42+
# A list of block delays for processing blocks multiple times. Each number represents
43+
# how many blocks to wait before processing. For example, [5, 10, 20] means process
44+
# blocks after 5 blocks, then again after 10 blocks, and finally after 20 blocks.
45+
block_delays: [5, 10, 20]
46+
4247
# Historical commitments -- delete this block for local development purposes
4348
commitments:
4449
# prettier-ignore
@@ -78,5 +83,3 @@ keeper:
7883
value: 0xabcd
7984
# For production, you can store the private key in a file.
8085
# file: keeper-key.txt
81-
# Number of blocks to wait before processing new blocks (in addition to reveal_delay_blocks)
82-
delay_blocks: 5

apps/fortuna/src/config.rs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,16 @@ pub struct EthereumConfig {
177177
/// Maximum number of hashes to record in a request.
178178
/// This should be set according to the maximum gas limit the provider supports for callbacks.
179179
pub max_num_hashes: Option<u32>,
180+
181+
/// A list of delays (in blocks) that indicates how many blocks should be delayed
182+
/// before we process a block. For retry logic, we can process blocks multiple times
183+
/// at each specified delay. For example: [5, 10, 20].
184+
#[serde(default = "default_block_delays")]
185+
pub block_delays: Vec<u64>,
186+
}
187+
188+
fn default_block_delays() -> Vec<u64> {
189+
vec![5]
180190
}
181191

182192
fn default_priority_fee_multiplier_pct() -> u64 {
@@ -341,14 +351,6 @@ pub struct KeeperConfig {
341351
/// This key *does not need to be a registered provider*. In particular, production deployments
342352
/// should ensure this is a different key in order to reduce the severity of security breaches.
343353
pub private_key: SecretString,
344-
345-
/// Number of blocks to wait before processing new blocks (in addition to reveal_delay_blocks)
346-
#[serde(default = "default_delay_blocks")]
347-
pub delay_blocks: u64,
348-
}
349-
350-
fn default_delay_blocks() -> u64 {
351-
5
352354
}
353355

354356
// A secret is a string that can be provided either as a literal in the config,

apps/fortuna/src/keeper.rs

Lines changed: 29 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ impl KeeperMetrics {
250250
}
251251
}
252252

253-
#[derive(Debug)]
253+
#[derive(Debug, Clone)]
254254
pub struct BlockRange {
255255
pub from: BlockNumber,
256256
pub to: BlockNumber,
@@ -335,7 +335,7 @@ pub async fn run_keeper_threads(
335335
.in_current_span(),
336336
);
337337

338-
let (tx, _rx) = mpsc::channel::<BlockRange>(1000);
338+
let (tx, rx) = mpsc::channel::<BlockRange>(1000);
339339
// Spawn a thread to watch for new blocks and send the range of blocks for which events has not been handled to the `tx` channel.
340340
spawn(
341341
watch_blocks_wrapper(
@@ -346,57 +346,18 @@ pub async fn run_keeper_threads(
346346
)
347347
.in_current_span(),
348348
);
349-
// Create channels for both immediate and delayed block processing
350-
let (tx_immediate, rx_immediate) = mpsc::channel::<BlockRange>(1000);
351-
let (tx_delayed, rx_delayed) = mpsc::channel::<BlockRange>(1000);
352349

353-
// Spawn a thread to watch for new blocks and send the range of blocks to both channels
354-
spawn(
355-
watch_blocks_wrapper(
356-
chain_state.clone(),
357-
latest_safe_block,
358-
tx_immediate,
359-
chain_eth_config.geth_rpc_wss.clone(),
360-
)
361-
.in_current_span(),
362-
);
363-
364-
// Clone the tx_delayed channel for the second watch_blocks_wrapper
365-
spawn(
366-
watch_blocks_wrapper(
367-
chain_state.clone(),
368-
latest_safe_block,
369-
tx_delayed,
370-
chain_eth_config.geth_rpc_wss.clone(),
371-
)
372-
.in_current_span(),
373-
);
374-
375-
// Spawn a thread for immediate block processing
350+
// Spawn a thread for block processing with configured delays
376351
spawn(
377352
process_new_blocks(
378353
chain_state.clone(),
379-
rx_immediate,
354+
rx,
380355
Arc::clone(&contract),
381356
gas_limit,
382357
chain_eth_config.escalation_policy.clone(),
383358
metrics.clone(),
384359
fulfilled_requests_cache.clone(),
385-
)
386-
.in_current_span(),
387-
);
388-
389-
// Spawn a thread for delayed block processing
390-
spawn(
391-
process_new_blocks_delayed(
392-
chain_state.clone(),
393-
rx_delayed,
394-
Arc::clone(&contract),
395-
gas_limit,
396-
chain_eth_config.escalation_policy.clone(),
397-
metrics.clone(),
398-
fulfilled_requests_cache.clone(),
399-
5,
360+
chain_eth_config.clone(),
400361
)
401362
.in_current_span(),
402363
);
@@ -1006,8 +967,10 @@ pub async fn watch_blocks(
1006967
}
1007968
}
1008969

1009-
/// It waits on rx channel to receive block ranges and then calls process_block_range to process them.
970+
/// It waits on rx channel to receive block ranges and then calls process_block_range to process them
971+
/// for each configured block delay.
1010972
#[tracing::instrument(skip_all)]
973+
#[allow(clippy::too_many_arguments)]
1011974
pub async fn process_new_blocks(
1012975
chain_state: BlockchainState,
1013976
mut rx: mpsc::Receiver<BlockRange>,
@@ -1016,12 +979,14 @@ pub async fn process_new_blocks(
1016979
escalation_policy: EscalationPolicyConfig,
1017980
metrics: Arc<KeeperMetrics>,
1018981
fulfilled_requests_cache: Arc<RwLock<HashSet<u64>>>,
982+
chain_eth_config: EthereumConfig,
1019983
) {
1020984
tracing::info!("Waiting for new block ranges to process");
1021985
loop {
1022986
if let Some(block_range) = rx.recv().await {
987+
// Process blocks immediately first
1023988
process_block_range(
1024-
block_range,
989+
block_range.clone(),
1025990
Arc::clone(&contract),
1026991
gas_limit,
1027992
escalation_policy.clone(),
@@ -1031,44 +996,25 @@ pub async fn process_new_blocks(
1031996
)
1032997
.in_current_span()
1033998
.await;
1034-
}
1035-
}
1036-
}
1037999

1038-
#[tracing::instrument(skip_all)]
1039-
#[allow(clippy::too_many_arguments)]
1040-
pub async fn process_new_blocks_delayed(
1041-
chain_state: BlockchainState,
1042-
mut rx: mpsc::Receiver<BlockRange>,
1043-
contract: Arc<InstrumentedSignablePythContract>,
1044-
gas_limit: U256,
1045-
escalation_policy: EscalationPolicyConfig,
1046-
metrics: Arc<KeeperMetrics>,
1047-
fulfilled_requests_cache: Arc<RwLock<HashSet<u64>>>,
1048-
delay_blocks: u64,
1049-
) {
1050-
tracing::info!(
1051-
"Waiting for new block ranges to process with {} block delay",
1052-
delay_blocks
1053-
);
1054-
loop {
1055-
if let Some(block_range) = rx.recv().await {
1056-
let from_block_after_delay = block_range.from + delay_blocks;
1057-
let adjusted_range = BlockRange {
1058-
from: from_block_after_delay,
1059-
to: block_range.to + delay_blocks,
1060-
};
1061-
process_block_range(
1062-
adjusted_range,
1063-
Arc::clone(&contract),
1064-
gas_limit,
1065-
escalation_policy.clone(),
1066-
chain_state.clone(),
1067-
metrics.clone(),
1068-
fulfilled_requests_cache.clone(),
1069-
)
1070-
.in_current_span()
1071-
.await;
1000+
// Then process with each configured delay
1001+
for delay in &chain_eth_config.block_delays {
1002+
let adjusted_range = BlockRange {
1003+
from: block_range.from + delay,
1004+
to: block_range.to + delay,
1005+
};
1006+
process_block_range(
1007+
adjusted_range,
1008+
Arc::clone(&contract),
1009+
gas_limit,
1010+
escalation_policy.clone(),
1011+
chain_state.clone(),
1012+
metrics.clone(),
1013+
fulfilled_requests_cache.clone(),
1014+
)
1015+
.in_current_span()
1016+
.await;
1017+
}
10721018
}
10731019
}
10741020
}

0 commit comments

Comments
 (0)