add dynamic gas price adjustment when submitting pora (#324)

This commit is contained in:
0g-peterzhb 2025-02-11 16:34:58 +08:00 committed by GitHub
parent 40d435597a
commit 9ce215b919
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -1,9 +1,10 @@
use contract_interface::PoraAnswer; use contract_interface::PoraAnswer;
use contract_interface::{PoraMine, ZgsFlow}; use contract_interface::{PoraMine, ZgsFlow};
use ethereum_types::U256; use ethereum_types::U256;
use ethers::abi::Detokenize;
use ethers::contract::ContractCall; use ethers::contract::ContractCall;
use ethers::prelude::{Http, Provider, RetryClient}; use ethers::prelude::{Http, Provider, RetryClient};
use ethers::providers::PendingTransaction; use ethers::providers::{Middleware, ProviderError};
use hex::ToHex; use hex::ToHex;
use shared_types::FlowRangeProof; use shared_types::FlowRangeProof;
use std::sync::Arc; use std::sync::Arc;
@ -20,6 +21,7 @@ use crate::watcher::MineContextMessage;
use zgs_spec::{BYTES_PER_SEAL, SECTORS_PER_SEAL}; use zgs_spec::{BYTES_PER_SEAL, SECTORS_PER_SEAL};
const SUBMISSION_RETRIES: usize = 15; const SUBMISSION_RETRIES: usize = 15;
const ADJUST_GAS_RETRIES: usize = 20;
pub struct Submitter { pub struct Submitter {
mine_answer_receiver: mpsc::UnboundedReceiver<AnswerWithoutProof>, mine_answer_receiver: mpsc::UnboundedReceiver<AnswerWithoutProof>,
@ -28,6 +30,7 @@ pub struct Submitter {
flow_contract: ZgsFlow<Provider<RetryClient<Http>>>, flow_contract: ZgsFlow<Provider<RetryClient<Http>>>,
default_gas_limit: Option<U256>, default_gas_limit: Option<U256>,
store: Arc<Store>, store: Arc<Store>,
provider: Arc<Provider<RetryClient<Http>>>,
} }
impl Submitter { impl Submitter {
@ -41,7 +44,7 @@ impl Submitter {
config: &MinerConfig, config: &MinerConfig,
) { ) {
let mine_contract = PoraMine::new(config.mine_address, signing_provider); let mine_contract = PoraMine::new(config.mine_address, signing_provider);
let flow_contract = ZgsFlow::new(config.flow_address, provider); let flow_contract = ZgsFlow::new(config.flow_address, provider.clone());
let default_gas_limit = config.submission_gas; let default_gas_limit = config.submission_gas;
let submitter = Submitter { let submitter = Submitter {
@ -51,6 +54,7 @@ impl Submitter {
flow_contract, flow_contract,
store, store,
default_gas_limit, default_gas_limit,
provider,
}; };
executor.spawn( executor.spawn(
async move { Box::pin(submitter.start()).await }, async move { Box::pin(submitter.start()).await },
@ -153,29 +157,82 @@ impl Submitter {
submission_call.estimate_gas().await submission_call.estimate_gas().await
); );
let pending_transaction: PendingTransaction<'_, _> = submission_call self.submit_with_retry(submission_call).await
.send() }
async fn submit_with_retry<M: Middleware, T: Detokenize>(
&self,
mut submission_call: ContractCall<M, T>,
) -> Result<(), String> {
let mut gas_price = self
.provider
.get_gas_price()
.await .await
.map_err(|e| format!("Fail to send PoRA submission transaction: {:?}", e))?; .map_err(|e| format!("Failed to get current gas price {:?}", e))?;
let mut n_retry = 0;
while n_retry < ADJUST_GAS_RETRIES {
n_retry += 1;
submission_call = submission_call.gas_price(gas_price);
let pending_transaction = match submission_call.send().await {
Ok(tx) => tx,
Err(e) => {
if e.to_string().contains("insufficient funds")
|| e.to_string().contains("out of gas")
{
return Err(format!(
"Fail to execute PoRA submission transaction: {:?}",
e
));
}
// Log the error and increase gas.
debug!("Error sending transaction: {:?}", e);
gas_price = next_gas_price(gas_price);
continue; // retry sending
}
};
debug!( debug!(
"Signed submission transaction hash: {:?}", "Signed submission transaction hash: {:?}",
pending_transaction.tx_hash() pending_transaction.tx_hash()
); );
let receipt = pending_transaction let receipt_result = pending_transaction
.retries(SUBMISSION_RETRIES) .retries(SUBMISSION_RETRIES)
.interval(Duration::from_secs(2)) .interval(Duration::from_secs(2))
.await .await;
.map_err(|e| format!("Fail to execute PoRA submission transaction: {:?}", e))?
.ok_or(format!(
"PoRA submission transaction dropped after {} retries",
SUBMISSION_RETRIES
))?;
match receipt_result {
Ok(Some(receipt)) => {
// Successfully executed the transaction.
info!("Submit PoRA success, receipt: {:?}", receipt); info!("Submit PoRA success, receipt: {:?}", receipt);
return Ok(());
}
Ok(None) => {
// The transaction did not complete within the specified waiting time.
debug!(
"Transaction dropped after {} retries; increasing gas and retrying",
SUBMISSION_RETRIES
);
gas_price = next_gas_price(gas_price);
continue;
}
Err(ProviderError::HTTPError(e)) => {
// For HTTP errors, increase gas and retry.
debug!("HTTP error retrieving receipt: {:?}", e);
gas_price = next_gas_price(gas_price);
continue;
}
Err(e) => {
// For all other errors, return immediately.
return Err(format!(
"Fail to execute PoRA submission transaction: {:?}",
e
));
}
}
}
Ok(()) Err("Submission failed after retries".to_string())
} }
} }
@ -186,3 +243,7 @@ fn flow_proof_to_pora_merkle_proof(flow_proof: FlowRangeProof) -> Vec<[u8; 32]>
// Exclude `item`, the nodes in the sealed data subtree, and `root`. // Exclude `item`, the nodes in the sealed data subtree, and `root`.
full_proof[depth_in_sealed_data + 1..full_proof.len() - 1].to_vec() full_proof[depth_in_sealed_data + 1..full_proof.len() - 1].to_vec()
} }
fn next_gas_price(current_gas_price: U256) -> U256 {
current_gas_price * U256::from(11) / U256::from(10)
}