From 35fe8300bf3635e8db0d7b6d1c1982d5107b6808 Mon Sep 17 00:00:00 2001 From: Dmitry Lavrenov Date: Mon, 29 Apr 2024 14:44:07 +0300 Subject: [PATCH] Handle bioauth transaction status and properly process it --- Cargo.lock | 1 + crates/bioauth-flow-rpc/Cargo.toml | 1 + .../src/errors/authenticate.rs | 11 +++++- crates/bioauth-flow-rpc/src/errors/mod.rs | 1 + .../src/errors/tx_not_finalized.rs | 23 ++++++++++++ crates/bioauth-flow-rpc/src/lib.rs | 37 +++++++++++++++++-- 6 files changed, 69 insertions(+), 5 deletions(-) create mode 100644 crates/bioauth-flow-rpc/src/errors/tx_not_finalized.rs diff --git a/Cargo.lock b/Cargo.lock index 247aa87ce..198dbe625 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -779,6 +779,7 @@ dependencies = [ "async-trait", "bioauth-flow-api", "bioauth-keys", + "futures", "jsonrpsee", "pallet-bioauth", "primitives-liveness-data", diff --git a/crates/bioauth-flow-rpc/Cargo.toml b/crates/bioauth-flow-rpc/Cargo.toml index b1d6f7f24..6ded69182 100644 --- a/crates/bioauth-flow-rpc/Cargo.toml +++ b/crates/bioauth-flow-rpc/Cargo.toml @@ -15,6 +15,7 @@ rpc-error-response = { path = "../rpc-error-response" } rpc-validator-key-logic = { path = "../rpc-validator-key-logic" } async-trait = { workspace = true } +futures = { workspace = true } jsonrpsee = { workspace = true, features = ["server", "macros"] } sc-transaction-pool-api = { workspace = true } serde = { workspace = true, features = ["default"] } diff --git a/crates/bioauth-flow-rpc/src/errors/authenticate.rs b/crates/bioauth-flow-rpc/src/errors/authenticate.rs index 7cf7749ee..d62c98bfa 100644 --- a/crates/bioauth-flow-rpc/src/errors/authenticate.rs +++ b/crates/bioauth-flow-rpc/src/errors/authenticate.rs @@ -4,7 +4,9 @@ use rpc_validator_key_logic::Error as ValidatorKeyError; use sp_api::ApiError; use sp_runtime::transaction_validity::InvalidTransaction; -use super::{api_error_code, sign::Error as SignError}; +use super::{ + api_error_code, sign::Error as SignError, tx_not_finalized::Error as TxNotFinalizedError, +}; use crate::error_data::{self, BioauthTxErrorDetails}; /// The `authenticate` method error kinds. @@ -20,6 +22,8 @@ pub enum Error { RuntimeApi(ApiError), /// An error that can occur with transaction pool logic. BioauthTx(TxPoolError), + /// An error that can occur with transaction finalization logic. + BioauthTxNotFinalized(TxNotFinalizedError), } impl From> for jsonrpsee::core::Error @@ -61,6 +65,11 @@ where let (message, data) = map_txpool_error(err); rpc_error_response::raw(api_error_code::TRANSACTION, message, data) } + Error::BioauthTxNotFinalized(err) => rpc_error_response::data( + api_error_code::TRANSACTION, + err.to_string(), + error_data::ShouldRetry, + ), } } } diff --git a/crates/bioauth-flow-rpc/src/errors/mod.rs b/crates/bioauth-flow-rpc/src/errors/mod.rs index 77911d346..34d81999f 100644 --- a/crates/bioauth-flow-rpc/src/errors/mod.rs +++ b/crates/bioauth-flow-rpc/src/errors/mod.rs @@ -6,6 +6,7 @@ pub mod get_facetec_device_sdk_params; pub mod get_facetec_session_token; pub mod sign; pub mod status; +pub mod tx_not_finalized; /// Custom rpc error codes. pub mod api_error_code { diff --git a/crates/bioauth-flow-rpc/src/errors/tx_not_finalized.rs b/crates/bioauth-flow-rpc/src/errors/tx_not_finalized.rs new file mode 100644 index 000000000..21ba1acda --- /dev/null +++ b/crates/bioauth-flow-rpc/src/errors/tx_not_finalized.rs @@ -0,0 +1,23 @@ +//! The bioauth transaction not finalized related error kinds. + +/// The bioauth transaction not finalized related error kinds. +#[derive(Debug, thiserror::Error)] +pub enum Error { + /// Transaction is no longer valid in the current state. + #[error("transaction is no longer valid in the current state")] + Invalid, + /// Transaction has been dropped from the pool because of the limit. + #[error("transaction has been dropped from the pool because of the limit")] + Dropped, + /// Transaction has been replaced in the pool, by another transaction + /// that provides the same tags. (e.g. same (sender, nonce)). + #[error("transaction has been replaced in the pool, by another transaction")] + Usurped, + /// The block this transaction was included in has been retracted. + #[error("the block this transaction was included in has been retracted")] + Retracted, + /// Maximum number of finality watchers has been reached, + /// old watchers are being removed. + #[error("finality timeout")] + FinalityTimeout, +} diff --git a/crates/bioauth-flow-rpc/src/lib.rs b/crates/bioauth-flow-rpc/src/lib.rs index 3a36b27f5..f8edf5fa1 100644 --- a/crates/bioauth-flow-rpc/src/lib.rs +++ b/crates/bioauth-flow-rpc/src/lib.rs @@ -13,13 +13,14 @@ use errors::{ authenticate::Error as AuthenticateError, enroll::Error as EnrollError, get_facetec_device_sdk_params::Error as GetFacetecDeviceSdkParamsError, get_facetec_session_token::Error as GetFacetecSessionToken, sign::Error as SignError, - status::Error as StatusError, + status::Error as StatusError, tx_not_finalized::Error as TxNotFinalizedError, }; +use futures::StreamExt; use jsonrpsee::{core::RpcResult, proc_macros::rpc}; use primitives_liveness_data::{LivenessData, OpaqueLivenessData}; use robonode_client::{AuthenticateRequest, EnrollRequest}; use rpc_deny_unsafe::DenyUnsafe; -use sc_transaction_pool_api::TransactionPool as TransactionPoolT; +use sc_transaction_pool_api::{TransactionPool as TransactionPoolT, TransactionStatus}; use serde::{Deserialize, Serialize}; use serde_json::{Map, Value}; use sp_api::{BlockT, Decode, Encode, ProvideRuntimeApi}; @@ -366,14 +367,42 @@ where ) .map_err(AuthenticateError::RuntimeApi).map_err(errtype)?; - self.pool + let mut watch = self.pool .submit_and_watch( &sp_api::BlockId::Hash(at), sp_runtime::transaction_validity::TransactionSource::Local, ext, ) .await - .map_err(AuthenticateError::BioauthTx).map_err(errtype)?; + .map_err(AuthenticateError::BioauthTx).map_err(errtype)?.fuse(); + + loop { + let tx_status = watch.select_next_some().await; + + match tx_status { + TransactionStatus::Finalized(_)=> break, + TransactionStatus::Retracted(_) => Err( + errtype(AuthenticateError::BioauthTxNotFinalized(TxNotFinalizedError::Retracted)) + )?, + TransactionStatus::Usurped(_) => Err( + errtype(AuthenticateError::BioauthTxNotFinalized(TxNotFinalizedError::Usurped)) + )?, + TransactionStatus::Dropped => Err( + errtype(AuthenticateError::BioauthTxNotFinalized(TxNotFinalizedError::Invalid)) + )?, + TransactionStatus::FinalityTimeout(_) => Err( + errtype(AuthenticateError::BioauthTxNotFinalized(TxNotFinalizedError::FinalityTimeout)) + )?, + TransactionStatus::Invalid => Err( + errtype(AuthenticateError::BioauthTxNotFinalized(TxNotFinalizedError::Invalid)) + )?, + // Valid and expected statuses of transaction to be finalized. + TransactionStatus::Ready + | TransactionStatus::Broadcast(_) + | TransactionStatus::InBlock(_) + | TransactionStatus::Future => {}, + } + } info!("Bioauth flow - authenticate transaction complete");