Skip to content

Commit 85643d6

Browse files
feat(aggregation-mode): Bump fee when proof verification times out
1 parent ba483d3 commit 85643d6

1 file changed

Lines changed: 160 additions & 80 deletions

File tree

  • aggregation_mode/proof_aggregator/src/backend

aggregation_mode/proof_aggregator/src/backend/mod.rs

Lines changed: 160 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use alloy::{
2222
consensus::{BlobTransactionSidecar, EnvKzgSettings, EthereumTxEnvelope, TxEip4844WithSidecar},
2323
eips::{eip4844::BYTES_PER_BLOB, eip7594::BlobTransactionSidecarEip7594, Encodable2718},
2424
hex,
25-
network::EthereumWallet,
25+
network::{EthereumWallet, TransactionBuilder},
2626
primitives::{utils::parse_ether, Address, U256},
2727
providers::{PendingTransactionError, Provider, ProviderBuilder},
2828
rpc::types::TransactionReceipt,
@@ -334,90 +334,170 @@ impl ProofAggregator {
334334

335335
info!("Sending proof to ProofAggregationService contract...");
336336

337-
let tx_req = match aggregated_proof {
338-
AlignedProof::SP1(proof) => self
339-
.proof_aggregation_service
340-
.verifyAggregationSP1(
341-
blob_versioned_hash.into(),
342-
proof.proof_with_pub_values.public_values.to_vec().into(),
343-
proof.proof_with_pub_values.bytes().into(),
344-
self.sp1_chunk_aggregator_vk_hash_bytes.into(),
345-
)
346-
.sidecar(blob)
347-
.into_transaction_request(),
348-
AlignedProof::Risc0(proof) => {
349-
let encoded_seal = encode_seal(&proof.receipt)
350-
.map_err(|e| AggregatedProofSubmissionError::Risc0EncodingSeal(e.to_string()))
351-
.map_err(RetryError::Permanent)?;
352-
self.proof_aggregation_service
353-
.verifyAggregationRisc0(
337+
// TODO: Read from config
338+
let max_retries = 5;
339+
let retry_interval = Duration::from_secs(120);
340+
let fee_multiplier: f64 = 1.2;
341+
342+
for attempt in 0..max_retries {
343+
let mut tx_req = match aggregated_proof {
344+
AlignedProof::SP1(proof) => self
345+
.proof_aggregation_service
346+
.verifyAggregationSP1(
354347
blob_versioned_hash.into(),
355-
encoded_seal.into(),
356-
proof.receipt.journal.bytes.clone().into(),
357-
self.risc0_chunk_aggregator_image_id_bytes.into(),
348+
proof.proof_with_pub_values.public_values.to_vec().into(),
349+
proof.proof_with_pub_values.bytes().into(),
350+
self.sp1_chunk_aggregator_vk_hash_bytes.into(),
358351
)
359-
.sidecar(blob)
360-
.into_transaction_request()
361-
}
362-
};
363-
364-
let provider = self.proof_aggregation_service.provider();
365-
let envelope = provider
366-
.fill(tx_req)
367-
.await
368-
.map_err(|err| {
369-
AggregatedProofSubmissionError::SendVerifyAggregatedProofTransaction(
370-
err.to_string(),
371-
)
372-
})
373-
.map_err(RetryError::Transient)?
374-
.try_into_envelope()
375-
.map_err(|err| {
376-
AggregatedProofSubmissionError::SendVerifyAggregatedProofTransaction(
377-
err.to_string(),
378-
)
379-
})
380-
.map_err(RetryError::Transient)?;
381-
let tx: EthereumTxEnvelope<TxEip4844WithSidecar<BlobTransactionSidecarEip7594>> = envelope
382-
.try_into_pooled()
383-
.map_err(|err| {
384-
AggregatedProofSubmissionError::SendVerifyAggregatedProofTransaction(
385-
err.to_string(),
386-
)
387-
})
388-
.map_err(RetryError::Transient)?
389-
.try_map_eip4844(|tx| {
390-
tx.try_map_sidecar(|sidecar| sidecar.try_into_7594(EnvKzgSettings::Default.get()))
391-
})
392-
.map_err(|err| {
393-
AggregatedProofSubmissionError::SendVerifyAggregatedProofTransaction(
394-
err.to_string(),
395-
)
396-
})
397-
.map_err(RetryError::Transient)?;
352+
.sidecar(blob.clone())
353+
.into_transaction_request(),
354+
AlignedProof::Risc0(proof) => {
355+
let encoded_seal = encode_seal(&proof.receipt)
356+
.map_err(|e| {
357+
AggregatedProofSubmissionError::Risc0EncodingSeal(e.to_string())
358+
})
359+
.map_err(RetryError::Permanent)?;
360+
self.proof_aggregation_service
361+
.verifyAggregationRisc0(
362+
blob_versioned_hash.into(),
363+
encoded_seal.into(),
364+
proof.receipt.journal.bytes.clone().into(),
365+
self.risc0_chunk_aggregator_image_id_bytes.into(),
366+
)
367+
.sidecar(blob.clone())
368+
.into_transaction_request()
369+
}
370+
};
398371

399-
let encoded_tx = tx.encoded_2718();
400-
let pending_tx = provider
401-
.send_raw_transaction(&encoded_tx)
402-
.await
403-
.map_err(|err| {
404-
AggregatedProofSubmissionError::SendVerifyAggregatedProofTransaction(
405-
err.to_string(),
406-
)
407-
})
408-
.map_err(RetryError::Transient)?;
372+
let provider = self.proof_aggregation_service.provider();
373+
374+
// TODO: Move this to a separate method reset_gas_fees()
375+
// Increase gas price/fees for retries before filling
376+
if attempt > 0 {
377+
let multiplier = fee_multiplier.powi(attempt as i32);
378+
379+
info!(
380+
"Retry attempt {} with increased fee ({}x)",
381+
attempt, multiplier
382+
);
383+
384+
// Obtain the current gas price if not set
385+
if tx_req.max_fee_per_gas.is_none() {
386+
let current_gas_price = provider.get_gas_price().await.map_err(|e| {
387+
RetryError::Transient(AggregatedProofSubmissionError::GasPriceError(
388+
e.to_string(),
389+
))
390+
})?;
391+
392+
let new_max_fee = (current_gas_price as f64 * multiplier) as u128;
393+
let new_priority_fee = (current_gas_price as f64 * multiplier * 0.1) as u128;
394+
395+
tx_req = tx_req
396+
.with_max_fee_per_gas(new_max_fee)
397+
.with_max_priority_fee_per_gas(new_priority_fee);
398+
} else {
399+
// If set, multiplicate the current ones
400+
if let Some(max_fee) = tx_req.max_fee_per_gas {
401+
let new_max_fee = (max_fee as f64 * multiplier) as u128;
402+
tx_req = tx_req.with_max_fee_per_gas(new_max_fee);
403+
}
404+
if let Some(priority_fee) = tx_req.max_priority_fee_per_gas {
405+
let new_priority_fee = (priority_fee as f64 * multiplier * 0.1) as u128;
406+
tx_req = tx_req.with_max_priority_fee_per_gas(new_priority_fee);
407+
}
408+
}
409+
}
409410

410-
let receipt = pending_tx
411-
.get_receipt()
412-
.await
413-
.map_err(|err| {
414-
AggregatedProofSubmissionError::SendVerifyAggregatedProofTransaction(
415-
err.to_string(),
416-
)
417-
})
418-
.map_err(RetryError::Transient)?;
411+
let envelope = provider
412+
.fill(tx_req)
413+
.await
414+
.map_err(|err| {
415+
AggregatedProofSubmissionError::SendVerifyAggregatedProofTransaction(
416+
err.to_string(),
417+
)
418+
})
419+
.map_err(RetryError::Transient)?
420+
.try_into_envelope()
421+
.map_err(|err| {
422+
AggregatedProofSubmissionError::SendVerifyAggregatedProofTransaction(
423+
err.to_string(),
424+
)
425+
})
426+
.map_err(RetryError::Transient)?;
427+
428+
let tx: EthereumTxEnvelope<TxEip4844WithSidecar<BlobTransactionSidecarEip7594>> =
429+
envelope
430+
.try_into_pooled()
431+
.map_err(|err| {
432+
AggregatedProofSubmissionError::SendVerifyAggregatedProofTransaction(
433+
err.to_string(),
434+
)
435+
})
436+
.map_err(RetryError::Transient)?
437+
.try_map_eip4844(|tx| {
438+
tx.try_map_sidecar(|sidecar| {
439+
sidecar.try_into_7594(EnvKzgSettings::Default.get())
440+
})
441+
})
442+
.map_err(|err| {
443+
AggregatedProofSubmissionError::SendVerifyAggregatedProofTransaction(
444+
err.to_string(),
445+
)
446+
})
447+
.map_err(RetryError::Transient)?;
448+
449+
let encoded_tx = tx.encoded_2718();
450+
let pending_tx = provider
451+
.send_raw_transaction(&encoded_tx)
452+
.await
453+
.map_err(|err| {
454+
AggregatedProofSubmissionError::SendVerifyAggregatedProofTransaction(
455+
err.to_string(),
456+
)
457+
})
458+
.map_err(RetryError::Transient)?;
459+
460+
// Wait for the receipt with timeout
461+
let receipt_result =
462+
tokio::time::timeout(retry_interval, pending_tx.get_receipt()).await;
463+
464+
match receipt_result {
465+
Ok(Ok(receipt)) => {
466+
info!(
467+
"Transaction confirmed successfully on attempt {}",
468+
attempt + 1
469+
);
470+
return Ok(receipt);
471+
}
472+
Ok(Err(err)) => {
473+
warn!("Error getting receipt on attempt {}: {}", attempt + 1, err);
474+
if attempt == max_retries - 1 {
475+
return Err(RetryError::Transient(
476+
AggregatedProofSubmissionError::SendVerifyAggregatedProofTransaction(
477+
err.to_string(),
478+
),
479+
));
480+
}
481+
}
482+
Err(_) => {
483+
warn!("Transaction not confirmed after {} seconds on attempt {}, retrying with higher fee...",
484+
retry_interval.as_secs(), attempt + 1);
485+
if attempt == max_retries - 1 {
486+
return Err(RetryError::Transient(
487+
AggregatedProofSubmissionError::SendVerifyAggregatedProofTransaction(
488+
"Transaction timeout after all retries".to_string(),
489+
),
490+
));
491+
}
492+
}
493+
}
494+
}
419495

420-
Ok(receipt)
496+
Err(RetryError::Transient(
497+
AggregatedProofSubmissionError::SendVerifyAggregatedProofTransaction(
498+
"Max retries exceeded".to_string(),
499+
),
500+
))
421501
}
422502

423503
async fn wait_until_can_submit_aggregated_proof(

0 commit comments

Comments
 (0)