From 22eda6a9681720f9c876e6621dae5620b4f43b2b Mon Sep 17 00:00:00 2001 From: Dmitry Lavrenov <39522748+dmitrylavrenov@users.noreply.github.com> Date: Mon, 6 May 2024 20:34:52 +0300 Subject: [PATCH] Handle bioauth transaction status and properly process it (#1018) * Handle bioauth transaction status and properly process it * Fix typo * Use simple rpc error response * Rename BioauthTxNotFinalized to TxNotFinalized * Move TxNotFinalizedError to authenticate mod * Rewrite error message for finality timeout * Add log to indicate sending transactions * Add intermediate logs for authenticate transaction * Improve log for submitting authenticate transaction Co-authored-by: MOZGIII * Return tx hash during authenticate flow * Simplify info log for trx included into block and being finalized * Use just next().await * Spawn transaction authenticate progress * Remove unused transaction not finalized error * Bove authenticate transaction complete log message to spawned progress * Properly handle transaction statuses * Handle None case for transaction flow --------- Co-authored-by: MOZGIII --- Cargo.lock | 2 + crates/bioauth-flow-rpc/Cargo.toml | 2 + crates/bioauth-flow-rpc/src/lib.rs | 91 ++++++++++++++++++++++++++---- 3 files changed, 84 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 56001b25f..b9d1119a4 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", @@ -793,6 +794,7 @@ dependencies = [ "sp-blockchain", "sp-runtime", "thiserror", + "tokio", "tracing", ] diff --git a/crates/bioauth-flow-rpc/Cargo.toml b/crates/bioauth-flow-rpc/Cargo.toml index b1d6f7f24..96c0357ec 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"] } @@ -23,4 +24,5 @@ sp-api = { workspace = true } sp-blockchain = { workspace = true } sp-runtime = { workspace = true } thiserror = { workspace = true } +tokio = { workspace = true } tracing = { workspace = true } diff --git a/crates/bioauth-flow-rpc/src/lib.rs b/crates/bioauth-flow-rpc/src/lib.rs index 3a36b27f5..3f1a93abd 100644 --- a/crates/bioauth-flow-rpc/src/lib.rs +++ b/crates/bioauth-flow-rpc/src/lib.rs @@ -15,11 +15,12 @@ use errors::{ get_facetec_session_token::Error as GetFacetecSessionToken, sign::Error as SignError, status::Error as StatusError, }; +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, TxHash}; use serde::{Deserialize, Serialize}; use serde_json::{Map, Value}; use sp_api::{BlockT, Decode, Encode, ProvideRuntimeApi}; @@ -93,7 +94,7 @@ impl From> for BioauthStatus { /// The API exposed via JSON-RPC. #[rpc(server)] -pub trait Bioauth { +pub trait Bioauth { /// Get the configuration required for the Device SDK. #[method(name = "bioauth_getFacetecDeviceSdkParams")] async fn get_facetec_device_sdk_params(&self) -> RpcResult; @@ -112,7 +113,7 @@ pub trait Bioauth { /// Authenticate with provided liveness data. #[method(name = "bioauth_authenticate")] - async fn authenticate(&self, liveness_data: LivenessData) -> RpcResult<()>; + async fn authenticate(&self, liveness_data: LivenessData) -> RpcResult; } /// The RPC implementation. @@ -229,7 +230,7 @@ impl< Block, Timestamp, TransactionPool, - > BioauthServer + > BioauthServer> for Bioauth< RobonodeClient, ValidatorKeyExtractor, @@ -329,7 +330,7 @@ where Ok(()) } - async fn authenticate(&self, liveness_data: LivenessData) -> RpcResult<()> { + async fn authenticate(&self, liveness_data: LivenessData) -> RpcResult> { self.deny_unsafe.check_if_safe()?; info!("Bioauth flow - authentication in progress"); @@ -366,17 +367,85 @@ where ) .map_err(AuthenticateError::RuntimeApi).map_err(errtype)?; - self.pool + info!("Bioauth flow - submitting authenticate transaction"); + + let tx_hash = self.pool.hash_of(&ext); + + 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)?; - - info!("Bioauth flow - authenticate transaction complete"); - - Ok(()) + .map_err(AuthenticateError::BioauthTx).map_err(errtype)?.fuse(); + + tokio::spawn(async move { + loop { + let maybe_tx_status = watch.next().await; + + match maybe_tx_status { + Some(TransactionStatus::Finalized((block_hash, _)))=> { + info!( + message = "Bioauth flow - authenticate transaction is in finalized block", + %block_hash, + ); + break + }, + Some(TransactionStatus::Retracted(block_hash)) => { + error!( + message = "Bioauth flow - the block this transaction was included in has been retracted", + %block_hash, + ); + break + }, + Some(TransactionStatus::Usurped(_)) => { + error!( + "Bioauth flow - transaction has been replaced in the pool, by another transaction", + ); + break + }, + Some(TransactionStatus::Dropped) => { + error!( + "Bioauth flow - transaction has been dropped from the pool because of the limit", + ); + break + }, + Some(TransactionStatus::FinalityTimeout(_)) => { + error!( + "Bioauth flow - maximum number of finality watchers has been reached, old watchers are being removed", + ); + break + }, + Some(TransactionStatus::Invalid) => { + error!( + "Bioauth flow - transaction is no longer valid in the current state", + ); + break + }, + Some(TransactionStatus::Ready) => info!("Bioauth flow - authenticate transaction is in ready queue"), + Some(TransactionStatus::Broadcast(_)) => { + info!("Bioauth flow - authenticate transaction is broadcasted"); + }, + Some(TransactionStatus::InBlock((block_hash, _))) => { + info!( + message = "Bioauth flow - authenticate transaction is in block", + %block_hash, + ); + }, + Some(TransactionStatus::Future) => info!("Bioauth flow - authenticate transaction is in future queue"), + None => { + error!( + "Bioauth flow - unexpected transaction flow interruption", + ); + break + } + } + } + + info!("Bioauth flow - authenticate transaction complete"); + }); + + Ok(tx_hash) } }