Skip to content

Commit 62cb33b

Browse files
Include the bump part in the retryable function
1 parent 36a8369 commit 62cb33b

File tree

1 file changed

+100
-112
lines changed
  • aggregation_mode/proof_aggregator/src/backend

1 file changed

+100
-112
lines changed

aggregation_mode/proof_aggregator/src/backend/mod.rs

Lines changed: 100 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -175,40 +175,12 @@ impl ProofAggregator {
175175
hex::encode(blob_versioned_hash)
176176
);
177177

178-
// We start on 24 hours because the proof aggregator runs once a day, so the time elapsed
179-
// should be considered over a 24h period.
180-
let mut time_elapsed = Duration::from_secs(24 * 3600);
181-
182-
// Iterate until we can send the proof on-chain
183-
loop {
184-
// Fetch gas price from network
185-
let gas_price = self
186-
.rpc_provider
187-
.get_gas_price()
188-
.await
189-
.map_err(|e| AggregatedProofSubmissionError::GasPriceError(e.to_string()))?;
190-
191-
if Self::should_send_proof_to_verify_on_chain(
192-
time_elapsed,
193-
self.config.monthly_budget_eth,
194-
U256::from(gas_price),
195-
) {
196-
break;
197-
} else {
198-
info!("Skipping sending proof to ProofAggregationService contract due to budget/time constraints.");
199-
}
200-
201-
// Sleep for 3 minutes (15 blocks) before re-evaluating
202-
let time_to_sleep = Duration::from_secs(180);
203-
time_elapsed += time_to_sleep;
204-
sleep(time_to_sleep);
205-
}
206-
207-
info!("Sending proof to ProofAggregationService contract...");
208-
209-
// Retry in case of failure
210178
let receipt = self
211-
.send_proof_to_verify_on_chain_retryable(blob, blob_versioned_hash, aggregated_proof)
179+
.bump_and_send_proof_to_verify_on_chain_retryable(
180+
blob,
181+
blob_versioned_hash,
182+
aggregated_proof,
183+
)
212184
.await?;
213185
info!(
214186
"Proof sent and verified, tx hash {:?}",
@@ -239,84 +211,35 @@ impl ProofAggregator {
239211
Ok(())
240212
}
241213

242-
fn max_to_spend_in_wei(time_elapsed: Duration, monthly_eth_budget: f64) -> U256 {
243-
const SECONDS_PER_MONTH: u64 = 30 * 24 * 60 * 60;
244-
245-
// Note: this expect is safe because in case it was invalid, should have been caught at startup
246-
let monthly_budget_in_wei = parse_ether(&monthly_eth_budget.to_string())
247-
.expect("The monthly budget should be a non-negative value");
248-
249-
let elapsed_seconds = U256::from(time_elapsed.as_secs());
250-
251-
let budget_available_per_second_in_wei =
252-
monthly_budget_in_wei / U256::from(SECONDS_PER_MONTH);
253-
254-
budget_available_per_second_in_wei * elapsed_seconds
255-
}
256-
257-
/// Decides whether to send the aggregated proof to be verified on-chain based on
258-
/// time elapsed since last submission and monthly ETH budget.
259-
/// We make a linear function with the eth to spend this month and the time elapsed since last submission.
260-
/// If eth to spend / elapsed time is over the linear function, we skip the submission.
261-
fn should_send_proof_to_verify_on_chain(
262-
time_elapsed: Duration,
263-
monthly_eth_budget: f64,
264-
network_gas_price: U256,
265-
) -> bool {
266-
// We assume a fixed gas cost of 300,000 for each of the 2 transactions
267-
const ON_CHAIN_COST_IN_GAS_UNITS: u64 = 600_000u64;
268-
269-
let on_chain_cost_in_gas: U256 = U256::from(ON_CHAIN_COST_IN_GAS_UNITS);
270-
let max_to_spend_in_wei = Self::max_to_spend_in_wei(time_elapsed, monthly_eth_budget);
271-
272-
let expected_cost_in_wei = network_gas_price * on_chain_cost_in_gas;
273-
274-
expected_cost_in_wei <= max_to_spend_in_wei
275-
}
276-
277-
async fn send_proof_to_verify_on_chain_retryable(
214+
async fn bump_and_send_proof_to_verify_on_chain_retryable(
278215
&self,
279216
blob: BlobTransactionSidecar,
280217
blob_versioned_hash: [u8; 32],
281218
aggregated_proof: AlignedProof,
282219
) -> Result<TransactionReceipt, AggregatedProofSubmissionError> {
283-
match send_proof_to_verify_on_chain(
284-
blob.clone(),
285-
blob_versioned_hash,
286-
aggregated_proof.clone(),
287-
self.proof_aggregation_service.clone(),
288-
self.sp1_chunk_aggregator_vk_hash_bytes,
289-
self.risc0_chunk_aggregator_image_id_bytes,
220+
retry_function(
221+
|| {
222+
bump_and_send_proof_to_verify_on_chain(
223+
blob.clone(),
224+
blob_versioned_hash,
225+
aggregated_proof.clone(),
226+
self.proof_aggregation_service.clone(),
227+
self.sp1_chunk_aggregator_vk_hash_bytes,
228+
self.risc0_chunk_aggregator_image_id_bytes,
229+
self.rpc_provider.clone(),
230+
self.config.monthly_budget_eth,
231+
)
232+
},
233+
ETHEREUM_CALL_MIN_RETRY_DELAY,
234+
ETHEREUM_CALL_BACKOFF_FACTOR,
235+
ETHEREUM_CALL_MAX_RETRIES,
236+
ETHEREUM_CALL_MAX_RETRY_DELAY,
290237
)
291238
.await
292-
{
293-
Ok(tx_receipt) => Ok(tx_receipt),
294-
Err(err) => {
295-
tracing::error!("Failed to send proof to be verified on chain: {err:?}");
296-
297-
retry_function(
298-
|| {
299-
send_proof_to_verify_on_chain(
300-
blob.clone(),
301-
blob_versioned_hash,
302-
aggregated_proof.clone(),
303-
self.proof_aggregation_service.clone(),
304-
self.sp1_chunk_aggregator_vk_hash_bytes,
305-
self.risc0_chunk_aggregator_image_id_bytes,
306-
)
307-
},
308-
ETHEREUM_CALL_MIN_RETRY_DELAY,
309-
ETHEREUM_CALL_BACKOFF_FACTOR,
310-
ETHEREUM_CALL_MAX_RETRIES,
311-
ETHEREUM_CALL_MAX_RETRY_DELAY,
312-
)
313-
.await
314-
.map_err(|e| {
315-
error!("Could't get nonce: {:?}", e);
316-
e.inner()
317-
})
318-
}
319-
}
239+
.map_err(|e| {
240+
error!("Could't get nonce: {:?}", e);
241+
e.inner()
242+
})
320243
}
321244

322245
/// ### Blob capacity
@@ -392,14 +315,45 @@ impl ProofAggregator {
392315
}
393316
}
394317

395-
async fn send_proof_to_verify_on_chain(
318+
async fn bump_and_send_proof_to_verify_on_chain(
396319
blob: BlobTransactionSidecar,
397320
blob_versioned_hash: [u8; 32],
398321
aggregated_proof: AlignedProof,
399322
proof_aggregation_service: AlignedProofAggregationServiceContract,
400323
sp1_chunk_aggregator_vk_hash_bytes: [u8; 32],
401324
risc0_chunk_aggregator_image_id_bytes: [u8; 32],
325+
rpc_provider: RPCProvider,
326+
monthly_budget_eth: f64,
402327
) -> Result<TransactionReceipt, RetryError<AggregatedProofSubmissionError>> {
328+
// We start on 24 hours because the proof aggregator runs once a day, so the time elapsed
329+
// should be considered over a 24h period.
330+
let mut time_elapsed = Duration::from_secs(24 * 3600);
331+
332+
// Iterate until we can send the proof on-chain
333+
loop {
334+
// Fetch gas price from network
335+
let gas_price = rpc_provider.get_gas_price().await.map_err(|e| {
336+
RetryError::Transient(AggregatedProofSubmissionError::GasPriceError(e.to_string()))
337+
})?;
338+
339+
if should_send_proof_to_verify_on_chain(
340+
time_elapsed,
341+
monthly_budget_eth,
342+
U256::from(gas_price),
343+
) {
344+
break;
345+
} else {
346+
info!("Skipping sending proof to ProofAggregationService contract due to budget/time constraints.");
347+
}
348+
349+
// Sleep for 3 minutes (15 blocks) before re-evaluating
350+
let time_to_sleep = Duration::from_secs(180);
351+
time_elapsed += time_to_sleep;
352+
sleep(time_to_sleep);
353+
}
354+
355+
info!("Sending proof to ProofAggregationService contract...");
356+
403357
let tx_req = match aggregated_proof {
404358
AlignedProof::SP1(proof) => proof_aggregation_service
405359
.verifyAggregationSP1(
@@ -473,6 +427,40 @@ async fn send_proof_to_verify_on_chain(
473427
Ok(receipt)
474428
}
475429

430+
/// Decides whether to send the aggregated proof to be verified on-chain based on
431+
/// time elapsed since last submission and monthly ETH budget.
432+
/// We make a linear function with the eth to spend this month and the time elapsed since last submission.
433+
/// If eth to spend / elapsed time is over the linear function, we skip the submission.
434+
fn should_send_proof_to_verify_on_chain(
435+
time_elapsed: Duration,
436+
monthly_eth_budget: f64,
437+
network_gas_price: U256,
438+
) -> bool {
439+
// We assume a fixed gas cost of 300,000 for each of the 2 transactions
440+
const ON_CHAIN_COST_IN_GAS_UNITS: u64 = 600_000u64;
441+
442+
let on_chain_cost_in_gas: U256 = U256::from(ON_CHAIN_COST_IN_GAS_UNITS);
443+
let max_to_spend_in_wei = max_to_spend_in_wei(time_elapsed, monthly_eth_budget);
444+
445+
let expected_cost_in_wei = network_gas_price * on_chain_cost_in_gas;
446+
447+
expected_cost_in_wei <= max_to_spend_in_wei
448+
}
449+
450+
fn max_to_spend_in_wei(time_elapsed: Duration, monthly_eth_budget: f64) -> U256 {
451+
const SECONDS_PER_MONTH: u64 = 30 * 24 * 60 * 60;
452+
453+
// Note: this expect is safe because in case it was invalid, should have been caught at startup
454+
let monthly_budget_in_wei = parse_ether(&monthly_eth_budget.to_string())
455+
.expect("The monthly budget should be a non-negative value");
456+
457+
let elapsed_seconds = U256::from(time_elapsed.as_secs());
458+
459+
let budget_available_per_second_in_wei = monthly_budget_in_wei / U256::from(SECONDS_PER_MONTH);
460+
461+
budget_available_per_second_in_wei * elapsed_seconds
462+
}
463+
476464
use backon::ExponentialBuilder;
477465
use backon::Retryable;
478466
use std::future::Future;
@@ -554,7 +542,7 @@ mod tests {
554542
// Max to spend: 0.000000058 ETH/hour * 24 hours = 0.005 ETH
555543
// Expected cost: 600,000 * 1 Gwei = 0.0006 ETH
556544
// Expected cost < Max to spend, so we can send the proof
557-
assert!(ProofAggregator::should_send_proof_to_verify_on_chain(
545+
assert!(should_send_proof_to_verify_on_chain(
558546
Duration::from_secs(ONE_DAY_SECONDS), // 24 hours
559547
BUDGET_PER_MONTH_IN_ETH, // 0.15 ETH monthly budget
560548
gas_price, // 1 Gwei gas price
@@ -567,7 +555,7 @@ mod tests {
567555
// Max to spend: 0.000000058 ETH/hour * 24 hours = 0.005 ETH
568556
// Expected cost: 600,000 * 8 Gwei = 0.0048 ETH
569557
// Expected cost < Max to spend, so we can send the proof
570-
assert!(ProofAggregator::should_send_proof_to_verify_on_chain(
558+
assert!(should_send_proof_to_verify_on_chain(
571559
Duration::from_secs(ONE_DAY_SECONDS), // 24 hours
572560
BUDGET_PER_MONTH_IN_ETH, // 0.15 ETH monthly budget
573561
U256::from(8_000_000_000u64), // 8 Gwei gas price
@@ -580,7 +568,7 @@ mod tests {
580568
// Max to spend: 0.000000058 ETH/hour * 24 hours = 0.005 ETH
581569
// Expected cost: 600,000 * 10 Gwei = 0.006 ETH
582570
// Expected cost > Max to spend, so we cannot send the proof
583-
assert!(!ProofAggregator::should_send_proof_to_verify_on_chain(
571+
assert!(!should_send_proof_to_verify_on_chain(
584572
Duration::from_secs(ONE_DAY_SECONDS), // 24 hours
585573
BUDGET_PER_MONTH_IN_ETH, // 0.15 ETH monthly budget
586574
U256::from(10_000_000_000u64), // 10 Gwei gas price
@@ -593,7 +581,7 @@ mod tests {
593581
// Max to spend: 0.000000058 ETH/hour * 3 hours = 0.000625 ETH
594582
// Expected cost: 600,000 * 1 Gwei = 0.0006 ETH
595583
// Expected cost < Max to spend, so we can send the proof
596-
assert!(ProofAggregator::should_send_proof_to_verify_on_chain(
584+
assert!(should_send_proof_to_verify_on_chain(
597585
Duration::from_secs(3 * 3600), // 3 hours
598586
BUDGET_PER_MONTH_IN_ETH, // 0.15 ETH monthly budget
599587
gas_price, // 1 Gwei gas price
@@ -606,7 +594,7 @@ mod tests {
606594
// Max to spend: 0.000000058 ETH/hour * 1.2 hours = 0.00025 ETH
607595
// Expected cost: 600,000 * 1 Gwei = 0.0006 ETH
608596
// Expected cost > Max to spend, so we cannot send the proof
609-
assert!(!ProofAggregator::should_send_proof_to_verify_on_chain(
597+
assert!(!should_send_proof_to_verify_on_chain(
610598
Duration::from_secs_f64(1.2 * 3600.0), // 1.2 hours
611599
BUDGET_PER_MONTH_IN_ETH, // 0.15 ETH monthly budget
612600
gas_price, // 1 Gwei gas price
@@ -619,7 +607,7 @@ mod tests {
619607
// Max to spend: 0.000000038 ETH/hour * 24 hours = 0.0032832 ETH
620608
// Expected cost: 600,000 * 1 Gwei = 0.0006 ETH
621609
// Expected cost < Max to spend, so we can send the proof
622-
assert!(ProofAggregator::should_send_proof_to_verify_on_chain(
610+
assert!(should_send_proof_to_verify_on_chain(
623611
Duration::from_secs(ONE_DAY_SECONDS), // 24 hours
624612
0.1, // 0.1 ETH monthly budget
625613
gas_price, // 1 Gwei gas price
@@ -632,7 +620,7 @@ mod tests {
632620
// Max to spend: 0.0000000038 ETH/hour * 24 hours = 0.00032832 ETH
633621
// Expected cost: 600,000 * 1 Gwei = 0.0006 ETH
634622
// Expected cost > Max to spend, so we cannot send the proof
635-
assert!(!ProofAggregator::should_send_proof_to_verify_on_chain(
623+
assert!(!should_send_proof_to_verify_on_chain(
636624
Duration::from_secs(ONE_DAY_SECONDS), // 24 hours
637625
0.01, // 0.01 ETH monthly budget
638626
gas_price, // 1 Gwei gas price

0 commit comments

Comments
 (0)