use crate::error::Error;
use crate::types::AccountId;
use super::block_reference::TxExecutionStatus;
use super::rpc::{FinalExecutionOutcome, RawTransactionResponse, SendTxResponse};
mod sealed {
pub trait Sealed {}
}
pub trait WaitLevel: sealed::Sealed + Send + Sync + 'static {
type Response: Send + 'static;
fn status() -> TxExecutionStatus;
#[doc(hidden)]
fn convert(
response: RawTransactionResponse,
sender_id: &AccountId,
) -> Result<Self::Response, Error>;
}
#[derive(Clone, Copy, Debug)]
pub struct Submitted;
impl sealed::Sealed for Submitted {}
impl WaitLevel for Submitted {
type Response = SendTxResponse;
fn status() -> TxExecutionStatus {
TxExecutionStatus::None
}
fn convert(
response: RawTransactionResponse,
sender_id: &AccountId,
) -> Result<Self::Response, Error> {
Ok(SendTxResponse {
transaction_hash: response.transaction_hash,
sender_id: sender_id.clone(),
})
}
}
#[derive(Clone, Copy, Debug)]
pub struct Included;
impl sealed::Sealed for Included {}
impl WaitLevel for Included {
type Response = SendTxResponse;
fn status() -> TxExecutionStatus {
TxExecutionStatus::Included
}
fn convert(
response: RawTransactionResponse,
sender_id: &AccountId,
) -> Result<Self::Response, Error> {
Ok(SendTxResponse {
transaction_hash: response.transaction_hash,
sender_id: sender_id.clone(),
})
}
}
#[derive(Clone, Copy, Debug)]
pub struct IncludedFinal;
impl sealed::Sealed for IncludedFinal {}
impl WaitLevel for IncludedFinal {
type Response = SendTxResponse;
fn status() -> TxExecutionStatus {
TxExecutionStatus::IncludedFinal
}
fn convert(
response: RawTransactionResponse,
sender_id: &AccountId,
) -> Result<Self::Response, Error> {
Ok(SendTxResponse {
transaction_hash: response.transaction_hash,
sender_id: sender_id.clone(),
})
}
}
fn extract_outcome(
response: RawTransactionResponse,
level: &str,
) -> Result<FinalExecutionOutcome, Error> {
let outcome = response.outcome.ok_or_else(|| {
Error::InvalidTransaction(format!(
"RPC returned no execution outcome for transaction {} at wait level {}",
response.transaction_hash, level,
))
})?;
use super::error::TxExecutionError;
use super::rpc::FinalExecutionStatus;
match outcome.status {
FinalExecutionStatus::Failure(TxExecutionError::InvalidTxError(e)) => {
Err(Error::InvalidTx(Box::new(e)))
}
_ => Ok(outcome),
}
}
#[derive(Clone, Copy, Debug)]
pub struct ExecutedOptimistic;
impl sealed::Sealed for ExecutedOptimistic {}
impl WaitLevel for ExecutedOptimistic {
type Response = FinalExecutionOutcome;
fn status() -> TxExecutionStatus {
TxExecutionStatus::ExecutedOptimistic
}
fn convert(
response: RawTransactionResponse,
_sender_id: &AccountId,
) -> Result<Self::Response, Error> {
extract_outcome(response, "ExecutedOptimistic")
}
}
#[derive(Clone, Copy, Debug)]
pub struct Executed;
impl sealed::Sealed for Executed {}
impl WaitLevel for Executed {
type Response = FinalExecutionOutcome;
fn status() -> TxExecutionStatus {
TxExecutionStatus::Executed
}
fn convert(
response: RawTransactionResponse,
_sender_id: &AccountId,
) -> Result<Self::Response, Error> {
extract_outcome(response, "Executed")
}
}
#[derive(Clone, Copy, Debug)]
pub struct Final;
impl sealed::Sealed for Final {}
impl WaitLevel for Final {
type Response = FinalExecutionOutcome;
fn status() -> TxExecutionStatus {
TxExecutionStatus::Final
}
fn convert(
response: RawTransactionResponse,
_sender_id: &AccountId,
) -> Result<Self::Response, Error> {
extract_outcome(response, "Final")
}
}