From eb480f05803d9a80fcb0417fc68eb1acbd01a653 Mon Sep 17 00:00:00 2001 From: SW van Heerden Date: Mon, 15 Jan 2024 10:54:42 +0200 Subject: [PATCH 01/10] fix tms correctly updating merge --- .../minotari_app_grpc/proto/wallet.proto | 2 + .../src/conversions/transaction.rs | 1 + base_layer/common_types/src/transaction.rs | 29 +++--- .../wallet/src/transaction_service/service.rs | 2 +- .../transaction_service/storage/database.rs | 18 +++- .../transaction_service/storage/sqlite_db.rs | 90 +++++++++++++------ .../tasks/check_faux_transaction_status.rs | 65 +++++++++----- .../transaction_protocols.rs | 5 +- 8 files changed, 147 insertions(+), 65 deletions(-) diff --git a/applications/minotari_app_grpc/proto/wallet.proto b/applications/minotari_app_grpc/proto/wallet.proto index 7451aaf564..c82268545a 100644 --- a/applications/minotari_app_grpc/proto/wallet.proto +++ b/applications/minotari_app_grpc/proto/wallet.proto @@ -227,6 +227,8 @@ enum TransactionStatus { TRANSACTION_STATUS_COINBASE_UNCONFIRMED = 12; // This is Coinbase transaction that is detected from chain TRANSACTION_STATUS_COINBASE_CONFIRMED = 13; + // This is Coinbase transaction that is not currently detected as mined + TRANSACTION_STATUS_COINBASE_NOT_IN_BLOCK_CHAIN = 14; } message GetCompletedTransactionsRequest { } diff --git a/applications/minotari_app_grpc/src/conversions/transaction.rs b/applications/minotari_app_grpc/src/conversions/transaction.rs index fbb078c8c2..7c5ecc5362 100644 --- a/applications/minotari_app_grpc/src/conversions/transaction.rs +++ b/applications/minotari_app_grpc/src/conversions/transaction.rs @@ -104,6 +104,7 @@ impl From for grpc::TransactionStatus { OneSidedConfirmed => grpc::TransactionStatus::OneSidedConfirmed, CoinbaseUnconfirmed => grpc::TransactionStatus::CoinbaseUnconfirmed, CoinbaseConfirmed => grpc::TransactionStatus::CoinbaseConfirmed, + CoinbaseNotInBlockChain => grpc::TransactionStatus::CoinbaseNotInBlockChain, Queued => grpc::TransactionStatus::Queued, } } diff --git a/base_layer/common_types/src/transaction.rs b/base_layer/common_types/src/transaction.rs index 39004f602c..ab8d07ff27 100644 --- a/base_layer/common_types/src/transaction.rs +++ b/base_layer/common_types/src/transaction.rs @@ -38,10 +38,13 @@ pub enum TransactionStatus { OneSidedConfirmed = 9, /// This transaction is still being queued for initial sending Queued = 10, - /// This transaction import status is used when a one-sided transaction has been scanned but is unconfirmed + /// This transaction import status is used when a coinbase transaction has been scanned but is unconfirmed CoinbaseUnconfirmed = 11, - /// This transaction import status is used when a one-sided transaction has been scanned and confirmed + /// This transaction import status is used when a coinbase transaction has been scanned and confirmed CoinbaseConfirmed = 12, + /// This transaction import status is used when a coinbase transaction has been scanned but the outputs are not + /// currently confirmed on the blockchain via the output manager + CoinbaseNotInBlockChain = 13, } impl TransactionStatus { @@ -55,7 +58,9 @@ impl TransactionStatus { pub fn is_coinbase(&self) -> bool { matches!( self, - TransactionStatus::CoinbaseUnconfirmed | TransactionStatus::CoinbaseConfirmed + TransactionStatus::CoinbaseUnconfirmed | + TransactionStatus::CoinbaseConfirmed | + TransactionStatus::CoinbaseNotInBlockChain ) } @@ -81,9 +86,9 @@ impl TransactionStatus { TransactionStatus::Imported | TransactionStatus::OneSidedUnconfirmed | TransactionStatus::OneSidedConfirmed => TransactionStatus::OneSidedConfirmed, - TransactionStatus::CoinbaseConfirmed | TransactionStatus::CoinbaseUnconfirmed => { - TransactionStatus::CoinbaseConfirmed - }, + TransactionStatus::CoinbaseNotInBlockChain | + TransactionStatus::CoinbaseConfirmed | + TransactionStatus::CoinbaseUnconfirmed => TransactionStatus::CoinbaseConfirmed, } } @@ -100,9 +105,9 @@ impl TransactionStatus { TransactionStatus::Imported | TransactionStatus::OneSidedUnconfirmed | TransactionStatus::OneSidedConfirmed => TransactionStatus::OneSidedUnconfirmed, - TransactionStatus::CoinbaseConfirmed | TransactionStatus::CoinbaseUnconfirmed => { - TransactionStatus::CoinbaseUnconfirmed - }, + TransactionStatus::CoinbaseConfirmed | + TransactionStatus::CoinbaseUnconfirmed | + TransactionStatus::CoinbaseNotInBlockChain => TransactionStatus::CoinbaseUnconfirmed, } } } @@ -131,6 +136,7 @@ impl TryFrom for TransactionStatus { 10 => Ok(TransactionStatus::Queued), 11 => Ok(TransactionStatus::CoinbaseUnconfirmed), 12 => Ok(TransactionStatus::CoinbaseConfirmed), + 13 => Ok(TransactionStatus::CoinbaseNotInBlockChain), code => Err(TransactionConversionError { code }), } } @@ -152,6 +158,7 @@ impl Display for TransactionStatus { TransactionStatus::OneSidedConfirmed => write!(f, "One-Sided Confirmed"), TransactionStatus::CoinbaseUnconfirmed => write!(f, "Coinbase Unconfirmed"), TransactionStatus::CoinbaseConfirmed => write!(f, "Coinbase Confirmed"), + TransactionStatus::CoinbaseNotInBlockChain => write!(f, "Coinbase not mined"), TransactionStatus::Queued => write!(f, "Queued"), } } @@ -165,9 +172,9 @@ pub enum ImportStatus { OneSidedUnconfirmed, /// This transaction import status is used when a one-sided transaction has been scanned and confirmed OneSidedConfirmed, - /// This transaction import status is used when a one-sided transaction has been scanned but is unconfirmed + /// This transaction import status is used when a coinbasetransaction has been scanned but is unconfirmed CoinbaseUnconfirmed, - /// This transaction import status is used when a one-sided transaction has been scanned and confirmed + /// This transaction import status is used when a coinbase transaction has been scanned and confirmed CoinbaseConfirmed, } diff --git a/base_layer/wallet/src/transaction_service/service.rs b/base_layer/wallet/src/transaction_service/service.rs index ea231553b5..2a194648c6 100644 --- a/base_layer/wallet/src/transaction_service/service.rs +++ b/base_layer/wallet/src/transaction_service/service.rs @@ -2530,7 +2530,7 @@ where JoinHandle>>, >, ) -> Result { - self.resources.db.mark_all_transactions_as_unvalidated()?; + self.resources.db.mark_all_non_coinbases_transactions_as_unvalidated()?; self.start_transaction_validation_protocol(join_handles).await } diff --git a/base_layer/wallet/src/transaction_service/storage/database.rs b/base_layer/wallet/src/transaction_service/storage/database.rs index e3fa6f6f5b..8622d6bc70 100644 --- a/base_layer/wallet/src/transaction_service/storage/database.rs +++ b/base_layer/wallet/src/transaction_service/storage/database.rs @@ -136,7 +136,7 @@ pub trait TransactionBackend: Send + Sync + Clone { /// Clears the mined block and height of a transaction fn set_transaction_as_unmined(&self, tx_id: TxId) -> Result<(), TransactionStorageError>; /// Reset optional 'mined height' and 'mined in block' fields to nothing - fn mark_all_transactions_as_unvalidated(&self) -> Result<(), TransactionStorageError>; + fn mark_all_non_coinbases_transactions_as_unvalidated(&self) -> Result<(), TransactionStorageError>; /// Light weight method to retrieve pertinent transaction sender info for all pending inbound transactions fn get_pending_inbound_transaction_sender_info( &self, @@ -147,6 +147,10 @@ pub trait TransactionBackend: Send + Sync + Clone { &self, height: u64, ) -> Result, TransactionStorageError>; + fn fetch_unmined_coinbase_transactions_from_height( + &self, + height: u64, + ) -> Result, TransactionStorageError>; } #[derive(Clone, PartialEq)] @@ -429,6 +433,14 @@ where T: TransactionBackend + 'static Ok(t) } + pub fn get_unmined_coinbase_transactions( + &self, + height: u64, + ) -> Result, TransactionStorageError> { + let t = self.db.fetch_unmined_coinbase_transactions_from_height(height)?; + Ok(t) + } + pub fn fetch_last_mined_transaction(&self) -> Result, TransactionStorageError> { self.db.fetch_last_mined_transaction() } @@ -683,8 +695,8 @@ where T: TransactionBackend + 'static self.db.set_transaction_as_unmined(tx_id) } - pub fn mark_all_transactions_as_unvalidated(&self) -> Result<(), TransactionStorageError> { - self.db.mark_all_transactions_as_unvalidated() + pub fn mark_all_non_coinbases_transactions_as_unvalidated(&self) -> Result<(), TransactionStorageError> { + self.db.mark_all_non_coinbases_transactions_as_unvalidated() } pub fn set_transaction_mined_height( diff --git a/base_layer/wallet/src/transaction_service/storage/sqlite_db.rs b/base_layer/wallet/src/transaction_service/storage/sqlite_db.rs index bde3455804..3af3375933 100644 --- a/base_layer/wallet/src/transaction_service/storage/sqlite_db.rs +++ b/base_layer/wallet/src/transaction_service/storage/sqlite_db.rs @@ -918,18 +918,23 @@ impl TransactionBackend for TransactionServiceSqliteDatabase { Ok(result) } - fn mark_all_transactions_as_unvalidated(&self) -> Result<(), TransactionStorageError> { + // Exclude coinbases as they are validated from the OMS service, and we use these fields to know which tx to + // extract, thus we should not wipe it out. Coinbases can also not be mined in a different height so the data will + // never be wrong. + fn mark_all_non_coinbases_transactions_as_unvalidated(&self) -> Result<(), TransactionStorageError> { let start = Instant::now(); let mut conn = self.database_connection.get_pooled_connection()?; let acquire_lock = start.elapsed(); let result = diesel::update(completed_transactions::table) + .filter(completed_transactions::status.ne(TransactionStatus::CoinbaseNotInBlockChain as i32)) + .filter(completed_transactions::status.ne(TransactionStatus::CoinbaseUnconfirmed as i32)) + .filter(completed_transactions::status.ne(TransactionStatus::CoinbaseConfirmed as i32)) .set(( completed_transactions::cancelled.eq::>(None), completed_transactions::mined_height.eq::>(None), completed_transactions::mined_in_block.eq::>>(None), )) .execute(&mut conn)?; - trace!(target: LOG_TARGET, "rows updated: {:?}", result); if start.elapsed().as_millis() > 0 { trace!( @@ -1035,6 +1040,27 @@ impl TransactionBackend for TransactionServiceSqliteDatabase { Ok(coinbases) } + fn fetch_unmined_coinbase_transactions_from_height( + &self, + height: u64, + ) -> Result, TransactionStorageError> { + let mut conn = self.database_connection.get_pooled_connection()?; + let cipher = acquire_read_lock!(self.cipher); + + let coinbases = CompletedTransactionSql::index_by_status_and_cancelled_from_block_height( + TransactionStatus::CoinbaseNotInBlockChain, + false, + height as i64, + &mut conn, + )? + .into_iter() + .map(|ct: CompletedTransactionSql| { + CompletedTransaction::try_from(ct, &cipher).map_err(TransactionStorageError::from) + }) + .collect::, TransactionStorageError>>()?; + Ok(coinbases) + } + fn fetch_confirmed_detected_transactions_from_height( &self, height: u64, @@ -1849,37 +1875,46 @@ impl CompletedTransactionSql { } pub fn set_as_unmined(tx_id: TxId, conn: &mut SqliteConnection) -> Result<(), TransactionStorageError> { + let (current_status, current_mined_height) = TransactionStatus::try_from( + *completed_transactions::table + .filter(completed_transactions::tx_id.eq(tx_id.as_u64() as i64)) + .select(completed_transactions::status) + .select(completed_transactions::mined_height) + .load::<(i32, Option)>(conn)? + .first() + .ok_or(TransactionStorageError::DieselError(DieselError::NotFound))?, + ) + .map_err(|_| TransactionStorageError::UnexpectedResult("Unknown status".to_string()))?; + // let current_mined_height = *completed_transactions::table + // .filter(completed_transactions::tx_id.eq(tx_id.as_u64() as i64)) + // .select(completed_transactions::mined_height) + // .load::>(conn)? + // .first() + // .ok_or(TransactionStorageError::DieselError(DieselError::NotFound))?; // This query uses two sub-queries to retrieve existing values in the table diesel::update(completed_transactions::table.filter(completed_transactions::tx_id.eq(tx_id.as_u64() as i64))) .set(UpdateCompletedTransactionSql { - status: { - if let Some(status) = completed_transactions::table - .filter(completed_transactions::tx_id.eq(tx_id.as_u64() as i64)) - .select(completed_transactions::status) - .load::(conn)? - .first() - { - if *status == TransactionStatus::OneSidedConfirmed as i32 || - *status == TransactionStatus::OneSidedUnconfirmed as i32 - { - Some(TransactionStatus::OneSidedUnconfirmed as i32) - } else if *status == TransactionStatus::CoinbaseUnconfirmed as i32 || - *status == TransactionStatus::CoinbaseConfirmed as i32 - { - Some(TransactionStatus::CoinbaseUnconfirmed as i32) - } else if *status == TransactionStatus::Imported as i32 { - Some(TransactionStatus::Imported as i32) - } else if *status == TransactionStatus::Broadcast as i32 { - Some(TransactionStatus::Broadcast as i32) - } else { - Some(TransactionStatus::Completed as i32) - } + status: match current_status { + TransactionStatus::OneSidedConfirmed | TransactionStatus::OneSidedUnconfirmed => { + Some(TransactionStatus::OneSidedUnconfirmed as i32) + }, + TransactionStatus::CoinbaseUnconfirmed | + TransactionStatus::CoinbaseConfirmed | + TransactionStatus::CoinbaseNotInBlockChain => { + Some(TransactionStatus::CoinbaseNotInBlockChain as i32) + }, + TransactionStatus::Imported => Some(TransactionStatus::Imported as i32), + TransactionStatus::Broadcast => Some(TransactionStatus::Broadcast as i32), + _ => Some(TransactionStatus::Completed as i32), + }, + mined_in_block: Some(None), + mined_height: { + if current_status.is_coinbase() { + Some(current_mined_height) } else { - return Err(TransactionStorageError::DieselError(DieselError::NotFound)); + Some(None) } }, - mined_in_block: Some(None), - mined_height: Some(None), confirmations: Some(None), // Turns out it should not be cancelled cancelled: Some(None), @@ -2109,6 +2144,7 @@ impl UnconfirmedTransactionInfoSql { .and(completed_transactions::status.ne(TransactionStatus::OneSidedConfirmed as i32)) .and(completed_transactions::status.ne(TransactionStatus::CoinbaseUnconfirmed as i32)) .and(completed_transactions::status.ne(TransactionStatus::CoinbaseConfirmed as i32)) + .and(completed_transactions::status.ne(TransactionStatus::CoinbaseNotInBlockChain as i32)) // Filter out any transaction without a kernel signature .and(completed_transactions::transaction_signature_nonce.ne(vec![0u8; 32])) .and(completed_transactions::transaction_signature_key.ne(vec![0u8; 32])) diff --git a/base_layer/wallet/src/transaction_service/tasks/check_faux_transaction_status.rs b/base_layer/wallet/src/transaction_service/tasks/check_faux_transaction_status.rs index 6182d78193..0695f9e72f 100644 --- a/base_layer/wallet/src/transaction_service/tasks/check_faux_transaction_status.rs +++ b/base_layer/wallet/src/transaction_service/tasks/check_faux_transaction_status.rs @@ -20,10 +20,12 @@ // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +const SAFETY_HEIGHT_MARGIN: u64 = 1000; + use std::sync::Arc; use log::*; -use tari_common_types::types::{BlockHash, FixedHash}; +use tari_common_types::types::FixedHash; use crate::{ output_manager_service::handle::OutputManagerHandle, @@ -46,6 +48,20 @@ pub async fn check_detected_transactions event_publisher: TransactionEventSender, tip_height: u64, ) { + // Reorged faux transactions cannot be detected by excess signature, thus use last known confirmed transaction + // height or current tip height with safety margin to determine if these should be returned + let last_mined_transaction = match db.fetch_last_mined_transaction() { + Ok(tx) => tx, + Err(_) => None, + }; + + let height_with_margin = tip_height.saturating_sub(SAFETY_HEIGHT_MARGIN); + let check_height = if let Some(tx) = last_mined_transaction { + tx.mined_height.unwrap_or(height_with_margin) + } else { + height_with_margin + }; + let mut all_detected_transactions: Vec = match db.get_imported_transactions() { Ok(txs) => txs, Err(e) => { @@ -64,18 +80,19 @@ pub async fn check_detected_transactions }, }; all_detected_transactions.append(&mut unconfirmed_detected); - // Reorged faux transactions cannot be detected by excess signature, thus use last known confirmed transaction - // height or current tip height with safety margin to determine if these should be returned - let last_mined_transaction = match db.fetch_last_mined_transaction() { - Ok(tx) => tx, - Err(_) => None, - }; - let height_with_margin = tip_height.saturating_sub(100); - let check_height = if let Some(tx) = last_mined_transaction { - tx.mined_height.unwrap_or(height_with_margin) - } else { - height_with_margin + + let mut unmined_coinbases_detected = match db.get_unmined_coinbase_transactions(height_with_margin) { + Ok(txs) => txs, + Err(e) => { + error!( + target: LOG_TARGET, + "Problem retrieving unmined coinbase transactions: {}", e + ); + return; + }, }; + all_detected_transactions.append(&mut unmined_coinbases_detected); + let mut confirmed_dectected = match db.get_confirmed_detected_transactions_from_height(check_height) { Ok(txs) => txs, Err(e) => { @@ -101,17 +118,21 @@ pub async fn check_detected_transactions return; }, }; + // Its safe to assume that statuses should be the same as they are all in the same transaction and they cannot + // be different. let output_status = output_info_for_tx_id.statuses[0]; - let mined_height = if let Some(height) = output_info_for_tx_id.mined_height { - height - } else { - tip_height - }; - let mined_in_block: BlockHash = if let Some(hash) = output_info_for_tx_id.block_hash { - hash - } else { - FixedHash::zero() - }; + if output_info_for_tx_id.mined_height.is_none() || output_info_for_tx_id.block_hash.is_none() { + // this means the transaction is not detected as mined + if let Err(e) = db.set_transaction_as_unmined(tx.tx_id) { + error!( + target: LOG_TARGET, + "Error setting faux transaction to unmined: {}", e + ); + } + continue; + } + let mined_height = output_info_for_tx_id.mined_height.unwrap_or(0); + let mined_in_block = output_info_for_tx_id.block_hash.unwrap_or(FixedHash::zero()); let is_valid = tip_height >= mined_height; let previously_confirmed = tx.status.is_confirmed(); let must_be_confirmed = diff --git a/base_layer/wallet/tests/transaction_service_tests/transaction_protocols.rs b/base_layer/wallet/tests/transaction_service_tests/transaction_protocols.rs index 23cc579dde..9e4772b65e 100644 --- a/base_layer/wallet/tests/transaction_service_tests/transaction_protocols.rs +++ b/base_layer/wallet/tests/transaction_service_tests/transaction_protocols.rs @@ -997,7 +997,10 @@ async fn tx_revalidation() { rpc_service_state.set_transaction_query_batch_responses(batch_query_response.clone()); // revalidate sets all to unvalidated, so lets check that thay are - resources.db.mark_all_transactions_as_unvalidated().unwrap(); + resources + .db + .mark_all_non_coinbases_transactions_as_unvalidated() + .unwrap(); let completed_txs = resources.db.get_completed_transactions().unwrap(); assert_eq!( completed_txs.get(&2u64.into()).unwrap().status, From 2c3fbac1df893f522cbe18191a5b9b568a48c219 Mon Sep 17 00:00:00 2001 From: SW van Heerden Date: Tue, 16 Jan 2024 11:22:47 +0200 Subject: [PATCH 02/10] some code --- base_layer/core/src/base_node/rpc/service.rs | 2 +- .../protocols/transaction_validation_protocol.rs | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/base_layer/core/src/base_node/rpc/service.rs b/base_layer/core/src/base_node/rpc/service.rs index 6718f328ff..4a6d62032d 100644 --- a/base_layer/core/src/base_node/rpc/service.rs +++ b/base_layer/core/src/base_node/rpc/service.rs @@ -313,7 +313,7 @@ impl BaseNodeWalletService for BaseNodeWalletRpc location: response.location, block_hash: response.block_hash, confirmations: response.confirmations, - block_height: response.height_of_longest_chain - response.confirmations, + block_height: response.height_of_longest_chain.saturating_sub(response.confirmations), mined_timestamp: response.mined_timestamp, }); } diff --git a/base_layer/wallet/src/transaction_service/protocols/transaction_validation_protocol.rs b/base_layer/wallet/src/transaction_service/protocols/transaction_validation_protocol.rs index 568b745620..06295138ae 100644 --- a/base_layer/wallet/src/transaction_service/protocols/transaction_validation_protocol.rs +++ b/base_layer/wallet/src/transaction_service/protocols/transaction_validation_protocol.rs @@ -285,7 +285,10 @@ where .map_err(TransactionServiceError::ProtobufConversionError)?; let sig = response.signature; if let Some(unconfirmed_tx) = batch_signatures.get(&sig) { - if response.location == TxLocation::Mined && response.block_hash.is_some() { + if response.location == TxLocation::Mined && + response.block_hash.is_some() && + response.mined_timestamp.is_some() + { mined.push(( (*unconfirmed_tx).clone(), response.block_height, @@ -296,10 +299,8 @@ where } else { warn!( target: LOG_TARGET, - "Marking transaction {} as unmined and confirmed '{}' with block '{}' (Operation ID: {})", + "Transaction {} is unmined (Operation ID: {})", &unconfirmed_tx.tx_id, - response.confirmations >= self.config.num_confirmations_required, - response.block_hash.is_some(), self.operation_id, ); unmined.push((*unconfirmed_tx).clone()); From 9e406274ca09b9a6b818fb022701b2ed846c1faa Mon Sep 17 00:00:00 2001 From: SW van Heerden Date: Tue, 16 Jan 2024 12:41:51 +0200 Subject: [PATCH 03/10] fix db --- .../transaction_service/storage/sqlite_db.rs | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/base_layer/wallet/src/transaction_service/storage/sqlite_db.rs b/base_layer/wallet/src/transaction_service/storage/sqlite_db.rs index 3af3375933..0de365af85 100644 --- a/base_layer/wallet/src/transaction_service/storage/sqlite_db.rs +++ b/base_layer/wallet/src/transaction_service/storage/sqlite_db.rs @@ -1875,16 +1875,14 @@ impl CompletedTransactionSql { } pub fn set_as_unmined(tx_id: TxId, conn: &mut SqliteConnection) -> Result<(), TransactionStorageError> { - let (current_status, current_mined_height) = TransactionStatus::try_from( - *completed_transactions::table - .filter(completed_transactions::tx_id.eq(tx_id.as_u64() as i64)) - .select(completed_transactions::status) - .select(completed_transactions::mined_height) - .load::<(i32, Option)>(conn)? - .first() - .ok_or(TransactionStorageError::DieselError(DieselError::NotFound))?, - ) - .map_err(|_| TransactionStorageError::UnexpectedResult("Unknown status".to_string()))?; + let (current_status, current_mined_height) = *completed_transactions::table + .filter(completed_transactions::tx_id.eq(tx_id.as_u64() as i64)) + .select((completed_transactions::status, completed_transactions::mined_height)) + .load::<(i32, Option)>(conn)? + .first() + .ok_or(TransactionStorageError::DieselError(DieselError::NotFound))?; + let current_status = TransactionStatus::try_from(current_status) + .map_err(|_| TransactionStorageError::UnexpectedResult("Unknown status".to_string()))?; // let current_mined_height = *completed_transactions::table // .filter(completed_transactions::tx_id.eq(tx_id.as_u64() as i64)) // .select(completed_transactions::mined_height) From c2c0754a2296ec6fc0a38623eda9a5212637e3b6 Mon Sep 17 00:00:00 2001 From: SW van Heerden Date: Wed, 17 Jan 2024 17:42:18 +0200 Subject: [PATCH 04/10] fix tests --- .../transaction_service/storage/sqlite_db.rs | 7 - .../tasks/check_faux_transaction_status.rs | 2 +- .../transaction_service_tests/service.rs | 197 +++++++++++++++++- 3 files changed, 190 insertions(+), 16 deletions(-) diff --git a/base_layer/wallet/src/transaction_service/storage/sqlite_db.rs b/base_layer/wallet/src/transaction_service/storage/sqlite_db.rs index 0de365af85..010b35d342 100644 --- a/base_layer/wallet/src/transaction_service/storage/sqlite_db.rs +++ b/base_layer/wallet/src/transaction_service/storage/sqlite_db.rs @@ -1883,13 +1883,6 @@ impl CompletedTransactionSql { .ok_or(TransactionStorageError::DieselError(DieselError::NotFound))?; let current_status = TransactionStatus::try_from(current_status) .map_err(|_| TransactionStorageError::UnexpectedResult("Unknown status".to_string()))?; - // let current_mined_height = *completed_transactions::table - // .filter(completed_transactions::tx_id.eq(tx_id.as_u64() as i64)) - // .select(completed_transactions::mined_height) - // .load::>(conn)? - // .first() - // .ok_or(TransactionStorageError::DieselError(DieselError::NotFound))?; - // This query uses two sub-queries to retrieve existing values in the table diesel::update(completed_transactions::table.filter(completed_transactions::tx_id.eq(tx_id.as_u64() as i64))) .set(UpdateCompletedTransactionSql { status: match current_status { diff --git a/base_layer/wallet/src/transaction_service/tasks/check_faux_transaction_status.rs b/base_layer/wallet/src/transaction_service/tasks/check_faux_transaction_status.rs index 0695f9e72f..c4799fc81c 100644 --- a/base_layer/wallet/src/transaction_service/tasks/check_faux_transaction_status.rs +++ b/base_layer/wallet/src/transaction_service/tasks/check_faux_transaction_status.rs @@ -137,7 +137,7 @@ pub async fn check_detected_transactions let previously_confirmed = tx.status.is_confirmed(); let must_be_confirmed = tip_height.saturating_sub(mined_height) >= TransactionServiceConfig::default().num_confirmations_required; - let num_confirmations = tip_height - mined_height; + let num_confirmations = tip_height.saturating_sub(mined_height); debug!( target: LOG_TARGET, "Updating faux transaction: TxId({}), mined_height({}), must_be_confirmed({}), num_confirmations({}), \ diff --git a/base_layer/wallet/tests/transaction_service_tests/service.rs b/base_layer/wallet/tests/transaction_service_tests/service.rs index 24557d3ace..53af0511eb 100644 --- a/base_layer/wallet/tests/transaction_service_tests/service.rs +++ b/base_layer/wallet/tests/transaction_service_tests/service.rs @@ -85,7 +85,7 @@ use tari_common_types::{ chain_metadata::ChainMetadata, tari_address::TariAddress, transaction::{ImportStatus, TransactionDirection, TransactionStatus, TxId}, - types::{FixedHash, PrivateKey, PublicKey, Signature}, + types::{FixedHash, HashOutput, PrivateKey, PublicKey, Signature}, }; use tari_comms::{ message::EnvelopeBody, @@ -121,7 +121,7 @@ use tari_core::{ }, tari_amount::*, test_helpers::{create_wallet_output_with_data, TestParams}, - transaction_components::{KernelBuilder, OutputFeatures, Transaction}, + transaction_components::{KernelBuilder, OutputFeatures, RangeProofType, Transaction}, transaction_protocol::{ proto::protocol as proto, recipient::RecipientSignedMessage, @@ -304,7 +304,9 @@ async fn setup_transaction_service_no_comms( factories: CryptoFactories, db_connection: WalletDbConnection, config: Option, -) -> TransactionServiceNoCommsInterface { +) -> + TransactionServiceNoCommsInterface +{ let (oms_request_sender, oms_request_receiver) = reply_channel::unbounded(); let (output_manager_service_event_publisher, _) = broadcast::channel(200); @@ -1941,7 +1943,8 @@ async fn test_accepting_unknown_tx_id_and_malformed_reply() { let bob_node_identity = NodeIdentity::random(&mut OsRng, get_next_memory_address(), PeerFeatures::COMMUNICATION_NODE); - let mut alice_ts_interface = setup_transaction_service_no_comms(factories.clone(), connection_alice, None).await; + let mut alice_ts_interface= + setup_transaction_service_no_comms(factories.clone(), connection_alice, None).await; let uo = make_input( &mut OsRng, @@ -2036,7 +2039,8 @@ async fn finalize_tx_with_incorrect_pubkey() { let connection_alice = run_migration_and_create_sqlite_connection(&alice_db_path, 16).unwrap(); let connection_bob = run_migration_and_create_sqlite_connection(&bob_db_path, 16).unwrap(); - let mut alice_ts_interface = setup_transaction_service_no_comms(factories.clone(), connection_alice, None).await; + let mut alice_ts_interface = + setup_transaction_service_no_comms(factories.clone(), connection_alice, None).await; let mut alice_event_stream = alice_ts_interface.transaction_service_handle.get_event_stream(); let bob_node_identity = @@ -2160,7 +2164,8 @@ async fn finalize_tx_with_missing_output() { let connection_alice = run_migration_and_create_sqlite_connection(&alice_db_path, 16).unwrap(); let connection_bob = run_migration_and_create_sqlite_connection(&bob_db_path, 16).unwrap(); - let mut alice_ts_interface = setup_transaction_service_no_comms(factories.clone(), connection_alice, None).await; + let mut alice_ts_interface = + setup_transaction_service_no_comms(factories.clone(), connection_alice, None).await; let mut alice_event_stream = alice_ts_interface.transaction_service_handle.get_event_stream(); let bob_node_identity = @@ -3618,7 +3623,8 @@ async fn test_restarting_transaction_protocols() { let factories = CryptoFactories::default(); let (alice_connection, _temp_dir) = make_wallet_database_connection(None); - let mut alice_ts_interface = setup_transaction_service_no_comms(factories.clone(), alice_connection, None).await; + let mut alice_ts_interface = + setup_transaction_service_no_comms(factories.clone(), alice_connection, None).await; let alice_backend = alice_ts_interface.ts_db; @@ -5269,7 +5275,8 @@ async fn test_update_faux_tx_on_oms_validation() { let (connection, _temp_dir) = make_wallet_database_connection(None); - let mut alice_ts_interface = setup_transaction_service_no_comms(factories.clone(), connection, None).await; + let mut alice_ts_interface = + setup_transaction_service_no_comms(factories.clone(), connection, None).await; let alice_address = TariAddress::new( alice_ts_interface.base_node_identity.public_key().clone(), Network::LocalNet, @@ -5413,6 +5420,7 @@ async fn test_update_faux_tx_on_oms_validation() { if tx_id == tx_id_2 && tx.status == TransactionStatus::OneSidedUnconfirmed && !found_faux_unconfirmed { found_faux_unconfirmed = true; } + dbg!(&tx.status); if tx_id == tx_id_3 && tx.status == TransactionStatus::OneSidedConfirmed && !found_faux_confirmed { found_faux_confirmed = true; } @@ -5428,6 +5436,179 @@ async fn test_update_faux_tx_on_oms_validation() { ); } +#[tokio::test] +async fn test_update_coinbase_tx_on_oms_validation() { + let factories = CryptoFactories::default(); + + let (connection, _temp_dir) = make_wallet_database_connection(None); + + let mut alice_ts_interface = + setup_transaction_service_no_comms(factories.clone(), connection, None).await; + let alice_address = TariAddress::new( + alice_ts_interface.base_node_identity.public_key().clone(), + Network::LocalNet, + ); + + let uo_1 = make_input( + &mut OsRng.clone(), + MicroMinotari::from(10000), + &OutputFeatures::create_coinbase(5, None, RangeProofType::BulletProofPlus), + &alice_ts_interface.key_manager_handle, + ) + .await; + let uo_2 = make_input( + &mut OsRng.clone(), + MicroMinotari::from(20000), + &OutputFeatures::create_coinbase(5, None, RangeProofType::BulletProofPlus), + &alice_ts_interface.key_manager_handle, + ) + .await; + let uo_3 = make_input( + &mut OsRng.clone(), + MicroMinotari::from(30000), + &OutputFeatures::create_coinbase(5, None, RangeProofType::BulletProofPlus), + &alice_ts_interface.key_manager_handle, + ) + .await; + + let tx_id_1 = alice_ts_interface + .transaction_service_handle + .import_utxo_with_status( + MicroMinotari::from(10000), + alice_address.clone(), + "coinbase_confirmed".to_string(), + ImportStatus::CoinbaseConfirmed, + None, + None, + None, + uo_1.to_transaction_output(&alice_ts_interface.key_manager_handle) + .await + .unwrap(), + ) + .await + .unwrap(); + let tx_id_2 = alice_ts_interface + .transaction_service_handle + .import_utxo_with_status( + MicroMinotari::from(20000), + alice_address.clone(), + "one-coinbase_unconfirmed 1".to_string(), + ImportStatus::CoinbaseUnconfirmed, + None, + None, + None, + uo_2.to_transaction_output(&alice_ts_interface.key_manager_handle) + .await + .unwrap(), + ) + .await + .unwrap(); + let tx_id_3 = alice_ts_interface + .transaction_service_handle + .import_utxo_with_status( + MicroMinotari::from(30000), + alice_address, + "Coinbase_not_mined".to_string(), + ImportStatus::CoinbaseUnconfirmed, + None, + None, + None, + uo_3.to_transaction_output(&alice_ts_interface.key_manager_handle) + .await + .unwrap(), + ) + .await + .unwrap(); + + for (tx_id, uo) in [(tx_id_1, uo_1), (tx_id_2, uo_2), (tx_id_3, uo_3)] { + alice_ts_interface + .output_manager_service_handle + .add_output_with_tx_id(tx_id, uo.clone(), None) + .await + .unwrap(); + if uo.value != MicroMinotari::from(30000) { + let _ = alice_ts_interface.oms_db + .set_received_output_mined_height_and_status( + uo.hash(&alice_ts_interface.key_manager_handle).await.unwrap(), + 5, + HashOutput::zero(), + false, + 0, + ) + .unwrap(); + } + } + + for tx_id in [tx_id_1, tx_id_2, tx_id_3] { + let transaction = alice_ts_interface + .transaction_service_handle + .get_any_transaction(tx_id) + .await + .unwrap() + .unwrap(); + if tx_id == tx_id_1 { + if let WalletTransaction::Completed(tx) = &transaction { + assert_eq!(tx.status, TransactionStatus::CoinbaseConfirmed); + } else { + panic!("Should find a complete Imported transaction"); + } + } + if tx_id == tx_id_2 { + if let WalletTransaction::Completed(tx) = &transaction { + assert_eq!(tx.status, TransactionStatus::CoinbaseUnconfirmed); + } else { + panic!("Should find a complete FauxUnconfirmed transaction"); + } + } + if tx_id == tx_id_3 { + if let WalletTransaction::Completed(tx) = &transaction { + assert_eq!(tx.status, TransactionStatus::CoinbaseUnconfirmed); + } else { + panic!("Should find a complete FauxConfirmed transaction"); + } + } + } + + // This will change the status of the imported transaction + alice_ts_interface + .output_manager_service_event_publisher + .send(Arc::new(OutputManagerEvent::TxoValidationSuccess(1u64))) + .unwrap(); + + let mut coinbase_confirmed = false; + let mut coinbase_unconfirmed = false; + let mut coinbase_unmined = false; + for _ in 0..20 { + sleep(Duration::from_secs(1)).await; + for tx_id in [tx_id_1, tx_id_2, tx_id_3] { + let transaction = alice_ts_interface + .transaction_service_handle + .get_any_transaction(tx_id) + .await + .unwrap() + .unwrap(); + if let WalletTransaction::Completed(tx) = transaction { + if tx_id == tx_id_1 && tx.status == TransactionStatus::CoinbaseConfirmed && !coinbase_confirmed { + coinbase_confirmed = true; + } + if tx_id == tx_id_2 && tx.status == TransactionStatus::CoinbaseUnconfirmed && !coinbase_unconfirmed { + coinbase_unconfirmed = true; + } + if tx_id == tx_id_3 && tx.status == TransactionStatus::CoinbaseNotInBlockChain && !coinbase_unmined { + coinbase_unmined = true; + } + } + } + if coinbase_confirmed && coinbase_unconfirmed && coinbase_unmined { + break; + } + } + assert!( + coinbase_confirmed && coinbase_unconfirmed && coinbase_unmined, + "Should have found the updated statuses" + ); +} + #[tokio::test] async fn test_get_fee_per_gram_per_block_basic() { let factories = CryptoFactories::default(); From 23e1b96690a161c0a7f2c6508580dd6f5b8558b6 Mon Sep 17 00:00:00 2001 From: SW van Heerden Date: Thu, 18 Jan 2024 10:28:01 +0200 Subject: [PATCH 05/10] clippy --- .../wallet/tests/transaction_service_tests/service.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/base_layer/wallet/tests/transaction_service_tests/service.rs b/base_layer/wallet/tests/transaction_service_tests/service.rs index 53af0511eb..9be423521d 100644 --- a/base_layer/wallet/tests/transaction_service_tests/service.rs +++ b/base_layer/wallet/tests/transaction_service_tests/service.rs @@ -5362,6 +5362,14 @@ async fn test_update_faux_tx_on_oms_validation() { alice_ts_interface .oms_db .mark_output_as_unspent(uo.hash(&alice_ts_interface.key_manager_handle).await.unwrap()) + alice_db + .set_received_output_mined_height_and_status( + uo.hash(&alice_ts_interface.key_manager_handle).await.unwrap(), + 5, + HashOutput::zero(), + false, + 0, + ) .unwrap(); } From d6ed27b495891fad35203fd68f7ec4f4c43d0345 Mon Sep 17 00:00:00 2001 From: SW van Heerden Date: Thu, 18 Jan 2024 12:00:40 +0200 Subject: [PATCH 06/10] clippy tests fixes --- .../minotari_app_grpc/proto/block.proto | 1 - .../transaction_service_tests/service.rs | 31 +++++++------------ 2 files changed, 12 insertions(+), 20 deletions(-) diff --git a/applications/minotari_app_grpc/proto/block.proto b/applications/minotari_app_grpc/proto/block.proto index 4d71d2f7fe..f5ed70c3ee 100644 --- a/applications/minotari_app_grpc/proto/block.proto +++ b/applications/minotari_app_grpc/proto/block.proto @@ -121,7 +121,6 @@ message NewBlockHeaderTemplate { bytes total_kernel_offset = 4; // Proof of work metadata ProofOfWork pow = 5; -// uint64 target_difficulty = 6; // Sum of script offsets for all kernels in this block. bytes total_script_offset = 7; } diff --git a/base_layer/wallet/tests/transaction_service_tests/service.rs b/base_layer/wallet/tests/transaction_service_tests/service.rs index 9be423521d..e755842831 100644 --- a/base_layer/wallet/tests/transaction_service_tests/service.rs +++ b/base_layer/wallet/tests/transaction_service_tests/service.rs @@ -304,9 +304,7 @@ async fn setup_transaction_service_no_comms( factories: CryptoFactories, db_connection: WalletDbConnection, config: Option, -) -> - TransactionServiceNoCommsInterface -{ +) -> TransactionServiceNoCommsInterface { let (oms_request_sender, oms_request_receiver) = reply_channel::unbounded(); let (output_manager_service_event_publisher, _) = broadcast::channel(200); @@ -1943,8 +1941,7 @@ async fn test_accepting_unknown_tx_id_and_malformed_reply() { let bob_node_identity = NodeIdentity::random(&mut OsRng, get_next_memory_address(), PeerFeatures::COMMUNICATION_NODE); - let mut alice_ts_interface= - setup_transaction_service_no_comms(factories.clone(), connection_alice, None).await; + let mut alice_ts_interface = setup_transaction_service_no_comms(factories.clone(), connection_alice, None).await; let uo = make_input( &mut OsRng, @@ -2039,8 +2036,7 @@ async fn finalize_tx_with_incorrect_pubkey() { let connection_alice = run_migration_and_create_sqlite_connection(&alice_db_path, 16).unwrap(); let connection_bob = run_migration_and_create_sqlite_connection(&bob_db_path, 16).unwrap(); - let mut alice_ts_interface = - setup_transaction_service_no_comms(factories.clone(), connection_alice, None).await; + let mut alice_ts_interface = setup_transaction_service_no_comms(factories.clone(), connection_alice, None).await; let mut alice_event_stream = alice_ts_interface.transaction_service_handle.get_event_stream(); let bob_node_identity = @@ -2164,8 +2160,7 @@ async fn finalize_tx_with_missing_output() { let connection_alice = run_migration_and_create_sqlite_connection(&alice_db_path, 16).unwrap(); let connection_bob = run_migration_and_create_sqlite_connection(&bob_db_path, 16).unwrap(); - let mut alice_ts_interface = - setup_transaction_service_no_comms(factories.clone(), connection_alice, None).await; + let mut alice_ts_interface = setup_transaction_service_no_comms(factories.clone(), connection_alice, None).await; let mut alice_event_stream = alice_ts_interface.transaction_service_handle.get_event_stream(); let bob_node_identity = @@ -3623,8 +3618,7 @@ async fn test_restarting_transaction_protocols() { let factories = CryptoFactories::default(); let (alice_connection, _temp_dir) = make_wallet_database_connection(None); - let mut alice_ts_interface = - setup_transaction_service_no_comms(factories.clone(), alice_connection, None).await; + let mut alice_ts_interface = setup_transaction_service_no_comms(factories.clone(), alice_connection, None).await; let alice_backend = alice_ts_interface.ts_db; @@ -5275,8 +5269,7 @@ async fn test_update_faux_tx_on_oms_validation() { let (connection, _temp_dir) = make_wallet_database_connection(None); - let mut alice_ts_interface = - setup_transaction_service_no_comms(factories.clone(), connection, None).await; + let mut alice_ts_interface = setup_transaction_service_no_comms(factories.clone(), connection, None).await; let alice_address = TariAddress::new( alice_ts_interface.base_node_identity.public_key().clone(), Network::LocalNet, @@ -5359,10 +5352,11 @@ async fn test_update_faux_tx_on_oms_validation() { .add_output_with_tx_id(tx_id, uo.clone(), None) .await .unwrap(); + let _result = alice_ts_interface + .oms_db + .mark_output_as_unspent(uo.hash(&alice_ts_interface.key_manager_handle).await.unwrap()); alice_ts_interface .oms_db - .mark_output_as_unspent(uo.hash(&alice_ts_interface.key_manager_handle).await.unwrap()) - alice_db .set_received_output_mined_height_and_status( uo.hash(&alice_ts_interface.key_manager_handle).await.unwrap(), 5, @@ -5428,7 +5422,6 @@ async fn test_update_faux_tx_on_oms_validation() { if tx_id == tx_id_2 && tx.status == TransactionStatus::OneSidedUnconfirmed && !found_faux_unconfirmed { found_faux_unconfirmed = true; } - dbg!(&tx.status); if tx_id == tx_id_3 && tx.status == TransactionStatus::OneSidedConfirmed && !found_faux_confirmed { found_faux_confirmed = true; } @@ -5450,8 +5443,7 @@ async fn test_update_coinbase_tx_on_oms_validation() { let (connection, _temp_dir) = make_wallet_database_connection(None); - let mut alice_ts_interface = - setup_transaction_service_no_comms(factories.clone(), connection, None).await; + let mut alice_ts_interface = setup_transaction_service_no_comms(factories.clone(), connection, None).await; let alice_address = TariAddress::new( alice_ts_interface.base_node_identity.public_key().clone(), Network::LocalNet, @@ -5535,7 +5527,8 @@ async fn test_update_coinbase_tx_on_oms_validation() { .await .unwrap(); if uo.value != MicroMinotari::from(30000) { - let _ = alice_ts_interface.oms_db + let _ = alice_ts_interface + .oms_db .set_received_output_mined_height_and_status( uo.hash(&alice_ts_interface.key_manager_handle).await.unwrap(), 5, From 8bcf14afa5c3a06b90f5a72a0e608e046af900e1 Mon Sep 17 00:00:00 2001 From: SW van Heerden Date: Thu, 18 Jan 2024 12:14:11 +0200 Subject: [PATCH 07/10] clippy --- base_layer/wallet/tests/transaction_service_tests/service.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base_layer/wallet/tests/transaction_service_tests/service.rs b/base_layer/wallet/tests/transaction_service_tests/service.rs index e755842831..0a7925ac27 100644 --- a/base_layer/wallet/tests/transaction_service_tests/service.rs +++ b/base_layer/wallet/tests/transaction_service_tests/service.rs @@ -5527,7 +5527,7 @@ async fn test_update_coinbase_tx_on_oms_validation() { .await .unwrap(); if uo.value != MicroMinotari::from(30000) { - let _ = alice_ts_interface + alice_ts_interface .oms_db .set_received_output_mined_height_and_status( uo.hash(&alice_ts_interface.key_manager_handle).await.unwrap(), From 792dbd28dbed0e4afed613dc4da4849a72c3adcc Mon Sep 17 00:00:00 2001 From: SW van Heerden Date: Thu, 18 Jan 2024 13:02:10 +0200 Subject: [PATCH 08/10] add flaky tag --- integration_tests/tests/features/Sync.feature | 2 +- integration_tests/tests/features/WalletTransactions.feature | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/integration_tests/tests/features/Sync.feature b/integration_tests/tests/features/Sync.feature index e9a1abcf25..74daea7df2 100644 --- a/integration_tests/tests/features/Sync.feature +++ b/integration_tests/tests/features/Sync.feature @@ -30,7 +30,7 @@ Feature: Block Sync When I have 2 base nodes connected to all seed nodes Then all nodes are at height 20 - @critical @pie + @critical Scenario: Sync burned output Given I have a seed node NODE When I have a base node NODE1 connected to all seed nodes diff --git a/integration_tests/tests/features/WalletTransactions.feature b/integration_tests/tests/features/WalletTransactions.feature index 1df409c268..50d138ba1f 100644 --- a/integration_tests/tests/features/WalletTransactions.feature +++ b/integration_tests/tests/features/WalletTransactions.feature @@ -407,7 +407,7 @@ Feature: Wallet Transactions # When I wait 15 seconds # When wallet WALLET_RECV detects last transaction is Cancelled - @critical + @critical @flaky Scenario: Create burn transaction Given I have a seed node NODE When I have 2 base nodes connected to all seed nodes From a07ce0971f17f63f6f7e3967afec2c7535763bce Mon Sep 17 00:00:00 2001 From: SW van Heerden Date: Thu, 18 Jan 2024 13:23:42 +0200 Subject: [PATCH 09/10] more stricker code --- integration_tests/tests/steps/wallet_steps.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/integration_tests/tests/steps/wallet_steps.rs b/integration_tests/tests/steps/wallet_steps.rs index bb9265f241..136a50d8d9 100644 --- a/integration_tests/tests/steps/wallet_steps.rs +++ b/integration_tests/tests/steps/wallet_steps.rs @@ -153,7 +153,7 @@ async fn have_wallet_connect_to_seed_node(world: &mut TariWorld, wallet: String, #[when(expr = "wallet {word} detects all transactions as {word}")] #[then(expr = "wallet {word} detects all transactions as {word}")] -async fn wallet_detects_all_txs_as_mined_confirmed(world: &mut TariWorld, wallet_name: String, status: String) { +async fn wallet_detects_all_txs_as_mined_status(world: &mut TariWorld, wallet_name: String, status: String) { let mut client = create_wallet_client(world, wallet_name.clone()).await.unwrap(); let mut completed_tx_stream = client @@ -239,11 +239,6 @@ async fn wallet_detects_all_txs_as_mined_confirmed(world: &mut TariWorld, wallet _ => (), }, "Coinbase" => match tx_info.status() { - grpc::TransactionStatus::Pending | - grpc::TransactionStatus::Completed | - grpc::TransactionStatus::Broadcast | - grpc::TransactionStatus::MinedUnconfirmed | - grpc::TransactionStatus::MinedConfirmed | grpc::TransactionStatus::CoinbaseConfirmed | grpc::TransactionStatus::CoinbaseUnconfirmed => { break; From 89dc816efa0c48b582645df574083052555da322 Mon Sep 17 00:00:00 2001 From: SW van Heerden Date: Thu, 18 Jan 2024 13:31:42 +0200 Subject: [PATCH 10/10] fmt --- integration_tests/tests/steps/wallet_steps.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/integration_tests/tests/steps/wallet_steps.rs b/integration_tests/tests/steps/wallet_steps.rs index 136a50d8d9..7dff333a31 100644 --- a/integration_tests/tests/steps/wallet_steps.rs +++ b/integration_tests/tests/steps/wallet_steps.rs @@ -239,8 +239,7 @@ async fn wallet_detects_all_txs_as_mined_status(world: &mut TariWorld, wallet_na _ => (), }, "Coinbase" => match tx_info.status() { - grpc::TransactionStatus::CoinbaseConfirmed | - grpc::TransactionStatus::CoinbaseUnconfirmed => { + grpc::TransactionStatus::CoinbaseConfirmed | grpc::TransactionStatus::CoinbaseUnconfirmed => { break; }, _ => (),