use crate::{request::Request, IcError};
use evm_rpc_types::{MultiRpcResult, ProviderError, RpcError, RpcResult};
pub trait RetryPolicy<Config, Params, CandidOutput, Output> {
fn retry(
&mut self,
request: &mut Request<Config, Params, CandidOutput, Output>,
result: &mut Result<Output, IcError>,
) -> Option<Request<Config, Params, CandidOutput, Output>>;
fn clone_request(
&mut self,
request: &Request<Config, Params, CandidOutput, Output>,
) -> Option<Request<Config, Params, CandidOutput, Output>>;
}
#[derive(Debug, Clone)]
pub struct NoRetry;
impl<Config, Params, CandidOutput, Output> RetryPolicy<Config, Params, CandidOutput, Output>
for NoRetry
{
fn retry(
&mut self,
_request: &mut Request<Config, Params, CandidOutput, Output>,
_result: &mut Result<Output, IcError>,
) -> Option<Request<Config, Params, CandidOutput, Output>> {
None
}
fn clone_request(
&mut self,
_request: &Request<Config, Params, CandidOutput, Output>,
) -> Option<Request<Config, Params, CandidOutput, Output>> {
None
}
}
#[derive(Debug, Clone)]
pub struct DoubleCycles {
num_retries: u32,
}
impl DoubleCycles {
pub fn with_max_num_retries(max_num_retries: u32) -> Self {
DoubleCycles {
num_retries: max_num_retries,
}
}
}
impl<Config, Params, CandidOutput, Output>
RetryPolicy<Config, Params, CandidOutput, MultiRpcResult<Output>> for DoubleCycles
where
Request<Config, Params, CandidOutput, MultiRpcResult<Output>>: Clone,
{
fn retry(
&mut self,
request: &mut Request<Config, Params, CandidOutput, MultiRpcResult<Output>>,
result: &mut Result<MultiRpcResult<Output>, IcError>,
) -> Option<Request<Config, Params, CandidOutput, MultiRpcResult<Output>>> {
fn is_too_few_cycles_result<T>(result: &MultiRpcResult<T>) -> bool {
fn is_too_few_cycles_error<T>(result: &RpcResult<T>) -> bool {
matches!(
result,
Err(RpcError::ProviderError(ProviderError::TooFewCycles { .. }))
)
}
match result {
MultiRpcResult::Consistent(result) => is_too_few_cycles_error(result),
MultiRpcResult::Inconsistent(results) => results
.iter()
.any(|(_, result)| is_too_few_cycles_error(result)),
}
}
match result {
Ok(result) if is_too_few_cycles_result(result) => {
if self.num_retries > 0 {
self.num_retries = self.num_retries.saturating_sub(1);
request.cycles = request.cycles.saturating_mul(2);
Some(request.clone())
} else {
None
}
}
_ => None,
}
}
fn clone_request(
&mut self,
request: &Request<Config, Params, CandidOutput, MultiRpcResult<Output>>,
) -> Option<Request<Config, Params, CandidOutput, MultiRpcResult<Output>>> {
Some(request.clone())
}
}