From 2bc4e36fdd97d00b212030e784421b3c78fdfed1 Mon Sep 17 00:00:00 2001 From: Hansie Odendaal Date: Fri, 10 Nov 2023 11:00:49 +0200 Subject: [PATCH] Add one-sided coinbase Added one-sided and stealth coinbase transactions. Coinbases can now only be paid to a nominated wallet address directly. --- Cargo.lock | 6 + .../minotari_app_grpc/proto/wallet.proto | 14 - .../minotari_console_wallet/README.md | 12 +- .../minotari_console_wallet/src/grpc/mod.rs | 6 - .../src/grpc/wallet_grpc_server.rs | 21 - .../minotari_console_wallet/src/init/mod.rs | 1 - .../src/ui/components/transactions_tab.rs | 9 +- .../src/ui/state/app_state.rs | 32 +- .../minotari_merge_mining_proxy/Cargo.toml | 4 + .../src/block_template_protocol.rs | 90 +- .../src/common/merge_mining.rs | 11 +- .../minotari_merge_mining_proxy/src/config.rs | 10 +- .../minotari_merge_mining_proxy/src/error.rs | 18 +- .../minotari_merge_mining_proxy/src/proxy.rs | 9 +- .../src/run_merge_miner.rs | 26 +- applications/minotari_miner/Cargo.toml | 1 + applications/minotari_miner/README.md | 14 +- applications/minotari_miner/src/config.rs | 21 +- applications/minotari_miner/src/errors.rs | 11 +- applications/minotari_miner/src/lib.rs | 1 - applications/minotari_miner/src/main.rs | 1 - applications/minotari_miner/src/run_miner.rs | 144 +- applications/minotari_miner/src/utils.rs | 80 - base_layer/common_types/src/transaction.rs | 5 - base_layer/core/benches/mempool.rs | 4 +- .../tests/blockchain_database.rs | 112 +- base_layer/core/src/covenants/covenant.rs | 8 +- base_layer/core/src/covenants/fields.rs | 23 +- .../src/covenants/filters/absolute_height.rs | 8 +- base_layer/core/src/covenants/filters/and.rs | 4 +- .../core/src/covenants/filters/field_eq.rs | 16 +- .../src/covenants/filters/fields_hashed_eq.rs | 7 +- .../src/covenants/filters/fields_preserved.rs | 4 +- .../core/src/covenants/filters/identity.rs | 4 +- base_layer/core/src/covenants/filters/not.rs | 4 +- base_layer/core/src/covenants/filters/or.rs | 4 +- .../src/covenants/filters/output_hash_eq.rs | 4 +- base_layer/core/src/covenants/filters/test.rs | 4 +- base_layer/core/src/covenants/filters/xor.rs | 4 +- base_layer/core/src/covenants/test.rs | 7 +- .../priority/prioritized_transaction.rs | 9 +- .../core/src/mempool/reorg_pool/reorg_pool.rs | 8 +- .../core/src/mempool/sync_protocol/test.rs | 5 +- .../unconfirmed_pool/unconfirmed_pool.rs | 19 +- .../core/src/test_helpers/blockchain.rs | 64 +- base_layer/core/src/test_helpers/mod.rs | 52 +- .../core/src/transactions/coinbase_builder.rs | 208 ++- .../src/transactions/key_manager/error.rs | 13 +- .../key_manager/memory_db_key_manager.rs | 64 + .../core/src/transactions/key_manager/mod.rs | 10 + base_layer/core/src/transactions/mod.rs | 2 +- .../core/src/transactions/test_helpers.rs | 92 +- .../transaction_components/output_type.rs | 2 +- .../transaction_components/test.rs | 42 +- .../transaction_output.rs | 22 +- .../wallet_output_builder.rs | 9 +- .../transaction_protocol/recipient.rs | 11 +- .../transaction_protocol/sender.rs | 29 +- .../transaction_protocol/single_receiver.rs | 10 +- .../transaction_initializer.rs | 23 +- .../aggregate_body_chain_validator.rs | 1 + .../aggregate_body_internal_validator.rs | 6 +- .../block_body_internal_validator.rs | 1 - .../core/src/validation/block_body/test.rs | 121 +- base_layer/core/src/validation/helpers.rs | 10 +- base_layer/core/src/validation/test.rs | 21 +- .../chain_storage_tests/chain_storage.rs | 2 +- .../core/tests/helpers/block_builders.rs | 34 +- .../core/tests/helpers/block_malleability.rs | 2 +- base_layer/core/tests/helpers/database.rs | 4 +- .../core/tests/helpers/sample_blockchains.rs | 16 +- base_layer/core/tests/helpers/sync.rs | 8 +- .../core/tests/helpers/test_blockchain.rs | 4 +- base_layer/core/tests/tests/base_node_rpc.rs | 14 +- .../core/tests/tests/block_validation.rs | 18 +- base_layer/core/tests/tests/mempool.rs | 21 +- .../core/tests/tests/node_comms_interface.rs | 27 +- base_layer/core/tests/tests/node_service.rs | 21 +- .../core/tests/tests/node_state_machine.rs | 6 +- base_layer/wallet/README.md | 1 + .../2023-11-14-131400_coinbase/down.sql | 1 + .../2023-11-14-131400_coinbase/up.sql | 69 + .../src/output_manager_service/error.rs | 3 - .../src/output_manager_service/handle.rs | 47 - .../output_manager_service/input_selection.rs | 2 +- .../recovery/standard_outputs_recoverer.rs | 51 +- .../src/output_manager_service/service.rs | 87 +- .../storage/database/backend.rs | 2 - .../storage/database/mod.rs | 26 +- .../output_manager_service/storage/models.rs | 41 +- .../storage/output_source.rs | 26 +- .../storage/output_status.rs | 4 +- .../storage/sqlite_db/mod.rs | 83 +- .../storage/sqlite_db/new_output_sql.rs | 5 +- .../storage/sqlite_db/output_sql.rs | 26 +- base_layer/wallet/src/schema.rs | 2 - .../wallet/src/transaction_service/error.rs | 8 +- .../wallet/src/transaction_service/handle.rs | 47 +- .../protocols/transaction_receive_protocol.rs | 4 +- .../protocols/transaction_send_protocol.rs | 4 +- .../transaction_validation_protocol.rs | 122 +- .../wallet/src/transaction_service/service.rs | 119 +- .../transaction_service/storage/database.rs | 34 +- .../src/transaction_service/storage/models.rs | 27 +- .../transaction_service/storage/sqlite_db.rs | 290 +--- .../utxo_scanner_service/utxo_scanner_task.rs | 9 +- base_layer/wallet/src/wallet.rs | 1 - base_layer/wallet/tests/other/mod.rs | 7 +- .../output_manager_service_tests/service.rs | 199 +-- .../output_manager_service_tests/storage.rs | 26 +- base_layer/wallet/tests/support/utils.rs | 10 +- .../transaction_service_tests/service.rs | 1341 +++-------------- .../transaction_service_tests/storage.rs | 21 +- .../transaction_protocols.rs | 145 +- base_layer/wallet/tests/utxo_scanner/mod.rs | 34 +- .../wallet_ffi/src/callback_handler_tests.rs | 12 +- base_layer/wallet_ffi/src/lib.rs | 28 +- .../config/presets/f_merge_mining_proxy.toml | 3 - common/config/presets/g_miner.toml | 5 - common/src/exit_codes.rs | 6 + .../net_address/mutliaddresses_with_stats.rs | 18 +- integration_tests/Cargo.toml | 1 + integration_tests/src/miner.rs | 325 ++-- integration_tests/src/transaction.rs | 18 +- integration_tests/src/world.rs | 32 +- integration_tests/tests/steps/mining_steps.rs | 48 +- integration_tests/tests/steps/node_steps.rs | 36 +- integration_tests/tests/steps/wallet_steps.rs | 7 +- 128 files changed, 1844 insertions(+), 3414 deletions(-) delete mode 100644 applications/minotari_miner/src/utils.rs create mode 100644 base_layer/core/src/transactions/key_manager/memory_db_key_manager.rs create mode 100644 base_layer/wallet/migrations/2023-11-14-131400_coinbase/down.sql create mode 100644 base_layer/wallet/migrations/2023-11-14-131400_coinbase/up.sql diff --git a/Cargo.lock b/Cargo.lock index be84aacba9a..d027100323a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3201,13 +3201,17 @@ dependencies = [ "minotari_app_utilities", "minotari_node_grpc_client", "minotari_wallet_grpc_client", + "rand", "reqwest", "serde", "serde_json", "tari_common", + "tari_common_types", "tari_comms", "tari_core", + "tari_crypto", "tari_features", + "tari_key_manager", "tari_utilities", "thiserror", "tokio", @@ -3246,6 +3250,7 @@ dependencies = [ "tari_comms", "tari_core", "tari_crypto", + "tari_key_manager", "tari_utilities", "thiserror", "tokio", @@ -5913,6 +5918,7 @@ dependencies = [ "tari_contacts", "tari_core", "tari_crypto", + "tari_key_manager", "tari_p2p", "tari_script", "tari_shutdown", diff --git a/applications/minotari_app_grpc/proto/wallet.proto b/applications/minotari_app_grpc/proto/wallet.proto index d6919f55d70..cd936a68847 100644 --- a/applications/minotari_app_grpc/proto/wallet.proto +++ b/applications/minotari_app_grpc/proto/wallet.proto @@ -41,8 +41,6 @@ service Wallet { rpc Identify (GetIdentityRequest) returns (GetIdentityResponse); // This returns the tari address rpc GetAddress (Empty) returns (GetAddressResponse); - // This returns a coinbase transaction - rpc GetCoinbase (GetCoinbaseRequest) returns (GetCoinbaseResponse); // Send Minotari to a number of recipients rpc Transfer (TransferRequest) returns (TransferResponse); // Returns the transaction details for the given transaction IDs @@ -244,17 +242,6 @@ message GetUnspentAmountsResponse { repeated uint64 amount = 1; } -message GetCoinbaseRequest { - uint64 reward = 1; - uint64 fee = 2; - uint64 height = 3; - bytes extra = 4; -} - -message GetCoinbaseResponse { - Transaction transaction = 1; -} - message CoinSplitRequest { uint64 amount_per_split = 1; uint64 split_count = 2; @@ -329,7 +316,6 @@ message TransactionEvent { string direction = 6; uint64 amount = 7; string message = 8; - bool is_coinbase = 9; } message TransactionEventResponse { diff --git a/applications/minotari_console_wallet/README.md b/applications/minotari_console_wallet/README.md index a296987fdb2..a9c4246bbbf 100644 --- a/applications/minotari_console_wallet/README.md +++ b/applications/minotari_console_wallet/README.md @@ -195,13 +195,13 @@ Total value of UTXOs: 36105.165440 T example output - `--csv-file` (contents of `utxos.csv`) ``` -"#","Value (uT)","Spending Key","Commitment","Flags","Maturity" -"1","121999250","0b0ce2add569845ec8bb84256b731e644e2224580b568e75666399e868ea5701","22514e279bd7e7e0a6e45905e07323b16f6114e300bcc02f36b2baf44a17b43d","(empty)","0" -"2","124000000","8829254b5267de26fe926f30518604abeec156740abe64b435ac6081269f2f0d","88f4e7216353032b90bee1c8b4243c3f25b357902a5cb145fda1c98316525214","(empty)","0" -"3","125000000","295853fad02d56313920130c3a5fa3aa8be54297ee5375aa2d788f4e49f08309","72a42d2db4f8eebbc4d0074fcb04338b8caa22312ce6a68e8798c2452b52e465","(empty)","0" +"#","Value (uT)","Spending Key","Commitment","Maturity" +"1","121999250","0b0ce2add569845ec8bb84256b731e644e2224580b568e75666399e868ea5701","22514e279bd7e7e0a6e45905e07323b16f6114e300bcc02f36b2baf44a17b43d","0" +"2","124000000","8829254b5267de26fe926f30518604abeec156740abe64b435ac6081269f2f0d","88f4e7216353032b90bee1c8b4243c3f25b357902a5cb145fda1c98316525214","0" +"3","125000000","295853fad02d56313920130c3a5fa3aa8be54297ee5375aa2d788f4e49f08309","72a42d2db4f8eebbc4d0074fcb04338b8caa22312ce6a68e8798c2452b52e465","0" ... -"10","5513131148","a6323f62ef21c45f03c73b424d9823b1a0f44a4408be688e5f6fde6419a11407","dcec835619474a62b5cef8227481cebd5831aec515e85286f3932c8093e9d06b","COINBASE_OUTPUT","10655" -"11","5513145680","5af45bff0f533999c94ec799aa4789260a1b989207363c33ec6ec388899ec906","7ec353f1f005637192d50104b3c5b4621d1ebdafb5c5cc078cf3f86754669352","COINBASE_OUTPUT","10649" +"10","5513131148","a6323f62ef21c45f03c73b424d9823b1a0f44a4408be688e5f6fde6419a11407","dcec835619474a62b5cef8227481cebd5831aec515e85286f3932c8093e9d06b","10655" +"11","5513145680","5af45bff0f533999c94ec799aa4789260a1b989207363c33ec6ec388899ec906","7ec353f1f005637192d50104b3c5b4621d1ebdafb5c5cc078cf3f86754669352","10649" ``` - **count-utxos** diff --git a/applications/minotari_console_wallet/src/grpc/mod.rs b/applications/minotari_console_wallet/src/grpc/mod.rs index 92cc7812ea6..ecffc7ce38b 100644 --- a/applications/minotari_console_wallet/src/grpc/mod.rs +++ b/applications/minotari_console_wallet/src/grpc/mod.rs @@ -29,7 +29,6 @@ pub fn convert_to_transaction_event(event: String, source: TransactionWrapper) - direction: completed.direction.to_string(), amount: completed.amount.as_u64(), message: completed.message.to_string(), - is_coinbase: completed.is_coinbase(), }, TransactionWrapper::Outbound(outbound) => TransactionEvent { event, @@ -40,7 +39,6 @@ pub fn convert_to_transaction_event(event: String, source: TransactionWrapper) - direction: "outbound".to_string(), amount: outbound.amount.as_u64(), message: outbound.message, - is_coinbase: false, }, TransactionWrapper::Inbound(inbound) => TransactionEvent { event, @@ -51,10 +49,6 @@ pub fn convert_to_transaction_event(event: String, source: TransactionWrapper) - direction: "inbound".to_string(), amount: inbound.amount.as_u64(), message: inbound.message.clone(), - // The coinbase are technically Inbound. - // To determine whether a transaction is coinbase - // we will check whether the message contains `Coinbase`. - is_coinbase: inbound.message.to_lowercase().contains("coinbase"), }, } } diff --git a/applications/minotari_console_wallet/src/grpc/wallet_grpc_server.rs b/applications/minotari_console_wallet/src/grpc/wallet_grpc_server.rs index 8997f0294b3..ac7f8df2e31 100644 --- a/applications/minotari_console_wallet/src/grpc/wallet_grpc_server.rs +++ b/applications/minotari_console_wallet/src/grpc/wallet_grpc_server.rs @@ -47,8 +47,6 @@ use minotari_app_grpc::tari_rpc::{ GetAddressResponse, GetBalanceRequest, GetBalanceResponse, - GetCoinbaseRequest, - GetCoinbaseResponse, GetCompletedTransactionsRequest, GetCompletedTransactionsResponse, GetConnectivityRequest, @@ -309,24 +307,6 @@ impl wallet_server::Wallet for WalletGrpcServer { Ok(Response::new(RevalidateResponse {})) } - async fn get_coinbase( - &self, - request: Request, - ) -> Result, Status> { - let request = request.into_inner(); - let mut tx_service = self.get_transaction_service(); - - let coinbase = tx_service - .generate_coinbase_transaction(request.reward.into(), request.fee.into(), request.height, request.extra) - .await - .map_err(|err| Status::unknown(err.to_string()))?; - - let coinbase = coinbase.try_into().map_err(Status::internal)?; - Ok(Response::new(GetCoinbaseResponse { - transaction: Some(coinbase), - })) - } - async fn send_sha_atomic_swap_transaction( &self, request: Request, @@ -1090,7 +1070,6 @@ fn simple_event(event: &str) -> TransactionEvent { direction: event.to_string(), amount: 0, message: String::default(), - is_coinbase: false, } } diff --git a/applications/minotari_console_wallet/src/init/mod.rs b/applications/minotari_console_wallet/src/init/mod.rs index cbabc75a9e1..14df5dfbd1d 100644 --- a/applications/minotari_console_wallet/src/init/mod.rs +++ b/applications/minotari_console_wallet/src/init/mod.rs @@ -188,7 +188,6 @@ fn display_password_feedback(passphrase: &SafePassword) -> bool { "The password you chose is weak; a determined attacker with access to your device may be able to guess it." ); println!("You may want to consider changing it to a stronger one."); - println!("Here are some suggestions:"); for suggestion in feedback { println!("- {}", suggestion); } diff --git a/applications/minotari_console_wallet/src/ui/components/transactions_tab.rs b/applications/minotari_console_wallet/src/ui/components/transactions_tab.rs index b5814aefa79..50fa7ff213a 100644 --- a/applications/minotari_console_wallet/src/ui/components/transactions_tab.rs +++ b/applications/minotari_console_wallet/src/ui/components/transactions_tab.rs @@ -253,9 +253,7 @@ impl TransactionsTab { Style::default().fg(text_color), ))); - let status = if matches!(t.cancelled, Some(TxCancellationReason::AbandonedCoinbase)) { - "Abandoned".to_string() - } else if matches!(t.cancelled, Some(TxCancellationReason::UserCancelled)) { + let status = if matches!(t.cancelled, Some(TxCancellationReason::UserCancelled)) { "Cancelled".to_string() } else if t.cancelled.is_some() { "Rejected".to_string() @@ -364,9 +362,7 @@ impl TransactionsTab { let amount = tx.amount.to_string(); let content = &amount; let amount = Span::styled(content, Style::default().fg(Color::White)); - let fee_details = if tx.is_coinbase { - Span::raw("") - } else { + let fee_details = { Span::styled( format!( " (weight: {}g, #inputs: {}, #outputs: {})", @@ -602,7 +598,6 @@ impl Component for TransactionsTab { error!(target: LOG_TARGET, "Error rebroadcasting transactions: {}", e); } }, - 'a' => app_state.toggle_abandoned_coinbase_filter(), '\n' => match self.selected_tx_list { SelectedTransactionList::None => {}, SelectedTransactionList::PendingTxs => { diff --git a/applications/minotari_console_wallet/src/ui/state/app_state.rs b/applications/minotari_console_wallet/src/ui/state/app_state.rs index c2617b1e65c..cc2a3b51961 100644 --- a/applications/minotari_console_wallet/src/ui/state/app_state.rs +++ b/applications/minotari_console_wallet/src/ui/state/app_state.rs @@ -27,7 +27,6 @@ use std::{ time::{Duration, Instant}, }; -use bitflags::bitflags; use chrono::{DateTime, Local, NaiveDateTime}; use log::*; use minotari_wallet::{ @@ -97,7 +96,6 @@ pub struct AppState { inner: Arc>, cached_data: AppStateData, cache_update_cooldown: Option, - completed_tx_filter: TransactionFilter, config: AppStateConfig, wallet_config: WalletConfig, wallet_connectivity: WalletConnectivityHandle, @@ -122,7 +120,6 @@ impl AppState { inner: inner.clone(), cached_data, cache_update_cooldown: None, - completed_tx_filter: TransactionFilter::ABANDONED_COINBASES, config: AppStateConfig::default(), wallet_connectivity, balance_enquiry_debouncer: BalanceEnquiryDebouncer::new( @@ -559,19 +556,7 @@ impl AppState { } pub fn get_completed_txs(&self) -> Vec<&CompletedTransactionInfo> { - if self - .completed_tx_filter - .contains(TransactionFilter::ABANDONED_COINBASES) - { - self.cached_data - .completed_txs - .iter() - .filter(|tx| !matches!(tx.cancelled, Some(TxCancellationReason::AbandonedCoinbase))) - .filter(|tx| !matches!(tx.status, TransactionStatus::Coinbase)) - .collect() - } else { - self.cached_data.completed_txs.iter().collect() - } + self.cached_data.completed_txs.iter().collect() } pub fn get_confirmations(&self, tx_id: TxId) -> Option<&u64> { @@ -657,10 +642,6 @@ impl AppState { self.wallet_config.num_required_confirmations } - pub fn toggle_abandoned_coinbase_filter(&mut self) { - self.completed_tx_filter.toggle(TransactionFilter::ABANDONED_COINBASES); - } - pub fn get_notifications(&self) -> &[(DateTime, String)] { &self.cached_data.notifications } @@ -1166,7 +1147,6 @@ pub struct CompletedTransactionInfo { pub cancelled: Option, pub direction: TransactionDirection, pub mined_height: Option, - pub is_coinbase: bool, pub weight: u64, pub inputs_count: usize, pub outputs_count: usize, @@ -1182,7 +1162,6 @@ impl CompletedTransactionInfo { .first_kernel_excess_sig() .map(|s| s.get_signature().to_hex()) .unwrap_or_default(); - let is_coinbase = tx.is_coinbase(); let weight = tx.transaction.calculate_weight(transaction_weighting)?; let inputs_count = tx.transaction.body.inputs().len(); let outputs_count = tx.transaction.body.outputs().len(); @@ -1208,7 +1187,6 @@ impl CompletedTransactionInfo { cancelled: tx.cancelled, direction: tx.direction, mined_height: tx.mined_height, - is_coinbase, weight, inputs_count, outputs_count, @@ -1344,14 +1322,6 @@ pub enum UiTransactionBurnStatus { Error(String), } -bitflags! { - #[derive(Clone)] - pub struct TransactionFilter: u8 { - const NONE = 0b0000_0000; - const ABANDONED_COINBASES = 0b0000_0001; - } -} - #[derive(Clone)] struct AppStateConfig { pub cache_update_cooldown: Duration, diff --git a/applications/minotari_merge_mining_proxy/Cargo.toml b/applications/minotari_merge_mining_proxy/Cargo.toml index 5aebf91c49b..f782d849372 100644 --- a/applications/minotari_merge_mining_proxy/Cargo.toml +++ b/applications/minotari_merge_mining_proxy/Cargo.toml @@ -12,6 +12,7 @@ default = [] [dependencies] tari_common = { path = "../../common" } +tari_common_types = { path = "../../base_layer/common_types" } tari_comms = { path = "../../comms/core" } tari_core = { path = "../../base_layer/core", default-features = false, features = ["transactions"] } minotari_app_utilities = { path = "../minotari_app_utilities" } @@ -19,6 +20,8 @@ tari_utilities = { version = "0.6" } minotari_node_grpc_client = { path = "../../clients/rust/base_node_grpc_client" } minotari_wallet_grpc_client = { path = "../../clients/rust/wallet_grpc_client" } minotari_app_grpc = { path = "../minotari_app_grpc" } +tari_key_manager = { path = "../../base_layer/key_manager", features = ["key_manager_service"] } +tari_crypto = { version = "0.19", features = ["borsh"] } anyhow = "1.0.53" crossterm = { version = "0.25.0" } @@ -41,6 +44,7 @@ tokio = { version = "1.23", features = ["macros"] } tonic = "0.6.2" tracing = "0.1" url = "2.1.1" +rand = "0.8" [build-dependencies] tari_features = { path = "../../common/tari_features"} diff --git a/applications/minotari_merge_mining_proxy/src/block_template_protocol.rs b/applications/minotari_merge_mining_proxy/src/block_template_protocol.rs index 1cb70122f7d..718703c039f 100644 --- a/applications/minotari_merge_mining_proxy/src/block_template_protocol.rs +++ b/applications/minotari_merge_mining_proxy/src/block_template_protocol.rs @@ -22,15 +22,24 @@ //! Methods for seting up a new block. -use std::{cmp, sync::Arc}; +use std::{cmp, str::FromStr, sync::Arc}; use log::*; -use minotari_app_grpc::{ - authentication::ClientAuthenticationInterceptor, - tari_rpc::{base_node_client::BaseNodeClient, wallet_client::WalletClient}, -}; +use minotari_app_grpc::{authentication::ClientAuthenticationInterceptor, tari_rpc::base_node_client::BaseNodeClient}; use minotari_node_grpc_client::grpc; -use tari_core::proof_of_work::{monero_rx, monero_rx::FixedByteArray, Difficulty}; +use rand::rngs::OsRng; +use tari_common_types::{tari_address::TariAddress, types::PrivateKey}; +use tari_core::{ + consensus::ConsensusManager, + proof_of_work::{monero_rx, monero_rx::FixedByteArray, Difficulty}, + transactions::{ + generate_coinbase, + key_manager::{create_memory_db_key_manager, MemoryDbKeyManager, TariKeyId}, + transaction_components::{TransactionKernel, TransactionOutput}, + }, +}; +use tari_crypto::keys::SecretKey; +use tari_key_manager::key_manager_service::KeyManagerInterface; use tonic::{codegen::InterceptedService, transport::Channel}; use crate::{ @@ -46,20 +55,33 @@ const LOG_TARGET: &str = "minotari_mm_proxy::proxy::block_template_protocol"; pub struct BlockTemplateProtocol<'a> { config: Arc, base_node_client: &'a mut BaseNodeClient>, - wallet_client: &'a mut WalletClient>, + key_manager: MemoryDbKeyManager, + miner_node_script_key_id: TariKeyId, + wallet_payment_address: TariAddress, + consensus_manager: ConsensusManager, } impl<'a> BlockTemplateProtocol<'a> { pub fn new( base_node_client: &'a mut BaseNodeClient>, - wallet_client: &'a mut WalletClient>, config: Arc, - ) -> Self { - Self { - base_node_client, - wallet_client, + ) -> Result { + let key_manager = create_memory_db_key_manager(); + let wallet_private_key = PrivateKey::random(&mut OsRng); + let miner_node_script_key_id = tokio::runtime::Runtime::new() + .map_err(|err| MmProxyError::TokioRuntimeError(err.to_string()))? + .block_on(key_manager.import_key(wallet_private_key))?; + let wallet_payment_address = TariAddress::from_str(&config.wallet_payment_address) + .map_err(|err| MmProxyError::ConversionError(err.to_string()))?; + let consensus_manager = ConsensusManager::builder(config.network).build()?; + Ok(Self { config, - } + base_node_client, + key_manager, + miner_node_script_key_id, + wallet_payment_address, + consensus_manager, + }) } } @@ -71,7 +93,7 @@ impl BlockTemplateProtocol<'_> { ) -> Result { loop { let new_template = self.get_new_block_template().await?; - let coinbase = self.get_coinbase(&new_template).await?; + let (coinbase_output, coinbase_kernel) = self.get_coinbase(&new_template).await?; let template_height = new_template.template.header.as_ref().map(|h| h.height).unwrap_or(0); if !self.check_expected_tip(template_height).await? { @@ -83,7 +105,8 @@ impl BlockTemplateProtocol<'_> { } debug!(target: LOG_TARGET, "Added coinbase to new block template"); - let block_template_with_coinbase = merge_mining::add_coinbase(coinbase, new_template.template.clone())?; + let block_template_with_coinbase = + merge_mining::add_coinbase(&coinbase_output, &coinbase_kernel, new_template.template.clone())?; info!( target: LOG_TARGET, "Received new block template from Minotari base node for height #{}", @@ -183,31 +206,28 @@ impl BlockTemplateProtocol<'_> { } /// Get coinbase transaction for the [template](NewBlockTemplateData). - async fn get_coinbase(&mut self, template: &NewBlockTemplateData) -> Result { + async fn get_coinbase( + &mut self, + template: &NewBlockTemplateData, + ) -> Result<(TransactionOutput, TransactionKernel), MmProxyError> { let miner_data = &template.miner_data; let tari_height = template.height(); let block_reward = miner_data.reward; let total_fees = miner_data.total_fees; - let extra = self.config.coinbase_extra.as_bytes().to_vec(); - let coinbase_response = self - .wallet_client - .get_coinbase(grpc::GetCoinbaseRequest { - reward: block_reward, - fee: total_fees, - height: tari_height, - extra, - }) - .await - .map_err(|status| MmProxyError::GrpcRequestError { - status, - details: "failed to get new block template".to_string(), - })?; - let coinbase = coinbase_response - .into_inner() - .transaction - .ok_or_else(|| MmProxyError::MissingDataError("Coinbase Invalid".to_string()))?; - Ok(coinbase) + let (_, coinbase_output, coinbase_kernel, _) = generate_coinbase( + total_fees.into(), + block_reward.into(), + tari_height, + self.config.coinbase_extra.as_bytes(), + &self.key_manager, + &self.miner_node_script_key_id, + &self.wallet_payment_address, + self.config.stealth_payment, + self.consensus_manager.consensus_constants(tari_height), + ) + .await?; + Ok((coinbase_output, coinbase_kernel)) } /// Build the [FinalBlockTemplateData] from [template](NewBlockTemplateData) and with diff --git a/applications/minotari_merge_mining_proxy/src/common/merge_mining.rs b/applications/minotari_merge_mining_proxy/src/common/merge_mining.rs index e5d7ef03e32..b411e43cf65 100644 --- a/applications/minotari_merge_mining_proxy/src/common/merge_mining.rs +++ b/applications/minotari_merge_mining_proxy/src/common/merge_mining.rs @@ -34,16 +34,13 @@ use crate::error::MmProxyError; /// Add [coinbase](grpc::Transaction) to [block template](grpc::NewBlockTemplate) pub fn add_coinbase( - coinbase: grpc::Transaction, + coinbase_output: &TransactionOutput, + coinbase_kernel: &TransactionKernel, block_template: grpc::NewBlockTemplate, ) -> Result { let mut block_template = NewBlockTemplate::try_from(block_template) .map_err(|e| MmProxyError::MissingDataError(format!("GRPC Conversion Error: {}", e)))?; - let output = TransactionOutput::try_from(coinbase.body.as_ref().unwrap().outputs[0].clone()) - .map_err(MmProxyError::MissingDataError)?; - let kernel = TransactionKernel::try_from(coinbase.body.as_ref().unwrap().kernels[0].clone()) - .map_err(MmProxyError::MissingDataError)?; - block_template.body.add_output(output); - block_template.body.add_kernel(kernel); + block_template.body.add_output(coinbase_output.clone()); + block_template.body.add_kernel(coinbase_kernel.clone()); block_template.try_into().map_err(MmProxyError::ConversionError) } diff --git a/applications/minotari_merge_mining_proxy/src/config.rs b/applications/minotari_merge_mining_proxy/src/config.rs index 0684db75de2..5f3f8bd76ea 100644 --- a/applications/minotari_merge_mining_proxy/src/config.rs +++ b/applications/minotari_merge_mining_proxy/src/config.rs @@ -26,6 +26,7 @@ use tari_common::{ configuration::{Network, StringList}, SubConfigPath, }; +use tari_common_types::tari_address::TariAddress; use tari_comms::multiaddr::Multiaddr; #[derive(Clone, Debug, Deserialize, Serialize)] @@ -47,8 +48,6 @@ pub struct MergeMiningProxyConfig { pub base_node_grpc_authentication: GrpcAuthentication, /// The Minotari wallet's GRPC address pub console_wallet_grpc_address: Option, - /// GRPC authentication for console wallet - pub console_wallet_grpc_authentication: GrpcAuthentication, /// Address of the minotari_merge_mining_proxy application pub listener_address: Multiaddr, /// In sole merged mining, the block solution is usually submitted to the Monero blockchain (monerod) as well as to @@ -71,6 +70,10 @@ pub struct MergeMiningProxyConfig { pub coinbase_extra: String, /// Selected network pub network: Network, + /// The Tari wallet address where the mining funds will be sent to + pub wallet_payment_address: String, + /// Stealth payment yes or no + pub stealth_payment: bool, } impl Default for MergeMiningProxyConfig { @@ -84,7 +87,6 @@ impl Default for MergeMiningProxyConfig { base_node_grpc_address: None, base_node_grpc_authentication: GrpcAuthentication::default(), console_wallet_grpc_address: None, - console_wallet_grpc_authentication: GrpcAuthentication::default(), listener_address: "/ip4/127.0.0.1/tcp/18081".parse().unwrap(), submit_to_origin: true, wait_for_initial_sync_at_startup: true, @@ -92,6 +94,8 @@ impl Default for MergeMiningProxyConfig { max_randomx_vms: 5, coinbase_extra: "tari_merge_mining_proxy".to_string(), network: Default::default(), + wallet_payment_address: TariAddress::default().to_hex(), + stealth_payment: true, } } } diff --git a/applications/minotari_merge_mining_proxy/src/error.rs b/applications/minotari_merge_mining_proxy/src/error.rs index 954e21c9e55..8c7587a2a28 100644 --- a/applications/minotari_merge_mining_proxy/src/error.rs +++ b/applications/minotari_merge_mining_proxy/src/error.rs @@ -29,9 +29,11 @@ use hyper::header::InvalidHeaderValue; use minotari_wallet_grpc_client::BasicAuthError; use tari_common::{ConfigError, ConfigurationError}; use tari_core::{ + consensus::ConsensusBuilderError, proof_of_work::{monero_rx::MergeMineError, DifficultyError}, - transactions::CoinbaseBuildError, + transactions::{key_manager::CoreKeyManagerError, CoinbaseBuildError}, }; +use tari_key_manager::key_manager_service::KeyManagerServiceError; use thiserror::Error; use tonic::{codegen::http::uri::InvalidUri, transport}; @@ -96,6 +98,14 @@ pub enum MmProxyError { ServersUnavailable, #[error("Invalid difficulty: {0}")] DifficultyError(#[from] DifficultyError), + #[error("Tokio runtime error: {0}")] + TokioRuntimeError(String), + #[error("Key manager service error: `{0}`")] + KeyManagerServiceError(String), + #[error("Key manager error: {0}")] + CoreKeyManagerError(#[from] CoreKeyManagerError), + #[error("Consensus build error: {0}")] + ConsensusBuilderError(#[from] ConsensusBuilderError), } impl From for MmProxyError { @@ -107,6 +117,12 @@ impl From for MmProxyError { } } +impl From for MmProxyError { + fn from(err: KeyManagerServiceError) -> Self { + MmProxyError::KeyManagerServiceError(err.to_string()) + } +} + #[cfg(test)] pub mod test { use tonic::Code; diff --git a/applications/minotari_merge_mining_proxy/src/proxy.rs b/applications/minotari_merge_mining_proxy/src/proxy.rs index 17b4319c9ab..65471b959af 100644 --- a/applications/minotari_merge_mining_proxy/src/proxy.rs +++ b/applications/minotari_merge_mining_proxy/src/proxy.rs @@ -40,7 +40,7 @@ use hyper::{header::HeaderValue, service::Service, Body, Method, Request, Respon use json::json; use jsonrpc::error::StandardError; use minotari_node_grpc_client::{grpc, grpc::base_node_client::BaseNodeClient}; -use minotari_wallet_grpc_client::{grpc::wallet_client::WalletClient, ClientAuthenticationInterceptor}; +use minotari_wallet_grpc_client::ClientAuthenticationInterceptor; use reqwest::{ResponseBuilderExt, Url}; use serde_json as json; use tari_core::proof_of_work::{ @@ -77,7 +77,6 @@ impl MergeMiningProxyService { config: MergeMiningProxyConfig, http_client: reqwest::Client, base_node_client: BaseNodeClient>, - wallet_client: WalletClient>, block_templates: BlockTemplateRepository, randomx_factory: RandomXFactory, ) -> Self { @@ -88,7 +87,6 @@ impl MergeMiningProxyService { block_templates, http_client, base_node_client, - wallet_client, initial_sync_achieved: Arc::new(AtomicBool::new(false)), current_monerod_server: Arc::new(RwLock::new(None)), last_assigned_monerod_server: Arc::new(RwLock::new(None)), @@ -159,7 +157,6 @@ struct InnerService { block_templates: BlockTemplateRepository, http_client: reqwest::Client, base_node_client: BaseNodeClient>, - wallet_client: WalletClient>, initial_sync_achieved: Arc, current_monerod_server: Arc>>, last_assigned_monerod_server: Arc>>, @@ -395,7 +392,6 @@ impl InnerService { } let mut grpc_client = self.base_node_client.clone(); - let mut grpc_wallet_client = self.wallet_client.clone(); // Add merge mining tag on blocktemplate request debug!(target: LOG_TARGET, "Requested new block template from Minotari base node"); @@ -429,8 +425,7 @@ impl InnerService { } } - let new_block_protocol = - BlockTemplateProtocol::new(&mut grpc_client, &mut grpc_wallet_client, self.config.clone()); + let new_block_protocol = BlockTemplateProtocol::new(&mut grpc_client, self.config.clone())?; let seed_hash = FixedByteArray::from_hex(&monerod_resp["result"]["seed_hash"].to_string().replace('\"', "")) .map_err(|err| MmProxyError::InvalidMonerodResponse(format!("seed hash hex is invalid: {}", err)))?; diff --git a/applications/minotari_merge_mining_proxy/src/run_merge_miner.rs b/applications/minotari_merge_mining_proxy/src/run_merge_miner.rs index 420f9b78d83..ed98ce48f75 100644 --- a/applications/minotari_merge_mining_proxy/src/run_merge_miner.rs +++ b/applications/minotari_merge_mining_proxy/src/run_merge_miner.rs @@ -26,7 +26,7 @@ use futures::future; use hyper::{service::make_service_fn, Server}; use log::*; use minotari_node_grpc_client::grpc::base_node_client::BaseNodeClient; -use minotari_wallet_grpc_client::{grpc::wallet_client::WalletClient, ClientAuthenticationInterceptor}; +use minotari_wallet_grpc_client::ClientAuthenticationInterceptor; use tari_common::{ configuration::bootstrap::{grpc_default_port, ApplicationType}, load_configuration, @@ -64,7 +64,6 @@ pub async fn start_merge_miner(cli: Cli) -> Result<(), anyhow::Error> { .map_err(MmProxyError::ReqwestError)?; let base_node_client = connect_base_node(&config).await?; - let wallet_client = connect_wallet(&config).await?; let listen_addr = multiaddr_to_socketaddr(&config.listener_address)?; let randomx_factory = RandomXFactory::new(config.max_randomx_vms); @@ -72,7 +71,6 @@ pub async fn start_merge_miner(cli: Cli) -> Result<(), anyhow::Error> { config, client, base_node_client, - wallet_client, BlockTemplateRepository::new(), randomx_factory, ); @@ -98,28 +96,6 @@ pub async fn start_merge_miner(cli: Cli) -> Result<(), anyhow::Error> { } } -async fn connect_wallet( - config: &MergeMiningProxyConfig, -) -> Result>, MmProxyError> { - let wallet_addr = format!( - "http://{}", - multiaddr_to_socketaddr( - &config - .console_wallet_grpc_address - .clone() - .expect("Wallet grpc address not found") - )? - ); - info!(target: LOG_TARGET, "👛 Connecting to wallet at {}", wallet_addr); - let channel = Endpoint::from_str(&wallet_addr)?.connect().await?; - let wallet_conn = WalletClient::with_interceptor( - channel, - ClientAuthenticationInterceptor::create(&config.console_wallet_grpc_authentication)?, - ); - - Ok(wallet_conn) -} - async fn connect_base_node( config: &MergeMiningProxyConfig, ) -> Result>, MmProxyError> { diff --git a/applications/minotari_miner/Cargo.toml b/applications/minotari_miner/Cargo.toml index 09b0380dfc6..6045fd9ff84 100644 --- a/applications/minotari_miner/Cargo.toml +++ b/applications/minotari_miner/Cargo.toml @@ -16,6 +16,7 @@ minotari_app_utilities = { path = "../minotari_app_utilities" } minotari_app_grpc = { path = "../minotari_app_grpc" } tari_crypto = { version = "0.19" } tari_utilities = { version = "0.6" } +tari_key_manager = { path = "../../base_layer/key_manager", features = ["key_manager_service"] } borsh = "0.10" crossterm = { version = "0.25.0" } diff --git a/applications/minotari_miner/README.md b/applications/minotari_miner/README.md index c989c0c1831..37cc22b1853 100644 --- a/applications/minotari_miner/README.md +++ b/applications/minotari_miner/README.md @@ -20,12 +20,20 @@ is required. The Minotari Miner can also be located on a remote workstation. Configuration options for the Minotari Miner are as follows: - `base_node_grpc_address` - this is IPv4/IPv6 address including port number, by which the Minotari Base Node can be found; -- `wallet_grpc_address` - this is IPv4/IPv6 address including port number, by which the Minotari Wallet can be - found; - `num_mining_threads` - the number of mining threads, which defaults to the number of CPU cores; - `mine_on_tip_only` - mining will only start when the Minotari Base Node reports it is in the bootstrapped state; +- `proof_of_work_algo` - The proof of work algorithm to use - `validate_tip_timeout_sec` - the interval at which the current block height will be checked to determine if mining - must be restarted, whereby the tip might have advanced passed the block height that is in use in the current template. + must be restarted, whereby the tip might have advanced passed the block height that is in use in the current template. +- `mining_pool_address` - Stratum Mode configuration - mining pool address +- `mining_wallet_address` - `Stratum Mode configuration - mining wallet address/public key` +- `mining_worker_name` - `Stratum Mode configuration - mining worker name` +- `coinbase_extra` - Note that this data is publicly readable, but it is suggested you populate it so that pool + dominance can be seen before any one party has more than 51%. +- `network` - "Selected network" +- `wait_timeout_on_error` - "Base node reconnect timeout after any gRPC or miner error" +- `wallet_payment_address` - "The Tari wallet address where the mining funds will be sent to" +- `stealth_payment` - "Stealth payment yes or no" ### Caveats diff --git a/applications/minotari_miner/src/config.rs b/applications/minotari_miner/src/config.rs index aaef7be8b4d..29e114ea3eb 100644 --- a/applications/minotari_miner/src/config.rs +++ b/applications/minotari_miner/src/config.rs @@ -27,8 +27,6 @@ //! specific options: //! - base_node_grpc_address - is IPv4/IPv6 address including port //! number, by which Minotari Base Node can be found -//! - wallet_grpc_address - is IPv4/IPv6 address including port number, -//! where Minotari Wallet Node can be found //! - num_mining_threads - number of mining threads, defaults to number of cpu cores //! - mine_on_tip_only - will start mining only when node is reporting bootstrapped state //! - validate_tip_timeout_sec - will check tip with node every N seconds to validate that still @@ -41,20 +39,16 @@ use std::time::Duration; use minotari_app_grpc::tari_rpc::{pow_algo::PowAlgos, NewBlockTemplateRequest, PowAlgo}; use serde::{Deserialize, Serialize}; use tari_common::{configuration::Network, SubConfigPath}; -use tari_common_types::grpc_authentication::GrpcAuthentication; +use tari_common_types::{grpc_authentication::GrpcAuthentication, tari_address::TariAddress}; use tari_comms::multiaddr::Multiaddr; #[derive(Serialize, Deserialize, Debug)] #[serde(deny_unknown_fields)] pub struct MinerConfig { - /// GRPC address of base node + /// gRPC address of base node pub base_node_grpc_address: Option, /// GRPC authentication for base node pub base_node_grpc_authentication: GrpcAuthentication, - /// GRPC address of console wallet - pub wallet_grpc_address: Option, - /// GRPC authentication for console wallet - pub wallet_grpc_authentication: GrpcAuthentication, /// Number of mining threads pub num_mining_threads: usize, /// Start mining only when base node is bootstrapped and current block height is on the tip of network @@ -77,8 +71,12 @@ pub struct MinerConfig { pub coinbase_extra: String, /// Selected network pub network: Network, - /// Base node reconnect timeout after any GRPC or miner error + /// Base node reconnect timeout after any gRPC or miner error pub wait_timeout_on_error: u64, + /// The Tari wallet address where the mining funds will be sent to + pub wallet_payment_address: String, + /// Stealth payment yes or no + pub stealth_payment: bool, } /// The proof of work data structure that is included in the block header. For the Minotari miner only `Sha3x` is @@ -100,8 +98,6 @@ impl Default for MinerConfig { Self { base_node_grpc_address: None, base_node_grpc_authentication: GrpcAuthentication::default(), - wallet_grpc_address: None, - wallet_grpc_authentication: GrpcAuthentication::default(), num_mining_threads: num_cpus::get(), mine_on_tip_only: true, proof_of_work_algo: ProofOfWork::Sha3x, @@ -112,6 +108,8 @@ impl Default for MinerConfig { coinbase_extra: "minotari_miner".to_string(), network: Default::default(), wait_timeout_on_error: 10, + wallet_payment_address: TariAddress::default().to_hex(), + stealth_payment: true, } } } @@ -158,7 +156,6 @@ mine_on_tip_only = false .unwrap(); let config = MinerConfig::load_from(&cfg).expect("Failed to load config"); assert_eq!(config.num_mining_threads, 2); - assert_eq!(config.wallet_grpc_address, MinerConfig::default().wallet_grpc_address); assert_eq!( config.base_node_grpc_address, Some(Multiaddr::from_str("/dns4/my_base_node/tcp/1234").unwrap()) diff --git a/applications/minotari_miner/src/errors.rs b/applications/minotari_miner/src/errors.rs index 902660eb51c..e78749ca2ec 100644 --- a/applications/minotari_miner/src/errors.rs +++ b/applications/minotari_miner/src/errors.rs @@ -21,6 +21,7 @@ // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // use minotari_app_grpc::authentication::BasicAuthError; +use tari_core::consensus::ConsensusBuilderError; use thiserror::Error; use tonic::codegen::http::uri::InvalidUri; @@ -28,7 +29,7 @@ use tonic::codegen::http::uri::InvalidUri; pub enum MinerError { #[error("I/O error")] IOError(#[from] std::io::Error), - #[error("GRPC error: {0}")] + #[error("gRPC error: {0}")] GrpcStatus(#[from] tonic::Status), #[error("Connection error: {0}")] GrpcConnection(#[from] tonic::transport::Error), @@ -44,10 +45,14 @@ pub enum MinerError { BlockHeader(String), #[error("Conversion error: {0}")] Conversion(String), - #[error("Invalid grpc credentials: {0}")] + #[error("Invalid gRPC credentials: {0}")] BasicAuthError(#[from] BasicAuthError), - #[error("Invalid grpc url: {0}")] + #[error("Invalid gRPC url: {0}")] InvalidUri(#[from] InvalidUri), + #[error("Coinbase error: {0}")] + CoinbaseError(String), + #[error("Consensus build error: {0}")] + ConsensusBuilderError(#[from] ConsensusBuilderError), } pub fn err_empty(name: &str) -> MinerError { diff --git a/applications/minotari_miner/src/lib.rs b/applications/minotari_miner/src/lib.rs index 5d51320b1c6..cc5f6b1cd4b 100644 --- a/applications/minotari_miner/src/lib.rs +++ b/applications/minotari_miner/src/lib.rs @@ -33,7 +33,6 @@ mod difficulty; mod errors; mod miner; mod stratum; -mod utils; pub async fn run_miner(cli: Cli) -> Result<(), ExitError> { start_miner(cli).await diff --git a/applications/minotari_miner/src/main.rs b/applications/minotari_miner/src/main.rs index 036dec09cbe..13a96b686b7 100644 --- a/applications/minotari_miner/src/main.rs +++ b/applications/minotari_miner/src/main.rs @@ -42,7 +42,6 @@ mod errors; mod miner; mod run_miner; mod stratum; -mod utils; /// Application entry point fn main() { diff --git a/applications/minotari_miner/src/run_miner.rs b/applications/minotari_miner/src/run_miner.rs index 4c51695c564..2ad06925517 100644 --- a/applications/minotari_miner/src/run_miner.rs +++ b/applications/minotari_miner/src/run_miner.rs @@ -26,17 +26,28 @@ use futures::stream::StreamExt; use log::*; use minotari_app_grpc::{ authentication::ClientAuthenticationInterceptor, - tari_rpc::{base_node_client::BaseNodeClient, wallet_client::WalletClient}, + tari_rpc::{base_node_client::BaseNodeClient, TransactionOutput as GrpcTransactionOutput}, }; +use rand::rngs::OsRng; use tari_common::{ configuration::bootstrap::{grpc_default_port, ApplicationType}, exit_codes::{ExitCode, ExitError}, load_configuration, DefaultConfigLoader, }; +use tari_common_types::{tari_address::TariAddress, types::PrivateKey}; use tari_comms::utils::multiaddr::multiaddr_to_socketaddr; -use tari_core::blocks::BlockHeader; -use tari_crypto::ristretto::RistrettoPublicKey; +use tari_core::{ + blocks::BlockHeader, + consensus::ConsensusManager, + transactions::{ + generate_coinbase, + key_manager::{create_memory_db_key_manager, MemoryDbKeyManager, TariKeyId}, + tari_amount::MicroMinotari, + }, +}; +use tari_crypto::{keys::SecretKey, ristretto::RistrettoPublicKey}; +use tari_key_manager::key_manager_service::KeyManagerInterface; use tari_utilities::hex::Hex; use tokio::time::sleep; use tonic::{ @@ -50,13 +61,11 @@ use crate::{ errors::{err_empty, MinerError}, miner::{Miner, MiningReport}, stratum::stratum_controller::controller::Controller, - utils::{coinbase_request, extract_outputs_and_kernels}, }; pub const LOG_TARGET: &str = "minotari::miner::main"; pub const LOG_TARGET_FILE: &str = "minotari::logging::miner::main"; -type WalletGrpcClient = WalletClient>; type BaseNodeGrpcClient = BaseNodeClient>; #[allow(clippy::too_many_lines)] @@ -66,6 +75,17 @@ pub async fn start_miner(cli: Cli) -> Result<(), ExitError> { let mut config = MinerConfig::load_from(&cfg).expect("Failed to load config"); debug!(target: LOG_TARGET_FILE, "{:?}", config); setup_grpc_config(&mut config); + let key_manager = create_memory_db_key_manager(); + let wallet_private_key = PrivateKey::random(&mut OsRng); + let miner_node_script_key_id = tokio::runtime::Runtime::new() + .map_err(|err| ExitError::new(ExitCode::TokioRuntimeError, err.to_string()))? + .block_on(key_manager.import_key(wallet_private_key)) + .map_err(|err| ExitError::new(ExitCode::KeyManagerServiceError, err.to_string()))?; + let wallet_payment_address = TariAddress::from_str(&config.wallet_payment_address) + .map_err(|err| ExitError::new(ExitCode::ConversionError, err.to_string()))?; + let consensus_manager = ConsensusManager::builder(config.network) + .build() + .map_err(|err| ExitError::new(ExitCode::ConsensusManagerBuilderError, err.to_string()))?; if !config.mining_wallet_address.is_empty() && !config.mining_pool_address.is_empty() { let url = config.mining_pool_address.clone(); @@ -105,7 +125,7 @@ pub async fn start_miner(cli: Cli) -> Result<(), ExitError> { Ok(()) } else { - let (mut node_conn, mut wallet_conn) = connect(&config).await.map_err(|e| { + let mut node_conn = connect(&config).await.map_err(|e| { ExitError::new( ExitCode::GrpcError, format!("Could not connect to wallet or base node: {}", e), @@ -115,7 +135,17 @@ pub async fn start_miner(cli: Cli) -> Result<(), ExitError> { let mut blocks_found: u64 = 0; loop { debug!(target: LOG_TARGET, "Starting new mining cycle"); - match mining_cycle(&mut node_conn, &mut wallet_conn, &config, &cli).await { + match mining_cycle( + &mut node_conn, + &config, + &cli, + &key_manager, + &miner_node_script_key_id, + &wallet_payment_address, + &consensus_manager, + ) + .await + { err @ Err(MinerError::GrpcConnection(_)) | err @ Err(MinerError::GrpcStatus(_)) => { // Any GRPC error we will try to reconnect with a standard delay error!(target: LOG_TARGET, "Connection error: {:?}", err); @@ -123,9 +153,8 @@ pub async fn start_miner(cli: Cli) -> Result<(), ExitError> { info!(target: LOG_TARGET, "Holding for {:?}", config.wait_timeout()); sleep(config.wait_timeout()).await; match connect(&config).await { - Ok((nc, wc)) => { + Ok(nc) => { node_conn = nc; - wallet_conn = wc; break; }, Err(err) => { @@ -168,7 +197,7 @@ pub async fn start_miner(cli: Cli) -> Result<(), ExitError> { } } -async fn connect(config: &MinerConfig) -> Result<(BaseNodeGrpcClient, WalletGrpcClient), MinerError> { +async fn connect(config: &MinerConfig) -> Result { let node_conn = match connect_base_node(config).await { Ok(client) => client, Err(e) => { @@ -181,39 +210,7 @@ async fn connect(config: &MinerConfig) -> Result<(BaseNodeGrpcClient, WalletGrpc }, }; - let wallet_conn = match connect_wallet(config).await { - Ok(client) => client, - Err(e) => { - error!(target: LOG_TARGET, "Could not connect to wallet"); - error!( - target: LOG_TARGET, - "Is its grpc running? try running it with `--enable-grpc` or enable it in config" - ); - return Err(e); - }, - }; - - Ok((node_conn, wallet_conn)) -} - -async fn connect_wallet(config: &MinerConfig) -> Result { - let wallet_addr = format!( - "http://{}", - multiaddr_to_socketaddr( - &config - .wallet_grpc_address - .clone() - .expect("Wallet grpc address not found") - )? - ); - info!(target: LOG_TARGET, "👛 Connecting to wallet at {}", wallet_addr); - let channel = Endpoint::from_str(&wallet_addr)?.connect().await?; - let wallet_conn = WalletClient::with_interceptor( - channel, - ClientAuthenticationInterceptor::create(&config.wallet_grpc_authentication)?, - ); - - Ok(wallet_conn) + Ok(node_conn) } async fn connect_base_node(config: &MinerConfig) -> Result { @@ -236,49 +233,65 @@ async fn connect_base_node(config: &MinerConfig) -> Result Result { debug!(target: LOG_TARGET, "Getting new block template"); - let template = node_conn + let template_response = node_conn .get_new_block_template(config.pow_algo_request()) .await? .into_inner(); - let mut block_template = template + let mut block_template = template_response .new_block_template .clone() .ok_or_else(|| err_empty("new_block_template"))?; + let height = block_template + .header + .as_ref() + .ok_or_else(|| err_empty("header"))? + .height; if config.mine_on_tip_only { debug!( target: LOG_TARGET, "Checking if base node is synced, because mine_on_tip_only is true" ); - let height = block_template - .header - .as_ref() - .ok_or_else(|| err_empty("header"))? - .height; validate_tip(node_conn, height, cli.mine_until_height).await?; } debug!(target: LOG_TARGET, "Getting coinbase"); - let request = coinbase_request(&template, config.coinbase_extra.as_bytes().to_vec())?; - let coinbase = wallet_conn.get_coinbase(request).await?.into_inner(); - let (output, kernel) = extract_outputs_and_kernels(coinbase)?; + let miner_data = template_response.miner_data.ok_or_else(|| err_empty("miner_data"))?; + let fee = MicroMinotari::from(miner_data.total_fees); + let reward = MicroMinotari::from(miner_data.reward); + let (_, output, kernel, _) = generate_coinbase( + fee, + reward, + height, + config.coinbase_extra.as_bytes(), + key_manager, + miner_node_script_key_id, + wallet_payment_address, + config.stealth_payment, + consensus_manager.consensus_constants(height), + ) + .await + .map_err(|e| MinerError::CoinbaseError(e.to_string()))?; + let body = block_template .body .as_mut() .ok_or_else(|| err_empty("new_block_template.body"))?; - body.outputs.push(output); - body.kernels.push(kernel); - let target_difficulty = template - .miner_data - .ok_or_else(|| err_empty("miner_data"))? - .target_difficulty; + let grpc_output = GrpcTransactionOutput::try_from(output.clone()).map_err(MinerError::Conversion)?; + body.outputs.push(grpc_output); + body.kernels.push(kernel.into()); + let target_difficulty = miner_data.target_difficulty; debug!(target: LOG_TARGET, "Asking base node to assemble the MMR roots"); let block_result = node_conn.get_new_block(block_template).await?.into_inner(); @@ -394,15 +407,4 @@ fn setup_grpc_config(config: &mut MinerConfig) { .unwrap(), ); } - - if config.wallet_grpc_address.is_none() { - config.wallet_grpc_address = Some( - format!( - "/ip4/127.0.0.1/tcp/{}", - grpc_default_port(ApplicationType::ConsoleWallet, config.network) - ) - .parse() - .unwrap(), - ); - } } diff --git a/applications/minotari_miner/src/utils.rs b/applications/minotari_miner/src/utils.rs deleted file mode 100644 index a7f3794a4a4..00000000000 --- a/applications/minotari_miner/src/utils.rs +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2021. The Tari Project -// -// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the -// following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following -// disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the -// following disclaimer in the documentation and/or other materials provided with the distribution. -// -// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote -// products derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -// 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. -// -use minotari_app_grpc::tari_rpc::{ - GetCoinbaseRequest, - GetCoinbaseResponse, - NewBlockTemplateResponse, - TransactionKernel, - TransactionOutput, -}; - -use crate::errors::{err_empty, MinerError}; - -/// Convert NewBlockTemplateResponse to GetCoinbaseRequest -pub fn coinbase_request( - template_response: &NewBlockTemplateResponse, - extra: Vec, -) -> Result { - let template = template_response - .new_block_template - .as_ref() - .ok_or_else(|| err_empty("new_block_template"))?; - let miner_data = template_response - .miner_data - .as_ref() - .ok_or_else(|| err_empty("miner_data"))?; - let fee = miner_data.total_fees; - let reward = miner_data.reward; - let height = template - .header - .as_ref() - .ok_or_else(|| err_empty("template.header"))? - .height; - Ok(GetCoinbaseRequest { - reward, - fee, - height, - extra, - }) -} - -pub fn extract_outputs_and_kernels( - coinbase: GetCoinbaseResponse, -) -> Result<(TransactionOutput, TransactionKernel), MinerError> { - let transaction_body = coinbase - .transaction - .ok_or_else(|| err_empty("coinbase.transaction"))? - .body - .ok_or_else(|| err_empty("transaction.body"))?; - let output = transaction_body - .outputs - .get(0) - .cloned() - .ok_or_else(|| err_empty("transaction.body.outputs"))?; - let kernel = transaction_body - .kernels - .get(0) - .cloned() - .ok_or_else(|| err_empty("transaction.body.kernels"))?; - Ok((output, kernel)) -} diff --git a/base_layer/common_types/src/transaction.rs b/base_layer/common_types/src/transaction.rs index 56e2adbebb8..63f483606c1 100644 --- a/base_layer/common_types/src/transaction.rs +++ b/base_layer/common_types/src/transaction.rs @@ -103,8 +103,6 @@ pub enum ImportStatus { FauxUnconfirmed, /// This transaction import status is used when a one-sided transaction has been scanned and confirmed FauxConfirmed, - /// This is a coinbase that is imported - Coinbase, } impl TryFrom for TransactionStatus { @@ -115,7 +113,6 @@ impl TryFrom for TransactionStatus { ImportStatus::Imported => Ok(TransactionStatus::Imported), ImportStatus::FauxUnconfirmed => Ok(TransactionStatus::FauxUnconfirmed), ImportStatus::FauxConfirmed => Ok(TransactionStatus::FauxConfirmed), - ImportStatus::Coinbase => Ok(TransactionStatus::MinedConfirmed), } } } @@ -128,7 +125,6 @@ impl TryFrom for ImportStatus { TransactionStatus::Imported => Ok(ImportStatus::Imported), TransactionStatus::FauxUnconfirmed => Ok(ImportStatus::FauxUnconfirmed), TransactionStatus::FauxConfirmed => Ok(ImportStatus::FauxConfirmed), - TransactionStatus::Coinbase => Ok(ImportStatus::Coinbase), _ => Err(TransactionConversionError { code: i32::MAX }), } } @@ -140,7 +136,6 @@ impl fmt::Display for ImportStatus { ImportStatus::Imported => write!(f, "Imported"), ImportStatus::FauxUnconfirmed => write!(f, "FauxUnconfirmed"), ImportStatus::FauxConfirmed => write!(f, "FauxConfirmed"), - ImportStatus::Coinbase => write!(f, "Coinbase"), } } } diff --git a/base_layer/core/benches/mempool.rs b/base_layer/core/benches/mempool.rs index 24237ae43f1..7bf83933681 100644 --- a/base_layer/core/benches/mempool.rs +++ b/base_layer/core/benches/mempool.rs @@ -38,8 +38,8 @@ mod benches { mempool::{Mempool, MempoolConfig}, test_helpers::blockchain::create_new_blockchain, transactions::{ + key_manager::create_memory_db_key_manager, tari_amount::{uT, T}, - test_helpers::create_test_core_key_manager_with_memory_db, transaction_components::{OutputFeatures, Transaction, MAX_TRANSACTION_OUTPUTS}, CryptoFactories, }, @@ -54,7 +54,7 @@ mod benches { num_outputs: usize, features: OutputFeatures, ) -> std::io::Result>> { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let mut txs = Vec::new(); for _ in 0..num_txs { let (tx, _, _) = diff --git a/base_layer/core/src/chain_storage/tests/blockchain_database.rs b/base_layer/core/src/chain_storage/tests/blockchain_database.rs index 32afe373916..adcb206d163 100644 --- a/base_layer/core/src/chain_storage/tests/blockchain_database.rs +++ b/base_layer/core/src/chain_storage/tests/blockchain_database.rs @@ -22,6 +22,8 @@ // DAMAGE. use std::sync::Arc; +use tari_common_types::tari_address::TariAddress; + use crate::{ blocks::{Block, BlockHeader, BlockHeaderAccumulatedData, ChainHeader, NewBlockTemplate}, chain_storage::{BlockchainDatabase, ChainStorageError}, @@ -29,11 +31,13 @@ use crate::{ test_helpers::{ blockchain::{create_new_blockchain, TempDatabase}, create_block, + default_coinbase_entities, BlockSpec, }, transactions::{ + key_manager::{MemoryDbKeyManager, TariKeyId}, tari_amount::T, - test_helpers::{create_test_core_key_manager_with_memory_db, schema_to_transaction, TestKeyManager}, + test_helpers::schema_to_transaction, transaction_components::{Transaction, WalletOutput}, }, txn_schema, @@ -47,7 +51,9 @@ async fn create_next_block( db: &BlockchainDatabase, prev_block: &Block, transactions: Vec>, - key_manager: &TestKeyManager, + key_manager: &MemoryDbKeyManager, + miner_node_script_key_id: &TariKeyId, + wallet_payment_address: &TariAddress, ) -> (Arc, WalletOutput) { let rules = db.rules(); let (block, output) = create_block( @@ -57,6 +63,8 @@ async fn create_next_block( .with_transactions(transactions.into_iter().map(|t| (*t).clone()).collect()) .finish(), key_manager, + miner_node_script_key_id, + wallet_payment_address, ) .await; let block = apply_mmr_to_block(db, block); @@ -78,14 +86,23 @@ fn apply_mmr_to_block(db: &BlockchainDatabase, block: Block) -> Bl async fn add_many_chained_blocks( size: usize, db: &BlockchainDatabase, - key_manager: &TestKeyManager, + key_manager: &MemoryDbKeyManager, ) -> (Vec>, Vec) { let last_header = db.fetch_last_header().unwrap(); let mut prev_block = Arc::new(db.fetch_block(last_header.height, true).unwrap().into_block()); let mut blocks = Vec::with_capacity(size); let mut outputs = Vec::with_capacity(size); + let (miner_node_script_key_id, wallet_payment_address) = default_coinbase_entities(key_manager).await; for _ in 1..=size { - let (block, coinbase_utxo) = create_next_block(db, &prev_block, vec![], key_manager).await; + let (block, coinbase_utxo) = create_next_block( + db, + &prev_block, + vec![], + key_manager, + &miner_node_script_key_id, + &wallet_payment_address, + ) + .await; db.add_block(block.clone()).unwrap().assert_added(); prev_block = block.clone(); @@ -96,8 +113,8 @@ async fn add_many_chained_blocks( } mod fetch_blocks { - use super::*; + use crate::transactions::key_manager::create_memory_db_key_manager; #[test] fn it_returns_genesis() { @@ -109,7 +126,7 @@ mod fetch_blocks { #[tokio::test] async fn it_returns_all() { let db = setup(); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); add_many_chained_blocks(4, &db, &key_manager).await; let blocks = db.fetch_blocks(.., true).unwrap(); assert_eq!(blocks.len(), 5); @@ -121,7 +138,7 @@ mod fetch_blocks { #[tokio::test] async fn it_returns_one() { let db = setup(); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let (new_blocks, _) = add_many_chained_blocks(1, &db, &key_manager).await; let blocks = db.fetch_blocks(1..=1, true).unwrap(); assert_eq!(blocks.len(), 1); @@ -131,7 +148,7 @@ mod fetch_blocks { #[tokio::test] async fn it_returns_nothing_if_asking_for_blocks_out_of_range() { let db = setup(); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); add_many_chained_blocks(1, &db, &key_manager).await; let blocks = db.fetch_blocks(2.., true).unwrap(); assert!(blocks.is_empty()); @@ -140,7 +157,7 @@ mod fetch_blocks { #[tokio::test] async fn it_returns_blocks_between_bounds_exclusive() { let db = setup(); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); add_many_chained_blocks(5, &db, &key_manager).await; let blocks = db.fetch_blocks(3..5, true).unwrap(); assert_eq!(blocks.len(), 2); @@ -151,7 +168,7 @@ mod fetch_blocks { #[tokio::test] async fn it_returns_blocks_between_bounds_inclusive() { let db = setup(); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); add_many_chained_blocks(5, &db, &key_manager).await; let blocks = db.fetch_blocks(3..=5, true).unwrap(); assert_eq!(blocks.len(), 3); @@ -163,7 +180,7 @@ mod fetch_blocks { #[tokio::test] async fn it_returns_blocks_to_the_tip() { let db = setup(); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); add_many_chained_blocks(5, &db, &key_manager).await; let blocks = db.fetch_blocks(3.., true).unwrap(); assert_eq!(blocks.len(), 3); @@ -175,7 +192,7 @@ mod fetch_blocks { #[tokio::test] async fn it_returns_blocks_from_genesis() { let db = setup(); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); add_many_chained_blocks(5, &db, &key_manager).await; let blocks = db.fetch_blocks(..=3, true).unwrap(); assert_eq!(blocks.len(), 4); @@ -188,6 +205,7 @@ mod fetch_blocks { mod fetch_headers { use super::*; + use crate::transactions::key_manager::create_memory_db_key_manager; #[test] fn it_returns_genesis() { @@ -205,7 +223,7 @@ mod fetch_headers { #[tokio::test] async fn it_returns_all() { let db = setup(); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); add_many_chained_blocks(4, &db, &key_manager).await; let headers = db.fetch_headers(..).unwrap(); assert_eq!(headers.len(), 5); @@ -217,7 +235,7 @@ mod fetch_headers { #[tokio::test] async fn it_returns_nothing_if_asking_for_blocks_out_of_range() { let db = setup(); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); add_many_chained_blocks(1, &db, &key_manager).await; let headers = db.fetch_headers(2..).unwrap(); assert!(headers.is_empty()); @@ -226,7 +244,7 @@ mod fetch_headers { #[tokio::test] async fn it_returns_blocks_between_bounds_exclusive() { let db = setup(); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); add_many_chained_blocks(5, &db, &key_manager).await; let headers = db.fetch_headers(3..5).unwrap(); assert_eq!(headers.len(), 2); @@ -237,7 +255,7 @@ mod fetch_headers { #[tokio::test] async fn it_returns_blocks_between_bounds_inclusive() { let db = setup(); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); add_many_chained_blocks(5, &db, &key_manager).await; let headers = db.fetch_headers(3..=5).unwrap(); assert_eq!(headers.len(), 3); @@ -248,7 +266,7 @@ mod fetch_headers { #[tokio::test] async fn it_returns_blocks_to_the_tip() { let db = setup(); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); add_many_chained_blocks(5, &db, &key_manager).await; let headers = db.fetch_headers(3..).unwrap(); assert_eq!(headers.len(), 3); @@ -260,7 +278,7 @@ mod fetch_headers { #[tokio::test] async fn it_returns_blocks_from_genesis() { let db = setup(); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); add_many_chained_blocks(5, &db, &key_manager).await; let headers = db.fetch_headers(..=3).unwrap(); assert_eq!(headers.len(), 4); @@ -275,6 +293,7 @@ mod find_headers_after_hash { use tari_common_types::types::FixedHash; use super::*; + use crate::transactions::key_manager::create_memory_db_key_manager; #[test] fn it_returns_none_given_empty_vec() { @@ -287,7 +306,7 @@ mod find_headers_after_hash { async fn it_returns_from_genesis() { let db = setup(); let genesis_hash = db.fetch_block(0, true).unwrap().block().hash(); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); add_many_chained_blocks(1, &db, &key_manager).await; let hashes = vec![genesis_hash]; let (index, headers) = db.find_headers_after_hash(hashes, 1).unwrap().unwrap(); @@ -298,7 +317,7 @@ mod find_headers_after_hash { #[tokio::test] async fn it_returns_the_first_headers_found() { let db = setup(); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); add_many_chained_blocks(5, &db, &key_manager).await; let hashes = (1..=3) .rev() @@ -314,7 +333,7 @@ mod find_headers_after_hash { async fn fnit_ignores_unknown_hashes() { let db = setup(); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); add_many_chained_blocks(5, &db, &key_manager).await; let hashes = (2..=4) .map(|i| db.fetch_block(i, true).unwrap().block().hash()) @@ -329,6 +348,7 @@ mod find_headers_after_hash { mod fetch_block_hashes_from_header_tip { use super::*; + use crate::transactions::key_manager::create_memory_db_key_manager; #[test] fn it_returns_genesis() { @@ -341,7 +361,7 @@ mod fetch_block_hashes_from_header_tip { #[tokio::test] async fn it_returns_empty_set_for_big_offset() { let db = setup(); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); add_many_chained_blocks(5, &db, &key_manager).await; let hashes = db.fetch_block_hashes_from_header_tip(3, 6).unwrap(); assert!(hashes.is_empty()); @@ -350,7 +370,7 @@ mod fetch_block_hashes_from_header_tip { #[tokio::test] async fn it_returns_n_hashes_from_tip() { let db = setup(); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let (blocks, _) = add_many_chained_blocks(5, &db, &key_manager).await; let hashes = db.fetch_block_hashes_from_header_tip(3, 1).unwrap(); assert_eq!(hashes.len(), 3); @@ -362,7 +382,7 @@ mod fetch_block_hashes_from_header_tip { #[tokio::test] async fn it_returns_hashes_without_overlapping() { let db = setup(); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let (blocks, _) = add_many_chained_blocks(3, &db, &key_manager).await; let hashes = db.fetch_block_hashes_from_header_tip(2, 0).unwrap(); assert_eq!(hashes[0], blocks[2].hash()); @@ -375,7 +395,7 @@ mod fetch_block_hashes_from_header_tip { async fn it_returns_all_hashes_from_tip() { let db = setup(); let genesis = db.fetch_tip_header().unwrap(); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let (blocks, _) = add_many_chained_blocks(5, &db, &key_manager).await; let hashes = db.fetch_block_hashes_from_header_tip(10, 0).unwrap(); assert_eq!(hashes.len(), 6); @@ -397,12 +417,13 @@ mod get_stats { mod fetch_total_size_stats { use super::*; + use crate::transactions::key_manager::create_memory_db_key_manager; #[tokio::test] async fn it_measures_the_number_of_entries() { let db = setup(); let genesis_output_count = db.fetch_header(0).unwrap().unwrap().output_smt_size; - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let _block_and_outputs = add_many_chained_blocks(2, &db, &key_manager).await; let stats = db.fetch_total_size_stats().unwrap(); assert_eq!( @@ -454,6 +475,7 @@ mod prepare_new_block { mod fetch_header_containing_kernel_mmr { use super::*; + use crate::transactions::key_manager::create_memory_db_key_manager; #[test] fn it_returns_genesis() { @@ -474,7 +496,7 @@ mod fetch_header_containing_kernel_mmr { async fn it_returns_corresponding_header() { let db = setup(); let genesis = db.fetch_block(0, true).unwrap(); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let (blocks, outputs) = add_many_chained_blocks(1, &db, &key_manager).await; let num_genesis_kernels = genesis.block().body.kernels().len() as u64; @@ -484,7 +506,16 @@ mod fetch_header_containing_kernel_mmr { ) .await; - let (block, _) = create_next_block(&db, &blocks[0], txns, &key_manager).await; + let (miner_node_script_key_id, wallet_payment_address) = default_coinbase_entities(&key_manager).await; + let (block, _) = create_next_block( + &db, + &blocks[0], + txns, + &key_manager, + &miner_node_script_key_id, + &wallet_payment_address, + ) + .await; db.add_block(block).unwrap(); let _block_and_outputs = add_many_chained_blocks(3, &db, &key_manager).await; @@ -511,12 +542,13 @@ mod fetch_header_containing_kernel_mmr { mod clear_all_pending_headers { use super::*; + use crate::transactions::key_manager::create_memory_db_key_manager; #[tokio::test] async fn it_clears_no_headers() { let db = setup(); assert_eq!(db.clear_all_pending_headers().unwrap(), 0); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let _block_and_outputs = add_many_chained_blocks(2, &db, &key_manager).await; db.clear_all_pending_headers().unwrap(); let last_header = db.fetch_last_header().unwrap(); @@ -526,7 +558,7 @@ mod clear_all_pending_headers { #[tokio::test] async fn it_clears_headers_after_tip() { let db = setup(); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let _blocks_and_outputs = add_many_chained_blocks(2, &db, &key_manager).await; let prev_block = db.fetch_block(2, true).unwrap(); let mut prev_accum = prev_block.accumulated_data().clone(); @@ -577,13 +609,16 @@ mod validator_node_merkle_root { use super::*; use crate::{ chain_storage::calculate_validator_node_mr, - transactions::transaction_components::{OutputFeatures, ValidatorNodeSignature}, + transactions::{ + key_manager::create_memory_db_key_manager, + transaction_components::{OutputFeatures, ValidatorNodeSignature}, + }, ValidatorNodeBMT, }; #[tokio::test] async fn it_has_the_correct_genesis_merkle_root() { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let vn_mmr = ValidatorNodeBMT::create(Vec::new()); let db = setup(); let (blocks, _outputs) = add_many_chained_blocks(1, &db, &key_manager).await; @@ -593,7 +628,7 @@ mod validator_node_merkle_root { #[tokio::test] async fn it_has_the_correct_merkle_root_for_current_vn_set() { let db = setup(); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let (blocks, outputs) = add_many_chained_blocks(1, &db, &key_manager).await; let (sk, public_key) = PublicKey::random_keypair(&mut OsRng); @@ -609,7 +644,16 @@ mod validator_node_merkle_root { &key_manager, ) .await; - let (block, _) = create_next_block(&db, &blocks[0], tx, &key_manager).await; + let (miner_node_script_key_id, wallet_payment_address) = default_coinbase_entities(&key_manager).await; + let (block, _) = create_next_block( + &db, + &blocks[0], + tx, + &key_manager, + &miner_node_script_key_id, + &wallet_payment_address, + ) + .await; db.add_block(block).unwrap().assert_added(); let consts = db.consensus_constants().unwrap(); diff --git a/base_layer/core/src/covenants/covenant.rs b/base_layer/core/src/covenants/covenant.rs index 9ef38befffe..b9fc7ebf120 100644 --- a/base_layer/core/src/covenants/covenant.rs +++ b/base_layer/core/src/covenants/covenant.rs @@ -189,12 +189,12 @@ mod test { test::{create_input, create_outputs}, Covenant, }, - transactions::test_helpers::{create_test_core_key_manager_with_memory_db, UtxoTestParams}, + transactions::{key_manager::create_memory_db_key_manager, test_helpers::UtxoTestParams}, }; #[tokio::test] async fn it_succeeds_when_empty() { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let outputs = create_outputs(10, UtxoTestParams::default(), &key_manager).await; let input = create_input(&key_manager).await; let covenant = covenant!(); @@ -204,7 +204,7 @@ mod test { #[tokio::test] async fn it_executes_the_covenant() { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let mut outputs = create_outputs(10, UtxoTestParams::default(), &key_manager).await; outputs[4].features.maturity = 42; outputs[5].features.maturity = 42; @@ -221,7 +221,7 @@ mod test { #[tokio::test] async fn test_borsh_de_serialization() { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let mut outputs = create_outputs(10, UtxoTestParams::default(), &key_manager).await; outputs[4].features.maturity = 42; outputs[5].features.maturity = 42; diff --git a/base_layer/core/src/covenants/fields.rs b/base_layer/core/src/covenants/fields.rs index f0fde63f02a..d53293ffb3a 100644 --- a/base_layer/core/src/covenants/fields.rs +++ b/base_layer/core/src/covenants/fields.rs @@ -393,14 +393,14 @@ mod test { mod is_eq { use super::*; use crate::transactions::{ + key_manager::create_memory_db_key_manager, tari_amount::MicroMinotari, - test_helpers::create_test_core_key_manager_with_memory_db, transaction_components::RangeProofType, }; #[tokio::test] async fn it_returns_true_if_eq() { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let side_chain_features = make_sample_sidechain_feature(); let output = create_outputs( 1, @@ -443,7 +443,7 @@ mod test { #[tokio::test] async fn it_returns_false_if_not_eq() { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let side_chain_features = make_sample_sidechain_feature(); let output = create_outputs( 1, @@ -490,11 +490,11 @@ mod test { mod is_eq_input { use super::*; - use crate::transactions::test_helpers::create_test_core_key_manager_with_memory_db; + use crate::transactions::key_manager::create_memory_db_key_manager; #[tokio::test] async fn it_returns_true_if_eq_input() { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let output = create_outputs( 1, UtxoTestParams { @@ -561,6 +561,7 @@ mod test { mod output_fields { use super::*; + use crate::transactions::key_manager::create_memory_db_key_manager; mod construct_challenge_from { use blake2::Digest; @@ -568,15 +569,11 @@ mod test { use tari_crypto::hashing::DomainSeparation; use super::*; - use crate::transactions::{ - tari_amount::MicroMinotari, - test_helpers::create_test_core_key_manager_with_memory_db, - transaction_components::RangeProofType, - }; + use crate::transactions::{tari_amount::MicroMinotari, transaction_components::RangeProofType}; #[tokio::test] async fn it_constructs_challenge_using_consensus_encoding() { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let features = OutputFeatures { maturity: 42, output_type: OutputType::Coinbase, @@ -621,14 +618,14 @@ mod test { mod get_field_value_ref { use super::*; use crate::transactions::{ + key_manager::create_memory_db_key_manager, tari_amount::MicroMinotari, - test_helpers::create_test_core_key_manager_with_memory_db, transaction_components::RangeProofType, }; #[tokio::test] async fn it_retrieves_the_value_as_ref() { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let features = OutputFeatures { maturity: 42, range_proof_type: RangeProofType::RevealedValue, diff --git a/base_layer/core/src/covenants/filters/absolute_height.rs b/base_layer/core/src/covenants/filters/absolute_height.rs index c990ecf9e79..a01cfd39551 100644 --- a/base_layer/core/src/covenants/filters/absolute_height.rs +++ b/base_layer/core/src/covenants/filters/absolute_height.rs @@ -67,12 +67,12 @@ mod test { use crate::{ covenant, covenants::{filters::test::setup_filter_test, test::create_input}, - transactions::test_helpers::create_test_core_key_manager_with_memory_db, + transactions::key_manager::create_memory_db_key_manager, }; #[tokio::test] async fn it_filters_all_out_if_height_not_reached() { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let covenant = covenant!(absolute_height(@uint(100))); let input = create_input(&key_manager).await; let (mut context, outputs) = setup_filter_test(&covenant, &input, 42, |_| {}, &key_manager).await; @@ -85,7 +85,7 @@ mod test { #[tokio::test] async fn it_filters_all_in_if_height_reached() { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let covenant = covenant!(absolute_height(@uint(100))); let input = create_input(&key_manager).await; let (mut context, outputs) = setup_filter_test(&covenant, &input, 100, |_| {}, &key_manager).await; @@ -98,7 +98,7 @@ mod test { #[tokio::test] async fn it_filters_all_in_if_height_exceeded() { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let covenant = covenant!(absolute_height(@uint(42))); let input = create_input(&key_manager).await; let (mut context, outputs) = setup_filter_test(&covenant, &input, 100, |_| {}, &key_manager).await; diff --git a/base_layer/core/src/covenants/filters/and.rs b/base_layer/core/src/covenants/filters/and.rs index cd4533244d4..857ae2a5b09 100644 --- a/base_layer/core/src/covenants/filters/and.rs +++ b/base_layer/core/src/covenants/filters/and.rs @@ -48,12 +48,12 @@ mod test { use crate::{ covenant, covenants::{filters::test::setup_filter_test, test::create_input}, - transactions::test_helpers::create_test_core_key_manager_with_memory_db, + transactions::key_manager::create_memory_db_key_manager, }; #[tokio::test] async fn it_filters_outputset_using_intersection() { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let script = script!(CheckHeight(101)); let covenant = covenant!(and(field_eq(@field::features_maturity, @uint(42),), field_eq(@field::script, @script(script.clone())))); let input = create_input(&key_manager).await; diff --git a/base_layer/core/src/covenants/filters/field_eq.rs b/base_layer/core/src/covenants/filters/field_eq.rs index 9d8180c6369..51e512e1778 100644 --- a/base_layer/core/src/covenants/filters/field_eq.rs +++ b/base_layer/core/src/covenants/filters/field_eq.rs @@ -85,12 +85,12 @@ mod test { use crate::{ covenant, covenants::test::{create_context, create_input, create_outputs}, - transactions::{test_helpers::create_test_core_key_manager_with_memory_db, transaction_components::OutputType}, + transactions::{key_manager::create_memory_db_key_manager, transaction_components::OutputType}, }; #[tokio::test] async fn it_filters_uint() { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let covenant = covenant!(field_eq(@field::features_maturity, @uint(42))); let input = create_input(&key_manager).await; let mut context = create_context(&covenant, &input, 0); @@ -108,7 +108,7 @@ mod test { #[tokio::test] async fn it_filters_sender_offset_public_key() { let pk = PublicKey::from_hex("5615a327e1d19da34e5aa8bbd2ecc97addf29b158844b885bfc4efa0dab17052").unwrap(); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let covenant = covenant!(field_eq( @field::sender_offset_public_key, @public_key(pk.clone()) @@ -128,7 +128,7 @@ mod test { #[tokio::test] async fn it_filters_commitment() { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let commitment = Commitment::from_hex("7ca31ba517d8b563609ed6707fedde5a2be64ac1d67b254cb5348bc2f680557f").unwrap(); let covenant = covenant!(field_eq( @@ -151,7 +151,7 @@ mod test { #[tokio::test] async fn it_filters_tari_script() { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let script = script!(CheckHeight(100)); let covenant = covenant!(field_eq( @field::script, @@ -173,7 +173,7 @@ mod test { #[tokio::test] async fn it_filters_covenant() { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let next_cov = covenant!(and(identity(), or(field_eq(@field::features_maturity, @uint(42))))); let covenant = covenant!(field_eq(@field::covenant, @covenant(next_cov.clone()))); let input = create_input(&key_manager).await; @@ -192,7 +192,7 @@ mod test { #[tokio::test] async fn it_filters_output_type() { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let covenant = covenant!(field_eq(@field::features_output_type, @output_type(Coinbase))); let input = create_input(&key_manager).await; let mut context = create_context(&covenant, &input, 0); @@ -210,7 +210,7 @@ mod test { #[tokio::test] async fn it_errors_if_field_has_an_incorrect_type() { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let covenant = covenant!(field_eq(@field::features, @uint(42))); let input = create_input(&key_manager).await; let mut context = create_context(&covenant, &input, 0); diff --git a/base_layer/core/src/covenants/filters/fields_hashed_eq.rs b/base_layer/core/src/covenants/filters/fields_hashed_eq.rs index fe26c56453d..6cbb9a0d5c4 100644 --- a/base_layer/core/src/covenants/filters/fields_hashed_eq.rs +++ b/base_layer/core/src/covenants/filters/fields_hashed_eq.rs @@ -58,15 +58,12 @@ mod test { BaseLayerCovenantsDomain, COVENANTS_FIELD_HASHER_LABEL, }, - transactions::{ - test_helpers::create_test_core_key_manager_with_memory_db, - transaction_components::OutputFeatures, - }, + transactions::{key_manager::create_memory_db_key_manager, transaction_components::OutputFeatures}, }; #[tokio::test] async fn it_filters_outputs_with_fields_that_hash_to_given_hash() { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let features = OutputFeatures { maturity: 42, sidechain_feature: Some(make_sample_sidechain_feature()), diff --git a/base_layer/core/src/covenants/filters/fields_preserved.rs b/base_layer/core/src/covenants/filters/fields_preserved.rs index 2ecd2bacbea..06caf4881f3 100644 --- a/base_layer/core/src/covenants/filters/fields_preserved.rs +++ b/base_layer/core/src/covenants/filters/fields_preserved.rs @@ -44,13 +44,13 @@ mod test { use crate::{ covenant, covenants::{filters::test::setup_filter_test, test::create_input}, - transactions::{test_helpers::create_test_core_key_manager_with_memory_db, transaction_components::OutputType}, + transactions::{key_manager::create_memory_db_key_manager, transaction_components::OutputType}, }; #[tokio::test] async fn it_filters_outputs_that_match_input_fields() { let covenant = covenant!(fields_preserved(@fields(@field::features_maturity, @field::features_output_type))); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let mut input = create_input(&key_manager).await; input.set_maturity(42).unwrap(); input.features_mut().unwrap().output_type = OutputType::ValidatorNodeRegistration; diff --git a/base_layer/core/src/covenants/filters/identity.rs b/base_layer/core/src/covenants/filters/identity.rs index 1785dd2a8cd..88d1e5c03d5 100644 --- a/base_layer/core/src/covenants/filters/identity.rs +++ b/base_layer/core/src/covenants/filters/identity.rs @@ -39,12 +39,12 @@ mod tests { use crate::{ covenant, covenants::{filters::test::setup_filter_test, test::create_input}, - transactions::test_helpers::create_test_core_key_manager_with_memory_db, + transactions::key_manager::create_memory_db_key_manager, }; #[tokio::test] async fn it_returns_the_outputset_unchanged() { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let covenant = covenant!(identity()); let input = create_input(&key_manager).await; let (mut context, outputs) = setup_filter_test(&covenant, &input, 0, |_| {}, &key_manager).await; diff --git a/base_layer/core/src/covenants/filters/not.rs b/base_layer/core/src/covenants/filters/not.rs index 0d5d71a58c3..811b18854ed 100644 --- a/base_layer/core/src/covenants/filters/not.rs +++ b/base_layer/core/src/covenants/filters/not.rs @@ -45,12 +45,12 @@ mod test { use crate::{ covenant, covenants::{filters::test::setup_filter_test, test::create_input}, - transactions::test_helpers::create_test_core_key_manager_with_memory_db, + transactions::key_manager::create_memory_db_key_manager, }; #[tokio::test] async fn it_filters_compliment_of_filter() { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let script = script!(CheckHeight(100)); let covenant = covenant!(not(or(field_eq(@field::features_maturity, @uint(42),), field_eq(@field::script, @script(script.clone()))))); let input = create_input(&key_manager).await; diff --git a/base_layer/core/src/covenants/filters/or.rs b/base_layer/core/src/covenants/filters/or.rs index 07ad183efd2..6401ce4bc32 100644 --- a/base_layer/core/src/covenants/filters/or.rs +++ b/base_layer/core/src/covenants/filters/or.rs @@ -51,12 +51,12 @@ mod test { use crate::{ covenant, covenants::{filters::test::setup_filter_test, test::create_input}, - transactions::test_helpers::create_test_core_key_manager_with_memory_db, + transactions::key_manager::create_memory_db_key_manager, }; #[tokio::test] async fn it_filters_outputset_using_union() { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let script = script!(CheckHeight(100)); let covenant = covenant!(or(field_eq(@field::features_maturity, @uint(42),), field_eq(@field::script, @script(script.clone())))); let input = create_input(&key_manager).await; diff --git a/base_layer/core/src/covenants/filters/output_hash_eq.rs b/base_layer/core/src/covenants/filters/output_hash_eq.rs index 46cf3117a3e..82c02117b3a 100644 --- a/base_layer/core/src/covenants/filters/output_hash_eq.rs +++ b/base_layer/core/src/covenants/filters/output_hash_eq.rs @@ -47,12 +47,12 @@ mod test { filters::test::setup_filter_test, test::{create_input, create_outputs}, }, - transactions::test_helpers::create_test_core_key_manager_with_memory_db, + transactions::key_manager::create_memory_db_key_manager, }; #[tokio::test] async fn it_filters_output_with_specific_hash() { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let output = create_outputs(1, Default::default(), &key_manager).await.remove(0); let output_hash = output.hash(); let mut hash = [0u8; 32]; diff --git a/base_layer/core/src/covenants/filters/test.rs b/base_layer/core/src/covenants/filters/test.rs index a02f1445a89..65cc0484738 100644 --- a/base_layer/core/src/covenants/filters/test.rs +++ b/base_layer/core/src/covenants/filters/test.rs @@ -27,7 +27,7 @@ use crate::{ Covenant, }, transactions::{ - test_helpers::TestKeyManager, + key_manager::MemoryDbKeyManager, transaction_components::{TransactionInput, TransactionOutput}, }, }; @@ -40,7 +40,7 @@ pub async fn setup_filter_test<'a, F>( input: &'a TransactionInput, block_height: u64, output_mod: F, - key_manager: &TestKeyManager, + key_manager: &MemoryDbKeyManager, ) -> (CovenantContext<'a>, Vec) where F: FnOnce(&mut Vec), diff --git a/base_layer/core/src/covenants/filters/xor.rs b/base_layer/core/src/covenants/filters/xor.rs index c6520395b74..5ffa78c50f4 100644 --- a/base_layer/core/src/covenants/filters/xor.rs +++ b/base_layer/core/src/covenants/filters/xor.rs @@ -53,12 +53,12 @@ mod test { use crate::{ covenant, covenants::{filters::test::setup_filter_test, test::create_input}, - transactions::test_helpers::create_test_core_key_manager_with_memory_db, + transactions::key_manager::create_memory_db_key_manager, }; #[tokio::test] async fn it_filters_outputset_using_symmetric_difference() { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let script = script!(CheckHeight(100)); let covenant = covenant!(and(field_eq(@field::features_maturity, @uint(42),), field_eq(@field::script, @script(script.clone())))); let input = create_input(&key_manager).await; diff --git a/base_layer/core/src/covenants/test.rs b/base_layer/core/src/covenants/test.rs index 37bb2636369..91a3272289b 100644 --- a/base_layer/core/src/covenants/test.rs +++ b/base_layer/core/src/covenants/test.rs @@ -25,7 +25,8 @@ use std::convert::TryInto; use crate::{ covenants::{context::CovenantContext, Covenant}, transactions::{ - test_helpers::{TestKeyManager, TestParams, UtxoTestParams}, + key_manager::MemoryDbKeyManager, + test_helpers::{TestParams, UtxoTestParams}, transaction_components::{ BuildInfo, CodeTemplateRegistration, @@ -40,7 +41,7 @@ use crate::{ pub async fn create_outputs( n: usize, utxo_params: UtxoTestParams, - key_manager: &TestKeyManager, + key_manager: &MemoryDbKeyManager, ) -> Vec { let mut outputs = Vec::new(); for _i in 0..n { @@ -51,7 +52,7 @@ pub async fn create_outputs( outputs } -pub async fn create_input(key_manager: &TestKeyManager) -> TransactionInput { +pub async fn create_input(key_manager: &MemoryDbKeyManager) -> TransactionInput { let params = TestParams::new(key_manager).await; let output = params.create_output(Default::default(), key_manager).await.unwrap(); output.to_transaction_input(key_manager).await.unwrap() diff --git a/base_layer/core/src/mempool/priority/prioritized_transaction.rs b/base_layer/core/src/mempool/priority/prioritized_transaction.rs index 3cb3bb26610..d656a8cfd63 100644 --- a/base_layer/core/src/mempool/priority/prioritized_transaction.rs +++ b/base_layer/core/src/mempool/priority/prioritized_transaction.rs @@ -118,11 +118,12 @@ impl Display for PrioritizedTransaction { mod tests { use super::*; use crate::transactions::{ + key_manager::{create_memory_db_key_manager, MemoryDbKeyManager}, tari_amount::{uT, MicroMinotari, T}, - test_helpers::{create_test_core_key_manager_with_memory_db, create_tx, TestKeyManager}, + test_helpers::create_tx, }; - async fn create_tx_with_fee(fee_per_gram: MicroMinotari, key_manager: &TestKeyManager) -> Transaction { + async fn create_tx_with_fee(fee_per_gram: MicroMinotari, key_manager: &MemoryDbKeyManager) -> Transaction { let (tx, _, _) = create_tx(10 * T, fee_per_gram, 0, 1, 0, 1, Default::default(), key_manager) .await .expect("Failed to get tx"); @@ -131,7 +132,7 @@ mod tests { #[tokio::test] async fn fee_increases_priority() { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let weighting = TransactionWeight::latest(); let epoch = u64::MAX / 2; let tx = create_tx_with_fee(2 * uT, &key_manager).await; @@ -145,7 +146,7 @@ mod tests { #[tokio::test] async fn age_increases_priority() { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let weighting = TransactionWeight::latest(); let epoch = u64::MAX / 2; let tx = create_tx_with_fee(2 * uT, &key_manager).await; diff --git a/base_layer/core/src/mempool/reorg_pool/reorg_pool.rs b/base_layer/core/src/mempool/reorg_pool/reorg_pool.rs index 8770f712c18..b3b11e94c62 100644 --- a/base_layer/core/src/mempool/reorg_pool/reorg_pool.rs +++ b/base_layer/core/src/mempool/reorg_pool/reorg_pool.rs @@ -343,13 +343,13 @@ mod test { use crate::{ consensus::ConsensusManagerBuilder, test_helpers::create_orphan_block, - transactions::{tari_amount::MicroMinotari, test_helpers::create_test_core_key_manager_with_memory_db}, + transactions::{key_manager::create_memory_db_key_manager, tari_amount::MicroMinotari}, tx, }; #[tokio::test] async fn test_insert_expire_by_height() { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let tx1 = Arc::new( tx!(MicroMinotari(100_000), fee: MicroMinotari(100), lock: 4000, inputs: 2, outputs: 1, &key_manager) .expect("Failed to get tx") @@ -409,7 +409,7 @@ mod test { #[tokio::test] async fn test_remove_all() { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let tx1 = Arc::new( tx!(MicroMinotari(100_000), fee: MicroMinotari(100), lock: 4000, inputs: 2, outputs: 1, &key_manager) .expect("Failed to get tx") @@ -446,7 +446,7 @@ mod test { #[tokio::test] async fn remove_scan_for_and_remove_reorged_txs() { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let network = Network::LocalNet; let consensus = ConsensusManagerBuilder::new(network).build().unwrap(); let tx1 = Arc::new( diff --git a/base_layer/core/src/mempool/sync_protocol/test.rs b/base_layer/core/src/mempool/sync_protocol/test.rs index 228adf90133..47b4719a868 100644 --- a/base_layer/core/src/mempool/sync_protocol/test.rs +++ b/base_layer/core/src/mempool/sync_protocol/test.rs @@ -52,15 +52,16 @@ use crate::{ Mempool, }, transactions::{ + key_manager::create_memory_db_key_manager, tari_amount::uT, - test_helpers::{create_test_core_key_manager_with_memory_db, create_tx}, + test_helpers::create_tx, transaction_components::Transaction, }, validation::mocks::MockValidator, }; pub async fn create_transactions(n: usize) -> Vec { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let mut transactions = Vec::new(); for _i in 0..n { let (transaction, _, _) = create_tx(5000 * uT, 3 * uT, 1, 2, 1, 3, Default::default(), &key_manager) diff --git a/base_layer/core/src/mempool/unconfirmed_pool/unconfirmed_pool.rs b/base_layer/core/src/mempool/unconfirmed_pool/unconfirmed_pool.rs index 2ed8e7fe7d8..8c7568a9bed 100644 --- a/base_layer/core/src/mempool/unconfirmed_pool/unconfirmed_pool.rs +++ b/base_layer/core/src/mempool/unconfirmed_pool/unconfirmed_pool.rs @@ -883,8 +883,9 @@ mod test { transactions::{ aggregated_body::AggregateBody, fee::Fee, + key_manager::create_memory_db_key_manager, tari_amount::MicroMinotari, - test_helpers::{create_test_core_key_manager_with_memory_db, TestParams, UtxoTestParams}, + test_helpers::{TestParams, UtxoTestParams}, weight::TransactionWeight, SenderTransactionProtocol, }, @@ -893,7 +894,7 @@ mod test { #[tokio::test] async fn test_find_duplicate_input() { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let tx1 = Arc::new( tx!(MicroMinotari(5000), fee: MicroMinotari(50), inputs: 2, outputs: 1, &key_manager) .expect("Failed to get tx") @@ -922,7 +923,7 @@ mod test { #[tokio::test] async fn test_insert_and_retrieve_highest_priority_txs() { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let tx1 = Arc::new( tx!(MicroMinotari(5_000), fee: MicroMinotari(5), inputs: 2, outputs: 1, &key_manager) .expect("Failed to get tx") @@ -985,7 +986,7 @@ mod test { #[tokio::test] async fn test_double_spend_inputs() { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let (tx1, _, _) = tx!(MicroMinotari(5_000), fee: MicroMinotari(10), inputs: 1, outputs: 1, &key_manager) .expect("Failed to get tx"); const INPUT_AMOUNT: MicroMinotari = MicroMinotari(5_000); @@ -1072,7 +1073,7 @@ mod test { #[tokio::test] async fn test_remove_reorg_txs() { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let network = Network::LocalNet; let consensus = ConsensusManagerBuilder::new(network).build().unwrap(); let tx1 = Arc::new( @@ -1144,7 +1145,7 @@ mod test { #[tokio::test] async fn test_discard_double_spend_txs() { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let consensus = create_consensus_rules(); let tx1 = Arc::new( tx!(MicroMinotari(5_000), fee: MicroMinotari(5), inputs:2, outputs:1, &key_manager) @@ -1219,7 +1220,7 @@ mod test { #[tokio::test] async fn test_multiple_transactions_with_same_outputs_in_mempool() { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let (tx1, _, _) = tx!(MicroMinotari(150_000), fee: MicroMinotari(50), inputs:5, outputs:5, &key_manager) .expect("Failed to get tx"); let (tx2, _, _) = tx!(MicroMinotari(250_000), fee: MicroMinotari(50), inputs:5, outputs:5, &key_manager) @@ -1322,7 +1323,7 @@ mod test { #[tokio::test] async fn it_compiles_correct_stats_for_single_block() { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let (tx1, _, _) = tx!(MicroMinotari(150_000), fee: MicroMinotari(5), inputs:5, outputs:1, &key_manager) .expect("Failed to get tx"); let (tx2, _, _) = tx!(MicroMinotari(250_000), fee: MicroMinotari(5), inputs:5, outputs:5, &key_manager) @@ -1352,7 +1353,7 @@ mod test { #[tokio::test] async fn it_compiles_correct_stats_for_multiple_blocks() { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let expected_stats = [ FeePerGramStat { order: 0, diff --git a/base_layer/core/src/test_helpers/blockchain.rs b/base_layer/core/src/test_helpers/blockchain.rs index 31e126ad1fd..d7f24491a32 100644 --- a/base_layer/core/src/test_helpers/blockchain.rs +++ b/base_layer/core/src/test_helpers/blockchain.rs @@ -31,6 +31,7 @@ use std::{ use tari_common::configuration::Network; use tari_common_types::{ chain_metadata::ChainMetadata, + tari_address::TariAddress, types::{Commitment, FixedHash, HashOutput, PublicKey, Signature}, }; use tari_storage::lmdb_store::LMDBConfig; @@ -62,9 +63,9 @@ use crate::{ }, consensus::{chain_strength_comparer::ChainStrengthComparerBuilder, ConsensusConstantsBuilder, ConsensusManager}, proof_of_work::{AchievedTargetDifficulty, Difficulty, PowAlgorithm}, - test_helpers::{block_spec::BlockSpecs, create_consensus_rules, BlockSpec}, + test_helpers::{block_spec::BlockSpecs, create_consensus_rules, default_coinbase_entities, BlockSpec}, transactions::{ - test_helpers::{create_test_core_key_manager_with_memory_db, TestKeyManager}, + key_manager::{create_memory_db_key_manager, MemoryDbKeyManager, TariKeyId}, transaction_components::{TransactionInput, TransactionKernel, TransactionOutput, WalletOutput}, CryptoFactories, }, @@ -422,16 +423,25 @@ pub async fn create_chained_blocks>( let mut block_hashes = HashMap::new(); block_hashes.insert("GB".to_string(), genesis_block); let rules = ConsensusManager::builder(Network::LocalNet).build().unwrap(); - let km = create_test_core_key_manager_with_memory_db(); + let km = create_memory_db_key_manager(); let blocks: BlockSpecs = blocks.into(); let mut block_names = Vec::with_capacity(blocks.len()); + let (miner_node_script_key_id, wallet_payment_address) = default_coinbase_entities(&km).await; for block_spec in blocks { let prev_block = block_hashes .get(block_spec.parent) .unwrap_or_else(|| panic!("Could not find block {}", block_spec.parent)); let name = block_spec.name; let difficulty = block_spec.difficulty; - let (block, _) = create_block(&rules, prev_block.block(), block_spec, &km).await; + let (block, _) = create_block( + &rules, + prev_block.block(), + block_spec, + &km, + &miner_node_script_key_id, + &wallet_payment_address, + ) + .await; let block = mine_block(block, prev_block.accumulated_data(), difficulty); block_names.push(name.to_string()); block_hashes.insert(name.to_string(), block); @@ -491,31 +501,36 @@ pub struct TestBlockchain { db: BlockchainDatabase, chain: Vec<(&'static str, Arc)>, rules: ConsensusManager, - pub km: TestKeyManager, + pub km: MemoryDbKeyManager, + miner_node_script_key_id: TariKeyId, + wallet_payment_address: TariAddress, } impl TestBlockchain { - pub fn new(db: BlockchainDatabase, rules: ConsensusManager) -> Self { + pub async fn new(db: BlockchainDatabase, rules: ConsensusManager) -> Self { let genesis = db .fetch_block(0, true) .unwrap() .try_into_chain_block() .map(Arc::new) .unwrap(); - let km = create_test_core_key_manager_with_memory_db(); + let km = create_memory_db_key_manager(); + let (miner_node_script_key_id, wallet_payment_address) = default_coinbase_entities(&km).await; let mut blockchain = Self { db, chain: Default::default(), rules, km, + miner_node_script_key_id, + wallet_payment_address, }; blockchain.chain.push(("GB", genesis)); blockchain } - pub fn create(rules: ConsensusManager) -> Self { - Self::new(create_custom_blockchain(rules.clone()), rules) + pub async fn create(rules: ConsensusManager) -> Self { + Self::new(create_custom_blockchain(rules.clone()), rules).await } pub async fn append_chain( @@ -545,10 +560,10 @@ impl TestBlockchain { Ok(()) } - pub fn with_validators(validators: Validators) -> Self { + pub async fn with_validators(validators: Validators) -> Self { let rules = ConsensusManager::builder(Network::LocalNet).build().unwrap(); let db = create_store_with_consensus_and_validators(rules.clone(), validators); - Self::new(db, rules) + Self::new(db, rules).await } pub fn rules(&self) -> &ConsensusManager { @@ -605,7 +620,15 @@ impl TestBlockchain { .ok_or_else(|| format!("Parent block not found with name '{}'", block_spec.parent)) .unwrap(); let difficulty = block_spec.difficulty; - let (block, coinbase) = create_block(&self.rules, parent.block(), block_spec, &self.km).await; + let (block, coinbase) = create_block( + &self.rules, + parent.block(), + block_spec, + &self.km, + &self.miner_node_script_key_id, + &self.wallet_payment_address, + ) + .await; let block = mine_block(block, parent.accumulated_data(), difficulty); (block, coinbase) } @@ -615,7 +638,15 @@ impl TestBlockchain { .get_block_by_name(block_spec.parent) .ok_or_else(|| format!("Parent block not found with name '{}'", block_spec.parent)) .unwrap(); - let (mut block, outputs) = create_block(&self.rules, parent.block(), block_spec, &self.km).await; + let (mut block, outputs) = create_block( + &self.rules, + parent.block(), + block_spec, + &self.km, + &self.miner_node_script_key_id, + &self.wallet_payment_address, + ) + .await; block.body.sort(); (block, outputs) } @@ -649,10 +680,3 @@ impl TestBlockchain { self.chain.first().map(|(_, block)| block).unwrap().clone() } } - -impl Default for TestBlockchain { - fn default() -> Self { - let rules = ConsensusManager::builder(Network::LocalNet).build().unwrap(); - TestBlockchain::create(rules) - } -} diff --git a/base_layer/core/src/test_helpers/mod.rs b/base_layer/core/src/test_helpers/mod.rs index b8c462c6790..f1e98df02cc 100644 --- a/base_layer/core/src/test_helpers/mod.rs +++ b/base_layer/core/src/test_helpers/mod.rs @@ -30,10 +30,13 @@ pub use block_spec::{BlockSpec, BlockSpecs}; use digest::consts::U32; use rand::{distributions::Alphanumeric, rngs::OsRng, Rng}; use tari_common::configuration::Network; -use tari_common_types::types::PublicKey; +use tari_common_types::{ + tari_address::TariAddress, + types::{PrivateKey, PublicKey}, +}; use tari_comms::PeerManager; -use tari_crypto::keys::PublicKey as PublicKeyT; -use tari_key_manager::key_manager_service::KeyId; +use tari_crypto::keys::{PublicKey as PublicKeyT, SecretKey}; +use tari_key_manager::key_manager_service::KeyManagerInterface; use tari_storage::{lmdb_store::LMDBBuilder, LMDBWrapper}; use tari_utilities::epoch_time::EpochTime; @@ -42,10 +45,10 @@ use crate::{ consensus::{ConsensusConstants, ConsensusManager}, proof_of_work::{difficulty::CheckedAdd, sha3x_difficulty, AchievedTargetDifficulty, Difficulty}, transactions::{ - key_manager::TransactionKeyManagerBranch, - test_helpers::TestKeyManager, + generate_coinbase, + key_manager::{MemoryDbKeyManager, TariKeyId}, + tari_amount::MicroMinotari, transaction_components::{Transaction, WalletOutput}, - CoinbaseBuilder, }, }; @@ -69,16 +72,24 @@ pub fn create_orphan_block(block_height: u64, transactions: Vec, co header.into_builder().with_transactions(transactions).build() } +pub async fn default_coinbase_entities(key_manager: &MemoryDbKeyManager) -> (TariKeyId, TariAddress) { + let wallet_private_key = PrivateKey::random(&mut OsRng); + let miner_node_script_key_id = key_manager.import_key(wallet_private_key.clone()).await.unwrap(); + let wallet_payment_address = TariAddress::new(PublicKey::from_secret_key(&wallet_private_key), Network::LocalNet); + (miner_node_script_key_id, wallet_payment_address) +} + pub async fn create_block( rules: &ConsensusManager, prev_block: &Block, spec: BlockSpec, - km: &TestKeyManager, + km: &MemoryDbKeyManager, + miner_node_script_key_id: &TariKeyId, + wallet_payment_address: &TariAddress, ) -> (Block, WalletOutput) { let mut header = BlockHeader::from_previous(&prev_block.header); let block_height = spec.height_override.unwrap_or(prev_block.header.height + 1); header.height = block_height; - // header.prev_hash = prev_block.hash(); let reward = spec.reward_override.unwrap_or_else(|| { rules .calculate_coinbase_and_fees( @@ -92,18 +103,19 @@ pub async fn create_block( .unwrap() }); - let spend_key_id = KeyId::Managed { - branch: TransactionKeyManagerBranch::Coinbase.get_branch_key(), - index: block_height, - }; - let (coinbase, coinbase_output) = CoinbaseBuilder::new(km.clone()) - .with_block_height(header.height) - .with_fees(0.into()) - .with_spend_key_id(spend_key_id.clone()) - .with_script_key_id(spend_key_id) - .build_with_reward(rules.consensus_constants(block_height), reward) - .await - .unwrap(); + let (coinbase, _, _, coinbase_output) = generate_coinbase( + MicroMinotari::from(0), + reward, + header.height, + &[], + km, + miner_node_script_key_id, + wallet_payment_address, + false, + rules.consensus_constants(header.height), + ) + .await + .unwrap(); let mut block = header .into_builder() diff --git a/base_layer/core/src/transactions/coinbase_builder.rs b/base_layer/core/src/transactions/coinbase_builder.rs index d844cbe4420..25c78f41b2d 100644 --- a/base_layer/core/src/transactions/coinbase_builder.rs +++ b/base_layer/core/src/transactions/coinbase_builder.rs @@ -21,9 +21,15 @@ // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // -use tari_common_types::types::{Commitment, PrivateKey}; -use tari_key_manager::key_manager_service::KeyManagerServiceError; -use tari_script::{inputs, script, TariScript}; +use chacha20poly1305::aead::OsRng; +use tari_common_types::{ + tari_address::TariAddress, + types::{Commitment, PrivateKey, PublicKey}, +}; +use tari_crypto::keys::PublicKey as PK; +use tari_key_manager::key_manager_service::{KeyManagerInterface, KeyManagerServiceError}; +use tari_script::{one_sided_payment_script, stealth_payment_script, ExecutionStack, TariScript}; +use tari_utilities::ByteArrayError; use thiserror::Error; use crate::{ @@ -32,8 +38,21 @@ use crate::{ ConsensusConstants, }, covenants::Covenant, + one_sided::{ + diffie_hellman_stealth_domain_hasher, + shared_secret_to_output_encryption_key, + shared_secret_to_output_spending_key, + stealth_address_script_spending_key, + }, transactions::{ - key_manager::{TariKeyId, TransactionKeyManagerBranch, TransactionKeyManagerInterface, TxoStage}, + key_manager::{ + CoreKeyManagerError, + MemoryDbKeyManager, + TariKeyId, + TransactionKeyManagerBranch, + TransactionKeyManagerInterface, + TxoStage, + }, tari_amount::{uT, MicroMinotari}, transaction_components::{ KernelBuilder, @@ -64,6 +83,14 @@ pub enum CoinbaseBuildError { MissingSpendKey, #[error("The script key for this coinbase transaction wasn't provided")] MissingScriptKey, + #[error("The script for this coinbase transaction wasn't provided")] + MissingScript, + #[error("The wallet public key for this coinbase transaction wasn't provided")] + MissingWalletPublicKey, + #[error("The encryption key for this coinbase transaction wasn't provided")] + MissingEncryptionKey, + #[error("The sender offset key for this coinbase transaction wasn't provided")] + MissingSenderOffsetKey, #[error("The value encryption was not succeed")] ValueEncryptionFailed, #[error("An error occurred building the final transaction: `{0}`")] @@ -74,8 +101,24 @@ pub enum CoinbaseBuildError { InvalidSenderOffsetKey, #[error("An invalid transaction has been encountered: {0}")] TransactionError(#[from] TransactionError), + #[error("Key manager error: {0}")] + CoreKeyManagerError(String), #[error("Key manager service error: `{0}`")] KeyManagerServiceError(String), + #[error("Conversion error: {0}")] + ByteArrayError(String), +} + +impl From for CoinbaseBuildError { + fn from(err: ByteArrayError) -> Self { + CoinbaseBuildError::ByteArrayError(err.to_string()) + } +} + +impl From for CoinbaseBuildError { + fn from(err: CoreKeyManagerError) -> Self { + CoinbaseBuildError::CoreKeyManagerError(err.to_string()) + } } impl From for CoinbaseBuildError { @@ -90,6 +133,8 @@ pub struct CoinbaseBuilder { fees: Option, spend_key_id: Option, script_key_id: Option, + encryption_key_id: Option, + sender_offset_key_id: Option, script: Option, covenant: Covenant, extra: Option>, @@ -107,6 +152,8 @@ where TKeyManagerInterface: TransactionKeyManagerInterface fees: None, spend_key_id: None, script_key_id: None, + encryption_key_id: None, + sender_offset_key_id: None, script: None, covenant: Covenant::default(), extra: None, @@ -125,19 +172,33 @@ where TKeyManagerInterface: TransactionKeyManagerInterface self } - /// Provides the spend key for this transaction. This will usually be provided by a miner's wallet instance. + /// Provides the spend key ID for this transaction. This will usually be provided by a miner's wallet instance. pub fn with_spend_key_id(mut self, key: TariKeyId) -> Self { self.spend_key_id = Some(key); self } - /// Provides the script key for this transaction. This will usually be provided by a miner's wallet + /// Provides the script key ID for this transaction. This will usually be provided by a miner's wallet /// instance. pub fn with_script_key_id(mut self, key: TariKeyId) -> Self { self.script_key_id = Some(key); self } + /// Provides the encryption key ID for this transaction. This will usually be provided by a Diffie-Hellman shared + /// secret. + pub fn with_encryption_key_id(mut self, key: TariKeyId) -> Self { + self.encryption_key_id = Some(key); + self + } + + /// Provides the sender offset key ID for this transaction. This will usually be provided by a miner's wallet + /// instance. + pub fn with_sender_offset_key_id(mut self, key: TariKeyId) -> Self { + self.sender_offset_key_id = Some(key); + self + } + /// Provides the script for this transaction, usually by a miner's wallet instance. pub fn with_script(mut self, script: TariScript) -> Self { self.script = Some(script); @@ -187,8 +248,12 @@ where TKeyManagerInterface: TransactionKeyManagerInterface let total_reward = block_reward + self.fees.ok_or(CoinbaseBuildError::MissingFees)?; let spending_key_id = self.spend_key_id.ok_or(CoinbaseBuildError::MissingSpendKey)?; let script_key_id = self.script_key_id.ok_or(CoinbaseBuildError::MissingScriptKey)?; + let encryption_key_id = self.encryption_key_id.ok_or(CoinbaseBuildError::MissingEncryptionKey)?; + let sender_offset_key_id = self + .sender_offset_key_id + .ok_or(CoinbaseBuildError::MissingSenderOffsetKey)?; let covenant = self.covenant; - let script = self.script.unwrap_or_else(|| script!(Nop)); + let script = self.script.ok_or(CoinbaseBuildError::MissingScript)?; let kernel_features = KernelFeatures::create_coinbase(); let metadata = TransactionMetadata::new_with_features(0.into(), 0, kernel_features); @@ -207,7 +272,6 @@ where TKeyManagerInterface: TransactionKeyManagerInterface .await?; let public_spend_key = self.key_manager.get_public_key_at_key_id(&spending_key_id).await?; - let public_script_key = self.key_manager.get_public_key_at_key_id(&script_key_id).await?; let kernel_signature = self .key_manager @@ -229,7 +293,7 @@ where TKeyManagerInterface: TransactionKeyManagerInterface let output_features = OutputFeatures::create_coinbase(height + constants.coinbase_min_maturity(), self.extra); let encrypted_data = self .key_manager - .encrypt_data_for_recovery(&spending_key_id, None, total_reward.into()) + .encrypt_data_for_recovery(&spending_key_id, Some(&encryption_key_id), total_reward.into()) .await?; let minimum_value_promise = MicroMinotari::zero(); @@ -243,17 +307,14 @@ where TKeyManagerInterface: TransactionKeyManagerInterface &minimum_value_promise, ); - let (sender_offset_public_key_id, sender_offset_public_key) = self - .key_manager - .get_next_key(TransactionKeyManagerBranch::SenderOffset.get_branch_key()) - .await?; + let sender_offset_public_key = self.key_manager.get_public_key_at_key_id(&sender_offset_key_id).await?; let metadata_sig = self .key_manager .get_metadata_signature( &spending_key_id, &value.into(), - &sender_offset_public_key_id, + &sender_offset_key_id, &output_version, &metadata_message, output_features.range_proof_type, @@ -266,7 +327,7 @@ where TKeyManagerInterface: TransactionKeyManagerInterface spending_key_id, output_features, script, - inputs!(public_script_key), + ExecutionStack::default(), script_key_id, sender_offset_public_key, metadata_sig, @@ -306,10 +367,69 @@ where TKeyManagerInterface: TransactionKeyManagerInterface } } +pub async fn generate_coinbase( + fee: MicroMinotari, + reward: MicroMinotari, + height: u64, + extra: &[u8], + key_manager: &MemoryDbKeyManager, + miner_node_script_key_id: &TariKeyId, + wallet_payment_address: &TariAddress, + stealth_payment: bool, + consensus_constants: &ConsensusConstants, +) -> Result<(Transaction, TransactionOutput, TransactionKernel, WalletOutput), CoinbaseBuildError> { + let (sender_offset_key_id, _) = key_manager + .get_next_key(TransactionKeyManagerBranch::SenderOffset.get_branch_key()) + .await?; + let shared_secret = key_manager + .get_diffie_hellman_shared_secret(&sender_offset_key_id, wallet_payment_address.public_key()) + .await?; + let spending_key = shared_secret_to_output_spending_key(&shared_secret)?; + + let encryption_private_key = shared_secret_to_output_encryption_key(&shared_secret)?; + let encryption_key_id = key_manager.import_key(encryption_private_key).await?; + + let spending_key_id = key_manager.import_key(spending_key).await?; + + let script = if stealth_payment { + let (nonce_private_key, nonce_public_key) = PublicKey::random_keypair(&mut OsRng); + let c = diffie_hellman_stealth_domain_hasher(&nonce_private_key, wallet_payment_address.public_key()); + let script_spending_key = stealth_address_script_spending_key(&c, wallet_payment_address.public_key()); + stealth_payment_script(&nonce_public_key, &script_spending_key) + } else { + one_sided_payment_script(wallet_payment_address.public_key()) + }; + + let (transaction, wallet_output) = CoinbaseBuilder::new(key_manager.clone()) + .with_block_height(height) + .with_fees(fee) + .with_spend_key_id(spending_key_id) + .with_encryption_key_id(encryption_key_id) + .with_sender_offset_key_id(sender_offset_key_id) + .with_script_key_id(miner_node_script_key_id.clone()) + .with_script(script) + .with_extra(extra.to_vec()) + .build_with_reward(consensus_constants, reward) + .await?; + + let output = transaction + .body() + .outputs() + .first() + .ok_or(CoinbaseBuildError::BuildError("No output found".to_string()))?; + let kernel = transaction + .body() + .kernels() + .first() + .ok_or(CoinbaseBuildError::BuildError("No kernel found".to_string()))?; + + Ok((transaction.clone(), output.clone(), kernel.clone(), wallet_output)) +} + #[cfg(test)] mod test { use tari_common::configuration::Network; - use tari_common_types::types::Commitment; + use tari_common_types::{tari_address::TariAddress, types::Commitment}; use crate::{ consensus::{emission::Emission, ConsensusManager, ConsensusManagerBuilder}, @@ -325,14 +445,14 @@ mod test { }; fn get_builder() -> ( - CoinbaseBuilder, + CoinbaseBuilder, ConsensusManager, CryptoFactories, - TestKeyManager, + MemoryDbKeyManager, ) { let network = Network::LocalNet; let rules = ConsensusManagerBuilder::new(network).build().unwrap(); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let factories = CryptoFactories::default(); (CoinbaseBuilder::new(key_manager.clone()), rules, factories, key_manager) } @@ -382,11 +502,15 @@ mod test { async fn valid_coinbase() { let (builder, rules, factories, key_manager) = get_builder(); let p = TestParams::new(&key_manager).await; + let wallet_payment_address = TariAddress::default(); let builder = builder .with_block_height(42) .with_fees(145 * uT) .with_spend_key_id(p.spend_key_id.clone()) - .with_script_key_id(p.script_key_id); + .with_encryption_key_id(TariKeyId::default()) + .with_sender_offset_key_id(p.sender_offset_key_id) + .with_script_key_id(p.script_key_id) + .with_script(one_sided_payment_script(wallet_payment_address.public_key())); let (tx, _unblinded_output) = builder .build(rules.consensus_constants(42), rules.emission_schedule()) .await @@ -428,11 +552,15 @@ mod test { let (builder, rules, factories, key_manager) = get_builder(); let p = TestParams::new(&key_manager).await; let block_reward = rules.emission_schedule().block_reward(42) + 145 * uT; + let wallet_payment_address = TariAddress::default(); let builder = builder .with_block_height(42) .with_fees(145 * uT) .with_spend_key_id(p.spend_key_id) - .with_script_key_id(p.script_key_id); + .with_encryption_key_id(TariKeyId::default()) + .with_sender_offset_key_id(p.sender_offset_key_id) + .with_script_key_id(p.script_key_id) + .with_script(one_sided_payment_script(wallet_payment_address.public_key())); let (mut tx, _) = builder .build(rules.consensus_constants(42), rules.emission_schedule()) .await @@ -458,11 +586,15 @@ mod test { let p = TestParams::new(&key_manager).await; // We just want some small amount here. let missing_fee = rules.emission_schedule().block_reward(4200000) + (2 * uT); + let wallet_payment_address = TariAddress::default(); let builder = builder .with_block_height(42) .with_fees(1 * uT) .with_spend_key_id(p.spend_key_id.clone()) - .with_script_key_id(p.script_key_id.clone()); + .with_encryption_key_id(TariKeyId::default()) + .with_sender_offset_key_id(p.sender_offset_key_id.clone()) + .with_script_key_id(p.script_key_id.clone()) + .with_script(one_sided_payment_script(wallet_payment_address.public_key())); let (mut tx, _) = builder .build(rules.consensus_constants(0), rules.emission_schedule()) .await @@ -473,7 +605,10 @@ mod test { .with_block_height(4200000) .with_fees(1 * uT) .with_spend_key_id(p.spend_key_id.clone()) - .with_script_key_id(p.script_key_id.clone()); + .with_encryption_key_id(TariKeyId::default()) + .with_sender_offset_key_id(p.sender_offset_key_id.clone()) + .with_script_key_id(p.script_key_id.clone()) + .with_script(one_sided_payment_script(wallet_payment_address.public_key())); let (tx2, _) = builder .build(rules.consensus_constants(0), rules.emission_schedule()) .await @@ -501,7 +636,10 @@ mod test { .with_block_height(42) .with_fees(missing_fee) .with_spend_key_id(p.spend_key_id) - .with_script_key_id(p.script_key_id); + .with_encryption_key_id(TariKeyId::default()) + .with_sender_offset_key_id(p.sender_offset_key_id) + .with_script_key_id(p.script_key_id) + .with_script(one_sided_payment_script(wallet_payment_address.public_key())); let (tx3, _) = builder .build(rules.consensus_constants(0), rules.emission_schedule()) .await @@ -517,11 +655,18 @@ mod test { .is_ok()); } use tari_key_manager::key_manager_service::KeyManagerInterface; + use tari_script::one_sided_payment_script; use crate::transactions::{ aggregated_body::AggregateBody, - key_manager::{TransactionKeyManagerBranch, TransactionKeyManagerInterface, TxoStage}, - test_helpers::{create_test_core_key_manager_with_memory_db, TestKeyManager}, + key_manager::{ + create_memory_db_key_manager, + MemoryDbKeyManager, + TariKeyId, + TransactionKeyManagerBranch, + TransactionKeyManagerInterface, + TxoStage, + }, transaction_components::TransactionKernelVersion, }; @@ -535,11 +680,15 @@ mod test { let p = TestParams::new(&key_manager).await; // We just want some small amount here. let missing_fee = rules.emission_schedule().block_reward(4200000) + (2 * uT); + let wallet_payment_address = TariAddress::default(); let builder = builder .with_block_height(42) .with_fees(1 * uT) .with_spend_key_id(p.spend_key_id.clone()) - .with_script_key_id(p.script_key_id.clone()); + .with_encryption_key_id(TariKeyId::default()) + .with_sender_offset_key_id(p.sender_offset_key_id.clone()) + .with_script_key_id(p.script_key_id.clone()) + .with_script(one_sided_payment_script(wallet_payment_address.public_key())); let (mut tx, _) = builder .build(rules.consensus_constants(0), rules.emission_schedule()) .await @@ -552,7 +701,10 @@ mod test { .with_block_height(4200000) .with_fees(1 * uT) .with_spend_key_id(p.spend_key_id.clone()) - .with_script_key_id(p.script_key_id); + .with_encryption_key_id(TariKeyId::default()) + .with_sender_offset_key_id(p.sender_offset_key_id) + .with_script_key_id(p.script_key_id) + .with_script(one_sided_payment_script(wallet_payment_address.public_key())); let (tx2, output) = builder .build(rules.consensus_constants(0), rules.emission_schedule()) .await diff --git a/base_layer/core/src/transactions/key_manager/error.rs b/base_layer/core/src/transactions/key_manager/error.rs index 71f668fc4cf..ef92873c280 100644 --- a/base_layer/core/src/transactions/key_manager/error.rs +++ b/base_layer/core/src/transactions/key_manager/error.rs @@ -20,10 +20,10 @@ // 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. - use tari_crypto::signatures::CommitmentAndPublicKeySignatureError; -use thiserror::Error; use tari_key_manager::error::KeyManagerError; +use thiserror::Error; + use crate::transactions::transaction_components::TransactionError; #[derive(Debug, Error, PartialEq)] @@ -31,8 +31,13 @@ pub enum CoreKeyManagerError { #[error("KeyManagerError: `{0}`")] KeyManagerError(#[from] KeyManagerError), #[error("Error generating Commitment and PublicKey signature: `{0}`")] - CommitmentAndPublicKeySignatureError(#[from] CommitmentAndPublicKeySignatureError), + CommitmentAndPublicKeySignatureError(String), #[error("Transaction error: `{0}`")] TransactionError(#[from] TransactionError), +} -} \ No newline at end of file +impl From for CoreKeyManagerError { + fn from(err: CommitmentAndPublicKeySignatureError) -> Self { + CoreKeyManagerError::CommitmentAndPublicKeySignatureError(err.to_string()) + } +} diff --git a/base_layer/core/src/transactions/key_manager/memory_db_key_manager.rs b/base_layer/core/src/transactions/key_manager/memory_db_key_manager.rs new file mode 100644 index 00000000000..35e6776036c --- /dev/null +++ b/base_layer/core/src/transactions/key_manager/memory_db_key_manager.rs @@ -0,0 +1,64 @@ +// Copyright 2023 The Tari Project +// +// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +// following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following +// disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the +// following disclaimer in the documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote +// products derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// 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. + +use std::{iter, mem::size_of}; + +use chacha20poly1305::{Key, KeyInit, XChaCha20Poly1305}; +use rand::{distributions::Alphanumeric, rngs::OsRng, Rng, RngCore}; +use tari_common_sqlite::connection::{DbConnection, DbConnectionUrl}; +use tari_key_manager::{ + cipher_seed::CipherSeed, + key_manager_service::storage::{database::KeyManagerDatabase, sqlite_db::KeyManagerSqliteDatabase}, +}; + +use crate::transactions::{key_manager::TransactionKeyManagerWrapper, CryptoFactories}; + +pub type MemoryDbKeyManager = TransactionKeyManagerWrapper>; + +fn random_string(len: usize) -> String { + iter::repeat(()) + .map(|_| OsRng.sample(Alphanumeric) as char) + .take(len) + .collect() +} + +pub fn create_memory_db_key_manager_with_range_proof_size(size: usize) -> MemoryDbKeyManager { + let connection = DbConnection::connect_url(&DbConnectionUrl::MemoryShared(random_string(8))).unwrap(); + let cipher = CipherSeed::new(); + + let mut key = [0u8; size_of::()]; + OsRng.fill_bytes(&mut key); + let key_ga = Key::from_slice(&key); + let db_cipher = XChaCha20Poly1305::new(key_ga); + let factory = CryptoFactories::new(size); + + TransactionKeyManagerWrapper::>::new( + cipher, + KeyManagerDatabase::new(KeyManagerSqliteDatabase::init(connection, db_cipher)), + factory, + ) + .unwrap() +} + +pub fn create_memory_db_key_manager() -> MemoryDbKeyManager { + create_memory_db_key_manager_with_range_proof_size(64) +} diff --git a/base_layer/core/src/transactions/key_manager/mod.rs b/base_layer/core/src/transactions/key_manager/mod.rs index afa8aa808e6..2d803f06f06 100644 --- a/base_layer/core/src/transactions/key_manager/mod.rs +++ b/base_layer/core/src/transactions/key_manager/mod.rs @@ -36,4 +36,14 @@ mod initializer; pub use initializer::TransactionKeyManagerInitializer; mod inner; +/// This is a memory database implementation of the `TransactionKeyManager` trait. +mod memory_db_key_manager; pub use inner::TransactionKeyManagerInner; +pub use memory_db_key_manager::{ + create_memory_db_key_manager, + create_memory_db_key_manager_with_range_proof_size, + MemoryDbKeyManager, +}; + +mod error; +pub use error::CoreKeyManagerError; diff --git a/base_layer/core/src/transactions/mod.rs b/base_layer/core/src/transactions/mod.rs index a2dce5b4299..b0a51b8b604 100644 --- a/base_layer/core/src/transactions/mod.rs +++ b/base_layer/core/src/transactions/mod.rs @@ -9,7 +9,7 @@ pub use crypto_factories::CryptoFactories; use tari_crypto::hash_domain; mod coinbase_builder; -pub use coinbase_builder::{CoinbaseBuildError, CoinbaseBuilder}; +pub use coinbase_builder::{generate_coinbase, CoinbaseBuildError, CoinbaseBuilder}; pub mod fee; pub mod tari_amount; diff --git a/base_layer/core/src/transactions/test_helpers.rs b/base_layer/core/src/transactions/test_helpers.rs index 92b6a61ec86..4a4c412626b 100644 --- a/base_layer/core/src/transactions/test_helpers.rs +++ b/base_layer/core/src/transactions/test_helpers.rs @@ -20,21 +20,13 @@ // 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. -use std::{iter, mem::size_of, sync::Arc}; +use std::sync::Arc; -use chacha20poly1305::{Key, KeyInit, XChaCha20Poly1305}; -use rand::{distributions::Alphanumeric, rngs::OsRng, Rng, RngCore}; +use rand::rngs::OsRng; use tari_common::configuration::Network; -use tari_common_sqlite::connection::{DbConnection, DbConnectionUrl}; use tari_common_types::types::{Commitment, PrivateKey, PublicKey, Signature}; use tari_crypto::keys::{PublicKey as PK, SecretKey}; -use tari_key_manager::{ - cipher_seed::CipherSeed, - key_manager_service::{ - storage::{database::KeyManagerDatabase, sqlite_db::KeyManagerSqliteDatabase}, - KeyManagerInterface, - }, -}; +use tari_key_manager::key_manager_service::KeyManagerInterface; use tari_script::{inputs, script, ExecutionStack, TariScript}; use super::transaction_components::{TransactionInputVersion, TransactionOutputVersion}; @@ -46,10 +38,11 @@ use crate::{ crypto_factories::CryptoFactories, fee::Fee, key_manager::{ + create_memory_db_key_manager, + MemoryDbKeyManager, TariKeyId, TransactionKeyManagerBranch, TransactionKeyManagerInterface, - TransactionKeyManagerWrapper, TxoStage, }, tari_amount::MicroMinotari, @@ -71,7 +64,7 @@ use crate::{ }, }; -pub async fn create_test_input(amount: MicroMinotari, maturity: u64, key_manager: &TestKeyManager) -> WalletOutput { +pub async fn create_test_input(amount: MicroMinotari, maturity: u64, key_manager: &MemoryDbKeyManager) -> WalletOutput { let params = TestParams::new(key_manager).await; params .create_input( @@ -106,7 +99,7 @@ pub struct TestParams { } impl TestParams { - pub async fn new(key_manager: &TestKeyManager) -> TestParams { + pub async fn new(key_manager: &MemoryDbKeyManager) -> TestParams { let (spend_key_id, spend_key_pk, script_key_id, script_key_pk) = key_manager.get_next_spend_and_script_key_ids().await.unwrap(); let (sender_offset_key_id, sender_offset_key_pk) = key_manager @@ -150,7 +143,7 @@ impl TestParams { pub async fn create_output( &self, params: UtxoTestParams, - key_manager: &TestKeyManager, + key_manager: &MemoryDbKeyManager, ) -> Result { let version = match params.output_version { Some(v) => v, @@ -182,7 +175,7 @@ impl TestParams { /// Create a random transaction input for the given amount and maturity period. The input's wallet /// parameters are returned. - pub async fn create_input(&self, params: UtxoTestParams, key_manager: &TestKeyManager) -> WalletOutput { + pub async fn create_input(&self, params: UtxoTestParams, key_manager: &MemoryDbKeyManager) -> WalletOutput { self.create_output(params, key_manager).await.unwrap() } @@ -271,7 +264,7 @@ pub fn create_signature(k: PrivateKey, fee: MicroMinotari, lock_height: u64, fea /// Generate a random transaction signature given a key, returning the public key (excess) and the signature. pub async fn create_random_signature_from_secret_key( - key_manager: &TestKeyManager, + key_manager: &MemoryDbKeyManager, secret_key_id: TariKeyId, fee: MicroMinotari, lock_height: u64, @@ -318,7 +311,7 @@ pub async fn create_coinbase_wallet_output( extra: Option>, ) -> WalletOutput { let rules = create_consensus_manager(); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let constants = rules.consensus_constants(height); test_params .create_output( @@ -338,7 +331,7 @@ pub async fn create_wallet_output_with_data( output_features: OutputFeatures, test_params: &TestParams, value: MicroMinotari, - key_manager: &TestKeyManager, + key_manager: &MemoryDbKeyManager, ) -> Result { test_params .create_output( @@ -399,9 +392,9 @@ macro_rules! tx { /// The output of this macro is intended to be used in [spend_utxos]. #[macro_export] macro_rules! txn_schema { - (from: $input:expr, to: $outputs:expr, fee: $fee:expr, lock: $lock:expr, features: $features:expr, input_version: $input_version:expr, output_version: $output_version:expr) => {{ + (from: $inputs:expr, to: $outputs:expr, fee: $fee:expr, lock: $lock:expr, features: $features:expr, input_version: $input_version:expr, output_version: $output_version:expr) => {{ $crate::transactions::test_helpers::TransactionSchema { - from: $input.clone(), + from: $inputs.clone(), to: $outputs.clone(), to_outputs: vec![], fee: $fee, @@ -500,7 +493,7 @@ pub async fn create_tx( input_maturity: u64, output_count: usize, output_features: OutputFeatures, - key_manager: &TestKeyManager, + key_manager: &MemoryDbKeyManager, ) -> std::io::Result<(Transaction, Vec, Vec)> { let (inputs, outputs) = create_wallet_outputs( amount, @@ -527,7 +520,7 @@ pub async fn create_wallet_outputs( output_features: &OutputFeatures, output_script: &TariScript, output_covenant: &Covenant, - key_manager: &TestKeyManager, + key_manager: &MemoryDbKeyManager, ) -> std::io::Result<(Vec, Vec<(WalletOutput, TariKeyId)>)> { let weighting = TransactionWeight::latest(); // This is a best guess to not underestimate metadata size @@ -604,7 +597,7 @@ pub async fn create_transaction_with( fee_per_gram: MicroMinotari, inputs: Vec, outputs: Vec<(WalletOutput, TariKeyId)>, - key_manager: &TestKeyManager, + key_manager: &MemoryDbKeyManager, ) -> Transaction { let rules = ConsensusManager::builder(Network::LocalNet).build().unwrap(); let constants = rules.consensus_constants(0).clone(); @@ -639,7 +632,10 @@ pub async fn create_transaction_with( /// You only need to provide the wallet outputs to spend. This function will calculate the commitment for you. /// This is obviously less efficient, but is offered as a convenience. /// The output features will be applied to every output -pub async fn spend_utxos(schema: TransactionSchema, key_manager: &TestKeyManager) -> (Transaction, Vec) { +pub async fn spend_utxos( + schema: TransactionSchema, + key_manager: &MemoryDbKeyManager, +) -> (Transaction, Vec) { let (mut stx_protocol, outputs) = create_stx_protocol(schema, key_manager).await; stx_protocol.finalize(key_manager).await.unwrap(); let txn = stx_protocol.get_transaction().unwrap().clone(); @@ -649,7 +645,7 @@ pub async fn spend_utxos(schema: TransactionSchema, key_manager: &TestKeyManager #[allow(clippy::too_many_lines)] pub async fn create_stx_protocol( schema: TransactionSchema, - key_manager: &TestKeyManager, + key_manager: &MemoryDbKeyManager, ) -> (SenderTransactionProtocol, Vec) { let mut outputs = Vec::with_capacity(schema.to.len()); let stx_builder = create_stx_protocol_internal(schema, key_manager, &mut outputs).await; @@ -664,9 +660,9 @@ pub async fn create_stx_protocol( #[allow(clippy::too_many_lines)] pub async fn create_stx_protocol_internal( schema: TransactionSchema, - key_manager: &TestKeyManager, + key_manager: &MemoryDbKeyManager, outputs: &mut Vec, -) -> SenderTransactionInitializer { +) -> SenderTransactionInitializer { let constants = ConsensusManager::builder(Network::LocalNet) .build() .unwrap() @@ -759,7 +755,10 @@ pub async fn create_stx_protocol_internal( stx_builder } -pub async fn create_coinbase_kernel(spending_key_id: &TariKeyId, key_manager: &TestKeyManager) -> TransactionKernel { +pub async fn create_coinbase_kernel( + spending_key_id: &TariKeyId, + key_manager: &MemoryDbKeyManager, +) -> TransactionKernel { let kernel_version = TransactionKernelVersion::get_current_version(); let kernel_features = KernelFeatures::COINBASE_KERNEL; let kernel_message = @@ -808,7 +807,7 @@ pub fn create_test_kernel(fee: MicroMinotari, lock_height: u64, features: Kernel /// Create a new UTXO for the specified value and return the output and spending key pub async fn create_utxo( value: MicroMinotari, - key_manager: &TestKeyManager, + key_manager: &MemoryDbKeyManager, features: &OutputFeatures, script: &TariScript, covenant: &Covenant, @@ -878,7 +877,7 @@ pub async fn create_utxo( pub async fn schema_to_transaction( txns: &[TransactionSchema], - key_manager: &TestKeyManager, + key_manager: &MemoryDbKeyManager, ) -> (Vec>, Vec) { let mut txs = Vec::new(); let mut utxos = Vec::new(); @@ -890,34 +889,3 @@ pub async fn schema_to_transaction( (txs, utxos) } - -pub type TestKeyManager = TransactionKeyManagerWrapper>; - -fn random_string(len: usize) -> String { - iter::repeat(()) - .map(|_| OsRng.sample(Alphanumeric) as char) - .take(len) - .collect() -} - -pub fn create_test_core_key_manager_with_memory_db_with_range_proof_size(size: usize) -> TestKeyManager { - let connection = DbConnection::connect_url(&DbConnectionUrl::MemoryShared(random_string(8))).unwrap(); - let cipher = CipherSeed::new(); - - let mut key = [0u8; size_of::()]; - OsRng.fill_bytes(&mut key); - let key_ga = Key::from_slice(&key); - let db_cipher = XChaCha20Poly1305::new(key_ga); - let factory = CryptoFactories::new(size); - - TransactionKeyManagerWrapper::>::new( - cipher, - KeyManagerDatabase::new(KeyManagerSqliteDatabase::init(connection, db_cipher)), - factory, - ) - .unwrap() -} - -pub fn create_test_core_key_manager_with_memory_db() -> TestKeyManager { - create_test_core_key_manager_with_memory_db_with_range_proof_size(64) -} diff --git a/base_layer/core/src/transactions/transaction_components/output_type.rs b/base_layer/core/src/transactions/transaction_components/output_type.rs index 59a84d49a05..9eb15402edb 100644 --- a/base_layer/core/src/transactions/transaction_components/output_type.rs +++ b/base_layer/core/src/transactions/transaction_components/output_type.rs @@ -45,7 +45,7 @@ use serde_repr::{Deserialize_repr, Serialize_repr}; )] #[repr(u8)] pub enum OutputType { - /// An standard non-coinbase output. + /// An standard output. Standard = 0, /// Output is a coinbase output, must not be spent until maturity. Coinbase = 1, diff --git a/base_layer/core/src/transactions/transaction_components/test.rs b/base_layer/core/src/transactions/transaction_components/test.rs index dfb5a993af8..3265bfe9e8c 100644 --- a/base_layer/core/src/transactions/transaction_components/test.rs +++ b/base_layer/core/src/transactions/transaction_components/test.rs @@ -37,15 +37,14 @@ use crate::{ consensus::ConsensusManager, transactions::{ aggregated_body::AggregateBody, - key_manager::TransactionKeyManagerInterface, + key_manager::{ + create_memory_db_key_manager, + create_memory_db_key_manager_with_range_proof_size, + TransactionKeyManagerInterface, + }, tari_amount::{uT, MicroMinotari, T}, test_helpers, - test_helpers::{ - create_test_core_key_manager_with_memory_db, - create_test_core_key_manager_with_memory_db_with_range_proof_size, - TestParams, - UtxoTestParams, - }, + test_helpers::{TestParams, UtxoTestParams}, transaction_components::{transaction_output::batch_verify_range_proofs, EncryptedData, OutputFeatures}, transaction_protocol::TransactionProtocolError, CryptoFactories, @@ -56,7 +55,7 @@ use crate::{ #[tokio::test] async fn input_and_output_and_wallet_output_hash_match() { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let test_params = TestParams::new(&key_manager).await; let i = test_params @@ -80,7 +79,7 @@ fn test_smt_hashes() { #[tokio::test] async fn key_manager_input() { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let test_params = TestParams::new(&key_manager).await; let i = test_params @@ -105,7 +104,7 @@ async fn key_manager_input() { #[tokio::test] async fn range_proof_verification() { let factories = CryptoFactories::new(32); - let key_manager = create_test_core_key_manager_with_memory_db_with_range_proof_size(32); + let key_manager = create_memory_db_key_manager_with_range_proof_size(32); // Directly test the tx_output verification let test_params_1 = TestParams::new(&key_manager).await; let test_params_2 = TestParams::new(&key_manager).await; @@ -165,7 +164,7 @@ async fn range_proof_verification() { #[tokio::test] async fn range_proof_verification_batch() { let factories = CryptoFactories::new(64); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let wallet_output1 = TestParams::new(&key_manager) .await .create_output( @@ -256,7 +255,7 @@ async fn range_proof_verification_batch() { #[tokio::test] async fn sender_signature_verification() { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let test_params = TestParams::new(&key_manager).await; let wallet_output = test_params .create_output(Default::default(), &key_manager) @@ -383,7 +382,7 @@ fn check_timelocks() { #[tokio::test] async fn test_validate_internal_consistency() { let features = OutputFeatures { ..Default::default() }; - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let (tx, _, _) = test_helpers::create_tx(5000.into(), 3.into(), 1, 2, 1, 4, features, &key_manager) .await .expect("Failed to create tx"); @@ -396,7 +395,7 @@ async fn test_validate_internal_consistency() { #[tokio::test] #[allow(clippy::identity_op)] async fn check_cut_through() { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let (tx, _, outputs) = test_helpers::create_tx(50000000.into(), 3.into(), 1, 2, 1, 2, Default::default(), &key_manager) .await @@ -453,7 +452,7 @@ async fn check_cut_through() { #[tokio::test] async fn check_duplicate_inputs_outputs() { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let (tx, _, _outputs) = test_helpers::create_tx(50000000.into(), 3.into(), 1, 2, 1, 2, Default::default(), &key_manager) .await @@ -476,7 +475,7 @@ async fn check_duplicate_inputs_outputs() { #[tokio::test] async fn inputs_not_malleable() { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let (inputs, outputs) = test_helpers::create_wallet_outputs( 5000.into(), 1, @@ -511,7 +510,7 @@ async fn inputs_not_malleable() { #[tokio::test] async fn test_output_recover_openings() { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let test_params = TestParams::new(&key_manager).await; let v = MicroMinotari::from(42); @@ -543,14 +542,17 @@ mod validate_internal_consistency { use super::*; use crate::{ covenants::{BaseLayerCovenantsDomain, COVENANTS_FIELD_HASHER_LABEL}, - transactions::test_helpers::{create_transaction_with, create_wallet_outputs, TestKeyManager}, + transactions::{ + key_manager::{create_memory_db_key_manager, MemoryDbKeyManager}, + test_helpers::{create_transaction_with, create_wallet_outputs}, + }, }; async fn test_case( input_params: &UtxoTestParams, utxo_params: &UtxoTestParams, height: u64, - key_manager: &TestKeyManager, + key_manager: &MemoryDbKeyManager, ) -> Result<(), TransactionProtocolError> { let (mut inputs, outputs) = create_wallet_outputs( 100 * T, @@ -584,7 +586,7 @@ mod validate_internal_consistency { //---------------------------------- Case1 - PASS --------------------------------------------// let covenant = covenant!(fields_preserved(@fields( @field::covenant))); let features = OutputFeatures { ..Default::default() }; - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); test_case( &UtxoTestParams { features: features.clone(), diff --git a/base_layer/core/src/transactions/transaction_components/transaction_output.rs b/base_layer/core/src/transactions/transaction_components/transaction_output.rs index 5b4f24fd05d..0b35a48bf72 100644 --- a/base_layer/core/src/transactions/transaction_components/transaction_output.rs +++ b/base_layer/core/src/transactions/transaction_components/transaction_output.rs @@ -589,9 +589,9 @@ mod test { use super::{batch_verify_range_proofs, TransactionOutput}; use crate::transactions::{ - key_manager::TransactionKeyManagerInterface, + key_manager::{create_memory_db_key_manager, MemoryDbKeyManager, TransactionKeyManagerInterface}, tari_amount::MicroMinotari, - test_helpers::{create_test_core_key_manager_with_memory_db, TestKeyManager, TestParams, UtxoTestParams}, + test_helpers::{TestParams, UtxoTestParams}, transaction_components::{OutputFeatures, RangeProofType}, CryptoFactories, }; @@ -599,7 +599,7 @@ mod test { #[tokio::test] async fn it_builds_correctly() { let factories = CryptoFactories::default(); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let test_params = TestParams::new(&key_manager).await; let value = MicroMinotari(10); @@ -623,7 +623,7 @@ mod test { #[tokio::test] async fn it_does_not_verify_incorrect_minimum_value() { let factories = CryptoFactories::default(); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let test_params = TestParams::new(&key_manager).await; let value = MicroMinotari(10); @@ -643,7 +643,7 @@ mod test { #[tokio::test] async fn it_does_batch_verify_correct_minimum_values() { let factories = CryptoFactories::default(); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let test_params = TestParams::new(&key_manager).await; let outputs = [ @@ -681,7 +681,7 @@ mod test { #[tokio::test] async fn it_does_batch_verify_with_mixed_range_proof_types() { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let factories = CryptoFactories::default(); let test_params = TestParams::new(&key_manager).await; @@ -729,7 +729,7 @@ mod test { #[tokio::test] async fn invalid_revealed_value_proofs_are_blocked() { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let test_params = TestParams::new(&key_manager).await; assert!(create_output( &test_params, @@ -760,7 +760,7 @@ mod test { #[tokio::test] async fn revealed_value_proofs_only_succeed_with_valid_metadata_signatures() { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let test_params = TestParams::new(&key_manager).await; let mut output = create_output( &test_params, @@ -787,7 +787,7 @@ mod test { #[tokio::test] async fn it_does_not_batch_verify_incorrect_minimum_values() { let factories = CryptoFactories::default(); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let test_params = TestParams::new(&key_manager).await; let outputs = [ @@ -818,7 +818,7 @@ mod test { value: MicroMinotari, minimum_value_promise: MicroMinotari, range_proof_type: RangeProofType, - key_manager: &TestKeyManager, + key_manager: &MemoryDbKeyManager, ) -> Result { let utxo = test_params .create_output( @@ -845,7 +845,7 @@ mod test { value: MicroMinotari, minimum_value_promise: MicroMinotari, range_proof_type: RangeProofType, - key_manager: &TestKeyManager, + key_manager: &MemoryDbKeyManager, ) -> TransactionOutput { // we need first to create a valid minimum value, regardless of the minimum_value_promise // because this test function should allow creating an invalid proof for later testing diff --git a/base_layer/core/src/transactions/transaction_components/wallet_output_builder.rs b/base_layer/core/src/transactions/transaction_components/wallet_output_builder.rs index 3ab34ac40ed..2eaf9ebb9ac 100644 --- a/base_layer/core/src/transactions/transaction_components/wallet_output_builder.rs +++ b/base_layer/core/src/transactions/transaction_components/wallet_output_builder.rs @@ -229,14 +229,11 @@ mod test { use tari_key_manager::key_manager_service::KeyManagerInterface; use super::*; - use crate::transactions::{ - key_manager::TransactionKeyManagerBranch, - test_helpers::create_test_core_key_manager_with_memory_db, - }; + use crate::transactions::key_manager::{create_memory_db_key_manager, TransactionKeyManagerBranch}; #[tokio::test] async fn test_try_build() { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let (spending_key_id, _, script_key_id, _) = key_manager.get_next_spend_and_script_key_ids().await.unwrap(); let value = MicroMinotari(100); let kmob = WalletOutputBuilder::new(value, spending_key_id.clone()); @@ -278,7 +275,7 @@ mod test { #[tokio::test] async fn test_partial_metadata_signatures() { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let (spending_key_id, _, script_key_id, _) = key_manager.get_next_spend_and_script_key_ids().await.unwrap(); let value = MicroMinotari(100); let kmob = WalletOutputBuilder::new(value, spending_key_id.clone()); diff --git a/base_layer/core/src/transactions/transaction_protocol/recipient.rs b/base_layer/core/src/transactions/transaction_protocol/recipient.rs index 04c52c66bae..115e5edba8d 100644 --- a/base_layer/core/src/transactions/transaction_protocol/recipient.rs +++ b/base_layer/core/src/transactions/transaction_protocol/recipient.rs @@ -194,9 +194,14 @@ mod test { test_helpers::create_consensus_constants, transactions::{ crypto_factories::CryptoFactories, - key_manager::{TransactionKeyManagerBranch, TransactionKeyManagerInterface, TxoStage}, + key_manager::{ + create_memory_db_key_manager, + TransactionKeyManagerBranch, + TransactionKeyManagerInterface, + TxoStage, + }, tari_amount::*, - test_helpers::{create_test_core_key_manager_with_memory_db, TestParams, UtxoTestParams}, + test_helpers::{TestParams, UtxoTestParams}, transaction_components::{ OutputFeatures, TransactionKernel, @@ -213,7 +218,7 @@ mod test { #[tokio::test] async fn single_round_recipient() { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let factories = CryptoFactories::default(); let sender_test_params = TestParams::new(&key_manager).await; let m = TransactionMetadata::new(MicroMinotari(125), 0); diff --git a/base_layer/core/src/transactions/transaction_protocol/sender.rs b/base_layer/core/src/transactions/transaction_protocol/sender.rs index 8df23ac0a8e..776fe40e282 100644 --- a/base_layer/core/src/transactions/transaction_protocol/sender.rs +++ b/base_layer/core/src/transactions/transaction_protocol/sender.rs @@ -879,14 +879,9 @@ mod test { test_helpers::{create_consensus_constants, create_consensus_rules}, transactions::{ crypto_factories::CryptoFactories, - key_manager::{TransactionKeyManagerBranch, TransactionKeyManagerInterface}, + key_manager::{create_memory_db_key_manager, TransactionKeyManagerBranch, TransactionKeyManagerInterface}, tari_amount::*, - test_helpers::{ - create_test_core_key_manager_with_memory_db, - create_test_input, - create_wallet_output_with_data, - TestParams, - }, + test_helpers::{create_test_input, create_wallet_output_with_data, TestParams}, transaction_components::{ EncryptedData, OutputFeatures, @@ -911,7 +906,7 @@ mod test { #[tokio::test] async fn test_errors() { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let stp = SenderTransactionProtocol { state: SenderState::Failed(TransactionProtocolError::InvalidStateError), }; @@ -956,7 +951,7 @@ mod test { #[tokio::test] async fn test_metadata_signature_finalize() { // Defaults - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); // Sender data let (ephemeral_pubkey_id, ephemeral_pubkey) = key_manager @@ -1045,7 +1040,7 @@ mod test { #[tokio::test] async fn zero_recipients() { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let p1 = TestParams::new(&key_manager).await; let p2 = TestParams::new(&key_manager).await; let input = create_test_input(MicroMinotari(1200), 0, &key_manager).await; @@ -1107,7 +1102,7 @@ mod test { let rules = create_consensus_rules(); let factories = CryptoFactories::default(); // Alice's parameters - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let a_change_key = TestParams::new(&key_manager).await; // Bob's parameters let bob_key = TestParams::new(&key_manager).await; @@ -1212,7 +1207,7 @@ mod test { #[tokio::test] async fn single_recipient_with_change() { let rules = create_consensus_rules(); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let factories = CryptoFactories::default(); // Alice's parameters let alice_key = TestParams::new(&key_manager).await; @@ -1325,7 +1320,7 @@ mod test { #[tokio::test] async fn single_recipient_multiple_inputs_with_change() { let rules = create_consensus_rules(); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let factories = CryptoFactories::default(); // Bob's parameters let bob_key = TestParams::new(&key_manager).await; @@ -1434,7 +1429,7 @@ mod test { #[tokio::test] async fn disallow_fee_larger_than_amount() { // Alice's parameters - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let (utxo_amount, fee_per_gram, amount) = (MicroMinotari(2500), MicroMinotari(10), MicroMinotari(500)); let input = create_test_input(utxo_amount, 0, &key_manager).await; let script = script!(Nop); @@ -1472,7 +1467,7 @@ mod test { #[tokio::test] async fn allow_fee_larger_than_amount() { // Alice's parameters - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let (utxo_amount, fee_per_gram, amount) = (MicroMinotari(2500), MicroMinotari(10), MicroMinotari(500)); let input = create_test_input(utxo_amount, 0, &key_manager).await; let script = script!(Nop); @@ -1511,8 +1506,8 @@ mod test { #[tokio::test] async fn single_recipient_with_rewindable_change_and_receiver_outputs_bulletproofs() { // Alice's parameters - let key_manager_alice = create_test_core_key_manager_with_memory_db(); - let key_manager_bob = create_test_core_key_manager_with_memory_db(); + let key_manager_alice = create_memory_db_key_manager(); + let key_manager_bob = create_memory_db_key_manager(); // Bob's parameters let bob_test_params = TestParams::new(&key_manager_bob).await; let alice_value = MicroMinotari(25000); diff --git a/base_layer/core/src/transactions/transaction_protocol/single_receiver.rs b/base_layer/core/src/transactions/transaction_protocol/single_receiver.rs index 393c2f17486..8fb6feee3fa 100644 --- a/base_layer/core/src/transactions/transaction_protocol/single_receiver.rs +++ b/base_layer/core/src/transactions/transaction_protocol/single_receiver.rs @@ -149,9 +149,9 @@ mod test { covenants::Covenant, test_helpers::create_consensus_constants, transactions::{ - key_manager::TransactionKeyManagerInterface, + key_manager::{create_memory_db_key_manager, TransactionKeyManagerInterface}, tari_amount::*, - test_helpers::{create_test_core_key_manager_with_memory_db, TestParams}, + test_helpers::TestParams, transaction_components::{ EncryptedData, OutputFeatures, @@ -172,7 +172,7 @@ mod test { #[tokio::test] async fn zero_amount_fails() { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let test_params = TestParams::new(&key_manager).await; let consensus_constants = create_consensus_constants(0); let info = SingleRoundSenderData::default(); @@ -204,7 +204,7 @@ mod test { #[tokio::test] async fn invalid_version_fails() { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let test_params = TestParams::new(&key_manager).await; let consensus_constants = create_consensus_constants(0); @@ -250,7 +250,7 @@ mod test { tari_key_manager::key_manager_service::storage::sqlite_db::KeyManagerSqliteDatabase< tari_common_sqlite::connection::DbConnection, >, - > = create_test_core_key_manager_with_memory_db(); + > = create_memory_db_key_manager(); let consensus_constants = create_consensus_constants(0); let m = TransactionMetadata::new(MicroMinotari(100), 0); let test_params = TestParams::new(&key_manager).await; diff --git a/base_layer/core/src/transactions/transaction_protocol/transaction_initializer.rs b/base_layer/core/src/transactions/transaction_protocol/transaction_initializer.rs index 05ff1af532e..4bdb2e36df4 100644 --- a/base_layer/core/src/transactions/transaction_protocol/transaction_initializer.rs +++ b/base_layer/core/src/transactions/transaction_protocol/transaction_initializer.rs @@ -600,14 +600,9 @@ mod test { test_helpers::create_consensus_constants, transactions::{ fee::Fee, + key_manager::create_memory_db_key_manager, tari_amount::*, - test_helpers::{ - create_test_core_key_manager_with_memory_db, - create_test_input, - create_wallet_output_with_data, - TestParams, - UtxoTestParams, - }, + test_helpers::{create_test_input, create_wallet_output_with_data, TestParams, UtxoTestParams}, transaction_components::{OutputFeatures, MAX_TRANSACTION_INPUTS}, transaction_protocol::{sender::SenderState, transaction_initializer::SenderTransactionInitializer}, }, @@ -617,7 +612,7 @@ mod test { #[tokio::test] async fn no_receivers() -> std::io::Result<()> { // Create some inputs - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let p = TestParams::new(&key_manager).await; // Start the builder let builder = SenderTransactionInitializer::new(&create_consensus_constants(0), key_manager.clone()); @@ -694,7 +689,7 @@ mod test { #[tokio::test] async fn no_change_or_receivers() { // Create some inputs - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let p = TestParams::new(&key_manager).await; let input = create_test_input(MicroMinotari(5000), 0, &key_manager).await; let constants = create_consensus_constants(0); @@ -745,7 +740,7 @@ mod test { #[allow(clippy::identity_op)] async fn change_edge_case() { // Create some inputs - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let p = TestParams::new(&key_manager).await; let constants = create_consensus_constants(0); let weighting = constants.transaction_weight_params(); @@ -799,7 +794,7 @@ mod test { #[tokio::test] async fn too_many_inputs() { // Create some inputs - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let p = TestParams::new(&key_manager).await; let output = create_wallet_output_with_data( @@ -831,7 +826,7 @@ mod test { #[tokio::test] async fn fee_too_low() { // Create some inputs - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let p = TestParams::new(&key_manager).await; let tx_fee = p.fee().calculate( MicroMinotari(1), @@ -876,7 +871,7 @@ mod test { #[tokio::test] async fn not_enough_funds() { // Create some inputs - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let p = TestParams::new(&key_manager).await; let input = create_test_input(MicroMinotari(400), 0, &key_manager).await; let script = script!(Nop); @@ -928,7 +923,7 @@ mod test { #[tokio::test] async fn single_recipient() { // Create some inputs - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let p = TestParams::new(&key_manager).await; let input1 = create_test_input(MicroMinotari(2000), 0, &key_manager).await; let input2 = create_test_input(MicroMinotari(3000), 0, &key_manager).await; diff --git a/base_layer/core/src/validation/aggregate_body/aggregate_body_chain_validator.rs b/base_layer/core/src/validation/aggregate_body/aggregate_body_chain_validator.rs index 67c0824c200..81b1e836b6a 100644 --- a/base_layer/core/src/validation/aggregate_body/aggregate_body_chain_validator.rs +++ b/base_layer/core/src/validation/aggregate_body/aggregate_body_chain_validator.rs @@ -140,6 +140,7 @@ fn validate_input_not_pruned( fn validate_input_maturity(body: &AggregateBody, height: u64) -> Result<(), ValidationError> { for input in body.inputs() { + println!("input: {:?}", input); if !input.is_mature_at(height)? { return Err(TransactionError::InputMaturity.into()); } diff --git a/base_layer/core/src/validation/aggregate_body/aggregate_body_internal_validator.rs b/base_layer/core/src/validation/aggregate_body/aggregate_body_internal_validator.rs index 4b4a899eadd..0edff76f0ea 100644 --- a/base_layer/core/src/validation/aggregate_body/aggregate_body_internal_validator.rs +++ b/base_layer/core/src/validation/aggregate_body/aggregate_body_internal_validator.rs @@ -433,8 +433,8 @@ mod test { use crate::{ covenants::Covenant, transactions::{ + key_manager::create_memory_db_key_manager, test_helpers, - test_helpers::create_test_core_key_manager_with_memory_db, transaction_components::{KernelFeatures, OutputFeatures, TransactionInputVersion}, }, }; @@ -499,7 +499,7 @@ mod test { let mut kernel1 = test_helpers::create_test_kernel(0.into(), 0, KernelFeatures::create_burn()); let mut kernel2 = test_helpers::create_test_kernel(0.into(), 0, KernelFeatures::create_burn()); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let (output1, _, _) = test_helpers::create_utxo( 100.into(), &key_manager, @@ -561,7 +561,7 @@ mod test { // Sort the kernels, we'll check that the outputs fail the sorting check kernels.sort(); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let mut outputs = futures::stream::unfold((), |_| async { let (o, _, _) = test_helpers::create_utxo( 100.into(), diff --git a/base_layer/core/src/validation/block_body/block_body_internal_validator.rs b/base_layer/core/src/validation/block_body/block_body_internal_validator.rs index 2357a8988f3..ad75e454985 100644 --- a/base_layer/core/src/validation/block_body/block_body_internal_validator.rs +++ b/base_layer/core/src/validation/block_body/block_body_internal_validator.rs @@ -85,7 +85,6 @@ fn validate_block_specific_checks( warn!(target: LOG_TARGET, "Attempt to validate genesis block"); return Err(ValidationError::ValidatingGenesis); } - check_coinbase_output(block, consensus_manager, factories)?; check_coinbase_output_features(&block.body, constants)?; diff --git a/base_layer/core/src/validation/block_body/test.rs b/base_layer/core/src/validation/block_body/test.rs index 166c0c16251..1906acacacd 100644 --- a/base_layer/core/src/validation/block_body/test.rs +++ b/base_layer/core/src/validation/block_body/test.rs @@ -22,8 +22,9 @@ use std::sync::Arc; use tari_common::configuration::Network; +use tari_common_types::tari_address::TariAddress; use tari_key_manager::key_manager_service::KeyId; -use tari_script::script; +use tari_script::{one_sided_payment_script, script}; use tari_test_utils::unpack_enum; use tokio::time::Instant; @@ -36,7 +37,7 @@ use crate::{ test_helpers::{blockchain::TestBlockchain, BlockSpec}, transactions::{ aggregated_body::AggregateBody, - key_manager::TransactionKeyManagerBranch, + key_manager::{TariKeyId, TransactionKeyManagerBranch}, tari_amount::{uT, T}, test_helpers::schema_to_transaction, transaction_components::TransactionError, @@ -47,13 +48,13 @@ use crate::{ validation::{BlockBodyValidator, ValidationError}, }; -fn setup_with_rules(rules: ConsensusManager, check_rangeproof: bool) -> (TestBlockchain, BlockBodyFullValidator) { - let blockchain = TestBlockchain::create(rules.clone()); +async fn setup_with_rules(rules: ConsensusManager, check_rangeproof: bool) -> (TestBlockchain, BlockBodyFullValidator) { + let blockchain = TestBlockchain::create(rules.clone()).await; let validator = BlockBodyFullValidator::new(rules, check_rangeproof); (blockchain, validator) } -fn setup(check_rangeproof: bool) -> (TestBlockchain, BlockBodyFullValidator) { +async fn setup(check_rangeproof: bool) -> (TestBlockchain, BlockBodyFullValidator) { let rules = ConsensusManager::builder(Network::LocalNet) .add_consensus_constants( ConsensusConstantsBuilder::new(Network::LocalNet) @@ -63,13 +64,13 @@ fn setup(check_rangeproof: bool) -> (TestBlockchain, BlockBodyFullValidator) { ) .build() .unwrap(); - setup_with_rules(rules, check_rangeproof) + setup_with_rules(rules, check_rangeproof).await } #[tokio::test] async fn it_passes_if_large_output_block_is_valid() { // we use this test to benchmark a block with multiple outputs - let (mut blockchain, validator) = setup(false); + let (mut blockchain, validator) = setup(false).await; let (_, coinbase_a) = blockchain.add_next_tip(block_spec!("A")).await.unwrap(); let mut outs = Vec::new(); // create 498 outputs, so we have a block with 500 outputs, 498 + change + coinbase @@ -77,7 +78,7 @@ async fn it_passes_if_large_output_block_is_valid() { outs.push(9000 * uT); } - let schema1 = txn_schema!(from: vec![coinbase_a], to: outs); + let schema1 = txn_schema!(from: vec![coinbase_a.clone()], to: outs); let (txs, _outputs) = schema_to_transaction(&[schema1], &blockchain.km).await; let txs = txs.into_iter().map(|t| Arc::try_unwrap(t).unwrap()).collect::>(); @@ -106,12 +107,41 @@ async fn it_passes_if_large_output_block_is_valid() { println!("finished validating in: {}", finished.as_millis()); } +#[tokio::test] +async fn it_validates_when_a_coinbase_is_spent() { + // we use this test to benchmark a block with multiple outputs + let (mut blockchain, validator) = setup(false).await; + let (_, coinbase_a) = blockchain.add_next_tip(block_spec!("A")).await.unwrap(); + + let schema1 = txn_schema!(from: vec![coinbase_a.clone()], to: vec![9000 * uT]); + let (txs, _outputs) = schema_to_transaction(&[schema1], &blockchain.km).await; + + let txs = txs.into_iter().map(|t| Arc::try_unwrap(t).unwrap()).collect::>(); + let (chain_block, _coinbase_b) = blockchain + .create_next_tip(block_spec!("B",parent: "A", transactions: txs)) + .await; + let (mut block, mmr_roots) = blockchain + .db() + .calculate_mmr_roots(chain_block.block().clone()) + .unwrap(); + block.header.input_mr = mmr_roots.input_mr; + block.header.output_mr = mmr_roots.output_mr; + block.header.output_smt_size = mmr_roots.output_smt_size; + block.header.kernel_mr = mmr_roots.kernel_mr; + block.header.kernel_mmr_size = mmr_roots.kernel_mmr_size; + block.header.validator_node_mr = mmr_roots.validator_node_mr; + block.header.validator_node_size = mmr_roots.validator_node_size; + + let txn = blockchain.db().db_read_access().unwrap(); + assert!(validator.validate_body(&*txn, &block).is_ok()); +} + #[tokio::test] async fn it_passes_if_large_block_is_valid() { // we use this test to benchmark a block with multiple inputs and outputs - let (mut blockchain, validator) = setup(false); + let (mut blockchain, validator) = setup(false).await; let (_, coinbase_a) = blockchain.add_next_tip(block_spec!("A")).await.unwrap(); - let schema1 = txn_schema!(from: vec![coinbase_a], to: vec![5 * T, 5 * T, 5 * T, 5 * T, 5 * T, 5 * T, 5 * T, 5 * T, 5 * T, 5 * T, 5 * T, 5 * T]); + let schema1 = txn_schema!(from: vec![coinbase_a.clone()], to: vec![5 * T, 5 * T, 5 * T, 5 * T, 5 * T, 5 * T, 5 * T, 5 * T, 5 * T, 5 * T, 5 * T, 5 * T]); let (txs, outputs) = schema_to_transaction(&[schema1], &blockchain.km).await; let txs = txs.into_iter().map(|t| Arc::try_unwrap(t).unwrap()).collect::>(); @@ -122,7 +152,7 @@ async fn it_passes_if_large_block_is_valid() { let mut schemas = Vec::new(); for output in outputs { - let new_schema = txn_schema!(from: vec![output], to: vec![1 * T, 1 * T, 1 * T, 1 * T]); + let new_schema = txn_schema!(from: vec![output.clone()], to: vec![1 * T, 1 * T, 1 * T, 1 * T]); schemas.push(new_schema); } let (txs, _) = schema_to_transaction(&schemas, &blockchain.km).await; @@ -145,7 +175,8 @@ async fn it_passes_if_large_block_is_valid() { let txn = blockchain.db().db_read_access().unwrap(); let start = Instant::now(); - assert!(validator.validate_body(&*txn, &block).is_ok()); + validator.validate_body(&*txn, &block).unwrap(); + // assert!(validator.validate_body(&*txn, &block).is_ok()); let finished = start.elapsed(); // this here here for benchmarking purposes. // we can extrapolate full block validation by multiplying the time by 32.9, this we get from the max_weight /weight @@ -155,7 +186,7 @@ async fn it_passes_if_large_block_is_valid() { #[tokio::test] async fn it_passes_if_block_is_valid() { - let (blockchain, validator) = setup(true); + let (blockchain, validator) = setup(true).await; let (chain_block, _) = blockchain.create_next_tip(BlockSpec::default()).await; @@ -177,7 +208,7 @@ async fn it_passes_if_block_is_valid() { #[tokio::test] async fn it_checks_the_coinbase_reward() { - let (blockchain, validator) = setup(true); + let (blockchain, validator) = setup(true).await; let (block, _) = blockchain .create_chained_block(block_spec!("A", parent: "GB", reward: 10 * T, )) @@ -195,18 +226,22 @@ async fn it_checks_the_coinbase_reward() { #[tokio::test] async fn it_allows_multiple_coinbases() { - let (blockchain, validator) = setup(true); + let (blockchain, validator) = setup(true).await; let (mut block, coinbase) = blockchain.create_unmined_block(block_spec!("A1", parent: "GB")).await; let spend_key_id = KeyId::Managed { branch: TransactionKeyManagerBranch::Coinbase.get_branch_key(), index: 42, }; + let wallet_payment_address = TariAddress::default(); let (_, coinbase_output) = CoinbaseBuilder::new(blockchain.km.clone()) .with_block_height(1) .with_fees(0.into()) .with_spend_key_id(spend_key_id.clone()) - .with_script_key_id(spend_key_id) + .with_encryption_key_id(TariKeyId::default()) + .with_sender_offset_key_id(TariKeyId::default()) + .with_script_key_id(TariKeyId::default()) + .with_script(one_sided_payment_script(wallet_payment_address.public_key())) .build_with_reward(blockchain.rules().consensus_constants(1), coinbase.value) .await .unwrap(); @@ -231,11 +266,14 @@ async fn it_allows_multiple_coinbases() { #[tokio::test] async fn it_checks_duplicate_kernel() { - let (mut blockchain, validator) = setup(true); + let (mut blockchain, validator) = setup(true).await; let (_, coinbase_a) = blockchain.add_next_tip(block_spec!("A")).await.unwrap(); - let (txs, _) = - schema_to_transaction(&[txn_schema!(from: vec![coinbase_a], to: vec![50 * T])], &blockchain.km).await; + let (txs, _) = schema_to_transaction( + &[txn_schema!(from: vec![coinbase_a.clone()], to: vec![50 * T])], + &blockchain.km, + ) + .await; blockchain .add_next_tip(block_spec!("1", transactions: txs.iter().map(|t| (**t).clone()).collect())) @@ -255,7 +293,7 @@ async fn it_checks_duplicate_kernel() { #[tokio::test] async fn it_checks_double_spends() { - let (mut blockchain, validator) = setup(true); + let (mut blockchain, validator) = setup(true).await; let (_, coinbase_a) = blockchain.add_next_tip(block_spec!("A")).await.unwrap(); let (txs, _) = schema_to_transaction( @@ -269,8 +307,11 @@ async fn it_checks_double_spends() { .await .unwrap(); // lets create a new transction from the same input - let (txs2, _) = - schema_to_transaction(&[txn_schema!(from: vec![coinbase_a], to: vec![50 * T])], &blockchain.km).await; + let (txs2, _) = schema_to_transaction( + &[txn_schema!(from: vec![coinbase_a.clone()], to: vec![50 * T])], + &blockchain.km, + ) + .await; let (block, _) = blockchain .create_next_tip( BlockSpec::new() @@ -285,10 +326,10 @@ async fn it_checks_double_spends() { #[tokio::test] async fn it_checks_input_maturity() { - let (mut blockchain, validator) = setup(true); + let (mut blockchain, validator) = setup(true).await; let (_, coinbase_a) = blockchain.add_next_tip(block_spec!("A")).await.unwrap(); - let mut schema = txn_schema!(from: vec![coinbase_a], to: vec![50 * T]); + let mut schema = txn_schema!(from: vec![coinbase_a.clone()], to: vec![50 * T]); schema.from[0].features.maturity = 100; let (txs, _) = schema_to_transaction(&[schema], &blockchain.km).await; @@ -310,11 +351,11 @@ async fn it_checks_input_maturity() { #[tokio::test] async fn it_checks_txo_sort_order() { - let (mut blockchain, validator) = setup(true); + let (mut blockchain, validator) = setup(true).await; let (_, coinbase_a) = blockchain.add_next_tip(block_spec!("A")).await.unwrap(); - let schema1 = txn_schema!(from: vec![coinbase_a], to: vec![50 * T, 12 * T]); + let schema1 = txn_schema!(from: vec![coinbase_a.clone()], to: vec![50 * T, 12 * T]); let (txs, _) = schema_to_transaction(&[schema1], &blockchain.km).await; let txs = txs.into_iter().map(|t| Arc::try_unwrap(t).unwrap()).collect::>(); @@ -343,11 +384,11 @@ async fn it_limits_the_script_byte_size() { ) .build() .unwrap(); - let (mut blockchain, validator) = setup_with_rules(rules, true); + let (mut blockchain, validator) = setup_with_rules(rules, true).await; let (_, coinbase_a) = blockchain.add_next_tip(block_spec!("A")).await.unwrap(); - let mut schema1 = txn_schema!(from: vec![coinbase_a], to: vec![50 * T, 12 * T]); + let mut schema1 = txn_schema!(from: vec![coinbase_a.clone()], to: vec![50 * T, 12 * T]); schema1.script = script!(Nop Nop Nop); let (txs, _) = schema_to_transaction(&[schema1], &blockchain.km).await; let txs = txs.into_iter().map(|t| Arc::try_unwrap(t).unwrap()).collect::>(); @@ -368,11 +409,11 @@ async fn it_rejects_invalid_input_metadata() { ) .build() .unwrap(); - let (mut blockchain, validator) = setup_with_rules(rules, true); + let (mut blockchain, validator) = setup_with_rules(rules.clone(), true).await; let (_, coinbase_a) = blockchain.add_next_tip(block_spec!("A")).await.unwrap(); - let mut schema1 = txn_schema!(from: vec![coinbase_a], to: vec![50 * T, 12 * T]); + let mut schema1 = txn_schema!(from: vec![coinbase_a.clone()], to: vec![50 * T, 12 * T]); schema1.from[0].sender_offset_public_key = Default::default(); let (txs, _) = schema_to_transaction(&[schema1], &blockchain.km).await; let txs = txs.into_iter().map(|t| Arc::try_unwrap(t).unwrap()).collect::>(); @@ -385,10 +426,10 @@ async fn it_rejects_invalid_input_metadata() { #[tokio::test] async fn it_rejects_zero_conf_double_spends() { - let (mut blockchain, validator) = setup(true); + let (mut blockchain, validator) = setup(true).await; let (_, coinbase) = blockchain.append(block_spec!("1", parent: "GB")).await.unwrap(); - let schema = txn_schema!(from: vec![coinbase], to: vec![201 * T]); + let schema = txn_schema!(from: vec![coinbase.clone()], to: vec![201 * T]); let (initial_tx, outputs) = schema_to_transaction(&[schema], &blockchain.km).await; let schema = txn_schema!(from: vec![outputs[0].clone()], to: vec![200 * T]); @@ -426,12 +467,12 @@ mod body_only { ) .build() .unwrap(); - let mut blockchain = TestBlockchain::create(rules.clone()); + let mut blockchain = TestBlockchain::create(rules.clone()).await; let validator = BlockBodyFullValidator::new(rules, true); let (_, coinbase_a) = blockchain.add_next_tip(block_spec!("A")).await.unwrap(); - let mut schema1 = txn_schema!(from: vec![coinbase_a], to: vec![50 * T, 12 * T]); + let mut schema1 = txn_schema!(from: vec![coinbase_a.clone()], to: vec![50 * T, 12 * T]); schema1.from[0].sender_offset_public_key = Default::default(); let (txs, _) = schema_to_transaction(&[schema1], &blockchain.km).await; let txs = txs.into_iter().map(|t| Arc::try_unwrap(t).unwrap()).collect::>(); @@ -465,11 +506,11 @@ mod orphan_validator { ) .build() .unwrap(); - let mut blockchain = TestBlockchain::create(rules.clone()); + let mut blockchain = TestBlockchain::create(rules.clone()).await; let validator = BlockBodyInternalConsistencyValidator::new(rules, false, CryptoFactories::default()); let (_, coinbase) = blockchain.append(block_spec!("1", parent: "GB")).await.unwrap(); - let schema = txn_schema!(from: vec![coinbase], to: vec![201 * T]); + let schema = txn_schema!(from: vec![coinbase.clone()], to: vec![201 * T]); let (initial_tx, outputs) = schema_to_transaction(&[schema], &blockchain.km).await; let schema = txn_schema!(from: vec![outputs[0].clone()], to: vec![200 * T]); @@ -503,11 +544,11 @@ mod orphan_validator { ) .build() .unwrap(); - let mut blockchain = TestBlockchain::create(rules.clone()); + let mut blockchain = TestBlockchain::create(rules.clone()).await; let validator = BlockBodyInternalConsistencyValidator::new(rules, false, CryptoFactories::default()); let (_, coinbase) = blockchain.append(block_spec!("1", parent: "GB")).await.unwrap(); - let schema = txn_schema!(from: vec![coinbase], to: vec![201 * T]); + let schema = txn_schema!(from: vec![coinbase.clone()], to: vec![201 * T]); let (tx, _) = schema_to_transaction(&[schema], &blockchain.km).await; let transactions = tx.into_iter().map(|b| Arc::try_unwrap(b).unwrap()).collect::>(); @@ -531,11 +572,11 @@ mod orphan_validator { ) .build() .unwrap(); - let mut blockchain = TestBlockchain::create(rules.clone()); + let mut blockchain = TestBlockchain::create(rules.clone()).await; let validator = BlockBodyInternalConsistencyValidator::new(rules, false, CryptoFactories::default()); let (_, coinbase) = blockchain.append(block_spec!("1", parent: "GB")).await.unwrap(); - let schema = txn_schema!(from: vec![coinbase], to: vec![201 * T]); + let schema = txn_schema!(from: vec![coinbase.clone()], to: vec![201 * T]); let (tx, _) = schema_to_transaction(&[schema], &blockchain.km).await; let transactions = tx.into_iter().map(|b| Arc::try_unwrap(b).unwrap()).collect::>(); diff --git a/base_layer/core/src/validation/helpers.rs b/base_layer/core/src/validation/helpers.rs index 8011f17fafa..aae8d66b25b 100644 --- a/base_layer/core/src/validation/helpers.rs +++ b/base_layer/core/src/validation/helpers.rs @@ -534,17 +534,17 @@ mod test { use super::*; use crate::transactions::{ aggregated_body::AggregateBody, - test_helpers::create_test_core_key_manager_with_memory_db, + key_manager::create_memory_db_key_manager, transaction_components::TransactionError, }; #[tokio::test] async fn it_succeeds_for_valid_coinbase() { let height = 1; - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let test_params = TestParams::new(&key_manager).await; let rules = test_helpers::create_consensus_manager(); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let coinbase = block_on(test_helpers::create_coinbase_wallet_output(&test_params, height, None)); let coinbase_output = coinbase.to_transaction_output(&key_manager).await.unwrap(); let coinbase_kernel = test_helpers::create_coinbase_kernel(&coinbase.spending_key_id, &key_manager).await; @@ -560,7 +560,7 @@ mod test { #[tokio::test] async fn it_returns_error_for_invalid_coinbase_maturity() { let height = 1; - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let test_params = TestParams::new(&key_manager).await; let rules = test_helpers::create_consensus_manager(); let mut coinbase = test_helpers::create_coinbase_wallet_output(&test_params, height, None).await; @@ -582,7 +582,7 @@ mod test { #[tokio::test] async fn it_returns_error_for_invalid_coinbase_reward() { let height = 1; - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let test_params = TestParams::new(&key_manager).await; let rules = test_helpers::create_consensus_manager(); let mut coinbase = test_helpers::create_coinbase_wallet_output(&test_params, height, None).await; diff --git a/base_layer/core/src/validation/test.rs b/base_layer/core/src/validation/test.rs index 2a8166aeb40..7ac7af1d496 100644 --- a/base_layer/core/src/validation/test.rs +++ b/base_layer/core/src/validation/test.rs @@ -36,13 +36,9 @@ use crate::{ proof_of_work::AchievedTargetDifficulty, test_helpers::{blockchain::create_store_with_consensus, create_chain_header}, transactions::{ - key_manager::TxoStage, + key_manager::{create_memory_db_key_manager, TxoStage}, tari_amount::{uT, MicroMinotari}, - test_helpers::{ - create_random_signature_from_secret_key, - create_test_core_key_manager_with_memory_db, - create_utxo, - }, + test_helpers::{create_random_signature_from_secret_key, create_utxo}, transaction_components::{KernelBuilder, KernelFeatures, OutputFeatures, TransactionKernel}, CryptoFactories, }, @@ -177,7 +173,7 @@ async fn chain_balance_validation() { let consensus_manager = ConsensusManagerBuilder::new(Network::Esmeralda).build().unwrap(); let genesis = consensus_manager.get_genesis_block(); let faucet_value = 5000 * uT; - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let (faucet_utxo, faucet_key_id, _) = create_utxo( faucet_value, &key_manager, @@ -360,7 +356,7 @@ async fn chain_balance_validation_burned() { let consensus_manager = ConsensusManagerBuilder::new(Network::Esmeralda).build().unwrap(); let genesis = consensus_manager.get_genesis_block(); let faucet_value = 5000 * uT; - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let (faucet_utxo, faucet_key_id, _) = create_utxo( faucet_value, &key_manager, @@ -512,16 +508,13 @@ async fn chain_balance_validation_burned() { mod transaction_validator { use super::*; use crate::{ - transactions::{ - test_helpers::create_test_core_key_manager_with_memory_db, - transaction_components::{OutputType, TransactionError}, - }, + transactions::transaction_components::{OutputType, TransactionError}, validation::transaction::TransactionInternalConsistencyValidator, }; #[tokio::test] async fn it_rejects_coinbase_outputs() { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let consensus_manager = ConsensusManagerBuilder::new(Network::LocalNet).build().unwrap(); let db = create_store_with_consensus(consensus_manager.clone()); let factories = CryptoFactories::default(); @@ -543,7 +536,7 @@ mod transaction_validator { #[tokio::test] async fn coinbase_extra_must_be_empty() { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let consensus_manager = ConsensusManagerBuilder::new(Network::LocalNet).build().unwrap(); let db = create_store_with_consensus(consensus_manager.clone()); let factories = CryptoFactories::default(); diff --git a/base_layer/core/tests/chain_storage_tests/chain_storage.rs b/base_layer/core/tests/chain_storage_tests/chain_storage.rs index c6893dbb5c3..c5e35ff2160 100644 --- a/base_layer/core/tests/chain_storage_tests/chain_storage.rs +++ b/base_layer/core/tests/chain_storage_tests/chain_storage.rs @@ -1920,7 +1920,7 @@ fn test_fails_validation() { let mut blocks = vec![block0]; let mut outputs = vec![vec![]]; - let schemas = vec![txn_schema!(from: vec![output], to: vec![2 * T, 500_000 * uT])]; + let schemas = vec![txn_schema!(from: vec![output.clone()], to: vec![2 * T, 500_000 * uT])]; let err = generate_new_block_with_achieved_difficulty( &mut store, &mut blocks, diff --git a/base_layer/core/tests/helpers/block_builders.rs b/base_layer/core/tests/helpers/block_builders.rs index 3a7407e7476..be2afeca9e2 100644 --- a/base_layer/core/tests/helpers/block_builders.rs +++ b/base_layer/core/tests/helpers/block_builders.rs @@ -35,9 +35,9 @@ use tari_core::{ consensus::{emission::Emission, ConsensusConstants, ConsensusManager}, proof_of_work::{sha3x_difficulty, AccumulatedDifficulty, AchievedTargetDifficulty, Difficulty}, transactions::{ - key_manager::{TransactionKeyManagerBranch, TransactionKeyManagerInterface, TxoStage}, + key_manager::{MemoryDbKeyManager, TransactionKeyManagerBranch, TransactionKeyManagerInterface, TxoStage}, tari_amount::MicroMinotari, - test_helpers::{create_wallet_output_with_data, spend_utxos, TestKeyManager, TestParams, TransactionSchema}, + test_helpers::{create_wallet_output_with_data, spend_utxos, TestParams, TransactionSchema}, transaction_components::{ KernelBuilder, KernelFeatures, @@ -61,7 +61,7 @@ pub async fn create_coinbase( value: MicroMinotari, maturity_height: u64, extra: Option>, - key_manager: &TestKeyManager, + key_manager: &MemoryDbKeyManager, ) -> (TransactionOutput, TransactionKernel, WalletOutput) { let p = TestParams::new(key_manager).await; let public_exess = key_manager.get_public_key_at_key_id(&p.spend_key_id).await.unwrap(); @@ -117,7 +117,7 @@ pub async fn create_coinbase( async fn genesis_template( coinbase_value: MicroMinotari, consensus_constants: &ConsensusConstants, - key_manager: &TestKeyManager, + key_manager: &MemoryDbKeyManager, ) -> (NewBlockTemplate, WalletOutput) { let header = BlockHeader::new(consensus_constants.blockchain_version()); let (utxo, kernel, output) = create_coinbase( @@ -164,7 +164,7 @@ fn print_new_genesis_block_values() { /// value, and the maturity is zero. pub async fn create_genesis_block( consensus_constants: &ConsensusConstants, - key_manager: &TestKeyManager, + key_manager: &MemoryDbKeyManager, ) -> (ChainBlock, WalletOutput) { create_genesis_block_with_coinbase_value( consensus_constants.emission_amounts().0, @@ -199,7 +199,7 @@ fn update_genesis_block_mmr_roots(template: NewBlockTemplate) -> Result (ChainBlock, WalletOutput) { let (template, output) = genesis_template(coinbase_value, consensus_constants, key_manager).await; let mut block = update_genesis_block_mmr_roots(template).unwrap(); @@ -226,7 +226,7 @@ pub async fn create_genesis_block_with_coinbase_value( pub async fn create_genesis_block_with_utxos( values: &[MicroMinotari], consensus_constants: &ConsensusConstants, - key_manager: &TestKeyManager, + key_manager: &MemoryDbKeyManager, ) -> (ChainBlock, Vec) { let (mut template, coinbase) = genesis_template(100_000_000.into(), consensus_constants, key_manager).await; let script = script!(Nop); @@ -268,7 +268,7 @@ pub async fn chain_block( prev_block: &Block, transactions: Vec, consensus: &ConsensusManager, - key_manager: &TestKeyManager, + key_manager: &MemoryDbKeyManager, ) -> NewBlockTemplate { let mut header = BlockHeader::from_previous(&prev_block.header); header.version = consensus.consensus_constants(header.height).blockchain_version(); @@ -323,7 +323,7 @@ pub async fn chain_block_with_new_coinbase( transactions: Vec, consensus_manager: &ConsensusManager, extra: Option>, - key_manager: &TestKeyManager, + key_manager: &MemoryDbKeyManager, ) -> (NewBlockTemplate, WalletOutput) { let height = prev_block.height() + 1; let mut coinbase_value = consensus_manager.emission_schedule().block_reward(height); @@ -364,7 +364,7 @@ pub async fn append_block( txns: Vec, consensus: &ConsensusManager, achieved_difficulty: Difficulty, - key_manager: &TestKeyManager, + key_manager: &MemoryDbKeyManager, ) -> Result { append_block_with_coinbase(db, prev_block, txns, consensus, achieved_difficulty, key_manager) .await @@ -379,7 +379,7 @@ pub async fn append_block_with_coinbase( txns: Vec, consensus_manager: &ConsensusManager, achieved_difficulty: Difficulty, - key_manager: &TestKeyManager, + key_manager: &MemoryDbKeyManager, ) -> Result<(ChainBlock, WalletOutput), ChainStorageError> { let height = prev_block.height() + 1; let mut coinbase_value = consensus_manager.emission_schedule().block_reward(height); @@ -423,7 +423,7 @@ pub async fn generate_new_block( outputs: &mut Vec>, schemas: Vec, consensus: &ConsensusManager, - key_manager: &TestKeyManager, + key_manager: &MemoryDbKeyManager, ) -> Result { let coinbase_value = consensus.emission_schedule().block_reward(db.get_height().unwrap() + 1); generate_new_block_with_coinbase(db, blocks, outputs, schemas, coinbase_value, consensus, key_manager).await @@ -437,7 +437,7 @@ pub async fn generate_new_block_with_achieved_difficulty( schemas: Vec, achieved_difficulty: Difficulty, consensus: &ConsensusManager, - key_manager: &TestKeyManager, + key_manager: &MemoryDbKeyManager, ) -> Result { let mut txns = Vec::new(); let mut block_utxos = Vec::new(); @@ -459,7 +459,7 @@ pub async fn generate_new_block_with_coinbase( schemas: Vec, coinbase_value: MicroMinotari, consensus: &ConsensusManager, - key_manager: &TestKeyManager, + key_manager: &MemoryDbKeyManager, ) -> Result { let mut txns = Vec::new(); let mut block_utxos = Vec::new(); @@ -502,7 +502,7 @@ pub async fn generate_block( blocks: &mut Vec, transactions: Vec, consensus: &ConsensusManager, - key_manager: &TestKeyManager, + key_manager: &MemoryDbKeyManager, ) -> Result { let prev_block = blocks.last().unwrap(); let template = chain_block_with_new_coinbase(prev_block, transactions, consensus, None, key_manager) @@ -523,7 +523,7 @@ pub async fn generate_block_with_achieved_difficulty( transactions: Vec, achieved_difficulty: Difficulty, consensus: &ConsensusManager, - key_manager: &TestKeyManager, + key_manager: &MemoryDbKeyManager, ) -> Result { let template = chain_block_with_new_coinbase(blocks.last().unwrap(), transactions, consensus, None, key_manager) .await @@ -571,7 +571,7 @@ pub async fn construct_chained_blocks( block0: ChainBlock, consensus: &ConsensusManager, n: usize, - key_manager: &TestKeyManager, + key_manager: &MemoryDbKeyManager, ) -> Vec { let mut prev_block = block0; let mut blocks = Vec::new(); diff --git a/base_layer/core/tests/helpers/block_malleability.rs b/base_layer/core/tests/helpers/block_malleability.rs index 8eb6888e418..7593c4b416b 100644 --- a/base_layer/core/tests/helpers/block_malleability.rs +++ b/base_layer/core/tests/helpers/block_malleability.rs @@ -66,7 +66,7 @@ async fn check_block_changes_are_detected(field: MerkleMountainRangeField, block let (txs, _) = schema_to_transaction( &[txn_schema!( - from: vec![output], + from: vec![output.clone()], to: vec![50 * T], input_version: TransactionInputVersion::V0, output_version: TransactionOutputVersion::V0 diff --git a/base_layer/core/tests/helpers/database.rs b/base_layer/core/tests/helpers/database.rs index 2bb0ebc03c1..1ec525373c5 100644 --- a/base_layer/core/tests/helpers/database.rs +++ b/base_layer/core/tests/helpers/database.rs @@ -26,7 +26,7 @@ use tari_core::{ blocks::{Block, BlockHeader, NewBlockTemplate}, consensus::{emission::Emission, ConsensusManager}, proof_of_work::Difficulty, - transactions::{tari_amount::MicroMinotari, test_helpers::TestKeyManager, transaction_components::Transaction}, + transactions::{key_manager::MemoryDbKeyManager, tari_amount::MicroMinotari, transaction_components::Transaction}, }; use crate::helpers::block_builders::create_coinbase; @@ -38,7 +38,7 @@ pub async fn create_orphan_block( block_height: u64, transactions: Vec, consensus: &ConsensusManager, - key_manager: &TestKeyManager, + key_manager: &MemoryDbKeyManager, ) -> Block { let mut coinbase_value = consensus.emission_schedule().block_reward(block_height); let lock_height = consensus.consensus_constants(block_height).coinbase_min_maturity(); diff --git a/base_layer/core/tests/helpers/sample_blockchains.rs b/base_layer/core/tests/helpers/sample_blockchains.rs index 19b4868080f..a958186ec37 100644 --- a/base_layer/core/tests/helpers/sample_blockchains.rs +++ b/base_layer/core/tests/helpers/sample_blockchains.rs @@ -28,8 +28,8 @@ use tari_core::{ consensus::{ConsensusConstants, ConsensusConstantsBuilder, ConsensusManager, ConsensusManagerBuilder}, test_helpers::blockchain::{create_store_with_consensus, TempDatabase}, transactions::{ + key_manager::{create_memory_db_key_manager, MemoryDbKeyManager}, tari_amount::{uT, T}, - test_helpers::{create_test_core_key_manager_with_memory_db, TestKeyManager}, transaction_components::WalletOutput, }, txn_schema, @@ -84,7 +84,7 @@ pub async fn create_blockchain_db_no_cut_through() -> ( Vec, Vec>, ConsensusManager, - TestKeyManager, + MemoryDbKeyManager, ) { let network = Network::LocalNet; let (mut db, mut blocks, mut outputs, consensus_manager, key_manager) = create_new_blockchain(network).await; @@ -179,9 +179,9 @@ pub async fn create_new_blockchain( Vec, Vec>, ConsensusManager, - TestKeyManager, + MemoryDbKeyManager, ) { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let consensus_constants = ConsensusConstantsBuilder::new(network) .with_emission_amounts(100_000_000.into(), &EMISSION, 100.into()) .with_coinbase_lockheight(1) @@ -211,9 +211,9 @@ pub async fn create_new_blockchain_with_constants( Vec, Vec>, ConsensusManager, - TestKeyManager, + MemoryDbKeyManager, ) { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let (block0, output) = create_genesis_block(&constants, &key_manager).await; let consensus_manager = ConsensusManagerBuilder::new(network) .add_consensus_constants(constants) @@ -240,9 +240,9 @@ pub async fn create_new_blockchain_lmdb( Vec, Vec>, ConsensusManager, - TestKeyManager, + MemoryDbKeyManager, ) { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let consensus_constants = ConsensusConstantsBuilder::new(network) .with_emission_amounts(100_000_000.into(), &EMISSION, 100.into()) .with_coinbase_lockheight(1) diff --git a/base_layer/core/tests/helpers/sync.rs b/base_layer/core/tests/helpers/sync.rs index e3041b5bc91..c3af8050318 100644 --- a/base_layer/core/tests/helpers/sync.rs +++ b/base_layer/core/tests/helpers/sync.rs @@ -40,7 +40,7 @@ use tari_core::{ mempool::MempoolServiceConfig, proof_of_work::{randomx_factory::RandomXFactory, Difficulty}, test_helpers::blockchain::TempDatabase, - transactions::test_helpers::{create_test_core_key_manager_with_memory_db, TestKeyManager}, + transactions::key_manager::{create_memory_db_key_manager, MemoryDbKeyManager}, validation::mocks::MockValidator, }; use tari_p2p::{services::liveness::LivenessConfig, P2pConfig}; @@ -97,11 +97,11 @@ pub async fn create_network_with_local_and_peer_nodes() -> ( NodeInterfaces, ChainBlock, ConsensusManager, - TestKeyManager, + MemoryDbKeyManager, ) { let network = Network::LocalNet; let temp_dir = tempdir().unwrap(); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let consensus_constants = ConsensusConstantsBuilder::new(network) .with_emission_amounts(100_000_000.into(), &EMISSION, 100.into()) .build(); @@ -254,7 +254,7 @@ pub async fn create_and_add_some_blocks( start_block: &ChainBlock, number_of_blocks: usize, consensus_manager: &ConsensusManager, - key_manager: &TestKeyManager, + key_manager: &MemoryDbKeyManager, difficulties: &[u64], ) -> Vec { if number_of_blocks != difficulties.len() { diff --git a/base_layer/core/tests/helpers/test_blockchain.rs b/base_layer/core/tests/helpers/test_blockchain.rs index 865578e6104..fb9fbedcaee 100644 --- a/base_layer/core/tests/helpers/test_blockchain.rs +++ b/base_layer/core/tests/helpers/test_blockchain.rs @@ -33,7 +33,7 @@ use tari_core::{ consensus::ConsensusManager, proof_of_work::Difficulty, test_helpers::blockchain::TempDatabase, - transactions::{test_helpers::TestKeyManager, transaction_components::WalletOutput}, + transactions::{key_manager::MemoryDbKeyManager, transaction_components::WalletOutput}, }; use crate::helpers::{ @@ -51,7 +51,7 @@ pub struct TestBlockchain { hash_to_block: HashMap, consensus_manager: ConsensusManager, outputs: Vec>, - pub key_manager: TestKeyManager, + pub key_manager: MemoryDbKeyManager, } #[allow(dead_code)] diff --git a/base_layer/core/tests/tests/base_node_rpc.rs b/base_layer/core/tests/tests/base_node_rpc.rs index 571c40e168a..ec11eff7c3d 100644 --- a/base_layer/core/tests/tests/base_node_rpc.rs +++ b/base_layer/core/tests/tests/base_node_rpc.rs @@ -48,8 +48,9 @@ use tari_core::{ }, test_helpers::blockchain::TempDatabase, transactions::{ + key_manager::{create_memory_db_key_manager, MemoryDbKeyManager}, tari_amount::{uT, T}, - test_helpers::{create_test_core_key_manager_with_memory_db, schema_to_transaction, TestKeyManager}, + test_helpers::schema_to_transaction, transaction_components::{TransactionOutput, WalletOutput}, }, txn_schema, @@ -77,13 +78,13 @@ async fn setup() -> ( ChainBlock, WalletOutput, TempDir, - TestKeyManager, + MemoryDbKeyManager, ) { let network = NetworkConsensus::from(Network::LocalNet); let consensus_constants = ConsensusConstantsBuilder::new(Network::LocalNet) .with_coinbase_lockheight(1) .build(); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let temp_dir = tempdir().unwrap(); let (block0, utxo0) = create_genesis_block_with_coinbase_value(100_000_000.into(), &consensus_constants, &key_manager).await; @@ -212,8 +213,11 @@ async fn test_base_node_wallet_rpc() { assert_eq!(resp.rejection_reason, TxSubmissionRejectionReason::AlreadyMined); // Now create a different tx that uses the same input as Tx1 to produce a DoubleSpend rejection - let (txs1b, _utxos1) = - schema_to_transaction(&[txn_schema!(from: vec![utxo0], to: vec![2 * T, 1 * T])], &key_manager).await; + let (txs1b, _utxos1) = schema_to_transaction( + &[txn_schema!(from: vec![utxo0.clone()], to: vec![2 * T, 1 * T])], + &key_manager, + ) + .await; let tx1b = (*txs1b[0]).clone(); // Now if we submit Tx1 is should return as rejected as AlreadyMined diff --git a/base_layer/core/tests/tests/block_validation.rs b/base_layer/core/tests/tests/block_validation.rs index 9e2facf69f7..d7542cac2bc 100644 --- a/base_layer/core/tests/tests/block_validation.rs +++ b/base_layer/core/tests/tests/block_validation.rs @@ -49,7 +49,6 @@ use tari_core::{ key_manager::TransactionKeyManagerInterface, tari_amount::{uT, MicroMinotari, T}, test_helpers::{ - create_test_core_key_manager_with_memory_db, create_wallet_output_with_data, schema_to_transaction, spend_utxos, @@ -98,7 +97,7 @@ async fn test_monero_blocks() { let seed1 = "9f02e032f9b15d2aded991e0f68cc3c3427270b568b782e55fbd269ead0bad97"; let seed2 = "9f02e032f9b15d2aded991e0f68cc3c3427270b568b782e55fbd269ead0bad98"; - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let network = Network::Esmeralda; let cc = ConsensusConstantsBuilder::new(network) .with_max_randomx_seed_height(1) @@ -312,7 +311,7 @@ async fn inputs_are_not_malleable() { #[allow(clippy::too_many_lines)] async fn test_orphan_validator() { let factories = CryptoFactories::default(); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let network = Network::Igor; let consensus_constants = ConsensusConstantsBuilder::new(network) .with_max_block_transaction_weight(325) @@ -460,7 +459,7 @@ async fn test_orphan_body_validation() { .clear_proof_of_work() .add_proof_of_work(PowAlgorithm::Sha3x, sha3x_constants) .build(); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let (genesis, outputs) = create_genesis_block_with_utxos(&[T, T, T], &consensus_constants, &key_manager).await; let network = Network::LocalNet; let rules = ConsensusManager::builder(network) @@ -665,7 +664,7 @@ OutputFeatures::default()), #[allow(clippy::too_many_lines)] async fn test_header_validation() { let factories = CryptoFactories::default(); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let network = Network::Igor; // we dont want localnet's 1 difficulty or the full mined difficulty of weather wax but we want some. let sha3x_constants = PowAlgorithmConstants { @@ -790,7 +789,7 @@ async fn test_block_sync_body_validator() { let consensus_constants = ConsensusConstantsBuilder::new(network) .with_max_block_transaction_weight(400) .build(); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let (genesis, outputs) = create_genesis_block_with_utxos(&[T, T, T], &consensus_constants, &key_manager).await; let network = Network::LocalNet; let rules = ConsensusManager::builder(network) @@ -1050,7 +1049,7 @@ async fn add_block_with_large_block() { let factories = CryptoFactories::default(); let network = Network::LocalNet; let consensus_constants = ConsensusConstantsBuilder::new(network).build(); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let (genesis, outputs) = create_genesis_block_with_utxos( &[ 5 * T, @@ -1095,7 +1094,7 @@ async fn add_block_with_large_block() { // lets make our big block (1 -> 5) * 12 let mut schemas = Vec::new(); for output in outputs.into_iter().skip(1) { - let new_schema = txn_schema!(from: vec![output], to: vec![1 * T, 1 * T, 1 * T, 1 * T]); + let new_schema = txn_schema!(from: vec![output.clone()], to: vec![1 * T, 1 * T, 1 * T, 1 * T]); schemas.push(new_schema); } @@ -1127,7 +1126,7 @@ async fn add_block_with_large_many_output_block() { let consensus_constants = ConsensusConstantsBuilder::new(network) .with_max_block_transaction_weight(127_795) .build(); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let (genesis, outputs) = create_genesis_block_with_utxos(&[501 * T], &consensus_constants, &key_manager).await; let network = Network::LocalNet; let rules = ConsensusManager::builder(network) @@ -1183,6 +1182,7 @@ async fn add_block_with_large_many_output_block() { use tari_core::{ blocks::{BlockHeader, NewBlockTemplate}, transactions::{ + key_manager::create_memory_db_key_manager, test_helpers::create_stx_protocol_internal, transaction_components::{Transaction, TransactionKernel}, }, diff --git a/base_layer/core/tests/tests/mempool.rs b/base_layer/core/tests/tests/mempool.rs index 04d9133e290..0bb1d7a6d37 100644 --- a/base_layer/core/tests/tests/mempool.rs +++ b/base_layer/core/tests/tests/mempool.rs @@ -34,10 +34,14 @@ use tari_core::{ proto, transactions::{ fee::Fee, - key_manager::{TransactionKeyManagerBranch, TransactionKeyManagerInterface, TxoStage}, + key_manager::{ + create_memory_db_key_manager, + TransactionKeyManagerBranch, + TransactionKeyManagerInterface, + TxoStage, + }, tari_amount::{uT, MicroMinotari, T}, test_helpers::{ - create_test_core_key_manager_with_memory_db, create_wallet_output_with_data, schema_to_transaction, spend_utxos, @@ -1042,7 +1046,7 @@ async fn receive_and_propagate_transaction() { .with_coinbase_lockheight(100) .with_emission_amounts(100_000_000.into(), &EMISSION, 100.into()) .build(); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let (block0, utxo) = create_genesis_block(&consensus_constants, &key_manager).await; let consensus_manager = ConsensusManager::builder(network) .add_consensus_constants(consensus_constants) @@ -1077,7 +1081,7 @@ async fn receive_and_propagate_transaction() { }); let (tx, _) = spend_utxos( - txn_schema!(from: vec![utxo], to: vec![2 * T, 2 * T, 2 * T]), + txn_schema!(from: vec![utxo.clone()], to: vec![2 * T, 2 * T, 2 * T]), &key_manager, ) .await; @@ -1705,7 +1709,7 @@ async fn block_event_and_reorg_event_handling() { // When block B2A is submitted, then both nodes have TX2A and TX3A in their reorg pools // When block B2B is submitted with TX2B, TX3B, then TX2A, TX3A are discarded (Not Stored) let network = Network::LocalNet; - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let consensus_constants = ConsensusConstantsBuilder::new(Network::LocalNet) .with_coinbase_lockheight(1) .build(); @@ -1735,8 +1739,11 @@ async fn block_event_and_reorg_event_handling() { // Bob creates Block 1 and sends it to Alice. Alice adds it to her chain and creates a block event that the Mempool // service will receive. - let (tx1, utxos1) = - schema_to_transaction(&[txn_schema!(from: vec![utxos0], to: vec![1 * T, 1 * T])], &key_manager).await; + let (tx1, utxos1) = schema_to_transaction( + &[txn_schema!(from: vec![utxos0.clone()], to: vec![1 * T, 1 * T])], + &key_manager, + ) + .await; let (txs_a, _utxos2) = schema_to_transaction( &[ txn_schema!(from: vec![utxos1[0].clone()], to: vec![400_000 * uT, 590_000 * uT]), diff --git a/base_layer/core/tests/tests/node_comms_interface.rs b/base_layer/core/tests/tests/node_comms_interface.rs index 854d3becdec..f8edda06c91 100644 --- a/base_layer/core/tests/tests/node_comms_interface.rs +++ b/base_layer/core/tests/tests/node_comms_interface.rs @@ -39,15 +39,14 @@ use tari_core::{ create_consensus_rules, }, transactions::{ - key_manager::{TransactionKeyManagerBranch, TransactionKeyManagerInterface}, - tari_amount::MicroMinotari, - test_helpers::{ - create_test_core_key_manager_with_memory_db, - create_utxo, - TestKeyManager, - TestParams, - TransactionSchema, + key_manager::{ + create_memory_db_key_manager, + MemoryDbKeyManager, + TransactionKeyManagerBranch, + TransactionKeyManagerInterface, }, + tari_amount::MicroMinotari, + test_helpers::{create_utxo, TestParams, TransactionSchema}, transaction_components::{ OutputFeatures, TransactionOutput, @@ -203,7 +202,7 @@ async fn inbound_fetch_utxos() { let utxo_1 = block.body.outputs()[0].clone(); let hash_1 = utxo_1.hash(); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let (utxo_2, _, _) = create_utxo( MicroMinotari(10_000), &key_manager, @@ -265,9 +264,9 @@ async fn inbound_fetch_blocks() { } async fn initialize_sender_transaction_protocol_for_overflow_test( - key_manager: &TestKeyManager, + key_manager: &MemoryDbKeyManager, txn_schema: TransactionSchema, -) -> SenderTransactionInitializer { +) -> SenderTransactionInitializer { let constants = ConsensusManager::builder(Network::LocalNet) .build() .unwrap() @@ -361,7 +360,7 @@ async fn initialize_sender_transaction_protocol_for_overflow_test( #[tokio::test] async fn test_sender_transaction_protocol_for_overflow() { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let script = script!(Nop); let amount = MicroMinotari(u64::MAX); // This is the adversary's attack! let output_features = OutputFeatures::default(); @@ -419,7 +418,7 @@ async fn test_sender_transaction_protocol_for_overflow() { // Test overflow in total input value (inputs + outputs to self + fee) let txn_schema = // This is the adversary's attack! - txn_schema!(from: vec![wallet_output], to: vec![MicroMinotari(u64::MAX)]); + txn_schema!(from: vec![wallet_output.clone()], to: vec![MicroMinotari(u64::MAX)]); let stx_builder = initialize_sender_transaction_protocol_for_overflow_test(&key_manager, txn_schema).await; assert_eq!( format!("{:?}", stx_builder.build().await.unwrap_err()), @@ -432,7 +431,7 @@ async fn test_sender_transaction_protocol_for_overflow() { async fn inbound_fetch_blocks_before_horizon_height() { let consensus_manager = ConsensusManager::builder(Network::LocalNet).build().unwrap(); let block0 = consensus_manager.get_genesis_block(); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let validators = Validators::new( MockValidator::new(true), MockValidator::new(true), diff --git a/base_layer/core/tests/tests/node_service.rs b/base_layer/core/tests/tests/node_service.rs index 4a710f0c728..9877d99b445 100644 --- a/base_layer/core/tests/tests/node_service.rs +++ b/base_layer/core/tests/tests/node_service.rs @@ -35,8 +35,9 @@ use tari_core::{ mempool::TxStorageResponse, proof_of_work::{randomx_factory::RandomXFactory, Difficulty, PowAlgorithm}, transactions::{ + key_manager::create_memory_db_key_manager, tari_amount::{uT, T}, - test_helpers::{create_test_core_key_manager_with_memory_db, schema_to_transaction, spend_utxos}, + test_helpers::{schema_to_transaction, spend_utxos}, transaction_components::OutputFeatures, CryptoFactories, }, @@ -71,7 +72,7 @@ use crate::{ #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn propagate_and_forward_many_valid_blocks() { let temp_dir = tempdir().unwrap(); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); // Alice will propagate a number of block hashes to bob, bob will receive it, request the full block, verify and // then propagate the hash to carol and dan. Dan and Carol will also try to propagate the block hashes to each // other, but the block should not be re-requested. These duplicate blocks will be discarded and wont be @@ -220,7 +221,7 @@ async fn propagate_and_forward_invalid_block_hash() { let bob_node_identity = random_node_identity(); let carol_node_identity = random_node_identity(); let network = Network::LocalNet; - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let consensus_constants = ConsensusConstantsBuilder::new(network) .with_emission_amounts(100_000_000.into(), &EMISSION, 100.into()) .build(); @@ -270,7 +271,7 @@ async fn propagate_and_forward_invalid_block_hash() { // Add a transaction that Bob does not have to force a request let (txs, _) = schema_to_transaction( - &[txn_schema!(from: vec![genesis_coinbase], to: vec![5 * T], fee: 5.into())], + &[txn_schema!(from: vec![genesis_coinbase.clone()], to: vec![5 * T], fee: 5.into())], &key_manager, ) .await; @@ -343,7 +344,7 @@ async fn propagate_and_forward_invalid_block() { let bob_node_identity = random_node_identity(); let carol_node_identity = random_node_identity(); let dan_node_identity = random_node_identity(); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let network = Network::LocalNet; let consensus_constants = ConsensusConstantsBuilder::new(network) .with_emission_amounts(100_000_000.into(), &EMISSION, 100.into()) @@ -482,7 +483,7 @@ async fn propagate_and_forward_invalid_block() { async fn local_get_metadata() { let temp_dir = tempdir().unwrap(); let network = Network::LocalNet; - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let (mut node, consensus_manager) = BaseNodeBuilder::new(network.into()) .start(temp_dir.path().to_str().unwrap()) .await; @@ -506,7 +507,7 @@ async fn local_get_metadata() { async fn local_get_new_block_template_and_get_new_block() { let temp_dir = tempdir().unwrap(); let network = Network::LocalNet; - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let consensus_constants = NetworkConsensus::from(network).create_consensus_constants(); let (block0, outputs) = create_genesis_block_with_utxos(&[T, T], &consensus_constants[0], &key_manager).await; let rules = ConsensusManager::builder(network) @@ -549,7 +550,7 @@ async fn local_get_new_block_with_zero_conf() { let factories = CryptoFactories::default(); let temp_dir = tempdir().unwrap(); let network = Network::LocalNet; - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let consensus_constants = NetworkConsensus::from(network).create_consensus_constants(); let (block0, outputs) = create_genesis_block_with_utxos(&[T, T], &consensus_constants[0], &key_manager).await; let rules = ConsensusManagerBuilder::new(network) @@ -635,7 +636,7 @@ async fn local_get_new_block_with_combined_transaction() { let factories = CryptoFactories::default(); let temp_dir = tempdir().unwrap(); let network = Network::LocalNet; - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let consensus_constants = NetworkConsensus::from(network).create_consensus_constants(); let (block0, outputs) = create_genesis_block_with_utxos(&[T, T], &consensus_constants[0], &key_manager).await; let rules = ConsensusManagerBuilder::new(network) @@ -715,7 +716,7 @@ async fn local_get_new_block_with_combined_transaction() { async fn local_submit_block() { let temp_dir = tempdir().unwrap(); let network = Network::LocalNet; - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let (mut node, consensus_manager) = BaseNodeBuilder::new(network.into()) .start(temp_dir.path().to_str().unwrap()) .await; diff --git a/base_layer/core/tests/tests/node_state_machine.rs b/base_layer/core/tests/tests/node_state_machine.rs index db52c208e73..55e68c79de8 100644 --- a/base_layer/core/tests/tests/node_state_machine.rs +++ b/base_layer/core/tests/tests/node_state_machine.rs @@ -40,7 +40,7 @@ use tari_core::{ mempool::MempoolServiceConfig, proof_of_work::{randomx_factory::RandomXFactory, Difficulty}, test_helpers::blockchain::create_test_blockchain_db, - transactions::test_helpers::create_test_core_key_manager_with_memory_db, + transactions::key_manager::create_memory_db_key_manager, validation::mocks::MockValidator, }; use tari_p2p::{services::liveness::config::LivenessConfig, P2pConfig}; @@ -71,7 +71,7 @@ static EMISSION: [u64; 2] = [10, 10]; async fn test_listening_lagging() { let network = Network::LocalNet; let temp_dir = tempdir().unwrap(); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let consensus_constants = ConsensusConstantsBuilder::new(network) .with_emission_amounts(100_000_000.into(), &EMISSION, 100.into()) .build(); @@ -147,7 +147,7 @@ async fn test_listening_lagging() { async fn test_listening_initial_fallen_behind() { let network = Network::LocalNet; let temp_dir = tempdir().unwrap(); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let consensus_constants = ConsensusConstantsBuilder::new(network) .with_emission_amounts(100_000_000.into(), &EMISSION, 100.into()) .build(); diff --git a/base_layer/wallet/README.md b/base_layer/wallet/README.md index de4b41259b7..29f38ad1ad1 100644 --- a/base_layer/wallet/README.md +++ b/base_layer/wallet/README.md @@ -18,6 +18,7 @@ See README.md in wallet_ffi crate - Ensure that you installed diesel with the sqlite feature flag: - `cargo install diesel_cli --no-default-features --features sqlite` - If you updated the tables the following needs to be run from the `base_layer/wallet/` folder: + - manually delete `base_layer/wallet/test.sqlite3` if present - `diesel setup --database-url test.sqlite3` - `diesel migration run --database-url test.sqlite3` - After running this, make sure that the diesel update did not change BigInt to Integer in `schema.rs` (check for diff --git a/base_layer/wallet/migrations/2023-11-14-131400_coinbase/down.sql b/base_layer/wallet/migrations/2023-11-14-131400_coinbase/down.sql new file mode 100644 index 00000000000..291a97c5ce1 --- /dev/null +++ b/base_layer/wallet/migrations/2023-11-14-131400_coinbase/down.sql @@ -0,0 +1 @@ +-- This file should undo anything in `up.sql` \ No newline at end of file diff --git a/base_layer/wallet/migrations/2023-11-14-131400_coinbase/up.sql b/base_layer/wallet/migrations/2023-11-14-131400_coinbase/up.sql new file mode 100644 index 00000000000..129b3be0526 --- /dev/null +++ b/base_layer/wallet/migrations/2023-11-14-131400_coinbase/up.sql @@ -0,0 +1,69 @@ +-- Any old 'outputs' will not be valid due to the removal of 'coinbase_block_height' and 'coinbase_extra', +-- so we drop and recreate the table. + +DROP TABLE outputs; +CREATE TABLE outputs +( + id INTEGER PRIMARY KEY NOT NULL, + commitment BLOB NOT NULL, + rangeproof BLOB NULL, + spending_key TEXT NOT NULL, + value BIGINT NOT NULL, + output_type INTEGER NOT NULL, + maturity BIGINT NOT NULL, + status INTEGER NOT NULL, + hash BLOB NOT NULL, + script BLOB NOT NULL, + input_data BLOB NOT NULL, + script_private_key TEXT NOT NULL, + script_lock_height UNSIGNED BIGINT NOT NULL DEFAULT 0, + sender_offset_public_key BLOB NOT NULL, + metadata_signature_ephemeral_commitment BLOB NOT NULL, + metadata_signature_ephemeral_pubkey BLOB NOT NULL, + metadata_signature_u_a BLOB NOT NULL, + metadata_signature_u_x BLOB NOT NULL, + metadata_signature_u_y BLOB NOT NULL, + mined_height UNSIGNED BIGINT NULL, + mined_in_block BLOB NULL, + marked_deleted_at_height BIGINT NULL, + marked_deleted_in_block BLOB NULL, + received_in_tx_id BIGINT NULL, + spent_in_tx_id BIGINT NULL, + coinbase_extra BLOB NULL, + features_json TEXT NOT NULL DEFAULT '{}', + spending_priority UNSIGNED INTEGER NOT NULL, + covenant BLOB NOT NULL, + mined_timestamp DATETIME NULL, + encrypted_data BLOB NOT NULL, + minimum_value_promise BIGINT NOT NULL, + source INTEGER NOT NULL DEFAULT 0, + last_validation_timestamp DATETIME NULL, + CONSTRAINT unique_commitment UNIQUE (commitment) +); + +-- Any old 'completed_transactions' will not be valid due to the removal of 'coinbase_block_height', +-- so we drop and recreate the table. + +DROP TABLE completed_transactions; +CREATE TABLE completed_transactions +( + tx_id BIGINT PRIMARY KEY NOT NULL, + source_address BLOB NOT NULL, + destination_address BLOB NOT NULL, + amount BIGINT NOT NULL, + fee BIGINT NOT NULL, + transaction_protocol BLOB NOT NULL, + status INTEGER NOT NULL, + message TEXT NOT NULL, + timestamp DATETIME NOT NULL, + cancelled INTEGER NULL, + direction INTEGER NULL, + send_count INTEGER DEFAULT 0 NOT NULL, + last_send_timestamp DATETIME NULL, + confirmations BIGINT NULL, + mined_height BIGINT NULL, + mined_in_block BLOB NULL, + mined_timestamp DATETIME NULL, + transaction_signature_nonce BLOB DEFAULT 0 NOT NULL, + transaction_signature_key BLOB DEFAULT 0 NOT NULL +); diff --git a/base_layer/wallet/src/output_manager_service/error.rs b/base_layer/wallet/src/output_manager_service/error.rs index 0f0f31332bc..f7f7c3ea64a 100644 --- a/base_layer/wallet/src/output_manager_service/error.rs +++ b/base_layer/wallet/src/output_manager_service/error.rs @@ -28,7 +28,6 @@ use tari_comms_dht::outbound::DhtOutboundError; use tari_core::transactions::{ transaction_components::{EncryptedDataError, TransactionError}, transaction_protocol::TransactionProtocolError, - CoinbaseBuildError, }; use tari_crypto::errors::RangeProofError; use tari_key_manager::{ @@ -102,8 +101,6 @@ pub enum OutputManagerError { BaseNodeChanged, #[error("Invalid Sender Message Type")] InvalidSenderMessage, - #[error("Coinbase build error: `{0}`")] - CoinbaseBuildError(#[from] CoinbaseBuildError), #[error("TXO Validation protocol cancelled")] Cancellation, #[error("Base NodeService Error: `{0}`")] diff --git a/base_layer/wallet/src/output_manager_service/handle.rs b/base_layer/wallet/src/output_manager_service/handle.rs index 12cd02b847c..cd873af1b3f 100644 --- a/base_layer/wallet/src/output_manager_service/handle.rs +++ b/base_layer/wallet/src/output_manager_service/handle.rs @@ -61,13 +61,6 @@ pub enum OutputManagerRequest { AddUnvalidatedOutput((TxId, Box, Option)), UpdateOutputMetadataSignature(Box), GetRecipientTransaction(TransactionSenderMessage), - GetCoinbaseTransaction { - tx_id: TxId, - reward: MicroMinotari, - fees: MicroMinotari, - block_height: u64, - extra: Vec, - }, ConfirmPendingTransaction(TxId), PrepareToSendTransaction { tx_id: TxId, @@ -126,7 +119,6 @@ pub enum OutputManagerRequest { }, ReinstateCancelledInboundTx(TxId), - SetCoinbaseAbandoned(TxId, bool), CreateClaimShaAtomicSwapTransaction(HashOutput, PublicKey, MicroMinotari), CreateHtlcRefundTransaction(HashOutput, MicroMinotari), GetOutputStatusesByTxId(TxId), @@ -184,7 +176,6 @@ impl fmt::Display for OutputManagerRequest { "CreateCoinJoin: commitments={:#?}, fee_per_gram={}", commitments, fee_per_gram, ), - GetCoinbaseTransaction { .. } => write!(f, "GetCoinbaseTransaction"), FeeEstimate { amount, selection_criteria, @@ -204,7 +195,6 @@ impl fmt::Display for OutputManagerRequest { }, CreatePayToSelfWithOutputs { .. } => write!(f, "CreatePayToSelfWithOutputs"), ReinstateCancelledInboundTx(_) => write!(f, "ReinstateCancelledInboundTx"), - SetCoinbaseAbandoned(_, _) => write!(f, "SetCoinbaseAbandoned"), CreateClaimShaAtomicSwapTransaction(output, pre_image, fee_per_gram) => write!( f, "ClaimShaAtomicSwap(output hash: {}, pre_image: {}, fee_per_gram: {} )", @@ -232,7 +222,6 @@ pub enum OutputManagerResponse { ConvertedToTransactionOutput(Box), OutputMetadataSignatureUpdated, RecipientTransactionGenerated(ReceiverTransactionProtocol), - CoinbaseTransaction(Transaction), OutputConfirmed, PendingTransactionConfirmed, PayToSelfTransaction((MicroMinotari, Transaction)), @@ -254,7 +243,6 @@ pub enum OutputManagerResponse { CreateOutputWithFeatures { output: Box }, CreatePayToSelfWithOutputs { transaction: Box, tx_id: TxId }, ReinstatedCancelledInboundTx, - CoinbaseAbandonedSet, ClaimHtlcTransaction((TxId, MicroMinotari, MicroMinotari, Transaction)), OutputStatusesByTxId(OutputStatusesByTxId), CoinPreview((Vec, MicroMinotari)), @@ -438,30 +426,6 @@ impl OutputManagerHandle { } } - pub async fn get_coinbase_transaction( - &mut self, - tx_id: TxId, - reward: MicroMinotari, - fees: MicroMinotari, - block_height: u64, - extra: Vec, - ) -> Result { - match self - .handle - .call(OutputManagerRequest::GetCoinbaseTransaction { - tx_id, - reward, - fees, - block_height, - extra, - }) - .await?? - { - OutputManagerResponse::CoinbaseTransaction(tx) => Ok(tx), - _ => Err(OutputManagerError::UnexpectedApiResponse), - } - } - pub async fn prepare_transaction_to_send( &mut self, tx_id: TxId, @@ -800,17 +764,6 @@ impl OutputManagerHandle { } } - pub async fn set_coinbase_abandoned(&mut self, tx_id: TxId, abandoned: bool) -> Result<(), OutputManagerError> { - match self - .handle - .call(OutputManagerRequest::SetCoinbaseAbandoned(tx_id, abandoned)) - .await?? - { - OutputManagerResponse::CoinbaseAbandonedSet => Ok(()), - _ => Err(OutputManagerError::UnexpectedApiResponse), - } - } - pub async fn get_output_statuses_by_tx_id( &mut self, tx_id: TxId, diff --git a/base_layer/wallet/src/output_manager_service/input_selection.rs b/base_layer/wallet/src/output_manager_service/input_selection.rs index fdd0f2cc114..895c2d69e58 100644 --- a/base_layer/wallet/src/output_manager_service/input_selection.rs +++ b/base_layer/wallet/src/output_manager_service/input_selection.rs @@ -106,7 +106,7 @@ impl Display for UtxoSelectionOrdering { #[derive(Default, Debug, Clone)] pub enum UtxoSelectionFilter { - /// Select OutputType::Standard or OutputType::Coinbase outputs only + /// Select OutputType::Standard outputs only #[default] Standard, /// Selects specific outputs. All outputs must be exist and be spendable. diff --git a/base_layer/wallet/src/output_manager_service/recovery/standard_outputs_recoverer.rs b/base_layer/wallet/src/output_manager_service/recovery/standard_outputs_recoverer.rs index 623a8ba9489..94199c1d0ee 100644 --- a/base_layer/wallet/src/output_manager_service/recovery/standard_outputs_recoverer.rs +++ b/base_layer/wallet/src/output_manager_service/recovery/standard_outputs_recoverer.rs @@ -27,7 +27,7 @@ use tari_common_types::transaction::TxId; use tari_core::transactions::{ key_manager::{TariKeyId, TransactionKeyManagerBranch, TransactionKeyManagerInterface}, tari_amount::MicroMinotari, - transaction_components::{TransactionError, TransactionOutput, WalletOutput}, + transaction_components::{OutputType, TransactionError, TransactionOutput, WalletOutput}, }; use tari_script::{inputs, script, ExecutionStack, Opcode, TariScript}; use tari_utilities::hex::Hex; @@ -69,7 +69,7 @@ where let known_scripts = self.db.get_all_known_one_sided_payment_scripts()?; - let mut rewound_outputs: Vec = Vec::new(); + let mut rewound_outputs: Vec<(WalletOutput, bool)> = Vec::new(); let push_pub_key_script = script!(PushPubKey(Box::default())); for output in outputs { let known_script_index = known_scripts.iter().position(|s| s.script == output.script); @@ -109,7 +109,7 @@ where output.proof.clone(), ); - rewound_outputs.push(uo); + rewound_outputs.push((uo, known_script_index.is_some())); } let rewind_time = start.elapsed(); @@ -121,20 +121,12 @@ where ); let mut rewound_outputs_with_tx_id: Vec = Vec::new(); - for output in &mut rewound_outputs { - // Attempting to recognize output source by i.e., standard MimbleWimble, simple or stealth one-sided - let output_source = match *output.script.as_slice() { - [Opcode::Nop] => OutputSource::Standard, - [Opcode::PushPubKey(_), Opcode::Drop, Opcode::PushPubKey(_)] => OutputSource::StealthOneSided, - [Opcode::PushPubKey(_)] => OutputSource::OneSided, - _ => OutputSource::RecoveredButUnrecognized, - }; - + for (output, has_known_script) in &mut rewound_outputs { let db_output = DbWalletOutput::from_wallet_output( output.clone(), &self.master_key_manager, None, - output_source, + Self::output_source(output, *has_known_script), None, None, ) @@ -168,6 +160,28 @@ where Ok(rewound_outputs_with_tx_id) } + // Helper function to get the output source for a given output + fn output_source(output: &WalletOutput, has_known_script: bool) -> OutputSource { + match output.features.output_type { + OutputType::Standard => match *output.script.as_slice() { + [Opcode::Nop] => OutputSource::Standard, + [Opcode::PushPubKey(_), Opcode::Drop, Opcode::PushPubKey(_)] => OutputSource::StealthOneSided, + [Opcode::PushPubKey(_)] => { + if has_known_script { + OutputSource::OneSided + } else { + OutputSource::Standard + } + }, + _ => OutputSource::NonStandardScript, + }, + OutputType::Coinbase => OutputSource::Coinbase, + OutputType::Burn => OutputSource::Burn, + OutputType::ValidatorNodeRegistration => OutputSource::ValidatorNodeRegistration, + OutputType::CodeTemplateRegistration => OutputSource::CodeTemplateRegistration, + } + } + async fn find_script_key( &self, script: &TariScript, @@ -244,16 +258,7 @@ where .master_key_manager .get_public_key_at_key_id(&output.spending_key_id) .await?; - let script_key = if output.features.is_coinbase() { - let found_index = self - .master_key_manager - .find_key_index(TransactionKeyManagerBranch::Coinbase.get_branch_key(), &public_key) - .await?; - TariKeyId::Managed { - branch: TransactionKeyManagerBranch::CoinbaseScript.get_branch_key(), - index: found_index, - } - } else { + let script_key = { let found_index = self .master_key_manager .find_key_index( diff --git a/base_layer/wallet/src/output_manager_service/service.rs b/base_layer/wallet/src/output_manager_service/service.rs index 497c9016924..e1e145e21f5 100644 --- a/base_layer/wallet/src/output_manager_service/service.rs +++ b/base_layer/wallet/src/output_manager_service/service.rs @@ -53,7 +53,6 @@ use tari_core::{ WalletOutputBuilder, }, transaction_protocol::{sender::TransactionSenderMessage, TransactionMetadata}, - CoinbaseBuilder, CryptoFactories, ReceiverTransactionProtocol, SenderTransactionProtocol, @@ -237,16 +236,6 @@ where .get_default_recipient_transaction(tsm) .await .map(OutputManagerResponse::RecipientTransactionGenerated), - OutputManagerRequest::GetCoinbaseTransaction { - tx_id, - reward, - fees, - block_height, - extra, - } => self - .get_coinbase_transaction(tx_id, reward, fees, block_height, extra) - .await - .map(OutputManagerResponse::CoinbaseTransaction), OutputManagerRequest::PrepareToSendTransaction { tx_id, amount, @@ -411,9 +400,6 @@ where tx_id, }) }, - OutputManagerRequest::SetCoinbaseAbandoned(tx_id, abandoned) => self - .set_coinbase_abandoned(tx_id, abandoned) - .map(|_| OutputManagerResponse::CoinbaseAbandonedSet), OutputManagerRequest::CreateClaimShaAtomicSwapTransaction(output_hash, pre_image, fee_per_gram) => { self.claim_sha_atomic_swap_with_hash(output_hash, pre_image, fee_per_gram) .await @@ -782,7 +768,7 @@ where self.resources .db - .add_output_to_be_received(single_round_sender_data.tx_id, output, None)?; + .add_output_to_be_received(single_round_sender_data.tx_id, output)?; let rtp = ReceiverTransactionProtocol::new( sender_message.clone(), @@ -1000,70 +986,6 @@ where Ok(stp) } - /// Request a Coinbase transaction for a specific block height. All existing pending transactions with - /// the corresponding output hash will be cancelled. - /// The key will be derived from the coinbase specific keychain using the blockheight as an index. The coinbase - /// keychain is based on the wallets master_key and the "coinbase" branch. - async fn get_coinbase_transaction( - &mut self, - tx_id: TxId, - reward: MicroMinotari, - fees: MicroMinotari, - block_height: u64, - extra: Vec, - ) -> Result { - debug!( - target: LOG_TARGET, - "Building coinbase transaction for block_height {} with TxId: {}", block_height, tx_id - ); - - let (coinbase_spending_key, _) = self - .resources - .key_manager - .get_next_key(TransactionKeyManagerBranch::Coinbase.get_branch_key()) - .await?; - let (coinbase_script_key, _) = self - .resources - .key_manager - .get_next_key(TransactionKeyManagerBranch::CoinbaseScript.get_branch_key()) - .await?; - - let (tx, wallet_output) = CoinbaseBuilder::new(self.resources.key_manager.clone()) - .with_block_height(block_height) - .with_fees(fees) - .with_spend_key_id(coinbase_spending_key) - .with_script_key_id(coinbase_script_key) - .with_script(script!(Nop)) - .with_extra(extra) - .build_with_reward(&self.resources.consensus_constants, reward) - .await?; - - let output = DbWalletOutput::from_wallet_output( - wallet_output, - &self.resources.key_manager, - None, - OutputSource::Coinbase, - Some(tx_id), - None, - ) - .await?; - - // If there is no existing output available, we store the one we produced. - match self.resources.db.fetch_by_commitment(output.commitment.clone()) { - Ok(_) => {}, - Err(OutputManagerStorageError::ValueNotFound) => { - self.resources - .db - .add_output_to_be_received(tx_id, output, Some(block_height))?; - - self.confirm_encumberance(tx_id)?; - }, - Err(e) => return Err(e.into()), - }; - - Ok(tx) - } - #[allow(clippy::too_many_lines)] async fn create_pay_to_self_containing_outputs( &mut self, @@ -1465,11 +1387,6 @@ where Ok(self.resources.db.get_invalid_outputs()?) } - pub fn set_coinbase_abandoned(&self, tx_id: TxId, abandoned: bool) -> Result<(), OutputManagerError> { - self.resources.db.set_coinbase_abandoned(tx_id, abandoned)?; - Ok(()) - } - fn default_features_and_scripts_size(&self) -> Result { Ok(self .resources @@ -2299,7 +2216,7 @@ where wallet_output, &self.resources.key_manager, None, - OutputSource::Refund, + OutputSource::HtlcRefund, Some(tx_id), None, ) diff --git a/base_layer/wallet/src/output_manager_service/storage/database/backend.rs b/base_layer/wallet/src/output_manager_service/storage/database/backend.rs index c14deb29865..702e6f2cafa 100644 --- a/base_layer/wallet/src/output_manager_service/storage/database/backend.rs +++ b/base_layer/wallet/src/output_manager_service/storage/database/backend.rs @@ -88,8 +88,6 @@ pub trait OutputManagerBackend: Send + Sync + Clone { fn get_last_mined_output(&self) -> Result, OutputManagerStorageError>; /// Get the output that was most recently spent, ordered descending by mined height fn get_last_spent_output(&self) -> Result, OutputManagerStorageError>; - /// Set if a coinbase output is abandoned or not - fn set_coinbase_abandoned(&self, tx_id: TxId, abandoned: bool) -> Result<(), OutputManagerStorageError>; /// Reinstate a cancelled inbound output fn reinstate_cancelled_inbound_output(&self, tx_id: TxId) -> Result<(), OutputManagerStorageError>; /// Return the available, time locked, pending incoming and pending outgoing balance diff --git a/base_layer/wallet/src/output_manager_service/storage/database/mod.rs b/base_layer/wallet/src/output_manager_service/storage/database/mod.rs index 0f7d78b4787..20ec2edc8ed 100644 --- a/base_layer/wallet/src/output_manager_service/storage/database/mod.rs +++ b/base_layer/wallet/src/output_manager_service/storage/database/mod.rs @@ -110,7 +110,7 @@ pub enum DbValue { pub enum DbKeyValuePair { UnspentOutput(Commitment, Box), UnspentOutputWithTxId(Commitment, (TxId, Box)), - OutputToBeReceived(Commitment, (TxId, Box, Option)), + OutputToBeReceived(Commitment, (TxId, Box)), KnownOneSidedPaymentScripts(KnownOneSidedPaymentScript), } @@ -162,31 +162,15 @@ where T: OutputManagerBackend + 'static Ok(()) } - pub fn add_output_to_be_received_remove_this( - &self, - tx_id: TxId, - output: DbWalletOutput, - coinbase_block_height: Option, - ) -> Result<(), OutputManagerStorageError> { - self.db - .write(WriteOperation::Insert(DbKeyValuePair::OutputToBeReceived( - output.commitment.clone(), - (tx_id, Box::new(output), coinbase_block_height), - )))?; - - Ok(()) - } - pub fn add_output_to_be_received( &self, tx_id: TxId, output: DbWalletOutput, - coinbase_block_height: Option, ) -> Result<(), OutputManagerStorageError> { self.db .write(WriteOperation::Insert(DbKeyValuePair::OutputToBeReceived( output.commitment.clone(), - (tx_id, Box::new(output), coinbase_block_height), + (tx_id, Box::new(output)), )))?; Ok(()) @@ -445,12 +429,6 @@ where T: OutputManagerBackend + 'static Ok(()) } - pub fn set_coinbase_abandoned(&self, tx_id: TxId, abandoned: bool) -> Result<(), OutputManagerStorageError> { - let db = self.db.clone(); - db.set_coinbase_abandoned(tx_id, abandoned)?; - Ok(()) - } - pub fn fetch_outputs_by_tx_id(&self, tx_id: TxId) -> Result, OutputManagerStorageError> { let outputs = self.db.fetch_outputs_by_tx_id(tx_id)?; Ok(outputs) diff --git a/base_layer/wallet/src/output_manager_service/storage/models.rs b/base_layer/wallet/src/output_manager_service/storage/models.rs index 2a77e54b829..c66e1777f38 100644 --- a/base_layer/wallet/src/output_manager_service/storage/models.rs +++ b/base_layer/wallet/src/output_manager_service/storage/models.rs @@ -20,7 +20,7 @@ // 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. -use std::cmp::Ordering; +use std::{cmp::Ordering, convert::TryFrom}; use chrono::NaiveDateTime; use derivative::Derivative; @@ -114,27 +114,48 @@ impl Eq for DbWalletOutput {} // --------------------------------------------------------------------------- -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Eq, PartialEq)] pub enum SpendingPriority { Normal, HtlcSpendAsap, - Unknown, + // Unknown, } -impl From for SpendingPriority { - fn from(value: u32) -> Self { +// impl From for SpendingPriority { +// fn from(value: u32) -> Self { +// match value { +// 0 => SpendingPriority::Normal, +// 1 => SpendingPriority::HtlcSpendAsap, +// _ => SpendingPriority::Unknown, +// } +// } +// } + +impl TryFrom for SpendingPriority { + type Error = String; + + fn try_from(value: u32) -> Result { match value { - 0 => SpendingPriority::Normal, - 1 => SpendingPriority::HtlcSpendAsap, - _ => SpendingPriority::Unknown, + 0 => Ok(SpendingPriority::Normal), + 1 => Ok(SpendingPriority::HtlcSpendAsap), + _ => Err(format!("Invalid spending priority value: {}", value)), } } } -impl From for u32 { +// impl From for u32 { +// fn from(value: SpendingPriority) -> Self { +// match value { +// SpendingPriority::Normal => 0, +// SpendingPriority::HtlcSpendAsap => 1, +// } +// } +// } + +impl From for i32 { fn from(value: SpendingPriority) -> Self { match value { - SpendingPriority::Normal | SpendingPriority::Unknown => 0, + SpendingPriority::Normal => 0, SpendingPriority::HtlcSpendAsap => 1, } } diff --git a/base_layer/wallet/src/output_manager_service/storage/output_source.rs b/base_layer/wallet/src/output_manager_service/storage/output_source.rs index 51a85d03aa8..d64b7f8d262 100644 --- a/base_layer/wallet/src/output_manager_service/storage/output_source.rs +++ b/base_layer/wallet/src/output_manager_service/storage/output_source.rs @@ -34,15 +34,17 @@ use crate::output_manager_service::error::OutputManagerStorageError; // The source of where the output came from #[derive(Copy, Clone, Debug, PartialEq, Display, Default)] pub enum OutputSource { - Unknown, - Coinbase, - RecoveredButUnrecognized, #[default] Standard, + Coinbase, + NonStandardScript, OneSided, StealthOneSided, - Refund, + HtlcRefund, AtomicSwap, + Burn, + ValidatorNodeRegistration, + CodeTemplateRegistration, } impl TryFrom for OutputSource { @@ -50,14 +52,16 @@ impl TryFrom for OutputSource { fn try_from(value: i32) -> Result { Ok(match value { - 0 => OutputSource::Unknown, + 0 => OutputSource::Standard, 1 => OutputSource::Coinbase, - 2 => OutputSource::RecoveredButUnrecognized, - 3 => OutputSource::Standard, - 4 => OutputSource::OneSided, - 5 => OutputSource::StealthOneSided, - 6 => OutputSource::Refund, - 7 => OutputSource::AtomicSwap, + 2 => OutputSource::NonStandardScript, + 3 => OutputSource::OneSided, + 4 => OutputSource::StealthOneSided, + 5 => OutputSource::HtlcRefund, + 6 => OutputSource::AtomicSwap, + 7 => OutputSource::Burn, + 8 => OutputSource::ValidatorNodeRegistration, + 9 => OutputSource::CodeTemplateRegistration, _ => { return Err(OutputManagerStorageError::ConversionError { reason: "Was expecting value between 0 and 7 for OutputSource".to_string(), diff --git a/base_layer/wallet/src/output_manager_service/storage/output_status.rs b/base_layer/wallet/src/output_manager_service/storage/output_status.rs index 774e11106ac..495cc72e374 100644 --- a/base_layer/wallet/src/output_manager_service/storage/output_status.rs +++ b/base_layer/wallet/src/output_manager_service/storage/output_status.rs @@ -44,7 +44,6 @@ pub enum OutputStatus { ShortTermEncumberedToBeReceived, ShortTermEncumberedToBeSpent, SpentMinedUnconfirmed, - AbandonedCoinbase, NotStored, } @@ -63,8 +62,7 @@ impl TryFrom for OutputStatus { 7 => Ok(OutputStatus::ShortTermEncumberedToBeReceived), 8 => Ok(OutputStatus::ShortTermEncumberedToBeSpent), 9 => Ok(OutputStatus::SpentMinedUnconfirmed), - 10 => Ok(OutputStatus::AbandonedCoinbase), - 11 => Ok(OutputStatus::NotStored), + 10 => Ok(OutputStatus::NotStored), _ => Err(OutputManagerStorageError::ConversionError { reason: "Was expecting value between 0 and 11 for OutputStatus".to_string(), }), diff --git a/base_layer/wallet/src/output_manager_service/storage/sqlite_db/mod.rs b/base_layer/wallet/src/output_manager_service/storage/sqlite_db/mod.rs index a393588d71d..aba1729e6c5 100644 --- a/base_layer/wallet/src/output_manager_service/storage/sqlite_db/mod.rs +++ b/base_layer/wallet/src/output_manager_service/storage/sqlite_db/mod.rs @@ -85,26 +85,21 @@ impl OutputManagerSqliteDatabase { if OutputSql::find_by_commitment_and_cancelled(&c.to_vec(), false, conn).is_ok() { return Err(OutputManagerStorageError::DuplicateOutput); } - let new_output = NewOutputSql::new(*o, OutputStatus::Unspent, None, None)?; + let new_output = NewOutputSql::new(*o, OutputStatus::Unspent, None)?; new_output.commit(conn)? }, DbKeyValuePair::UnspentOutputWithTxId(c, (tx_id, o)) => { if OutputSql::find_by_commitment_and_cancelled(&c.to_vec(), false, conn).is_ok() { return Err(OutputManagerStorageError::DuplicateOutput); } - let new_output = NewOutputSql::new(*o, OutputStatus::Unspent, Some(tx_id), None)?; + let new_output = NewOutputSql::new(*o, OutputStatus::Unspent, Some(tx_id))?; new_output.commit(conn)? }, - DbKeyValuePair::OutputToBeReceived(c, (tx_id, o, coinbase_block_height)) => { + DbKeyValuePair::OutputToBeReceived(c, (tx_id, o)) => { if OutputSql::find_by_commitment_and_cancelled(&c.to_vec(), false, conn).is_ok() { return Err(OutputManagerStorageError::DuplicateOutput); } - let new_output = NewOutputSql::new( - *o, - OutputStatus::EncumberedToBeReceived, - Some(tx_id), - coinbase_block_height, - )?; + let new_output = NewOutputSql::new(*o, OutputStatus::EncumberedToBeReceived, Some(tx_id))?; new_output.commit(conn)? }, @@ -663,12 +658,7 @@ impl OutputManagerBackend for OutputManagerSqliteDatabase { })?; for co in outputs_to_receive { - let new_output = NewOutputSql::new( - co.clone(), - OutputStatus::ShortTermEncumberedToBeReceived, - Some(tx_id), - None, - )?; + let new_output = NewOutputSql::new(co.clone(), OutputStatus::ShortTermEncumberedToBeReceived, Some(tx_id))?; new_output.commit(&mut conn)?; } if start.elapsed().as_millis() > 0 { @@ -955,47 +945,6 @@ impl OutputManagerBackend for OutputManagerSqliteDatabase { Ok(()) } - fn set_coinbase_abandoned(&self, tx_id: TxId, abandoned: bool) -> Result<(), OutputManagerStorageError> { - let start = Instant::now(); - let mut conn = self.database_connection.get_pooled_connection()?; - let acquire_lock = start.elapsed(); - - if abandoned { - debug!( - target: LOG_TARGET, - "set_coinbase_abandoned(TxID: {}) as {}", tx_id, abandoned - ); - diesel::update( - outputs::table.filter( - outputs::received_in_tx_id - .eq(Some(tx_id.as_u64() as i64)) - .and(outputs::coinbase_block_height.is_not_null()), - ), - ) - .set((outputs::status.eq(OutputStatus::AbandonedCoinbase as i32),)) - .execute(&mut conn) - .num_rows_affected_or_not_found(1)?; - } else { - update_outputs_with_tx_id_and_status_to_new_status( - &mut conn, - tx_id, - OutputStatus::AbandonedCoinbase, - OutputStatus::EncumberedToBeReceived, - )?; - }; - if start.elapsed().as_millis() > 0 { - trace!( - target: LOG_TARGET, - "sqlite profile - set_coinbase_abandoned: lock {} + db_op {} = {} ms", - acquire_lock.as_millis(), - (start.elapsed() - acquire_lock).as_millis(), - start.elapsed().as_millis() - ); - } - - Ok(()) - } - fn reinstate_cancelled_inbound_output(&self, tx_id: TxId) -> Result<(), OutputManagerStorageError> { let start = Instant::now(); let mut conn = self.database_connection.get_pooled_connection()?; @@ -1028,7 +977,7 @@ impl OutputManagerBackend for OutputManagerSqliteDatabase { if OutputSql::find_by_commitment_and_cancelled(&output.commitment.to_vec(), false, &mut conn).is_ok() { return Err(OutputManagerStorageError::DuplicateOutput); } - let new_output = NewOutputSql::new(output, OutputStatus::EncumberedToBeReceived, Some(tx_id), None)?; + let new_output = NewOutputSql::new(output, OutputStatus::EncumberedToBeReceived, Some(tx_id))?; new_output.commit(&mut conn)?; if start.elapsed().as_millis() > 0 { @@ -1307,13 +1256,9 @@ mod test { use diesel_migrations::{EmbeddedMigrations, MigrationHarness}; use rand::{rngs::OsRng, RngCore}; use tari_core::transactions::{ + key_manager::{create_memory_db_key_manager, MemoryDbKeyManager}, tari_amount::MicroMinotari, - test_helpers::{ - create_test_core_key_manager_with_memory_db, - create_wallet_output_with_data, - TestKeyManager, - TestParams, - }, + test_helpers::{create_wallet_output_with_data, TestParams}, transaction_components::{OutputFeatures, TransactionInput, WalletOutput}, }; use tari_script::script; @@ -1326,7 +1271,7 @@ mod test { OutputSource, }; - pub async fn make_input(val: MicroMinotari, key_manager: &TestKeyManager) -> (TransactionInput, WalletOutput) { + pub async fn make_input(val: MicroMinotari, key_manager: &MemoryDbKeyManager) -> (TransactionInput, WalletOutput) { let test_params = TestParams::new(key_manager).await; let wallet_output = @@ -1371,13 +1316,13 @@ mod test { let mut outputs_spent = Vec::new(); let mut outputs_unspent = Vec::new(); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); for _i in 0..2 { let (_, uo) = make_input(MicroMinotari::from(100 + OsRng.next_u64() % 1000), &key_manager).await; - let uo = DbWalletOutput::from_wallet_output(uo, &key_manager, None, OutputSource::Unknown, None, None) + let uo = DbWalletOutput::from_wallet_output(uo, &key_manager, None, OutputSource::Standard, None, None) .await .unwrap(); - let o = NewOutputSql::new(uo, OutputStatus::Unspent, None, None).unwrap(); + let o = NewOutputSql::new(uo, OutputStatus::Unspent, None).unwrap(); outputs.push(o.clone()); outputs_unspent.push(o.clone()); o.commit(&mut conn).unwrap(); @@ -1385,10 +1330,10 @@ mod test { for _i in 0..3 { let (_, uo) = make_input(MicroMinotari::from(100 + OsRng.next_u64() % 1000), &key_manager).await; - let uo = DbWalletOutput::from_wallet_output(uo, &key_manager, None, OutputSource::Unknown, None, None) + let uo = DbWalletOutput::from_wallet_output(uo, &key_manager, None, OutputSource::Standard, None, None) .await .unwrap(); - let o = NewOutputSql::new(uo, OutputStatus::Spent, None, None).unwrap(); + let o = NewOutputSql::new(uo, OutputStatus::Spent, None).unwrap(); outputs.push(o.clone()); outputs_spent.push(o.clone()); o.commit(&mut conn).unwrap(); diff --git a/base_layer/wallet/src/output_manager_service/storage/sqlite_db/new_output_sql.rs b/base_layer/wallet/src/output_manager_service/storage/sqlite_db/new_output_sql.rs index 7eb606bc3bc..3719ddc81de 100644 --- a/base_layer/wallet/src/output_manager_service/storage/sqlite_db/new_output_sql.rs +++ b/base_layer/wallet/src/output_manager_service/storage/sqlite_db/new_output_sql.rs @@ -59,12 +59,12 @@ pub struct NewOutputSql { pub metadata_signature_u_x: Vec, pub metadata_signature_u_y: Vec, pub received_in_tx_id: Option, - pub coinbase_block_height: Option, pub features_json: String, pub covenant: Vec, pub encrypted_data: Vec, pub minimum_value_promise: i64, pub source: i32, + pub spending_priority: i32, } impl NewOutputSql { @@ -73,7 +73,6 @@ impl NewOutputSql { output: DbWalletOutput, status: OutputStatus, received_in_tx_id: Option, - coinbase_block_height: Option, ) -> Result { let mut covenant = Vec::new(); BorshSerialize::serialize(&output.wallet_output.covenant, &mut covenant)?; @@ -102,7 +101,6 @@ impl NewOutputSql { metadata_signature_u_a: output.wallet_output.metadata_signature.u_a().to_vec(), metadata_signature_u_x: output.wallet_output.metadata_signature.u_x().to_vec(), metadata_signature_u_y: output.wallet_output.metadata_signature.u_y().to_vec(), - coinbase_block_height: coinbase_block_height.map(|bh| bh as i64), features_json: serde_json::to_string(&output.wallet_output.features).map_err(|s| { OutputManagerStorageError::ConversionError { reason: format!("Could not parse features from JSON:{}", s), @@ -112,6 +110,7 @@ impl NewOutputSql { encrypted_data: output.wallet_output.encrypted_data.to_byte_vec(), minimum_value_promise: output.wallet_output.minimum_value_promise.as_u64() as i64, source: output.source as i32, + spending_priority: output.spending_priority.into(), }; Ok(output) diff --git a/base_layer/wallet/src/output_manager_service/storage/sqlite_db/output_sql.rs b/base_layer/wallet/src/output_manager_service/storage/sqlite_db/output_sql.rs index 9a932c365e4..8d722bb0467 100644 --- a/base_layer/wallet/src/output_manager_service/storage/sqlite_db/output_sql.rs +++ b/base_layer/wallet/src/output_manager_service/storage/sqlite_db/output_sql.rs @@ -50,7 +50,7 @@ use crate::{ service::Balance, storage::{ database::{OutputBackendQuery, SortDirection}, - models::DbWalletOutput, + models::{DbWalletOutput, SpendingPriority}, sqlite_db::{UpdateOutput, UpdateOutputSql}, OutputSource, OutputStatus, @@ -91,7 +91,6 @@ pub struct OutputSql { pub marked_deleted_in_block: Option>, pub received_in_tx_id: Option, pub spent_in_tx_id: Option, - pub coinbase_block_height: Option, pub coinbase_extra: Option>, pub features_json: String, pub spending_priority: i32, @@ -264,12 +263,6 @@ impl OutputSql { }, }; - // debug!( - // target: LOG_TARGET, - // "Executing UTXO select query: {}", - // diesel::debug_query(&query) - // ); - Ok(query.load(conn)?) } @@ -603,17 +596,6 @@ impl OutputSql { .first::(conn)?) } - /// Find a particular Output, if it exists and is in the specified Spent state - pub fn find_pending_coinbase_at_block_height( - block_height: u64, - conn: &mut SqliteConnection, - ) -> Result { - Ok(outputs::table - .filter(outputs::status.ne(OutputStatus::Unspent as i32)) - .filter(outputs::coinbase_block_height.eq(block_height as i64)) - .first::(conn)?) - } - pub fn delete(&self, conn: &mut SqliteConnection) -> Result<(), OutputManagerStorageError> { let num_deleted = diesel::delete(outputs::table.filter(outputs::spending_key.eq(&self.spending_key))).execute(conn)?; @@ -756,7 +738,11 @@ impl OutputSql { }); }, }; - let spending_priority = (self.spending_priority as u32).into(); + let spending_priority = SpendingPriority::try_from(self.spending_priority as u32).map_err(|e| { + OutputManagerStorageError::ConversionError { + reason: format!("Could not convert spending priority from i32: {}", e), + } + })?; let mined_in_block = match self.mined_in_block { Some(v) => match v.try_into() { Ok(v) => Some(v), diff --git a/base_layer/wallet/src/schema.rs b/base_layer/wallet/src/schema.rs index 5d734c2795d..fb49078d48e 100644 --- a/base_layer/wallet/src/schema.rs +++ b/base_layer/wallet/src/schema.rs @@ -29,7 +29,6 @@ diesel::table! { timestamp -> Timestamp, cancelled -> Nullable, direction -> Nullable, - coinbase_block_height -> Nullable, send_count -> Integer, last_send_timestamp -> Nullable, confirmations -> Nullable, @@ -109,7 +108,6 @@ diesel::table! { marked_deleted_in_block -> Nullable, received_in_tx_id -> Nullable, spent_in_tx_id -> Nullable, - coinbase_block_height -> Nullable, coinbase_extra -> Nullable, features_json -> Text, spending_priority -> Integer, diff --git a/base_layer/wallet/src/transaction_service/error.rs b/base_layer/wallet/src/transaction_service/error.rs index c7f4bf10c07..1743fa8a449 100644 --- a/base_layer/wallet/src/transaction_service/error.rs +++ b/base_layer/wallet/src/transaction_service/error.rs @@ -96,8 +96,6 @@ pub enum TransactionServiceError { DiscoveryProcessFailed(TxId), #[error("Invalid Completed Transaction provided")] InvalidCompletedTransaction, - #[error("Attempted to broadcast a coinbase transaction. TxId `{0}`")] - AttemptedToBroadcastCoinbaseTransaction(TxId), #[error("No Base Node public keys are provided for Base chain broadcast and monitoring")] NoBaseNodeKeysProvided, #[error("Base node changed during {task_name}")] @@ -112,8 +110,6 @@ pub enum TransactionServiceError { UnexpectedBaseNodeResponse, #[error("The current transaction has been cancelled")] TransactionCancelled, - #[error("Chain tip has moved beyond this coinbase before it was mined so it must be cancelled")] - ChainTipHigherThanCoinbaseHeight, #[error("DHT outbound error: `{0}`")] DhtOutboundError(#[from] DhtOutboundError), #[error("Output manager error: `{0}`")] @@ -271,10 +267,10 @@ pub enum TransactionStorageError { ByteArrayError(String), #[error("Tari address error: `{0}`")] TariAddressError(#[from] TariAddressError), - #[error("Not a coinbase transaction so cannot be abandoned")] - NotCoinbase, #[error("Db error: `{0}`")] SqliteStorageError(#[from] SqliteStorageError), + #[error("Coinbase transactions are not supported in the wallet")] + CoinbaseNotSupported, } impl From for TransactionStorageError { diff --git a/base_layer/wallet/src/transaction_service/handle.rs b/base_layer/wallet/src/transaction_service/handle.rs index 9f8c1279163..77cd21f9236 100644 --- a/base_layer/wallet/src/transaction_service/handle.rs +++ b/base_layer/wallet/src/transaction_service/handle.rs @@ -138,7 +138,6 @@ pub enum TransactionServiceRequest { amount: MicroMinotari, source_address: TariAddress, message: String, - maturity: Option, import_status: ImportStatus, tx_id: Option, current_height: Option, @@ -147,12 +146,6 @@ pub enum TransactionServiceRequest { SubmitTransactionToSelf(TxId, Transaction, MicroMinotari, MicroMinotari, String), SetLowPowerMode, SetNormalPowerMode, - GenerateCoinbaseTransaction { - reward: MicroMinotari, - fees: MicroMinotari, - block_height: u64, - extra: Vec, - }, RestartTransactionProtocols, RestartBroadcastProtocols, GetNumConfirmationsRequired, @@ -215,29 +208,18 @@ impl fmt::Display for TransactionServiceRequest { amount, source_address, message, - maturity, import_status, tx_id, current_height, mined_timestamp, } => write!( f, - "ImportUtxo (from {}, {}, {} with maturity {} and {:?} and {:?} and {:?} and {:?})", - source_address, - amount, - message, - maturity.unwrap_or(0), - import_status, - tx_id, - current_height, - mined_timestamp + "ImportUtxo (from {}, {}, {} and {:?} and {:?} and {:?} and {:?})", + source_address, amount, message, import_status, tx_id, current_height, mined_timestamp ), Self::SubmitTransactionToSelf(tx_id, _, _, _, _) => write!(f, "SubmitTransaction ({})", tx_id), Self::SetLowPowerMode => write!(f, "SetLowPowerMode "), Self::SetNormalPowerMode => write!(f, "SetNormalPowerMode"), - Self::GenerateCoinbaseTransaction { block_height, .. } => { - write!(f, "GenerateCoinbaseTransaction (Blockheight {})", block_height) - }, Self::RestartTransactionProtocols => write!(f, "RestartTransactionProtocols"), Self::RestartBroadcastProtocols => write!(f, "RestartBroadcastProtocols"), Self::GetNumConfirmationsRequired => write!(f, "GetNumConfirmationsRequired"), @@ -277,7 +259,6 @@ pub enum TransactionServiceResponse { TransactionSubmitted, LowPowerModeSet, NormalPowerModeSet, - CoinbaseTransactionGenerated(Box), ProtocolsRestarted, AnyTransaction(Box>), NumConfirmationsRequired(u64), @@ -749,7 +730,6 @@ impl TransactionServiceHandle { amount: MicroMinotari, source_address: TariAddress, message: String, - maturity: Option, import_status: ImportStatus, tx_id: Option, current_height: Option, @@ -761,7 +741,6 @@ impl TransactionServiceHandle { amount, source_address, message, - maturity, import_status, tx_id, current_height, @@ -845,28 +824,6 @@ impl TransactionServiceHandle { } } - pub async fn generate_coinbase_transaction( - &mut self, - reward: MicroMinotari, - fees: MicroMinotari, - block_height: u64, - extra: Vec, - ) -> Result { - match self - .handle - .call(TransactionServiceRequest::GenerateCoinbaseTransaction { - reward, - fees, - block_height, - extra, - }) - .await?? - { - TransactionServiceResponse::CoinbaseTransactionGenerated(tx) => Ok(*tx), - _ => Err(TransactionServiceError::UnexpectedApiResponse), - } - } - pub async fn restart_transaction_protocols(&mut self) -> Result<(), TransactionServiceError> { match self .handle diff --git a/base_layer/wallet/src/transaction_service/protocols/transaction_receive_protocol.rs b/base_layer/wallet/src/transaction_service/protocols/transaction_receive_protocol.rs index b7942e337eb..38d948a5f71 100644 --- a/base_layer/wallet/src/transaction_service/protocols/transaction_receive_protocol.rs +++ b/base_layer/wallet/src/transaction_service/protocols/transaction_receive_protocol.rs @@ -435,8 +435,8 @@ where TransactionDirection::Inbound, None, None, - None, - ); + ) + .map_err(|e| TransactionServiceProtocolError::new(self.id, TransactionServiceError::from(e)))?; self.resources .db diff --git a/base_layer/wallet/src/transaction_service/protocols/transaction_send_protocol.rs b/base_layer/wallet/src/transaction_service/protocols/transaction_send_protocol.rs index 24f5b332ba7..30eed38c442 100644 --- a/base_layer/wallet/src/transaction_service/protocols/transaction_send_protocol.rs +++ b/base_layer/wallet/src/transaction_service/protocols/transaction_send_protocol.rs @@ -578,8 +578,8 @@ where TransactionDirection::Outbound, None, None, - None, - ); + ) + .map_err(|e| TransactionServiceProtocolError::new(self.id, TransactionServiceError::from(e)))?; self.resources .db 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 3b8f7834b9f..f910bd114aa 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 @@ -44,14 +44,12 @@ use tari_utilities::hex::Hex; use crate::{ connectivity_service::WalletConnectivityInterface, - output_manager_service::handle::OutputManagerHandle, transaction_service::{ config::TransactionServiceConfig, error::{TransactionServiceError, TransactionServiceProtocolError, TransactionServiceProtocolErrorExt}, handle::{TransactionEvent, TransactionEventSender}, storage::{ database::{TransactionBackend, TransactionDatabase}, - models::TxCancellationReason, sqlite_db::UnconfirmedTransactionInfo, }, }, @@ -66,7 +64,6 @@ pub struct TransactionValidationProtocol Self { Self { operation_id, @@ -89,7 +85,6 @@ where connectivity, config, event_publisher, - output_manager_handle, } } @@ -147,43 +142,13 @@ where } if let Some((tip_height, tip_block, tip_mined_timestamp)) = tip_info { for unmined_tx in &unmined { - // Treat coinbases separately - if unmined_tx.is_coinbase() { - if unmined_tx.coinbase_block_height.unwrap_or_default() <= tip_height { - debug!( - target: LOG_TARGET, - "Updated coinbase {} as abandoned (Operation ID: {})", - unmined_tx.tx_id, - self.operation_id - ); - self.update_coinbase_as_abandoned( - unmined_tx.tx_id, - &tip_block, - tip_height, - tip_mined_timestamp, - tip_height.saturating_sub(unmined_tx.coinbase_block_height.unwrap_or_default()), - ) - .await?; - state_changed = true; - } else { - debug!( - target: LOG_TARGET, - "Coinbase not found, but it is for a block that is not yet in the chain. Coinbase \ - height: {}, tip height:{} (Operation ID: {})", - unmined_tx.coinbase_block_height.unwrap_or_default(), - tip_height, - self.operation_id - ); - } - } else { - debug!( - target: LOG_TARGET, - "Updated transaction {} as unmined (Operation ID: {})", unmined_tx.tx_id, self.operation_id - ); - self.update_transaction_as_unmined(unmined_tx.tx_id, &unmined_tx.status) - .await?; - self.publish_event(TransactionEvent::NewBlockMined(unmined_tx.tx_id)); - } + debug!( + target: LOG_TARGET, + "Updated transaction {} as unmined (Operation ID: {})", unmined_tx.tx_id, self.operation_id + ); + self.update_transaction_as_unmined(unmined_tx.tx_id, &unmined_tx.status) + .await?; + self.publish_event(TransactionEvent::NewBlockMined(unmined_tx.tx_id)); } } } @@ -430,67 +395,6 @@ where }) } - if *status == TransactionStatus::Coinbase { - if let Err(e) = self.output_manager_handle.set_coinbase_abandoned(tx_id, false).await { - warn!( - target: LOG_TARGET, - "Could not mark coinbase output for TxId: {} as not abandoned: {} (Operation ID: {})", - tx_id, - e, - self.operation_id - ); - }; - } - - Ok(()) - } - - #[allow(clippy::ptr_arg)] - async fn update_coinbase_as_abandoned( - &mut self, - tx_id: TxId, - mined_in_block: &BlockHash, - mined_height: u64, - mined_timestamp: u64, - num_confirmations: u64, - ) -> Result<(), TransactionServiceProtocolError> { - // This updates the OMS first before we update the TMS. If we update the TMS first and operation fail inside of - // the OMS, we have two databases that are out of sync, as the TMS would have been updated and OMS will be stuck - // forever as pending_incoming. - self.output_manager_handle - .set_coinbase_abandoned(tx_id, true) - .await - .map_err(|e| { - warn!( - target: LOG_TARGET, - "Could not mark coinbase output for TxId: {} as abandoned: {} (Operation ID: {})", - tx_id, - e, - self.operation_id - ); - e - }) - .for_protocol(self.operation_id)?; - self.db - .set_transaction_mined_height( - tx_id, - mined_height, - *mined_in_block, - mined_timestamp, - num_confirmations, - num_confirmations >= self.config.num_confirmations_required, - false, - ) - .for_protocol(self.operation_id)?; - - self.db - .abandon_coinbase_transaction(tx_id) - .for_protocol(self.operation_id)?; - - self.publish_event(TransactionEvent::TransactionCancelled( - tx_id, - TxCancellationReason::AbandonedCoinbase, - )); Ok(()) } @@ -499,18 +403,6 @@ where tx_id: TxId, status: &TransactionStatus, ) -> Result<(), TransactionServiceProtocolError> { - if *status == TransactionStatus::Coinbase { - if let Err(e) = self.output_manager_handle.set_coinbase_abandoned(tx_id, false).await { - warn!( - target: LOG_TARGET, - "Could not mark coinbase output for TxId: {} as not abandoned: {} (Operation ID: {})", - tx_id, - e, - self.operation_id - ); - }; - } - self.db .set_transaction_as_unmined(tx_id) .for_protocol(self.operation_id)?; diff --git a/base_layer/wallet/src/transaction_service/service.rs b/base_layer/wallet/src/transaction_service/service.rs index ec74eb53ab9..dc68b73bbad 100644 --- a/base_layer/wallet/src/transaction_service/service.rs +++ b/base_layer/wallet/src/transaction_service/service.rs @@ -778,7 +778,6 @@ where amount, source_address, message, - maturity, import_status, tx_id, current_height, @@ -788,7 +787,6 @@ where amount, source_address, message, - maturity, import_status, tx_id, current_height, @@ -800,15 +798,6 @@ where TransactionServiceRequest::SubmitTransactionToSelf(tx_id, tx, fee, amount, message) => self .submit_transaction_to_self(transaction_broadcast_join_handles, tx_id, tx, fee, amount, message) .map(|_| TransactionServiceResponse::TransactionSubmitted), - TransactionServiceRequest::GenerateCoinbaseTransaction { - reward, - fees, - block_height, - extra, - } => self - .generate_coinbase_transaction(reward, fees, block_height, extra) - .await - .map(|tx| TransactionServiceResponse::CoinbaseTransactionGenerated(Box::new(tx))), TransactionServiceRequest::SetLowPowerMode => { self.set_power_mode(PowerMode::Low).await?; Ok(TransactionServiceResponse::LowPowerModeSet) @@ -1013,8 +1002,7 @@ where TransactionDirection::Inbound, None, None, - None, - ), + )?, )?; let _result = reply_channel @@ -1263,8 +1251,7 @@ where TransactionDirection::Outbound, None, None, - None, - ), + )?, )?; let tx_output = output @@ -1452,8 +1439,7 @@ where TransactionDirection::Outbound, None, None, - None, - ), + )?, )?; Ok(tx_id) @@ -1714,8 +1700,7 @@ where TransactionDirection::Outbound, None, None, - None, - ), + )?, )?; info!(target: LOG_TARGET, "Submitted burning transaction - TxId: {}", tx_id); @@ -2530,7 +2515,7 @@ where .map_err(|resp| { error!( target: LOG_TARGET, - "Error restarting protocols for all coinbase transactions: {:?}", resp + "Error restarting protocols for all pending inbound transactions: {:?}", resp ); resp })?; @@ -2569,7 +2554,6 @@ where self.resources.connectivity.clone(), self.resources.config.clone(), self.event_publisher.clone(), - self.resources.output_manager_service.clone(), ); let mut base_node_watch = self.connectivity().get_current_base_node_watcher(); @@ -2686,11 +2670,6 @@ where { return Err(TransactionServiceError::InvalidCompletedTransaction); } - if completed_tx.is_coinbase() { - return Err(TransactionServiceError::AttemptedToBroadcastCoinbaseTransaction( - completed_tx.tx_id, - )); - } if !self.resources.connectivity.is_base_node_set() { return Err(TransactionServiceError::NoBaseNodeKeysProvided); @@ -2813,7 +2792,6 @@ where value: MicroMinotari, source_address: TariAddress, message: String, - maturity: Option, import_status: ImportStatus, tx_id: Option, current_height: Option, @@ -2829,7 +2807,6 @@ where source_address, self.resources.wallet_identity.address.clone(), message, - maturity, import_status.clone(), current_height, mined_timestamp, @@ -2841,9 +2818,7 @@ where num_confirmations: 0, is_valid: true, }, - ImportStatus::FauxConfirmed | ImportStatus::Coinbase => { - TransactionEvent::FauxTransactionConfirmed { tx_id, is_valid: true } - }, + ImportStatus::FauxConfirmed => TransactionEvent::FauxTransactionConfirmed { tx_id, is_valid: true }, }; let _size = self.event_publisher.send(Arc::new(transaction_event)).map_err(|e| { trace!( @@ -2913,84 +2888,11 @@ where TransactionDirection::Inbound, None, None, - None, - ), + )?, )?; Ok(()) } - async fn generate_coinbase_transaction( - &mut self, - reward: MicroMinotari, - fees: MicroMinotari, - block_height: u64, - extra: Vec, - ) -> Result { - let amount = reward + fees; - - // first check if we already have a coinbase tx for this height and amount - let find_result = self - .db - .find_coinbase_transaction_at_block_height(block_height, amount)?; - - let mut completed_transaction = None; - if let Some(tx) = find_result { - if let Some(coinbase) = tx.transaction.body.outputs().first() { - if coinbase.features.coinbase_extra == extra { - completed_transaction = Some(tx.transaction); - } - } - }; - if completed_transaction.is_none() { - // otherwise create a new coinbase tx - let tx_id = TxId::new_random(); - let tx = self - .resources - .output_manager_service - .get_coinbase_transaction(tx_id, reward, fees, block_height, extra) - .await?; - self.db.insert_completed_transaction( - tx_id, - CompletedTransaction::new( - tx_id, - self.resources.wallet_identity.address.clone(), - self.resources.wallet_identity.address.clone(), - amount, - MicroMinotari::from(0), - tx.clone(), - TransactionStatus::Coinbase, - format!("Coinbase Transaction for Block #{}", block_height), - Utc::now().naive_utc(), - TransactionDirection::Inbound, - Some(block_height), - None, - None, - ), - )?; - - let _size = self - .resources - .event_publisher - .send(Arc::new(TransactionEvent::ReceivedFinalizedTransaction(tx_id))) - .map_err(|e| { - trace!( - target: LOG_TARGET, - "Error sending event because there are no subscribers: {:?}", - e - ); - e - }); - - info!( - target: LOG_TARGET, - "Coinbase transaction (TxId: {}) for Block Height: {} added", tx_id, block_height - ); - completed_transaction = Some(tx); - }; - - Ok(completed_transaction.unwrap()) - } - /// Check if a Recovery Status is currently stored in the databse, this indicates that a wallet recovery is in /// progress fn check_recovery_status(&self) -> Result<(), TransactionServiceError> { @@ -3029,13 +2931,6 @@ enum PowerMode { Normal, } -/// Contains the generated TxId and SpendingKey for a Pending Coinbase transaction -#[derive(Debug)] -pub struct PendingCoinbaseSpendingKey { - pub tx_id: TxId, - pub spending_key: PrivateKey, -} - /// Contains the generated TxId and TransactionStatus transaction send result #[derive(Debug)] pub struct TransactionSendResult { diff --git a/base_layer/wallet/src/transaction_service/storage/database.rs b/base_layer/wallet/src/transaction_service/storage/database.rs index 17105d7cf5f..ca0e9e841a2 100644 --- a/base_layer/wallet/src/transaction_service/storage/database.rs +++ b/base_layer/wallet/src/transaction_service/storage/database.rs @@ -115,20 +115,10 @@ pub trait TransactionBackend: Send + Sync + Clone { ) -> Result; /// Mark a pending transaction direct send attempt as a success fn mark_direct_send_success(&self, tx_id: TxId) -> Result<(), TransactionStorageError>; - /// Cancel coinbase transactions at a specific block height - fn cancel_coinbase_transactions_at_block_height(&self, block_height: u64) -> Result<(), TransactionStorageError>; - /// Find coinbase transaction at a specific block height for a given amount - fn find_coinbase_transaction_at_block_height( - &self, - block_height: u64, - amount: MicroMinotari, - ) -> Result, TransactionStorageError>; /// Increment the send counter and timestamp of a transaction fn increment_send_count(&self, tx_id: TxId) -> Result<(), TransactionStorageError>; /// Update a transactions mined height. A transaction can either be mined as valid or mined as invalid /// A normal transaction can only be mined with valid = true, - /// A coinbase transaction can either be mined as valid = true, meaning that it is the coinbase in that block - /// or valid =false, meaning that the coinbase has been awarded to another tx, but this has been confirmed by blocks /// The mined height and block are used to determine reorgs fn update_mined_height( &self, @@ -154,7 +144,6 @@ pub trait TransactionBackend: Send + Sync + Clone { &self, height: u64, ) -> Result, TransactionStorageError>; - fn abandon_coinbase_transaction(&self, tx_id: TxId) -> Result<(), TransactionStorageError>; } #[derive(Clone, PartialEq)] @@ -649,7 +638,6 @@ where T: TransactionBackend + 'static source_address: TariAddress, comms_address: TariAddress, message: String, - maturity: Option, import_status: ImportStatus, current_height: Option, mined_timestamp: Option, @@ -671,10 +659,9 @@ where T: TransactionBackend + 'static message, mined_timestamp.unwrap_or_else(|| Utc::now().naive_utc()), TransactionDirection::Inbound, - maturity, current_height, mined_timestamp, - ); + )?; self.db .write(WriteOperation::Insert(DbKeyValuePair::CompletedTransaction( @@ -684,21 +671,6 @@ where T: TransactionBackend + 'static Ok(()) } - pub fn cancel_coinbase_transaction_at_block_height( - &self, - block_height: u64, - ) -> Result<(), TransactionStorageError> { - self.db.cancel_coinbase_transactions_at_block_height(block_height) - } - - pub fn find_coinbase_transaction_at_block_height( - &self, - block_height: u64, - amount: MicroMinotari, - ) -> Result, TransactionStorageError> { - self.db.find_coinbase_transaction_at_block_height(block_height, amount) - } - pub fn increment_send_count(&self, tx_id: TxId) -> Result<(), TransactionStorageError> { self.db.increment_send_count(tx_id) } @@ -741,10 +713,6 @@ where T: TransactionBackend + 'static }?; Ok(t) } - - pub fn abandon_coinbase_transaction(&self, tx_id: TxId) -> Result<(), TransactionStorageError> { - self.db.abandon_coinbase_transaction(tx_id) - } } impl Display for DbKey { diff --git a/base_layer/wallet/src/transaction_service/storage/models.rs b/base_layer/wallet/src/transaction_service/storage/models.rs index bd2a63b753b..1dbc29ab034 100644 --- a/base_layer/wallet/src/transaction_service/storage/models.rs +++ b/base_layer/wallet/src/transaction_service/storage/models.rs @@ -39,6 +39,8 @@ use tari_core::transactions::{ SenderTransactionProtocol, }; +use crate::transaction_service::error::TransactionStorageError; + #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] pub struct InboundTransaction { pub tx_id: TxId, @@ -138,7 +140,6 @@ pub struct CompletedTransaction { pub timestamp: NaiveDateTime, pub cancelled: Option, pub direction: TransactionDirection, - pub coinbase_block_height: Option, pub send_count: u32, pub last_send_timestamp: Option, pub transaction_signature: Signature, @@ -160,16 +161,18 @@ impl CompletedTransaction { message: String, timestamp: NaiveDateTime, direction: TransactionDirection, - coinbase_block_height: Option, mined_height: Option, mined_timestamp: Option, - ) -> Self { + ) -> Result { + if status == TransactionStatus::Coinbase { + return Err(TransactionStorageError::CoinbaseNotSupported); + } let transaction_signature = if let Some(excess_sig) = transaction.first_kernel_excess_sig() { excess_sig.clone() } else { Signature::default() }; - Self { + Ok(Self { tx_id, source_address, destination_address, @@ -181,7 +184,6 @@ impl CompletedTransaction { timestamp, cancelled: None, direction, - coinbase_block_height, send_count: 0, last_send_timestamp: None, transaction_signature, @@ -189,15 +191,7 @@ impl CompletedTransaction { mined_height, mined_in_block: None, mined_timestamp, - } - } - - pub fn is_coinbase(&self) -> bool { - if let Some(height) = self.coinbase_block_height { - height > 0 - } else { - false - } + }) } } @@ -269,7 +263,6 @@ impl From for CompletedTransaction { }, transaction, direction: TransactionDirection::Outbound, - coinbase_block_height: None, send_count: 0, last_send_timestamp: None, transaction_signature, @@ -299,7 +292,6 @@ impl From for CompletedTransaction { }, transaction: Transaction::new(vec![], vec![], vec![], PrivateKey::default(), PrivateKey::default()), direction: TransactionDirection::Inbound, - coinbase_block_height: None, send_count: 0, last_send_timestamp: None, transaction_signature: Signature::default(), @@ -338,7 +330,6 @@ pub enum TxCancellationReason { Orphan, // 4 TimeLocked, // 5 InvalidTransaction, // 6 - AbandonedCoinbase, // 7 } impl TryFrom for TxCancellationReason { @@ -353,7 +344,6 @@ impl TryFrom for TxCancellationReason { 4 => Ok(TxCancellationReason::Orphan), 5 => Ok(TxCancellationReason::TimeLocked), 6 => Ok(TxCancellationReason::InvalidTransaction), - 7 => Ok(TxCancellationReason::AbandonedCoinbase), code => Err(TransactionConversionError { code: code as i32 }), } } @@ -371,7 +361,6 @@ impl Display for TxCancellationReason { Orphan => "Orphan", TimeLocked => "TimeLocked", InvalidTransaction => "Invalid Transaction", - AbandonedCoinbase => "Abandoned Coinbase", }; fmt.write_str(response) } 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 30e17796d28..8da0e4c6c7a 100644 --- a/base_layer/wallet/src/transaction_service/storage/sqlite_db.rs +++ b/base_layer/wallet/src/transaction_service/storage/sqlite_db.rs @@ -754,59 +754,6 @@ impl TransactionBackend for TransactionServiceSqliteDatabase { Ok(()) } - fn cancel_coinbase_transactions_at_block_height(&self, block_height: u64) -> Result<(), TransactionStorageError> { - let start = Instant::now(); - let mut conn = self.database_connection.get_pooled_connection()?; - let acquire_lock = start.elapsed(); - - CompletedTransactionSql::reject_coinbases_at_block_height( - block_height as i64, - TxCancellationReason::AbandonedCoinbase, - &mut conn, - )?; - if start.elapsed().as_millis() > 0 { - trace!( - target: LOG_TARGET, - "sqlite profile - cancel_coinbase_transaction_at_block_height: lock {} + db_op {} = {} ms", - acquire_lock.as_millis(), - (start.elapsed() - acquire_lock).as_millis(), - start.elapsed().as_millis() - ); - } - - Ok(()) - } - - fn find_coinbase_transaction_at_block_height( - &self, - block_height: u64, - amount: MicroMinotari, - ) -> Result, TransactionStorageError> { - let start = Instant::now(); - let mut conn = self.database_connection.get_pooled_connection()?; - let acquire_lock = start.elapsed(); - let cipher = acquire_read_lock!(self.cipher); - - let coinbase_txs = CompletedTransactionSql::index_coinbase_at_block_height(block_height as i64, &mut conn)?; - for c in coinbase_txs { - let completed_tx = CompletedTransaction::try_from(c, &cipher)?; - if completed_tx.amount == amount { - return Ok(Some(completed_tx)); - } - } - if start.elapsed().as_millis() > 0 { - trace!( - target: LOG_TARGET, - "sqlite profile - find_coinbase_transaction_at_block_height: lock {} + db_op {} = {} ms", - acquire_lock.as_millis(), - (start.elapsed() - acquire_lock).as_millis(), - start.elapsed().as_millis() - ); - } - - Ok(None) - } - fn increment_send_count(&self, tx_id: TxId) -> Result<(), TransactionStorageError> { let start = Instant::now(); let mut conn = self.database_connection.get_pooled_connection()?; @@ -956,11 +903,6 @@ impl TransactionBackend for TransactionServiceSqliteDatabase { .eq(TransactionStatus::Completed as i32) .or(completed_transactions::status.eq(TransactionStatus::Broadcast as i32)), ) - .filter( - completed_transactions::coinbase_block_height - .is_null() - .or(completed_transactions::coinbase_block_height.eq(0)), - ) .filter(completed_transactions::cancelled.is_null()) .order_by(completed_transactions::tx_id) .load::(&mut conn)?; @@ -1102,21 +1044,6 @@ impl TransactionBackend for TransactionServiceSqliteDatabase { }) .collect::, TransactionStorageError>>() } - - fn abandon_coinbase_transaction(&self, tx_id: TxId) -> Result<(), TransactionStorageError> { - let mut conn = self.database_connection.get_pooled_connection()?; - match CompletedTransactionSql::find_and_abandon_coinbase(tx_id, &mut conn) { - Ok(_) => {}, - Err(TransactionStorageError::DieselError(DieselError::NotFound)) => { - return Err(TransactionStorageError::ValueNotFound(DbKey::CompletedTransaction( - tx_id, - ))); - }, - Err(e) => return Err(e), - }; - - Ok(()) - } } #[derive(Debug, PartialEq)] @@ -1688,7 +1615,6 @@ pub struct CompletedTransactionSql { timestamp: NaiveDateTime, cancelled: Option, direction: Option, - coinbase_block_height: Option, send_count: i32, last_send_timestamp: Option, confirmations: Option, @@ -1762,33 +1688,6 @@ impl CompletedTransactionSql { .load::(conn)?) } - pub fn index_coinbase_at_block_height( - block_height: i64, - conn: &mut SqliteConnection, - ) -> Result, TransactionStorageError> { - Ok(completed_transactions::table - .filter(completed_transactions::status.eq(TransactionStatus::Coinbase as i32)) - .filter(completed_transactions::coinbase_block_height.eq(block_height)) - .load::(conn)?) - } - - pub fn find_and_abandon_coinbase(tx_id: TxId, conn: &mut SqliteConnection) -> Result<(), TransactionStorageError> { - let _ = diesel::update( - completed_transactions::table - .filter(completed_transactions::tx_id.eq(tx_id.as_u64() as i64)) - .filter(completed_transactions::cancelled.is_null()) - .filter(completed_transactions::coinbase_block_height.is_not_null()), - ) - .set(UpdateCompletedTransactionSql { - cancelled: Some(Some(TxCancellationReason::AbandonedCoinbase as i32)), - ..Default::default() - }) - .execute(conn) - .num_rows_affected_or_not_found(1)?; - - Ok(()) - } - pub fn find(tx_id: TxId, conn: &mut SqliteConnection) -> Result { Ok(completed_transactions::table .filter(completed_transactions::tx_id.eq(tx_id.as_u64() as i64)) @@ -1859,24 +1758,6 @@ impl CompletedTransactionSql { Ok(()) } - pub fn reject_coinbases_at_block_height( - block_height: i64, - reason: TxCancellationReason, - conn: &mut SqliteConnection, - ) -> Result { - Ok(diesel::update( - completed_transactions::table - .filter(completed_transactions::status.eq(TransactionStatus::Coinbase as i32)) - .filter(completed_transactions::coinbase_block_height.eq(block_height)), - ) - .set(UpdateCompletedTransactionSql { - cancelled: Some(Some(reason as i32)), - status: Some(TransactionStatus::Rejected as i32), - ..Default::default() - }) - .execute(conn)?) - } - pub fn delete(&self, conn: &mut SqliteConnection) -> Result<(), TransactionStorageError> { let num_deleted = diesel::delete(completed_transactions::table.filter(completed_transactions::tx_id.eq(&self.tx_id))) @@ -1938,14 +1819,7 @@ impl CompletedTransactionSql { diesel::update(completed_transactions::table.filter(completed_transactions::tx_id.eq(tx_id.as_u64() as i64))) .set(UpdateCompletedTransactionSql { status: { - if let Some(Some(_coinbase_block_height)) = completed_transactions::table - .filter(completed_transactions::tx_id.eq(tx_id.as_u64() as i64)) - .select(completed_transactions::coinbase_block_height) - .load::>(conn)? - .first() - { - Some(TransactionStatus::Coinbase as i32) - } else if let Some(status) = completed_transactions::table + 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)? @@ -2007,7 +1881,6 @@ impl CompletedTransactionSql { timestamp: c.timestamp, cancelled: c.cancelled.map(|v| v as i32), direction: Some(c.direction as i32), - coinbase_block_height: c.coinbase_block_height.map(|b| b as i64), send_count: c.send_count as i32, last_send_timestamp: c.last_send_timestamp, confirmations: c.confirmations.map(|ic| ic as i64), @@ -2106,7 +1979,6 @@ impl CompletedTransaction { .cancelled .map(|v| TxCancellationReason::try_from(v as u32).unwrap_or(TxCancellationReason::Unknown)), direction: TransactionDirection::try_from(c.direction.unwrap_or(2i32))?, - coinbase_block_height: c.coinbase_block_height.map(|b| b as u64), send_count: c.send_count as u32, last_send_timestamp: c.last_send_timestamp, transaction_signature, @@ -2146,17 +2018,6 @@ pub struct UnconfirmedTransactionInfo { pub tx_id: TxId, pub signature: Signature, pub status: TransactionStatus, - pub coinbase_block_height: Option, -} - -impl UnconfirmedTransactionInfo { - pub fn is_coinbase(&self) -> bool { - if let Some(height) = self.coinbase_block_height { - height > 0 - } else { - false - } - } } impl TryFrom for UnconfirmedTransactionInfo { @@ -2170,7 +2031,6 @@ impl TryFrom for UnconfirmedTransactionInfo { PrivateKey::from_vec(&i.transaction_signature_key)?, ), status: TransactionStatus::try_from(i.status)?, - coinbase_block_height: i.coinbase_block_height.map(|b| b as u64), }) } } @@ -2181,7 +2041,6 @@ pub struct UnconfirmedTransactionInfoSql { pub status: i32, pub transaction_signature_nonce: Vec, pub transaction_signature_key: Vec, - pub coinbase_block_height: Option, } impl UnconfirmedTransactionInfoSql { @@ -2195,7 +2054,6 @@ impl UnconfirmedTransactionInfoSql { completed_transactions::status, completed_transactions::transaction_signature_nonce, completed_transactions::transaction_signature_key, - completed_transactions::coinbase_block_height, )) .filter( completed_transactions::status @@ -2233,8 +2091,9 @@ mod test { types::{PrivateKey, PublicKey, Signature}, }; use tari_core::transactions::{ + key_manager::create_memory_db_key_manager, tari_amount::MicroMinotari, - test_helpers::{create_test_core_key_manager_with_memory_db, create_wallet_output_with_data, TestParams}, + test_helpers::{create_wallet_output_with_data, TestParams}, transaction_components::{OutputFeatures, Transaction}, transaction_protocol::sender::TransactionSenderMessage, ReceiverTransactionProtocol, @@ -2265,7 +2124,7 @@ mod test { #[tokio::test] #[allow(clippy::too_many_lines)] async fn test_crud() { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let consensus_constants = create_consensus_constants(0); let db_name = format!("{}.sqlite3", string(8).as_str()); let temp_dir = tempdir().unwrap(); @@ -2512,7 +2371,6 @@ mod test { timestamp: Utc::now().naive_utc(), cancelled: None, direction: TransactionDirection::Unknown, - coinbase_block_height: None, send_count: 0, last_send_timestamp: None, transaction_signature: tx.first_kernel_excess_sig().unwrap_or(&Signature::default()).clone(), @@ -2541,7 +2399,6 @@ mod test { timestamp: Utc::now().naive_utc(), cancelled: None, direction: TransactionDirection::Unknown, - coinbase_block_height: None, send_count: 0, last_send_timestamp: None, transaction_signature: tx.first_kernel_excess_sig().unwrap_or(&Signature::default()).clone(), @@ -2661,116 +2518,6 @@ mod test { .unwrap(); assert!(CompletedTransactionSql::find_by_cancelled(completed_tx1.tx_id, false, &mut conn).is_err()); assert!(CompletedTransactionSql::find_by_cancelled(completed_tx1.tx_id, true, &mut conn).is_ok()); - - let source_address = TariAddress::new( - PublicKey::from_secret_key(&PrivateKey::random(&mut OsRng)), - Network::LocalNet, - ); - let destination_address = TariAddress::new( - PublicKey::from_secret_key(&PrivateKey::random(&mut OsRng)), - Network::LocalNet, - ); - let coinbase_tx1 = CompletedTransaction { - tx_id: 101u64.into(), - source_address, - destination_address, - amount, - fee: MicroMinotari::from(100), - transaction: tx.clone(), - status: TransactionStatus::Coinbase, - message: "Hey!".to_string(), - timestamp: Utc::now().naive_utc(), - cancelled: None, - direction: TransactionDirection::Unknown, - coinbase_block_height: Some(2), - send_count: 0, - last_send_timestamp: None, - transaction_signature: tx.first_kernel_excess_sig().unwrap_or(&Signature::default()).clone(), - confirmations: None, - mined_height: None, - mined_in_block: None, - mined_timestamp: None, - }; - - let source_address = TariAddress::new( - PublicKey::from_secret_key(&PrivateKey::random(&mut OsRng)), - Network::LocalNet, - ); - let destination_address = TariAddress::new( - PublicKey::from_secret_key(&PrivateKey::random(&mut OsRng)), - Network::LocalNet, - ); - let coinbase_tx2 = CompletedTransaction { - tx_id: 102u64.into(), - source_address, - destination_address, - amount, - fee: MicroMinotari::from(100), - transaction: tx.clone(), - status: TransactionStatus::Coinbase, - message: "Hey!".to_string(), - timestamp: Utc::now().naive_utc(), - cancelled: None, - direction: TransactionDirection::Unknown, - coinbase_block_height: Some(2), - send_count: 0, - last_send_timestamp: None, - transaction_signature: tx.first_kernel_excess_sig().unwrap_or(&Signature::default()).clone(), - confirmations: None, - mined_height: None, - mined_in_block: None, - mined_timestamp: None, - }; - - let source_address = TariAddress::new( - PublicKey::from_secret_key(&PrivateKey::random(&mut OsRng)), - Network::LocalNet, - ); - let destination_address = TariAddress::new( - PublicKey::from_secret_key(&PrivateKey::random(&mut OsRng)), - Network::LocalNet, - ); - let coinbase_tx3 = CompletedTransaction { - tx_id: 103u64.into(), - source_address, - destination_address, - amount, - fee: MicroMinotari::from(100), - transaction: tx.clone(), - status: TransactionStatus::Coinbase, - message: "Hey!".to_string(), - timestamp: Utc::now().naive_utc(), - cancelled: None, - direction: TransactionDirection::Unknown, - coinbase_block_height: Some(3), - send_count: 0, - last_send_timestamp: None, - transaction_signature: tx.first_kernel_excess_sig().unwrap_or(&Signature::default()).clone(), - confirmations: None, - mined_height: None, - mined_in_block: None, - mined_timestamp: None, - }; - - CompletedTransactionSql::try_from(coinbase_tx1, &cipher) - .unwrap() - .commit(&mut conn) - .unwrap(); - CompletedTransactionSql::try_from(coinbase_tx2, &cipher) - .unwrap() - .commit(&mut conn) - .unwrap(); - CompletedTransactionSql::try_from(coinbase_tx3, &cipher) - .unwrap() - .commit(&mut conn) - .unwrap(); - - let coinbase_txs = CompletedTransactionSql::index_coinbase_at_block_height(2, &mut conn).unwrap(); - - assert_eq!(coinbase_txs.len(), 2); - assert!(coinbase_txs.iter().any(|c| c.tx_id == 101)); - assert!(coinbase_txs.iter().any(|c| c.tx_id == 102)); - assert!(!coinbase_txs.iter().any(|c| c.tx_id == 103)); } #[test] @@ -2887,7 +2634,6 @@ mod test { timestamp: Utc::now().naive_utc(), cancelled: None, direction: TransactionDirection::Unknown, - coinbase_block_height: None, send_count: 0, last_send_timestamp: None, transaction_signature: Signature::default(), @@ -3016,7 +2762,6 @@ mod test { timestamp: Utc::now().naive_utc(), cancelled: None, direction: TransactionDirection::Unknown, - coinbase_block_height: None, send_count: 0, last_send_timestamp: None, transaction_signature: Signature::default(), @@ -3090,7 +2835,7 @@ mod test { let mut info_list_reference: Vec = vec![]; for i in 0..1000 { - let (cancelled, status, coinbase_block_height) = match i % 13 { + let (cancelled, status) = match i % 13 { 0 => ( if i % 3 == 0 { Some(TxCancellationReason::Unknown) @@ -3098,7 +2843,6 @@ mod test { None }, TransactionStatus::Completed, - None, ), 1 => ( if i % 5 == 0 { @@ -3107,7 +2851,6 @@ mod test { None }, TransactionStatus::Broadcast, - None, ), 2 => ( if i % 7 == 0 { @@ -3116,7 +2859,6 @@ mod test { None }, TransactionStatus::Completed, - Some(i % 2), ), 3 => ( if i % 11 == 0 { @@ -3125,16 +2867,14 @@ mod test { None }, TransactionStatus::Broadcast, - Some(i % 2), ), - 4 => (None, TransactionStatus::Completed, None), - 5 => (None, TransactionStatus::Broadcast, None), - 6 => (None, TransactionStatus::Pending, None), - 7 => (None, TransactionStatus::Coinbase, None), - 8 => (None, TransactionStatus::MinedUnconfirmed, None), - 9 => (None, TransactionStatus::Imported, None), - 10 => (None, TransactionStatus::MinedConfirmed, None), - _ => (None, TransactionStatus::Completed, Some(i)), + 4 => (None, TransactionStatus::Completed), + 5 => (None, TransactionStatus::Broadcast), + 6 => (None, TransactionStatus::Pending), + 8 => (None, TransactionStatus::MinedUnconfirmed), + 9 => (None, TransactionStatus::Imported), + 10 => (None, TransactionStatus::MinedConfirmed), + _ => (None, TransactionStatus::Completed), }; let source_address = TariAddress::new( PublicKey::from_secret_key(&PrivateKey::random(&mut OsRng)), @@ -3145,7 +2885,7 @@ mod test { Network::LocalNet, ); let completed_tx = CompletedTransaction { - tx_id: TxId::from(i), + tx_id: TxId::from(i as u64), source_address, destination_address, amount: MicroMinotari::from(100), @@ -3162,7 +2902,6 @@ mod test { timestamp: Utc::now().naive_utc(), cancelled, direction: TransactionDirection::Unknown, - coinbase_block_height, send_count: 0, last_send_timestamp: None, transaction_signature: Signature::default(), @@ -3192,11 +2931,10 @@ mod test { let db1 = TransactionServiceSqliteDatabase::new(connection, cipher); let txn_list = db1.get_transactions_to_be_broadcast().unwrap(); - assert_eq!(txn_list.len(), 335); + assert_eq!(txn_list.len(), 633); for txn in &txn_list { assert!(txn.status == TransactionStatus::Completed || txn.status == TransactionStatus::Broadcast); assert!(txn.cancelled.is_none()); - assert!(txn.coinbase_block_height.is_none() || txn.coinbase_block_height == Some(0)); } let info_list = db1.get_pending_inbound_transaction_sender_info().unwrap(); diff --git a/base_layer/wallet/src/utxo_scanner_service/utxo_scanner_task.rs b/base_layer/wallet/src/utxo_scanner_service/utxo_scanner_task.rs index 53e425a72a8..00cb88e7a09 100644 --- a/base_layer/wallet/src/utxo_scanner_service/utxo_scanner_task.rs +++ b/base_layer/wallet/src/utxo_scanner_service/utxo_scanner_task.rs @@ -563,11 +563,7 @@ where .await? .into_iter() .map(|ro| { - let status = if ro.output.features.is_coinbase() { - ImportStatus::Coinbase - } else { - ImportStatus::Imported - }; + let status = ImportStatus::Imported; (ro.output, self.resources.recovery_message.clone(), status, ro.tx_id) }) .collect(), @@ -603,7 +599,7 @@ where let mut total_amount = MicroMinotari::from(0); for (uo, message, import_status, tx_id) in utxos { let source_address = if uo.features.is_coinbase() { - // its a coinbase, so we know we mined it and it comes from us. + // It's a coinbase, so we know we mined it (we do mining with cold wallets). self.resources.wallet_identity.address.clone() } else { // Because we do not know the source public key we are making it the default key of zeroes to make it @@ -685,7 +681,6 @@ where wallet_output.value, source_address, message, - Some(wallet_output.features.maturity), import_status.clone(), Some(tx_id), Some(current_height), diff --git a/base_layer/wallet/src/wallet.rs b/base_layer/wallet/src/wallet.rs index ce38426b163..7bb1d3ed956 100644 --- a/base_layer/wallet/src/wallet.rs +++ b/base_layer/wallet/src/wallet.rs @@ -478,7 +478,6 @@ where unblinded_output.value, source_address, message, - Some(unblinded_output.features.maturity), ImportStatus::Imported, None, None, diff --git a/base_layer/wallet/tests/other/mod.rs b/base_layer/wallet/tests/other/mod.rs index 2bb7ba5dd95..b6ac783f17c 100644 --- a/base_layer/wallet/tests/other/mod.rs +++ b/base_layer/wallet/tests/other/mod.rs @@ -102,7 +102,6 @@ use minotari_wallet::{ }; use tempfile::tempdir; use tokio::{sync::mpsc, time::sleep}; -use tari_core::test_helpers::create_test_core_key_manager_with_memory_db; use crate::support::utils::make_input; @@ -284,7 +283,7 @@ async fn test_wallet() { let mut alice_event_stream = alice_wallet.transaction_service.get_event_stream(); let value = MicroMinotari::from(1000); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let (_utxo, uo1) = make_non_recoverable_input(&mut OsRng, MicroMinotari(2500), &OutputFeatures::default(), &key_manager).await; alice_wallet.output_manager_service.add_output(uo1, None).await.unwrap(); @@ -590,7 +589,7 @@ async fn test_store_and_forward_send_tx() { .unwrap(); let value = MicroMinotari::from(1000); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let (_utxo, uo1) = make_non_recoverable_input(&mut OsRng, MicroMinotari(2500), &OutputFeatures::default(), &key_manager).await; alice_wallet.output_manager_service.add_output(uo1, None).await.unwrap(); @@ -734,7 +733,7 @@ async fn test_import_utxo() { let input = inputs!(claim); let temp_features = OutputFeatures::create_coinbase(50, None); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let p = TestParams::new(&key_manager); let utxo = create_wallet_output_with_data(script.clone(), temp_features, &p, 20000 * uT, &key_manager).await.unwrap(); let output = utxo.as_transaction_output(&key_manager).unwrap(); diff --git a/base_layer/wallet/tests/output_manager_service_tests/service.rs b/base_layer/wallet/tests/output_manager_service_tests/service.rs index a25bdcb42c1..567cdd9083e 100644 --- a/base_layer/wallet/tests/output_manager_service_tests/service.rs +++ b/base_layer/wallet/tests/output_manager_service_tests/service.rs @@ -61,15 +61,15 @@ use tari_core::{ proto::base_node::{QueryDeletedData, QueryDeletedResponse, UtxoQueryResponse, UtxoQueryResponses}, transactions::{ fee::Fee, - key_manager::{TransactionKeyManagerBranch, TransactionKeyManagerInterface}, - tari_amount::{uT, MicroMinotari, T}, - test_helpers::{ - create_test_core_key_manager_with_memory_db, - create_wallet_output_with_data, - TestKeyManager, - TestParams, + key_manager::{ + create_memory_db_key_manager, + MemoryDbKeyManager, + TransactionKeyManagerBranch, + TransactionKeyManagerInterface, }, - transaction_components::{OutputFeatures, OutputType, TransactionOutput, WalletOutput}, + tari_amount::{uT, MicroMinotari, T}, + test_helpers::{create_wallet_output_with_data, TestParams}, + transaction_components::{OutputFeatures, TransactionOutput, WalletOutput}, transaction_protocol::{sender::TransactionSenderMessage, TransactionMetadata}, weight::TransactionWeight, CryptoFactories, @@ -108,7 +108,7 @@ struct TestOmsService { pub node_id: Arc, pub base_node_wallet_rpc_mock_state: BaseNodeWalletRpcMockState, pub node_event: broadcast::Sender>, - pub key_manager_handle: TestKeyManager, + pub key_manager_handle: MemoryDbKeyManager, } #[allow(clippy::type_complexity)] @@ -159,7 +159,7 @@ async fn setup_output_manager_service( wallet_connectivity_mock.set_base_node_wallet_rpc_client(connect_rpc_client(&mut connection).await); } - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let wallet_identity = WalletIdentity::new(server_node_identity.clone(), Network::LocalNet); let output_manager_service = OutputManagerService::new( @@ -204,7 +204,7 @@ pub async fn setup_oms_with_bn_state( TransactionServiceHandle, BaseNodeServiceHandle, broadcast::Sender>, - TestKeyManager, + MemoryDbKeyManager, ) { let shutdown = Shutdown::new(); let factories = CryptoFactories::default(); @@ -226,7 +226,7 @@ pub async fn setup_oms_with_bn_state( mock_base_node_service.set_base_node_state(height); task::spawn(mock_base_node_service.run()); let connectivity = create_wallet_connectivity_mock(); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let wallet_identity = WalletIdentity::new(node_identity.clone(), Network::LocalNet); let output_manager_service = OutputManagerService::new( OutputManagerServiceConfig { ..Default::default() }, @@ -259,7 +259,7 @@ pub async fn setup_oms_with_bn_state( async fn generate_sender_transaction_message( amount: MicroMinotari, - key_manager: &TestKeyManager, + key_manager: &MemoryDbKeyManager, ) -> (TxId, TransactionSenderMessage) { let input = make_input(&mut OsRng, 2 * amount, &OutputFeatures::default(), key_manager).await; let mut builder = SenderTransactionProtocol::builder(create_consensus_constants(0), key_manager.clone()); @@ -678,16 +678,34 @@ async fn test_utxo_selection_with_tx_priority() { let amount = MicroMinotari::from(2000); let fee_per_gram = MicroMinotari::from(2); - // we create two outputs, one as coinbase-high priority one as normal so we can track them - let uo = make_input_with_features( + // Low priority + let uo_low_1 = make_input_with_features( + &mut OsRng.clone(), + amount, + OutputFeatures { + maturity: 1, + ..Default::default() + }, + &key_manager, + ) + .await; + oms.add_output(uo_low_1.clone(), None).await.unwrap(); + // High priority + let uo_high = make_input_with_features( &mut OsRng.clone(), amount, - OutputFeatures::create_coinbase(1, None), + OutputFeatures { + maturity: 1, + ..Default::default() + }, &key_manager, ) .await; - oms.add_output(uo, Some(SpendingPriority::HtlcSpendAsap)).await.unwrap(); - let uo = make_input_with_features( + oms.add_output(uo_high.clone(), Some(SpendingPriority::HtlcSpendAsap)) + .await + .unwrap(); + // Low priority + let uo_low_2 = make_input_with_features( &mut OsRng.clone(), amount, OutputFeatures { @@ -697,10 +715,17 @@ async fn test_utxo_selection_with_tx_priority() { &key_manager, ) .await; - oms.add_output(uo, None).await.unwrap(); + oms.add_output(uo_low_2.clone(), None).await.unwrap(); let utxos = oms.get_unspent_outputs().await.unwrap(); - assert_eq!(utxos.len(), 2); + assert_eq!(utxos.len(), 3); + + assert_eq!(utxos[0].spending_priority, SpendingPriority::Normal); + assert_eq!(utxos[0].wallet_output.spending_key_id, uo_low_1.spending_key_id); + assert_eq!(utxos[1].spending_priority, SpendingPriority::HtlcSpendAsap); + assert_eq!(utxos[1].wallet_output.spending_key_id, uo_high.spending_key_id); + assert_eq!(utxos[2].spending_priority, SpendingPriority::Normal); + assert_eq!(utxos[2].wallet_output.spending_key_id, uo_low_2.spending_key_id); // test transactions let stp = oms @@ -720,11 +745,11 @@ async fn test_utxo_selection_with_tx_priority() { .unwrap(); assert!(stp.get_tx_id().is_ok()); - // test that the utxo with the lowest priority was left + // Test that the UTXOs with the lowest priority was left let utxos = oms.get_unspent_outputs().await.unwrap(); - assert_eq!(utxos.len(), 1); - - assert_ne!(utxos[0].wallet_output.features.output_type, OutputType::Coinbase); + assert_eq!(utxos.len(), 2); + assert_ne!(utxos[0].wallet_output.spending_key_id, uo_high.spending_key_id); + assert_ne!(utxos[1].wallet_output.spending_key_id, uo_high.spending_key_id); } #[tokio::test] @@ -783,7 +808,7 @@ async fn send_no_change() { .expect("Failed to get default features and scripts size byte size"), ); let value1 = 5000; - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); oms.output_manager_handle .add_output( create_wallet_output_with_data( @@ -800,7 +825,7 @@ async fn send_no_change() { .await .unwrap(); let value2 = 8000; - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); oms.output_manager_handle .add_output( create_wallet_output_with_data( @@ -855,7 +880,7 @@ async fn send_not_enough_for_change() { let constants = create_consensus_constants(0); let fee_without_change = Fee::new(*constants.transaction_weight_params()).calculate(fee_per_gram, 1, 2, 1, 0); let value1 = MicroMinotari(500); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); oms.output_manager_handle .add_output( create_wallet_output_with_data( @@ -1257,75 +1282,6 @@ async fn it_handles_large_coin_splits() { assert_eq!(coin_split_tx.body.outputs().len(), split_count + 1); } -#[tokio::test] -async fn handle_coinbase_with_bulletproofs_rewinding() { - let (connection, _tempdir) = get_temp_sqlite_database_connection(); - let backend = OutputManagerSqliteDatabase::new(connection.clone()); - let mut oms = setup_output_manager_service(backend, true).await; - - let reward1 = MicroMinotari::from(1000); - let fees1 = MicroMinotari::from(500); - let reward2 = MicroMinotari::from(2000); - let fees2 = MicroMinotari::from(500); - let reward3 = MicroMinotari::from(3000); - let fees3 = MicroMinotari::from(500); - let value3 = reward3 + fees3; - - let _transaction = oms - .output_manager_handle - .get_coinbase_transaction(1u64.into(), reward1, fees1, 1, b"test".to_vec()) - .await - .unwrap(); - assert_eq!(oms.output_manager_handle.get_unspent_outputs().await.unwrap().len(), 0); - // pending coinbases should not show up as pending incoming - assert_eq!( - oms.output_manager_handle - .get_balance() - .await - .unwrap() - .pending_incoming_balance, - MicroMinotari::from(0) - ); - - let _tx2 = oms - .output_manager_handle - .get_coinbase_transaction(2u64.into(), reward2, fees2, 1, b"test".to_vec()) - .await - .unwrap(); - assert_eq!(oms.output_manager_handle.get_unspent_outputs().await.unwrap().len(), 0); - assert_eq!( - oms.output_manager_handle - .get_balance() - .await - .unwrap() - .pending_incoming_balance, - MicroMinotari::from(0) - ); - let tx3 = oms - .output_manager_handle - .get_coinbase_transaction(3u64.into(), reward3, fees3, 2, b"test".to_vec()) - .await - .unwrap(); - assert_eq!(oms.output_manager_handle.get_unspent_outputs().await.unwrap().len(), 0); - assert_eq!( - oms.output_manager_handle - .get_balance() - .await - .unwrap() - .pending_incoming_balance, - MicroMinotari::from(0) - ); - - let output = tx3.body.outputs()[0].clone(); - - let (_, decrypted_value) = oms - .key_manager_handle - .try_output_key_recovery(&output, None) - .await - .unwrap(); - assert_eq!(decrypted_value, value3); -} - #[tokio::test] #[allow(clippy::too_many_lines)] async fn test_txo_validation() { @@ -1482,30 +1438,14 @@ async fn test_txo_validation() { .await .unwrap(); - oms.output_manager_handle - .get_coinbase_transaction( - 6u64.into(), - MicroMinotari::from(15_000_000), - MicroMinotari::from(1_000_000), - 2, - b"test".to_vec(), - ) - .await - .unwrap(); - let mut outputs = oms_db.fetch_pending_incoming_outputs().unwrap(); - assert_eq!(outputs.len(), 3); + assert_eq!(outputs.len(), 2); let o5_pos = outputs .iter() .position(|o| o.wallet_output.value == MicroMinotari::from(8_000_000)) .unwrap(); let output5 = outputs.remove(o5_pos); - let o6_pos = outputs - .iter() - .position(|o| o.wallet_output.value == MicroMinotari::from(16_000_000)) - .unwrap(); - let output6 = outputs.remove(o6_pos); let output4 = outputs[0].clone(); let output4_tx_output = output4 @@ -1518,11 +1458,6 @@ async fn test_txo_validation() { .to_transaction_output(&oms.key_manager_handle) .await .unwrap(); - let output6_tx_output = output6 - .wallet_output - .to_transaction_output(&oms.key_manager_handle) - .await - .unwrap(); let balance = oms.output_manager_handle.get_balance().await.unwrap(); @@ -1581,13 +1516,6 @@ async fn test_txo_validation() { output_hash: output5_tx_output.hash().to_vec(), mined_timestamp: 0, }, - UtxoQueryResponse { - output: Some(output6_tx_output.clone().try_into().unwrap()), - mined_at_height: 5, - mined_in_block: block5_header.hash().to_vec(), - output_hash: output6_tx_output.hash().to_vec(), - mined_timestamp: 0, - }, ]; let mut utxo_query_responses = UtxoQueryResponses { @@ -1648,14 +1576,14 @@ async fn test_txo_validation() { .await .unwrap(); - assert_eq!(utxo_query_calls[0].len(), 4); + assert_eq!(utxo_query_calls[0].len(), 3); let query_deleted_calls = oms .base_node_wallet_rpc_mock_state .wait_pop_query_deleted(1, Duration::from_secs(60)) .await .unwrap(); - assert_eq!(query_deleted_calls[0].hashes.len(), 5); + assert_eq!(query_deleted_calls[0].hashes.len(), 4); let balance = oms.output_manager_handle.get_balance().await.unwrap(); assert_eq!( @@ -1664,7 +1592,7 @@ async fn test_txo_validation() { ); assert_eq!(MicroMinotari::from(0), balance.time_locked_balance.unwrap()); - assert_eq!(oms.output_manager_handle.get_unspent_outputs().await.unwrap().len(), 5); + assert_eq!(oms.output_manager_handle.get_unspent_outputs().await.unwrap().len(), 4); assert!(oms.output_manager_handle.get_spent_outputs().await.unwrap().is_empty()); @@ -1695,7 +1623,7 @@ async fn test_txo_validation() { .unwrap(); // The spent transaction is not checked during this second validation - assert_eq!(utxo_query_calls[0].len(), 4); + assert_eq!(utxo_query_calls[0].len(), 3); let query_deleted_calls = oms .base_node_wallet_rpc_mock_state @@ -1703,7 +1631,7 @@ async fn test_txo_validation() { .await .unwrap(); - assert_eq!(query_deleted_calls[0].hashes.len(), 5); + assert_eq!(query_deleted_calls[0].hashes.len(), 4); let balance = oms.output_manager_handle.get_balance().await.unwrap(); assert_eq!( @@ -1711,10 +1639,9 @@ async fn test_txo_validation() { MicroMinotari::from(output2_value) + MicroMinotari::from(output3_value) + MicroMinotari::from(output1_value) - MicroMinotari::from(900_000) - MicroMinotari::from(1320) + //spent 900_000 and 1320 for fees - MicroMinotari::from(8_000_000) + //output 5 - MicroMinotari::from(16_000_000) // output 6 + MicroMinotari::from(8_000_000) // output 5 ); - assert_eq!(balance.pending_outgoing_balance, MicroMinotari::from(0)); + assert_eq!(balance.pending_outgoing_balance, MicroMinotari::from(1000000)); assert_eq!(balance.pending_incoming_balance, MicroMinotari::from(0)); assert_eq!(MicroMinotari::from(0), balance.time_locked_balance.unwrap()); @@ -1954,7 +1881,7 @@ async fn test_txo_revalidation() { .set_base_node_wallet_rpc_client(connect_rpc_client(&mut connection).await); let output1_value = 1_000_000; - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let output1 = create_wallet_output_with_data( script!(Nop), OutputFeatures::default(), @@ -2232,7 +2159,7 @@ async fn scan_for_recovery_test() { let mut non_recoverable_wallet_outputs = Vec::new(); // we need to create a new key_manager to make the outputs non recoverable - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); for i in 1..=NUM_NON_RECOVERABLE { let uo = make_input( &mut OsRng, @@ -2287,7 +2214,7 @@ async fn recovered_output_key_not_in_keychain() { let backend = OutputManagerSqliteDatabase::new(connection.clone()); let mut oms = setup_output_manager_service(backend.clone(), true).await; // we need to create a new key manager here as we dont want the input be recoverable from oms key chain - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let uo = make_input( &mut OsRng, MicroMinotari::from(1000u64), diff --git a/base_layer/wallet/tests/output_manager_service_tests/storage.rs b/base_layer/wallet/tests/output_manager_service_tests/storage.rs index 411e974e0db..88f2616f159 100644 --- a/base_layer/wallet/tests/output_manager_service_tests/storage.rs +++ b/base_layer/wallet/tests/output_manager_service_tests/storage.rs @@ -33,8 +33,8 @@ use minotari_wallet::output_manager_service::{ use rand::{rngs::OsRng, RngCore}; use tari_common_types::{transaction::TxId, types::FixedHash}; use tari_core::transactions::{ + key_manager::create_memory_db_key_manager, tari_amount::MicroMinotari, - test_helpers::create_test_core_key_manager_with_memory_db, transaction_components::OutputFeatures, }; @@ -46,7 +46,7 @@ pub async fn test_db_backend(backend: T) { // Add some unspent outputs let mut unspent_outputs = Vec::new(); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); for i in 0..5 { let uo = make_input( &mut OsRng, @@ -55,7 +55,7 @@ pub async fn test_db_backend(backend: T) { &key_manager, ) .await; - let mut kmo = DbWalletOutput::from_wallet_output(uo, &key_manager, None, OutputSource::Unknown, None, None) + let mut kmo = DbWalletOutput::from_wallet_output(uo, &key_manager, None, OutputSource::Standard, None, None) .await .unwrap(); kmo.wallet_output.features.maturity = i; @@ -106,7 +106,7 @@ pub async fn test_db_backend(backend: T) { &key_manager, ) .await; - let kmo = DbWalletOutput::from_wallet_output(kmo, &key_manager, None, OutputSource::Unknown, None, None) + let kmo = DbWalletOutput::from_wallet_output(kmo, &key_manager, None, OutputSource::Standard, None, None) .await .unwrap(); db.add_unspent_output(kmo.clone()).unwrap(); @@ -120,7 +120,7 @@ pub async fn test_db_backend(backend: T) { &key_manager, ) .await; - let kmo = DbWalletOutput::from_wallet_output(uo, &key_manager, None, OutputSource::Unknown, None, None) + let kmo = DbWalletOutput::from_wallet_output(uo, &key_manager, None, OutputSource::Standard, None, None) .await .unwrap(); pending_tx.outputs_to_be_received.push(kmo); @@ -257,10 +257,10 @@ pub async fn test_db_backend(backend: T) { ) .await; let output_to_be_received = - DbWalletOutput::from_wallet_output(uo, &key_manager, None, OutputSource::Unknown, None, None) + DbWalletOutput::from_wallet_output(uo, &key_manager, None, OutputSource::Standard, None, None) .await .unwrap(); - db.add_output_to_be_received(TxId::from(11u64), output_to_be_received.clone(), None) + db.add_output_to_be_received(TxId::from(11u64), output_to_be_received.clone()) .unwrap(); pending_incoming_balance += output_to_be_received.wallet_output.value; @@ -346,7 +346,7 @@ pub async fn test_short_term_encumberance() { let db = OutputManagerDatabase::new(backend); let mut unspent_outputs = Vec::new(); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); for i in 0..5 { let kmo = make_input( &mut OsRng, @@ -355,7 +355,7 @@ pub async fn test_short_term_encumberance() { &key_manager, ) .await; - let mut kmo = DbWalletOutput::from_wallet_output(kmo, &key_manager, None, OutputSource::Unknown, None, None) + let mut kmo = DbWalletOutput::from_wallet_output(kmo, &key_manager, None, OutputSource::Standard, None, None) .await .unwrap(); kmo.wallet_output.features.maturity = i; @@ -406,7 +406,7 @@ pub async fn test_no_duplicate_outputs() { let db = OutputManagerDatabase::new(backend); // create an output - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let uo = make_input( &mut OsRng, MicroMinotari::from(1000), @@ -414,7 +414,7 @@ pub async fn test_no_duplicate_outputs() { &key_manager, ) .await; - let kmo = DbWalletOutput::from_wallet_output(uo, &key_manager, None, OutputSource::Unknown, None, None) + let kmo = DbWalletOutput::from_wallet_output(uo, &key_manager, None, OutputSource::Standard, None, None) .await .unwrap(); @@ -448,7 +448,7 @@ pub async fn test_mark_as_unmined() { let db = OutputManagerDatabase::new(backend); // create an output - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let uo = make_input( &mut OsRng, MicroMinotari::from(1000), @@ -456,7 +456,7 @@ pub async fn test_mark_as_unmined() { &key_manager, ) .await; - let kmo = DbWalletOutput::from_wallet_output(uo, &key_manager, None, OutputSource::Unknown, None, None) + let kmo = DbWalletOutput::from_wallet_output(uo, &key_manager, None, OutputSource::Standard, None, None) .await .unwrap(); diff --git a/base_layer/wallet/tests/support/utils.rs b/base_layer/wallet/tests/support/utils.rs index b91be5482cc..704ff911f64 100644 --- a/base_layer/wallet/tests/support/utils.rs +++ b/base_layer/wallet/tests/support/utils.rs @@ -24,9 +24,9 @@ use rand::{CryptoRng, Rng}; use tari_core::{ covenants::Covenant, transactions::{ - key_manager::TransactionKeyManagerInterface, + key_manager::{MemoryDbKeyManager, TransactionKeyManagerInterface}, tari_amount::MicroMinotari, - test_helpers::{create_wallet_output_with_data, TestKeyManager, TestParams}, + test_helpers::{create_wallet_output_with_data, TestParams}, transaction_components::{ OutputFeatures, RangeProofType, @@ -44,7 +44,7 @@ pub async fn make_input( _rng: &mut R, val: MicroMinotari, features: &OutputFeatures, - key_manager: &TestKeyManager, + key_manager: &MemoryDbKeyManager, ) -> WalletOutput { let test_params = TestParams::new(key_manager).await; create_wallet_output_with_data(TariScript::default(), features.clone(), &test_params, val, key_manager) @@ -54,7 +54,7 @@ pub async fn make_input( pub async fn create_wallet_output_from_sender_data( info: &TransactionSenderMessage, - key_manager: &TestKeyManager, + key_manager: &MemoryDbKeyManager, ) -> WalletOutput { let test_params = TestParams::new(key_manager).await; let sender_data = info.single().unwrap(); @@ -104,7 +104,7 @@ pub async fn make_input_with_features( _rng: &mut R, value: MicroMinotari, features: OutputFeatures, - key_manager: &TestKeyManager, + key_manager: &MemoryDbKeyManager, ) -> WalletOutput { let test_params = TestParams::new(key_manager).await; create_wallet_output_with_data(script!(Nop), features, &test_params, value, key_manager) diff --git a/base_layer/wallet/tests/transaction_service_tests/service.rs b/base_layer/wallet/tests/transaction_service_tests/service.rs index d922c4d92d0..4b82480a2b0 100644 --- a/base_layer/wallet/tests/transaction_service_tests/service.rs +++ b/base_layer/wallet/tests/transaction_service_tests/service.rs @@ -21,7 +21,6 @@ // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. use std::{ - collections::HashMap, convert::{TryFrom, TryInto}, mem::size_of, path::Path, @@ -50,7 +49,7 @@ use minotari_wallet::{ output_manager_service::{ config::OutputManagerServiceConfig, handle::{OutputManagerEvent, OutputManagerHandle}, - service::{Balance, OutputManagerService}, + service::OutputManagerService, storage::{ database::OutputManagerDatabase, models::KnownOneSidedPaymentScript, @@ -108,29 +107,20 @@ use tari_core::{ proto::wallet_rpc::{TxLocation, TxQueryResponse, TxSubmissionRejectionReason, TxSubmissionResponse}, rpc::BaseNodeWalletRpcServer, }, - blocks::BlockHeader, consensus::{ConsensusConstantsBuilder, ConsensusManager}, covenants::Covenant, one_sided::shared_secret_to_output_encryption_key, - proto::{ - base_node as base_node_proto, - base_node::{ - TxLocation as TxLocationProto, - TxQueryBatchResponse as TxQueryBatchResponseProto, - TxQueryBatchResponses as TxQueryBatchResponsesProto, - }, - types::Signature as SignatureProto, - }, + proto::base_node as base_node_proto, transactions::{ fee::Fee, - key_manager::{TransactionKeyManagerInitializer, TransactionKeyManagerInterface}, - tari_amount::*, - test_helpers::{ - create_test_core_key_manager_with_memory_db, - create_wallet_output_with_data, - TestKeyManager, - TestParams, + key_manager::{ + create_memory_db_key_manager, + MemoryDbKeyManager, + TransactionKeyManagerInitializer, + TransactionKeyManagerInterface, }, + tari_amount::*, + test_helpers::{create_wallet_output_with_data, TestParams}, transaction_components::{KernelBuilder, OutputFeatures, Transaction}, transaction_protocol::{ proto::protocol as proto, @@ -159,7 +149,7 @@ use tari_script::{inputs, one_sided_payment_script, script, ExecutionStack}; use tari_service_framework::{reply_channel, RegisterHandle, StackBuilder}; use tari_shutdown::{Shutdown, ShutdownSignal}; use tari_test_utils::{comms_and_services::get_next_memory_address, random}; -use tari_utilities::{epoch_time::EpochTime, ByteArray, SafePassword}; +use tari_utilities::{ByteArray, SafePassword}; use tempfile::tempdir; use tokio::{ sync::{broadcast, broadcast::channel}, @@ -188,7 +178,7 @@ async fn setup_transaction_service>( OutputManagerHandle, CommsNode, WalletConnectivityHandle, - TestKeyManager, + MemoryDbKeyManager, ) { let (publisher, subscription_factory) = pubsub_connector(100); let subscription_factory = Arc::new(subscription_factory); @@ -230,7 +220,7 @@ async fn setup_transaction_service>( .add_initializer(RegisterHandle::new(comms.connectivity())) .add_initializer(OutputManagerServiceInitializer::< OutputManagerSqliteDatabase, - TestKeyManager, + MemoryDbKeyManager, >::new( OutputManagerServiceConfig::default(), oms_backend, @@ -243,7 +233,7 @@ async fn setup_transaction_service>( cipher, factories.clone(), )) - .add_initializer(TransactionServiceInitializer::<_, _, TestKeyManager>::new( + .add_initializer(TransactionServiceInitializer::<_, _, MemoryDbKeyManager>::new( TransactionServiceConfig { broadcast_monitoring_timeout: Duration::from_secs(5), chain_monitoring_timeout: Duration::from_secs(5), @@ -265,7 +255,7 @@ async fn setup_transaction_service>( .unwrap(); let output_manager_handle = handles.expect_handle::(); - let key_manager_handle = handles.expect_handle::(); + let key_manager_handle = handles.expect_handle::(); let transaction_service_handle = handles.expect_handle::(); let connectivity_service_handle = handles.expect_handle::(); @@ -283,7 +273,7 @@ async fn setup_transaction_service>( pub struct TransactionServiceNoCommsInterface { transaction_service_handle: TransactionServiceHandle, output_manager_service_handle: OutputManagerHandle, - key_manager_handle: TestKeyManager, + key_manager_handle: MemoryDbKeyManager, outbound_service_mock_state: OutboundServiceMockState, transaction_send_message_channel: Sender>>, @@ -373,7 +363,7 @@ async fn setup_transaction_service_no_comms( let ts_service_db = TransactionServiceSqliteDatabase::new(db_connection.clone(), cipher.clone()); let ts_db = TransactionDatabase::new(ts_service_db.clone()); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let oms_db = OutputManagerDatabase::new(OutputManagerSqliteDatabase::new(db_connection)); let wallet_identity = WalletIdentity::new(node_identity.clone(), Network::LocalNet); let output_manager_service = OutputManagerService::new( @@ -1980,7 +1970,7 @@ async fn test_accepting_unknown_tx_id_and_malformed_reply() { #[tokio::test] async fn finalize_tx_with_incorrect_pubkey() { let factories = CryptoFactories::default(); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let temp_dir = tempdir().unwrap(); let path_string = temp_dir.path().to_str().unwrap().to_string(); @@ -2101,7 +2091,7 @@ async fn finalize_tx_with_incorrect_pubkey() { #[tokio::test] async fn finalize_tx_with_missing_output() { let factories = CryptoFactories::default(); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let temp_dir = tempdir().unwrap(); let path_string = temp_dir.path().to_str().unwrap().to_string(); @@ -2463,7 +2453,6 @@ async fn test_power_mode_updates() { timestamp: Utc::now().naive_utc(), cancelled: None, direction: TransactionDirection::Outbound, - coinbase_block_height: None, send_count: 0, last_send_timestamp: None, transaction_signature: tx.first_kernel_excess_sig().unwrap_or(&Signature::default()).clone(), @@ -2493,7 +2482,6 @@ async fn test_power_mode_updates() { timestamp: Utc::now().naive_utc(), cancelled: None, direction: TransactionDirection::Outbound, - coinbase_block_height: None, send_count: 0, last_send_timestamp: None, transaction_signature: tx.first_kernel_excess_sig().unwrap_or(&Signature::default()).clone(), @@ -2749,7 +2737,7 @@ async fn test_transaction_cancellation() { .remove(&tx_id) .is_none()); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let input = create_wallet_output_with_data( script!(Nop), OutputFeatures::default(), @@ -2761,7 +2749,7 @@ async fn test_transaction_cancellation() { .unwrap(); let constants = create_consensus_constants(0); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let mut builder = SenderTransactionProtocol::builder(constants, key_manager.clone()); let amount = MicroMinotari::from(10_000); let change = TestParams::new(&key_manager).await; @@ -3567,7 +3555,7 @@ async fn test_restarting_transaction_protocols() { .await; let constants = create_consensus_constants(0); let fee_calc = Fee::new(*constants.transaction_weight_params()); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let mut builder = SenderTransactionProtocol::builder(constants.clone(), key_manager.clone()); let fee = fee_calc.calculate(MicroMinotari(4), 1, 1, 1, 0); let change = TestParams::new(&key_manager).await; @@ -3749,1150 +3737,205 @@ async fn test_restarting_transaction_protocols() { } #[tokio::test] -async fn test_coinbase_transactions_rejection_same_hash_but_accept_on_same_height() { +async fn test_transaction_resending() { let factories = CryptoFactories::default(); - let (connection, _temp_dir) = make_wallet_database_connection(None); - - let mut alice_ts_interface = setup_transaction_service_no_comms(factories, connection, None).await; - - let block_height_a = 10; - let block_height_b = block_height_a + 1; + let alice_node_identity = + NodeIdentity::random(&mut OsRng, get_next_memory_address(), PeerFeatures::COMMUNICATION_NODE); + let bob_node_identity = + NodeIdentity::random(&mut OsRng, get_next_memory_address(), PeerFeatures::COMMUNICATION_NODE); + // Setup Alice wallet with no comms stack + let (connection, _tempdir) = make_wallet_database_connection(None); - let fees1 = 1000 * uT; - let reward1 = 1_000_000 * uT; + let mut alice_ts_interface = setup_transaction_service_no_comms( + factories.clone(), + connection, + Some(TransactionServiceConfig { + transaction_resend_period: Duration::from_secs(20), + resend_response_cooldown: Duration::from_secs(10), + ..Default::default() + }), + ) + .await; - let fees2 = 2000 * uT; - let reward2 = 2_000_000 * uT; + // Send a transaction to Bob + let alice_total_available = 250000 * uT; + let uo = make_input( + &mut OsRng, + alice_total_available, + &OutputFeatures::default(), + &alice_ts_interface.key_manager_handle, + ) + .await; + alice_ts_interface + .output_manager_service_handle + .add_output(uo, None) + .await + .unwrap(); - let fees3 = 4000 * uT; - let reward3 = 4_000_000 * uT; + let amount_sent = 100000 * uT; - // Create a coinbase Txn at the first block height - let _tx1 = alice_ts_interface + let bob_address = TariAddress::new(bob_node_identity.public_key().clone(), Network::LocalNet); + let tx_id = alice_ts_interface .transaction_service_handle - .generate_coinbase_transaction(reward1, fees1, block_height_a, b"test".to_vec()) + .send_transaction( + bob_address, + amount_sent, + UtxoSelectionCriteria::default(), + OutputFeatures::default(), + 100 * uT, + "Testing Message".to_string(), + ) .await .unwrap(); - let transactions = alice_ts_interface - .transaction_service_handle - .get_completed_transactions() + + // Check that there were repeats + alice_ts_interface + .outbound_service_mock_state + .wait_call_count(2, Duration::from_secs(60)) .await - .unwrap(); - assert_eq!(transactions.len(), 1); - let _tx_id1 = transactions - .values() - .find(|tx| tx.amount == fees1 + reward1) - .unwrap() - .tx_id; - assert_eq!( - alice_ts_interface - .output_manager_service_handle - .get_balance() - .await - .unwrap() - .pending_incoming_balance, - MicroMinotari::from(0) - ); + .expect("Alice call wait 1"); - // Create a second coinbase txn at the first block height, with same output hash as the previous one - // the previous one should be cancelled - let _tx1b = alice_ts_interface - .transaction_service_handle - .generate_coinbase_transaction(reward1, fees1, block_height_a, b"test".to_vec()) + let mut alice_sender_message = TransactionSenderMessage::None; + for _ in 0..2 { + let call = alice_ts_interface.outbound_service_mock_state.pop_call().await.unwrap(); + alice_sender_message = try_decode_sender_message(call.1.to_vec().clone()).unwrap(); + if let TransactionSenderMessage::Single(data) = alice_sender_message.clone() { + assert_eq!(data.tx_id, tx_id); + } else { + panic!("Should be a Single Transaction Sender Message") + } + } + + // Setup Bob's wallet with no comms stack + let (connection, _tempdir) = make_wallet_database_connection(None); + + let mut bob_ts_interface = setup_transaction_service_no_comms( + factories, + connection, + Some(TransactionServiceConfig { + transaction_resend_period: Duration::from_secs(20), + resend_response_cooldown: Duration::from_secs(10), + ..Default::default() + }), + ) + .await; + + // Pass sender message to Bob's wallet + bob_ts_interface + .transaction_send_message_channel + .send(create_dummy_message( + alice_sender_message.clone().try_into().unwrap(), + alice_node_identity.public_key(), + )) .await .unwrap(); - let transactions = alice_ts_interface - .transaction_service_handle - .get_completed_transactions() + + // Check that the reply was repeated + bob_ts_interface + .outbound_service_mock_state + .wait_call_count(2, Duration::from_secs(60)) .await - .unwrap(); - assert_eq!(transactions.len(), 1); - let _tx_id1b = transactions - .values() - .find(|tx| tx.amount == fees1 + reward1) - .unwrap() - .tx_id; - assert_eq!( - alice_ts_interface - .output_manager_service_handle - .get_balance() - .await - .unwrap() - .pending_incoming_balance, - MicroMinotari::from(0) - ); + .expect("Bob call wait 1"); - // Create another coinbase Txn at the same block height; the previous one should not be cancelled - let _tx2 = alice_ts_interface - .transaction_service_handle - .generate_coinbase_transaction(reward2, fees2, block_height_a, b"test".to_vec()) + let mut bob_reply_message; + for _ in 0..2 { + let call = bob_ts_interface.outbound_service_mock_state.pop_call().await.unwrap(); + bob_reply_message = try_decode_transaction_reply_message(call.1.to_vec().clone()).unwrap(); + assert_eq!(bob_reply_message.tx_id, tx_id); + } + + sleep(Duration::from_secs(2)).await; + // See if sending a second message too soon is ignored + bob_ts_interface + .transaction_send_message_channel + .send(create_dummy_message( + alice_sender_message.clone().try_into().unwrap(), + alice_node_identity.public_key(), + )) .await .unwrap(); - let transactions = alice_ts_interface - .transaction_service_handle - .get_completed_transactions() + + assert!(bob_ts_interface + .outbound_service_mock_state + .wait_call_count(1, Duration::from_secs(2)) .await - .unwrap(); // Only one valid coinbase txn remains - assert_eq!(transactions.len(), 2); - let _tx_id2 = transactions - .values() - .find(|tx| tx.amount == fees2 + reward2) - .unwrap() - .tx_id; - assert_eq!( - alice_ts_interface - .output_manager_service_handle - .get_balance() - .await - .unwrap() - .pending_incoming_balance, - MicroMinotari::from(0) - ); + .is_err()); - // Create a third coinbase Txn at the second block height; all the three should be valid - let _tx3 = alice_ts_interface - .transaction_service_handle - .generate_coinbase_transaction(reward3, fees3, block_height_b, b"test".to_vec()) + // Wait for the cooldown to expire but before the resend period has elapsed see if a repeat illicits a response. + sleep(Duration::from_secs(8)).await; + bob_ts_interface + .transaction_send_message_channel + .send(create_dummy_message( + alice_sender_message.try_into().unwrap(), + alice_node_identity.public_key(), + )) .await .unwrap(); - let transactions = alice_ts_interface - .transaction_service_handle - .get_completed_transactions() + bob_ts_interface + .outbound_service_mock_state + .wait_call_count(2, Duration::from_secs(60)) .await - .unwrap(); - assert_eq!(transactions.len(), 3); - let _tx_id3 = transactions - .values() - .find(|tx| tx.amount == fees3 + reward3) - .unwrap() - .tx_id; - assert_eq!( - alice_ts_interface - .output_manager_service_handle - .get_balance() - .await - .unwrap() - .pending_incoming_balance, - MicroMinotari::from(0) - ); - - assert!(transactions.values().any(|tx| tx.amount == fees1 + reward1)); - assert!(transactions.values().any(|tx| tx.amount == fees2 + reward2)); - assert!(transactions.values().any(|tx| tx.amount == fees3 + reward3)); -} - -#[tokio::test] -async fn test_coinbase_generation_and_monitoring() { - let factories = CryptoFactories::default(); + .expect("Bob call wait 2"); + let _result = bob_ts_interface.outbound_service_mock_state.pop_call().await.unwrap(); + let call = bob_ts_interface.outbound_service_mock_state.pop_call().await.unwrap(); + bob_reply_message = try_decode_transaction_reply_message(call.1.to_vec()).unwrap(); + assert_eq!(bob_reply_message.tx_id, tx_id); - let (connection, _temp_dir) = make_wallet_database_connection(None); - let mut alice_ts_interface = setup_transaction_service_no_comms(factories, connection, None).await; + let _result = alice_ts_interface.outbound_service_mock_state.take_calls().await; - let tx_backend = alice_ts_interface.ts_db; - let db = TransactionDatabase::new(tx_backend); - let mut alice_event_stream = alice_ts_interface.transaction_service_handle.get_event_stream(); + // Send the reply to Alice alice_ts_interface - .base_node_rpc_mock_state - .set_response_delay(Some(Duration::from_secs(1))); - - let block_height_a = 10; - let block_height_b = block_height_a + 1; + .transaction_ack_message_channel + .send(create_dummy_message( + bob_reply_message.clone().try_into().unwrap(), + bob_node_identity.public_key(), + )) + .await + .unwrap(); - let fees1 = 1000 * uT; - let reward1 = 1_000_000 * uT; + alice_ts_interface + .outbound_service_mock_state + .wait_call_count(2, Duration::from_secs(60)) + .await + .expect("Alice call wait 2"); - let fees2 = 2000 * uT; - let fees2b = 5000 * uT; - let reward2 = 2_000_000 * uT; + let _result = alice_ts_interface.outbound_service_mock_state.pop_call().await.unwrap(); + let call = alice_ts_interface.outbound_service_mock_state.pop_call().await.unwrap(); + let alice_finalize_message = try_decode_finalized_transaction_message(call.1.to_vec()).unwrap(); + assert_eq!(alice_finalize_message.tx_id, tx_id.as_u64()); - // Create a coinbase Txn at the first block height - let _tx1 = alice_ts_interface - .transaction_service_handle - .generate_coinbase_transaction(reward1, fees1, block_height_a, b"test".to_vec()) + // See if sending a second message before cooldown and see if it is ignored + alice_ts_interface + .transaction_ack_message_channel + .send(create_dummy_message( + bob_reply_message.clone().try_into().unwrap(), + bob_node_identity.public_key(), + )) .await .unwrap(); - let transactions = alice_ts_interface - .transaction_service_handle - .get_completed_transactions() + + assert!(alice_ts_interface + .outbound_service_mock_state + .wait_call_count(1, Duration::from_secs(8)) .await - .unwrap(); - assert_eq!(transactions.len(), 1); - let tx_id1 = transactions - .values() - .find(|tx| tx.amount == fees1 + reward1) - .unwrap() - .tx_id; - assert_eq!( - alice_ts_interface - .output_manager_service_handle - .get_balance() - .await - .unwrap() - .pending_incoming_balance, - MicroMinotari::from(0) - ); + .is_err()); - // Create another coinbase Txn at the next block height - let _tx2 = alice_ts_interface - .transaction_service_handle - .generate_coinbase_transaction(reward2, fees2, block_height_b, b"test".to_vec()) + // Wait for the cooldown to expire but before the resend period has elapsed see if a repeat illicts a response. + sleep(Duration::from_secs(6)).await; + + alice_ts_interface + .transaction_ack_message_channel + .send(create_dummy_message( + bob_reply_message.try_into().unwrap(), + bob_node_identity.public_key(), + )) .await .unwrap(); - let transactions = alice_ts_interface - .transaction_service_handle - .get_completed_transactions() - .await - .unwrap(); - assert_eq!(transactions.len(), 2); - let tx_id2 = transactions - .values() - .find(|tx| tx.amount == fees2 + reward2) - .unwrap() - .tx_id; - assert_eq!( - alice_ts_interface - .output_manager_service_handle - .get_balance() - .await - .unwrap() - .pending_incoming_balance, - MicroMinotari::from(0) - ); - - // Take out a second one at the second height which should not overwrite the initial one - let _tx2b = alice_ts_interface - .transaction_service_handle - .generate_coinbase_transaction(reward2, fees2b, block_height_b, b"test".to_vec()) - .await - .unwrap(); - let transactions = alice_ts_interface - .transaction_service_handle - .get_completed_transactions() - .await - .unwrap(); - assert_eq!(transactions.len(), 3); - let tx_id2b = transactions - .values() - .find(|tx| tx.amount == fees2b + reward2) - .unwrap() - .tx_id; - assert_eq!( - alice_ts_interface - .output_manager_service_handle - .get_balance() - .await - .unwrap() - .pending_incoming_balance, - MicroMinotari::from(0) - ); - - assert!(transactions.values().any(|tx| tx.amount == fees1 + reward1)); - assert!(transactions.values().any(|tx| tx.amount == fees2b + reward2)); - - let delay = sleep(Duration::from_secs(30)); - tokio::pin!(delay); - let mut count = 0usize; - loop { - tokio::select! { - event = alice_event_stream.recv() => { - if let TransactionEvent::ReceivedFinalizedTransaction(tx_id) = &*event.unwrap() { - if tx_id == &tx_id1 || tx_id == &tx_id2 || tx_id == &tx_id2b { - count += 1; - } - if count == 3 { - break; - } - } - }, - () = &mut delay => { - break; - }, - } - } - assert_eq!( - count, 3, - "Expected exactly two 'ReceivedFinalizedTransaction(_)' events" - ); - - // Now we will test validation where tx1 will not be found but tx2b will be unconfirmed, then confirmed. - let tx1 = db.get_completed_transaction(tx_id1).unwrap(); - let tx2b = db.get_completed_transaction(tx_id2b).unwrap(); - - let timestamp = EpochTime::now().as_u64(); - let mut block_headers = HashMap::new(); - for i in 0..=4 { - let mut block_header = BlockHeader::new(1); - block_header.height = i; - block_headers.insert(i, block_header.clone()); - } - alice_ts_interface - .base_node_rpc_mock_state - .set_blocks(block_headers.clone()); - let mut transaction_query_batch_responses = vec![ - TxQueryBatchResponseProto { - signature: Some(SignatureProto::from( - tx1.transaction.first_kernel_excess_sig().unwrap().clone(), - )), - location: TxLocationProto::from(TxLocation::NotStored) as i32, - block_hash: vec![], - confirmations: 0, - block_height: 0, - mined_timestamp: 0, - }, - TxQueryBatchResponseProto { - signature: Some(SignatureProto::from( - tx2b.transaction.first_kernel_excess_sig().unwrap().clone(), - )), - location: TxLocationProto::from(TxLocation::Mined) as i32, - block_hash: block_headers.get(&1).unwrap().hash().to_vec(), - confirmations: 0, - block_height: 1, - mined_timestamp: timestamp, - }, - ]; - let batch_query_response = TxQueryBatchResponsesProto { - responses: transaction_query_batch_responses.clone(), - is_synced: true, - tip_hash: block_headers.get(&1).unwrap().hash().to_vec(), - height_of_longest_chain: 1, - tip_mined_timestamp: timestamp, - }; - - alice_ts_interface - .base_node_rpc_mock_state - .set_transaction_query_batch_responses(batch_query_response); - - alice_ts_interface - .transaction_service_handle - .validate_transactions() - .await - .expect("Validation should start"); - - let _tx_batch_query_calls = alice_ts_interface - .base_node_rpc_mock_state - .wait_pop_transaction_batch_query_calls(2, Duration::from_secs(30)) - .await - .unwrap(); - - let completed_txs = alice_ts_interface - .transaction_service_handle - .get_completed_transactions() - .await - .unwrap(); - - assert_eq!(completed_txs.len(), 3); - - let tx = completed_txs.get(&tx_id1).unwrap(); - assert_eq!(tx.status, TransactionStatus::Coinbase); - - let tx = completed_txs.get(&tx_id2b).unwrap(); - assert_eq!(tx.status, TransactionStatus::MinedUnconfirmed); - - // Now we will have tx_id2b becoming confirmed - let _tx_query_batch_responses = transaction_query_batch_responses.pop(); - transaction_query_batch_responses.push(TxQueryBatchResponseProto { - signature: Some(SignatureProto::from( - tx2b.transaction.first_kernel_excess_sig().unwrap().clone(), - )), - location: TxLocationProto::from(TxLocation::Mined) as i32, - block_hash: block_headers.get(&4).unwrap().hash().to_vec(), - confirmations: 3, - block_height: 4, - mined_timestamp: timestamp, - }); - - let batch_query_response = TxQueryBatchResponsesProto { - responses: transaction_query_batch_responses, - is_synced: true, - tip_hash: block_headers.get(&4).unwrap().hash().to_vec(), - height_of_longest_chain: 4, - tip_mined_timestamp: timestamp, - }; - alice_ts_interface - .base_node_rpc_mock_state - .set_transaction_query_batch_responses(batch_query_response); - - alice_ts_interface - .transaction_service_handle - .validate_transactions() - .await - .expect("Validation should start"); - - let _tx_batch_query_calls = alice_ts_interface - .base_node_rpc_mock_state - .wait_pop_transaction_batch_query_calls(2, Duration::from_secs(30)) - .await - .unwrap(); - - let completed_txs = alice_ts_interface - .transaction_service_handle - .get_completed_transactions() - .await - .unwrap(); - - let tx = completed_txs.get(&tx_id2b).unwrap(); - assert_eq!(tx.status, TransactionStatus::MinedConfirmed); -} - -#[tokio::test] -async fn test_coinbase_abandoned() { - let factories = CryptoFactories::default(); - - let (connection, _temp_dir) = make_wallet_database_connection(None); - - let mut alice_ts_interface = setup_transaction_service_no_comms(factories, connection, None).await; - let mut alice_event_stream = alice_ts_interface.transaction_service_handle.get_event_stream(); - - let block_height_a = 10; - - // First we create un unmined coinbase and then abandon it - let fees1 = 1000 * uT; - let reward1 = 1_000_000 * uT; - - let tx1 = alice_ts_interface - .transaction_service_handle - .generate_coinbase_transaction(reward1, fees1, block_height_a, b"test".to_vec()) - .await - .unwrap(); - let transactions = alice_ts_interface - .transaction_service_handle - .get_completed_transactions() - .await - .unwrap(); - assert_eq!(transactions.len(), 1); - let tx_id1 = transactions - .values() - .find(|tx| tx.amount == fees1 + reward1) - .unwrap() - .tx_id; - assert_eq!( - alice_ts_interface - .output_manager_service_handle - .get_balance() - .await - .unwrap() - .pending_incoming_balance, - MicroMinotari::from(0) - ); - - let timestamp = EpochTime::now().as_u64(); - - let transaction_query_batch_responses = vec![TxQueryBatchResponseProto { - signature: Some(SignatureProto::from(tx1.first_kernel_excess_sig().unwrap().clone())), - location: TxLocationProto::from(TxLocation::InMempool) as i32, - block_hash: vec![], - confirmations: 0, - block_height: 0, - mined_timestamp: 0, - }]; - - let batch_query_response = TxQueryBatchResponsesProto { - responses: transaction_query_batch_responses, - is_synced: true, - tip_hash: [5u8; 32].to_vec(), - height_of_longest_chain: block_height_a + TransactionServiceConfig::default().num_confirmations_required + 1, - tip_mined_timestamp: timestamp, - }; - - alice_ts_interface - .base_node_rpc_mock_state - .set_transaction_query_batch_responses(batch_query_response); - - let balance = alice_ts_interface - .output_manager_service_handle - .get_balance() - .await - .unwrap(); - assert_eq!(balance.pending_incoming_balance, MicroMinotari::from(0)); - - let validation_id = alice_ts_interface - .transaction_service_handle - .validate_transactions() - .await - .expect("Validation should start"); - - let delay = sleep(Duration::from_secs(30)); - tokio::pin!(delay); - let mut cancelled = false; - let mut completed = false; - loop { - tokio::select! { - event = alice_event_stream.recv() => { - match &*event.unwrap() { - TransactionEvent::TransactionValidationCompleted(id) => { - if id == &validation_id { - completed = true; - } - }, - TransactionEvent::TransactionCancelled(tx_id, _) => { - if tx_id == &tx_id1 { - cancelled = true; - } - }, - _ => (), - } - - if cancelled && completed { - break; - } - }, - () = &mut delay => { - break; - }, - } - } - assert!(cancelled, "Expected a TransactionCancelled event"); - assert!(completed, "Expected a TransactionValidationCompleted event"); - - let txs = alice_ts_interface - .transaction_service_handle - .get_cancelled_completed_transactions() - .await - .unwrap(); - assert!(txs.get(&tx_id1).is_some()); - - let balance = alice_ts_interface - .output_manager_service_handle - .get_balance() - .await - .unwrap(); - assert_eq!(balance, Balance { - available_balance: MicroMinotari(0), - time_locked_balance: Some(MicroMinotari(0)), - pending_incoming_balance: MicroMinotari(0), - pending_outgoing_balance: MicroMinotari(0) - }); - - let invalid_txs = alice_ts_interface - .output_manager_service_handle - .get_invalid_outputs() - .await - .unwrap(); - assert!(invalid_txs.is_empty()); - - // Now we will make a coinbase that will be mined, reorged out and then reorged back in - let fees2 = 2000 * uT; - let reward2 = 2_000_000 * uT; - let block_height_b = 11; - - let tx2 = alice_ts_interface - .transaction_service_handle - .generate_coinbase_transaction(reward2, fees2, block_height_b, b"test".to_vec()) - .await - .unwrap(); - let transactions = alice_ts_interface - .transaction_service_handle - .get_completed_transactions() - .await - .unwrap(); - assert_eq!(transactions.len(), 1); - let tx_id2 = transactions - .values() - .find(|tx| tx.amount == fees2 + reward2) - .unwrap() - .tx_id; - assert_eq!( - alice_ts_interface - .output_manager_service_handle - .get_balance() - .await - .unwrap() - .pending_incoming_balance, - MicroMinotari::from(0) - ); - - let transaction_query_batch_responses = vec![ - TxQueryBatchResponseProto { - signature: Some(SignatureProto::from(tx1.first_kernel_excess_sig().unwrap().clone())), - location: TxLocationProto::from(TxLocation::NotStored) as i32, - block_hash: vec![], - confirmations: 0, - block_height: 0, - mined_timestamp: 0, - }, - TxQueryBatchResponseProto { - signature: Some(SignatureProto::from(tx2.first_kernel_excess_sig().unwrap().clone())), - location: TxLocationProto::from(TxLocation::Mined) as i32, - block_hash: [11u8; 32].to_vec(), - confirmations: 2, - block_height: block_height_b, - mined_timestamp: timestamp, - }, - ]; - - let batch_query_response = TxQueryBatchResponsesProto { - responses: transaction_query_batch_responses, - is_synced: true, - tip_hash: [13u8; 32].to_vec(), - height_of_longest_chain: block_height_b + 2, - tip_mined_timestamp: timestamp, - }; - - alice_ts_interface - .base_node_rpc_mock_state - .set_transaction_query_batch_responses(batch_query_response); - - let mut block_headers = HashMap::new(); - for i in 0..=(block_height_b + 2) { - let mut block_header = BlockHeader::new(1); - block_header.height = i; - block_headers.insert(i, block_header.clone()); - } - alice_ts_interface.base_node_rpc_mock_state.set_blocks(block_headers); - - let validation_id = alice_ts_interface - .transaction_service_handle - .validate_transactions() - .await - .expect("Validation should start"); - - let delay = sleep(Duration::from_secs(30)); - tokio::pin!(delay); - let mut completed = false; - let mut mined_unconfirmed = false; - loop { - tokio::select! { - event = alice_event_stream.recv() => { - match &*event.unwrap() { - TransactionEvent::TransactionValidationCompleted(id) => { - if id == &validation_id { - completed = true; - } - }, - TransactionEvent::TransactionMinedUnconfirmed{tx_id, num_confirmations:_, is_valid: _} => { - if tx_id == &tx_id2 { - mined_unconfirmed = true; - } - }, - _ => (), - } - - if mined_unconfirmed && completed { - break; - } - }, - () = &mut delay => { - break; - }, - } - } - assert!(mined_unconfirmed, "Expected a TransactionMinedUnconfirmed event"); - assert!(completed, "Expected a TransactionValidationCompleted event"); - - let tx = alice_ts_interface - .transaction_service_handle - .get_completed_transaction(tx_id2) - .await - .unwrap(); - assert_eq!(tx.status, TransactionStatus::MinedUnconfirmed); - - // Now we create a reorg - let transaction_query_batch_responses = vec![ - TxQueryBatchResponseProto { - signature: Some(SignatureProto::from(tx1.first_kernel_excess_sig().unwrap().clone())), - location: TxLocationProto::from(TxLocation::NotStored) as i32, - block_hash: vec![], - confirmations: 0, - block_height: 0, - mined_timestamp: 0, - }, - TxQueryBatchResponseProto { - signature: Some(SignatureProto::from(tx2.first_kernel_excess_sig().unwrap().clone())), - location: TxLocationProto::from(TxLocation::NotStored) as i32, - block_hash: vec![], - confirmations: 0, - block_height: 0, - mined_timestamp: 0, - }, - ]; - - let batch_query_response = TxQueryBatchResponsesProto { - responses: transaction_query_batch_responses, - is_synced: true, - tip_hash: [12u8; 32].to_vec(), - height_of_longest_chain: block_height_b + TransactionServiceConfig::default().num_confirmations_required + 1, - tip_mined_timestamp: timestamp, - }; - - alice_ts_interface - .base_node_rpc_mock_state - .set_transaction_query_batch_responses(batch_query_response); - - let mut block_headers = HashMap::new(); - for i in 0..=(block_height_b + TransactionServiceConfig::default().num_confirmations_required + 1) { - let mut block_header = BlockHeader::new(2); - block_header.height = i; - block_headers.insert(i, block_header.clone()); - } - alice_ts_interface.base_node_rpc_mock_state.set_blocks(block_headers); - - let validation_id = alice_ts_interface - .transaction_service_handle - .validate_transactions() - .await - .expect("Validation should start"); - - let delay = sleep(Duration::from_secs(30)); - tokio::pin!(delay); - let mut completed = false; - let mut broadcast = false; - let mut cancelled = false; - loop { - tokio::select! { - event = alice_event_stream.recv() => { - match &*event.unwrap() { - TransactionEvent::TransactionBroadcast(tx_id) => { - if tx_id == &tx_id2 { - broadcast = true; - } - }, - TransactionEvent::TransactionCancelled(tx_id, _) => { - if tx_id == &tx_id2 { - cancelled = true; - } - }, - TransactionEvent::TransactionValidationCompleted(id) => { - if id == &validation_id { - completed = true; - } - }, - _ => (), - } - - if cancelled && broadcast && completed { - break; - } - }, - () = &mut delay => { - break; - }, - } - } - assert!(cancelled, "Expected a TransactionCancelled event"); - assert!(broadcast, "Expected a TransactionBroadcast event"); - assert!(completed, "Expected a TransactionValidationCompleted event"); - - let txs = alice_ts_interface - .transaction_service_handle - .get_cancelled_completed_transactions() - .await - .unwrap(); - - assert!(txs.get(&tx_id1).is_some()); - assert!(txs.get(&tx_id2).is_some()); - - let balance = alice_ts_interface - .output_manager_service_handle - .get_balance() - .await - .unwrap(); - assert_eq!(balance, Balance { - available_balance: MicroMinotari(0), - time_locked_balance: Some(MicroMinotari(0)), - pending_incoming_balance: MicroMinotari(0), - pending_outgoing_balance: MicroMinotari(0) - }); - - // Now reorg again and have tx2 be mined - let mut block_headers = HashMap::new(); - for i in 0..=15 { - let mut block_header = BlockHeader::new(1); - block_header.height = i; - block_headers.insert(i, block_header.clone()); - } - alice_ts_interface - .base_node_rpc_mock_state - .set_blocks(block_headers.clone()); - - let transaction_query_batch_responses = vec![ - TxQueryBatchResponseProto { - signature: Some(SignatureProto::from(tx1.first_kernel_excess_sig().unwrap().clone())), - location: TxLocationProto::from(TxLocation::NotStored) as i32, - block_hash: vec![], - confirmations: 0, - block_height: 0, - mined_timestamp: 0, - }, - TxQueryBatchResponseProto { - signature: Some(SignatureProto::from(tx2.first_kernel_excess_sig().unwrap().clone())), - location: TxLocationProto::from(TxLocation::Mined) as i32, - block_hash: block_headers.get(&10).unwrap().hash().to_vec(), - confirmations: 5, - block_height: 10, - mined_timestamp: timestamp, - }, - ]; - - let batch_query_response = TxQueryBatchResponsesProto { - responses: transaction_query_batch_responses, - is_synced: true, - tip_hash: [20u8; 32].to_vec(), - height_of_longest_chain: 20, - tip_mined_timestamp: timestamp, - }; - - alice_ts_interface - .base_node_rpc_mock_state - .set_transaction_query_batch_responses(batch_query_response); - - let validation_id = alice_ts_interface - .transaction_service_handle - .validate_transactions() - .await - .expect("Validation should start"); - - let delay = sleep(Duration::from_secs(60)); - tokio::pin!(delay); - let mut mined = false; - let mut cancelled = false; - let mut completed = false; - loop { - tokio::select! { - event = alice_event_stream.recv() => { - match &*event.unwrap() { - TransactionEvent::TransactionMined { tx_id, is_valid: _ } => { - if tx_id == &tx_id2 { - mined = true; - } - }, - TransactionEvent::TransactionCancelled(tx_id, _) => { - if tx_id == &tx_id1 { - cancelled = true; - } - }, - TransactionEvent::TransactionValidationCompleted(id) => { - if id == &validation_id { - completed = true; - } - }, - _ => (), - } - - if mined && cancelled && completed { - break; - } - }, - () = &mut delay => { - break; - }, - } - } - assert!(mined, "Expected to received TransactionMined event"); - assert!(cancelled, "Expected to received TransactionCancelled event"); - assert!(completed, "Expected a TransactionValidationCompleted event"); -} - -#[tokio::test] -async fn test_coinbase_transaction_reused_for_same_height() { - let factories = CryptoFactories::default(); - let (connection, _temp_dir) = make_wallet_database_connection(None); - - let mut ts_interface = setup_transaction_service_no_comms(factories, connection, None).await; - - let blockheight1 = 10; - let fees1 = 2000 * uT; - let reward1 = 1_000_000 * uT; - - let blockheight2 = 11; - let fees2 = 3000 * uT; - let reward2 = 2_000_000 * uT; - - // a requested coinbase transaction for the same height and amount should be the same - let tx1 = ts_interface - .transaction_service_handle - .generate_coinbase_transaction(reward1, fees1, blockheight1, b"test".to_vec()) - .await - .unwrap(); - - let tx2 = ts_interface - .transaction_service_handle - .generate_coinbase_transaction(reward1, fees1, blockheight1, b"test".to_vec()) - .await - .unwrap(); - - assert_eq!(tx1, tx2); - let transactions = ts_interface - .transaction_service_handle - .get_completed_transactions() - .await - .unwrap(); - - assert_eq!(transactions.len(), 1); - let mut amount = MicroMinotari::zero(); - for tx in transactions.values() { - amount += tx.amount; - } - assert_eq!(amount, fees1 + reward1); - assert_eq!( - ts_interface - .output_manager_service_handle - .get_balance() - .await - .unwrap() - .pending_incoming_balance, - MicroMinotari::from(0) - ); - - // a requested coinbase transaction for the same height but new amount should be different - let tx3 = ts_interface - .transaction_service_handle - .generate_coinbase_transaction(reward2, fees2, blockheight1, b"test".to_vec()) - .await - .unwrap(); - - assert_ne!(tx3, tx1); - let transactions = ts_interface - .transaction_service_handle - .get_completed_transactions() - .await - .unwrap(); - assert_eq!(transactions.len(), 2); - let mut amount = MicroMinotari::zero(); - for tx in transactions.values() { - amount += tx.amount; - } - assert_eq!(amount, fees1 + reward1 + fees2 + reward2); - assert_eq!( - ts_interface - .output_manager_service_handle - .get_balance() - .await - .unwrap() - .pending_incoming_balance, - MicroMinotari::from(0) - ); - - // a requested coinbase transaction for a new height should be different - let tx_height2 = ts_interface - .transaction_service_handle - .generate_coinbase_transaction(reward2, fees2, blockheight2, b"test".to_vec()) - .await - .unwrap(); - - assert_ne!(tx1, tx_height2); - let transactions = ts_interface - .transaction_service_handle - .get_completed_transactions() - .await - .unwrap(); - assert_eq!(transactions.len(), 3); - let mut amount = MicroMinotari::zero(); - for tx in transactions.values() { - amount += tx.amount; - } - assert_eq!(amount, fees1 + reward1 + fees2 + reward2 + fees2 + reward2); - assert_eq!( - ts_interface - .output_manager_service_handle - .get_balance() - .await - .unwrap() - .pending_incoming_balance, - MicroMinotari::from(0) - ); -} - -#[tokio::test] -async fn test_transaction_resending() { - let factories = CryptoFactories::default(); - - let alice_node_identity = - NodeIdentity::random(&mut OsRng, get_next_memory_address(), PeerFeatures::COMMUNICATION_NODE); - let bob_node_identity = - NodeIdentity::random(&mut OsRng, get_next_memory_address(), PeerFeatures::COMMUNICATION_NODE); - // Setup Alice wallet with no comms stack - let (connection, _tempdir) = make_wallet_database_connection(None); - - let mut alice_ts_interface = setup_transaction_service_no_comms( - factories.clone(), - connection, - Some(TransactionServiceConfig { - transaction_resend_period: Duration::from_secs(20), - resend_response_cooldown: Duration::from_secs(10), - ..Default::default() - }), - ) - .await; - - // Send a transaction to Bob - let alice_total_available = 250000 * uT; - let uo = make_input( - &mut OsRng, - alice_total_available, - &OutputFeatures::default(), - &alice_ts_interface.key_manager_handle, - ) - .await; - alice_ts_interface - .output_manager_service_handle - .add_output(uo, None) - .await - .unwrap(); - - let amount_sent = 100000 * uT; - - let bob_address = TariAddress::new(bob_node_identity.public_key().clone(), Network::LocalNet); - let tx_id = alice_ts_interface - .transaction_service_handle - .send_transaction( - bob_address, - amount_sent, - UtxoSelectionCriteria::default(), - OutputFeatures::default(), - 100 * uT, - "Testing Message".to_string(), - ) - .await - .unwrap(); - - // Check that there were repeats - alice_ts_interface - .outbound_service_mock_state - .wait_call_count(2, Duration::from_secs(60)) - .await - .expect("Alice call wait 1"); - - let mut alice_sender_message = TransactionSenderMessage::None; - for _ in 0..2 { - let call = alice_ts_interface.outbound_service_mock_state.pop_call().await.unwrap(); - alice_sender_message = try_decode_sender_message(call.1.to_vec().clone()).unwrap(); - if let TransactionSenderMessage::Single(data) = alice_sender_message.clone() { - assert_eq!(data.tx_id, tx_id); - } else { - panic!("Should be a Single Transaction Sender Message") - } - } - - // Setup Bob's wallet with no comms stack - let (connection, _tempdir) = make_wallet_database_connection(None); - - let mut bob_ts_interface = setup_transaction_service_no_comms( - factories, - connection, - Some(TransactionServiceConfig { - transaction_resend_period: Duration::from_secs(20), - resend_response_cooldown: Duration::from_secs(10), - ..Default::default() - }), - ) - .await; - - // Pass sender message to Bob's wallet - bob_ts_interface - .transaction_send_message_channel - .send(create_dummy_message( - alice_sender_message.clone().try_into().unwrap(), - alice_node_identity.public_key(), - )) - .await - .unwrap(); - - // Check that the reply was repeated - bob_ts_interface - .outbound_service_mock_state - .wait_call_count(2, Duration::from_secs(60)) - .await - .expect("Bob call wait 1"); - - let mut bob_reply_message; - for _ in 0..2 { - let call = bob_ts_interface.outbound_service_mock_state.pop_call().await.unwrap(); - bob_reply_message = try_decode_transaction_reply_message(call.1.to_vec().clone()).unwrap(); - assert_eq!(bob_reply_message.tx_id, tx_id); - } - - sleep(Duration::from_secs(2)).await; - // See if sending a second message too soon is ignored - bob_ts_interface - .transaction_send_message_channel - .send(create_dummy_message( - alice_sender_message.clone().try_into().unwrap(), - alice_node_identity.public_key(), - )) - .await - .unwrap(); - - assert!(bob_ts_interface - .outbound_service_mock_state - .wait_call_count(1, Duration::from_secs(2)) - .await - .is_err()); - - // Wait for the cooldown to expire but before the resend period has elapsed see if a repeat illicits a response. - sleep(Duration::from_secs(8)).await; - bob_ts_interface - .transaction_send_message_channel - .send(create_dummy_message( - alice_sender_message.try_into().unwrap(), - alice_node_identity.public_key(), - )) - .await - .unwrap(); - bob_ts_interface - .outbound_service_mock_state - .wait_call_count(2, Duration::from_secs(60)) - .await - .expect("Bob call wait 2"); - let _result = bob_ts_interface.outbound_service_mock_state.pop_call().await.unwrap(); - let call = bob_ts_interface.outbound_service_mock_state.pop_call().await.unwrap(); - bob_reply_message = try_decode_transaction_reply_message(call.1.to_vec()).unwrap(); - assert_eq!(bob_reply_message.tx_id, tx_id); - - let _result = alice_ts_interface.outbound_service_mock_state.take_calls().await; - - // Send the reply to Alice - alice_ts_interface - .transaction_ack_message_channel - .send(create_dummy_message( - bob_reply_message.clone().try_into().unwrap(), - bob_node_identity.public_key(), - )) - .await - .unwrap(); - - alice_ts_interface - .outbound_service_mock_state - .wait_call_count(2, Duration::from_secs(60)) - .await - .expect("Alice call wait 2"); - - let _result = alice_ts_interface.outbound_service_mock_state.pop_call().await.unwrap(); - let call = alice_ts_interface.outbound_service_mock_state.pop_call().await.unwrap(); - let alice_finalize_message = try_decode_finalized_transaction_message(call.1.to_vec()).unwrap(); - assert_eq!(alice_finalize_message.tx_id, tx_id.as_u64()); - - // See if sending a second message before cooldown and see if it is ignored - alice_ts_interface - .transaction_ack_message_channel - .send(create_dummy_message( - bob_reply_message.clone().try_into().unwrap(), - bob_node_identity.public_key(), - )) - .await - .unwrap(); - - assert!(alice_ts_interface - .outbound_service_mock_state - .wait_call_count(1, Duration::from_secs(8)) - .await - .is_err()); - - // Wait for the cooldown to expire but before the resend period has elapsed see if a repeat illicts a response. - sleep(Duration::from_secs(6)).await; - - alice_ts_interface - .transaction_ack_message_channel - .send(create_dummy_message( - bob_reply_message.try_into().unwrap(), - bob_node_identity.public_key(), - )) - .await - .unwrap(); - - alice_ts_interface - .outbound_service_mock_state - .wait_call_count(1, Duration::from_secs(30)) + + alice_ts_interface + .outbound_service_mock_state + .wait_call_count(1, Duration::from_secs(30)) .await .expect("Alice call wait 3"); @@ -4911,7 +3954,7 @@ async fn test_resend_on_startup() { NodeIdentity::random(&mut OsRng, get_next_memory_address(), PeerFeatures::COMMUNICATION_NODE); // First we will check the Send Tranasction message - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let input = create_wallet_output_with_data( script!(Nop), OutputFeatures::default(), @@ -4922,7 +3965,7 @@ async fn test_resend_on_startup() { .await .unwrap(); let constants = create_consensus_constants(0); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let mut builder = SenderTransactionProtocol::builder(constants.clone(), key_manager.clone()); let amount = MicroMinotari::from(10_000); let change = TestParams::new(&key_manager).await; @@ -5418,7 +4461,7 @@ async fn test_transaction_timeout_cancellation() { // Now to test if the timeout has elapsed during downtime and that it is honoured on startup // First we will check the Send Transction message - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let input = create_wallet_output_with_data( script!(Nop), OutputFeatures::default(), @@ -5429,7 +4472,7 @@ async fn test_transaction_timeout_cancellation() { .await .unwrap(); let constants = create_consensus_constants(0); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let mut builder = SenderTransactionProtocol::builder(constants, key_manager.clone()); let amount = MicroMinotari::from(10_000); let change = TestParams::new(&key_manager).await; @@ -6003,7 +5046,6 @@ async fn broadcast_all_completed_transactions_on_startup() { timestamp: Utc::now().naive_utc(), cancelled: None, direction: TransactionDirection::Outbound, - coinbase_block_height: None, send_count: 0, last_send_timestamp: None, transaction_signature: tx.first_kernel_excess_sig().unwrap_or(&Signature::default()).clone(), @@ -6119,7 +5161,6 @@ async fn test_update_faux_tx_on_oms_validation() { MicroMinotari::from(10000), alice_address.clone(), "blah".to_string(), - None, ImportStatus::Imported, None, None, @@ -6133,7 +5174,6 @@ async fn test_update_faux_tx_on_oms_validation() { MicroMinotari::from(20000), alice_address.clone(), "one-sided 1".to_string(), - None, ImportStatus::FauxUnconfirmed, None, None, @@ -6148,7 +5188,6 @@ async fn test_update_faux_tx_on_oms_validation() { MicroMinotari::from(30000), alice_address, "one-sided 2".to_string(), - None, ImportStatus::FauxConfirmed, None, None, diff --git a/base_layer/wallet/tests/transaction_service_tests/storage.rs b/base_layer/wallet/tests/transaction_service_tests/storage.rs index fb4044c888d..f6db4a41580 100644 --- a/base_layer/wallet/tests/transaction_service_tests/storage.rs +++ b/base_layer/wallet/tests/transaction_service_tests/storage.rs @@ -50,9 +50,9 @@ use tari_common_types::{ use tari_core::{ covenants::Covenant, transactions::{ - key_manager::{TransactionKeyManagerBranch, TransactionKeyManagerInterface}, + key_manager::{create_memory_db_key_manager, TransactionKeyManagerBranch, TransactionKeyManagerInterface}, tari_amount::{uT, MicroMinotari}, - test_helpers::{create_test_core_key_manager_with_memory_db, create_wallet_output_with_data, TestParams}, + test_helpers::{create_wallet_output_with_data, TestParams}, transaction_components::{ OutputFeatures, RangeProofType, @@ -74,7 +74,7 @@ use tempfile::tempdir; pub async fn test_db_backend(backend: T) { let mut db = TransactionDatabase::new(backend); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let input = create_wallet_output_with_data( script!(Nop), OutputFeatures::default(), @@ -85,7 +85,7 @@ pub async fn test_db_backend(backend: T) { .await .unwrap(); let constants = create_consensus_constants(0); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let mut builder = SenderTransactionProtocol::builder(constants.clone(), key_manager.clone()); let amount = MicroMinotari::from(10_000); builder @@ -323,7 +323,6 @@ pub async fn test_db_backend(backend: T) { timestamp: Utc::now().naive_utc(), cancelled: None, direction: TransactionDirection::Outbound, - coinbase_block_height: None, send_count: 0, last_send_timestamp: None, @@ -574,10 +573,10 @@ async fn import_tx_and_read_it_from_db() { "message".to_string(), Utc::now().naive_utc(), TransactionDirection::Inbound, - Some(0), Some(5), Some(NaiveDateTime::from_timestamp_opt(0, 0).unwrap()), - ); + ) + .unwrap(); sqlite_db .write(WriteOperation::Insert(DbKeyValuePair::CompletedTransaction( @@ -603,10 +602,10 @@ async fn import_tx_and_read_it_from_db() { "message".to_string(), Utc::now().naive_utc(), TransactionDirection::Inbound, - Some(0), Some(6), Some(NaiveDateTime::from_timestamp_opt(0, 0).unwrap()), - ); + ) + .unwrap(); sqlite_db .write(WriteOperation::Insert(DbKeyValuePair::CompletedTransaction( @@ -632,10 +631,10 @@ async fn import_tx_and_read_it_from_db() { "message".to_string(), Utc::now().naive_utc(), TransactionDirection::Inbound, - Some(0), Some(7), Some(NaiveDateTime::from_timestamp_opt(0, 0).unwrap()), - ); + ) + .unwrap(); sqlite_db .write(WriteOperation::Insert(DbKeyValuePair::CompletedTransaction( 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 9bad0758236..23cc579ddef 100644 --- a/base_layer/wallet/tests/transaction_service_tests/transaction_protocols.rs +++ b/base_layer/wallet/tests/transaction_service_tests/transaction_protocols.rs @@ -43,7 +43,7 @@ use minotari_wallet::{ service::TransactionServiceResources, storage::{ database::TransactionDatabase, - models::{CompletedTransaction, TxCancellationReason}, + models::CompletedTransaction, sqlite_db::TransactionServiceSqliteDatabase, }, }, @@ -78,8 +78,9 @@ use tari_core::{ types::Signature as SignatureProto, }, transactions::{ + key_manager::{create_memory_db_key_manager, MemoryDbKeyManager}, tari_amount::{uT, MicroMinotari, T}, - test_helpers::{create_test_core_key_manager_with_memory_db, schema_to_transaction, TestKeyManager}, + test_helpers::schema_to_transaction, transaction_components::OutputFeatures, CryptoFactories, }, @@ -98,7 +99,7 @@ use crate::support::{ }; pub async fn setup() -> ( - TransactionServiceResources, + TransactionServiceResources, OutboundServiceMockState, MockRpcServer>, Arc, @@ -145,7 +146,7 @@ pub async fn setup() -> ( let (oms_event_publisher, _) = broadcast::channel(200); let output_manager_service_handle = OutputManagerHandle::new(oms_request_sender, oms_event_publisher); - let core_key_manager_service_handle = create_test_core_key_manager_with_memory_db(); + let core_key_manager_service_handle = create_memory_db_key_manager(); let (outbound_message_requester, mock_outbound_service) = create_outbound_service_mock(100); let outbound_mock_state = mock_outbound_service.get_state(); @@ -193,13 +194,15 @@ pub async fn add_transaction_to_database( tx_id: TxId, amount: MicroMinotari, status: Option, - coinbase_block_height: Option, db: TransactionDatabase, ) { - let key_manager_handle = create_test_core_key_manager_with_memory_db(); + let key_manager_handle = create_memory_db_key_manager(); let uo0 = make_input(&mut OsRng, 10 * amount, &OutputFeatures::default(), &key_manager_handle).await; - let (txs1, _uou1) = - schema_to_transaction(&[txn_schema!(from: vec![uo0], to: vec![amount])], &key_manager_handle).await; + let (txs1, _uou1) = schema_to_transaction( + &[txn_schema!(from: vec![uo0.clone()], to: vec![amount])], + &key_manager_handle, + ) + .await; let tx1 = (*txs1[0]).clone(); let completed_tx1 = CompletedTransaction::new( tx_id, @@ -212,10 +215,10 @@ pub async fn add_transaction_to_database( "Test".to_string(), Utc::now().naive_local(), TransactionDirection::Outbound, - coinbase_block_height, None, None, - ); + ) + .unwrap(); db.insert_completed_transaction(tx_id, completed_tx1).unwrap(); } @@ -228,7 +231,6 @@ pub async fn oms_reply_channel_task( let (request, reply_tx) = request_context.split(); let response = match request { OutputManagerRequest::CancelTransaction(_) => Ok(OutputManagerResponse::TransactionCancelled), - OutputManagerRequest::SetCoinbaseAbandoned(_, _) => Ok(OutputManagerResponse::CoinbaseAbandonedSet), _ => Err(OutputManagerError::InvalidResponseError( "Unhandled request type".to_string(), )), @@ -270,7 +272,7 @@ async fn tx_broadcast_protocol_submit_success() { // Fails because there is no transaction in the database to be broadcast assert!(join_handle.await.unwrap().is_err()); - add_transaction_to_database(1u64.into(), 1 * T, None, None, resources.db.clone()).await; + add_transaction_to_database(1u64.into(), 1 * T, None, resources.db.clone()).await; let db_completed_tx = resources.db.get_completed_transaction(1u64.into()).unwrap(); assert!(db_completed_tx.confirmations.is_none()); @@ -339,7 +341,7 @@ async fn tx_broadcast_protocol_submit_rejection() { ) = setup().await; let mut event_stream = resources.event_publisher.subscribe(); - add_transaction_to_database(1u64.into(), 1 * T, None, None, resources.db.clone()).await; + add_transaction_to_database(1u64.into(), 1 * T, None, resources.db.clone()).await; let timeout_update_watch = Watch::new(Duration::from_secs(1)); wallet_connectivity.notify_base_node_set(server_node_identity.to_peer()); // Now we add the connection @@ -410,7 +412,7 @@ async fn tx_broadcast_protocol_restart_protocol_as_query() { wallet_connectivity, ) = setup().await; - add_transaction_to_database(1u64.into(), 1 * T, None, None, resources.db.clone()).await; + add_transaction_to_database(1u64.into(), 1 * T, None, resources.db.clone()).await; // Set Base Node query response to be not stored, as if the base node does not have the tx in its pool rpc_service_state.set_transaction_query_response(TxQueryResponse { @@ -502,7 +504,7 @@ async fn tx_broadcast_protocol_submit_success_followed_by_rejection() { ) = setup().await; let mut event_stream = resources.event_publisher.subscribe(); - add_transaction_to_database(1u64.into(), 1 * T, None, None, resources.db.clone()).await; + add_transaction_to_database(1u64.into(), 1 * T, None, resources.db.clone()).await; resources.config.transaction_mempool_resubmission_window = Duration::from_secs(3); resources.config.broadcast_monitoring_timeout = Duration::from_secs(60); @@ -592,7 +594,7 @@ async fn tx_broadcast_protocol_submit_already_mined() { _transaction_event_receiver, wallet_connectivity, ) = setup().await; - add_transaction_to_database(1u64.into(), 1 * T, None, None, resources.db.clone()).await; + add_transaction_to_database(1u64.into(), 1 * T, None, resources.db.clone()).await; // Set Base Node to respond with AlreadyMined rpc_service_state.set_submit_transaction_response(TxSubmissionResponse { @@ -659,7 +661,7 @@ async fn tx_broadcast_protocol_submit_and_base_node_gets_changed() { wallet_connectivity, ) = setup().await; - add_transaction_to_database(1u64.into(), 1 * T, None, None, resources.db.clone()).await; + add_transaction_to_database(1u64.into(), 1 * T, None, resources.db.clone()).await; resources.config.broadcast_monitoring_timeout = Duration::from_secs(60); @@ -766,7 +768,6 @@ async fn tx_validation_protocol_tx_becomes_mined_unconfirmed_then_confirmed() { 1u64.into(), 1 * T, Some(TransactionStatus::Broadcast), - None, resources.db.clone(), ) .await; @@ -774,7 +775,6 @@ async fn tx_validation_protocol_tx_becomes_mined_unconfirmed_then_confirmed() { 2u64.into(), 2 * T, Some(TransactionStatus::Completed), - None, resources.db.clone(), ) .await; @@ -809,7 +809,6 @@ async fn tx_validation_protocol_tx_becomes_mined_unconfirmed_then_confirmed() { wallet_connectivity.clone(), resources.config.clone(), resources.event_publisher.clone(), - resources.output_manager_service.clone(), ); let join_handle = task::spawn(protocol.execute()); @@ -837,7 +836,6 @@ async fn tx_validation_protocol_tx_becomes_mined_unconfirmed_then_confirmed() { wallet_connectivity.clone(), resources.config.clone(), resources.event_publisher.clone(), - resources.output_manager_service.clone(), ); let join_handle = task::spawn(protocol.execute()); @@ -883,7 +881,6 @@ async fn tx_validation_protocol_tx_becomes_mined_unconfirmed_then_confirmed() { wallet_connectivity.clone(), resources.config.clone(), resources.event_publisher.clone(), - resources.output_manager_service.clone(), ); let join_handle = task::spawn(protocol.execute()); @@ -923,7 +920,6 @@ async fn tx_revalidation() { 1u64.into(), 1 * T, Some(TransactionStatus::Completed), - None, resources.db.clone(), ) .await; @@ -931,7 +927,6 @@ async fn tx_revalidation() { 2u64.into(), 2 * T, Some(TransactionStatus::Completed), - None, resources.db.clone(), ) .await; @@ -967,7 +962,6 @@ async fn tx_revalidation() { wallet_connectivity.clone(), resources.config.clone(), resources.event_publisher.clone(), - resources.output_manager_service.clone(), ); let join_handle = task::spawn(protocol.execute()); @@ -1018,7 +1012,6 @@ async fn tx_revalidation() { wallet_connectivity.clone(), resources.config.clone(), resources.event_publisher.clone(), - resources.output_manager_service.clone(), ); let join_handle = task::spawn(protocol.execute()); @@ -1061,7 +1054,6 @@ async fn tx_validation_protocol_reorg() { i.into(), i * T, Some(TransactionStatus::Broadcast), - None, resources.db.clone(), ) .await; @@ -1070,8 +1062,7 @@ async fn tx_validation_protocol_reorg() { add_transaction_to_database( 6u64.into(), 6 * T, - Some(TransactionStatus::Coinbase), - Some(8), + Some(TransactionStatus::Broadcast), resources.db.clone(), ) .await; @@ -1079,8 +1070,7 @@ async fn tx_validation_protocol_reorg() { add_transaction_to_database( 7u64.into(), 7 * T, - Some(TransactionStatus::Coinbase), - Some(9), + Some(TransactionStatus::Broadcast), resources.db.clone(), ) .await; @@ -1098,8 +1088,8 @@ async fn tx_validation_protocol_reorg() { let tx3 = resources.db.get_completed_transaction(3u64.into()).unwrap(); let tx4 = resources.db.get_completed_transaction(4u64.into()).unwrap(); let tx5 = resources.db.get_completed_transaction(5u64.into()).unwrap(); - let coinbase_tx1 = resources.db.get_completed_transaction(6u64.into()).unwrap(); - let coinbase_tx2 = resources.db.get_completed_transaction(7u64.into()).unwrap(); + let tx6 = resources.db.get_completed_transaction(6u64.into()).unwrap(); + let tx7 = resources.db.get_completed_transaction(7u64.into()).unwrap(); let timestamp = EpochTime::now().as_u64(); let transaction_query_batch_responses = vec![ @@ -1145,27 +1135,27 @@ async fn tx_validation_protocol_reorg() { }, TxQueryBatchResponseProto { signature: Some(SignatureProto::from( - coinbase_tx1.transaction.first_kernel_excess_sig().unwrap().clone(), + tx5.transaction.first_kernel_excess_sig().unwrap().clone(), )), location: TxLocationProto::from(TxLocation::Mined) as i32, - block_hash: block_headers.get(&8).unwrap().hash().to_vec(), - confirmations: 2, - block_height: 8, + block_hash: block_headers.get(&9).unwrap().hash().to_vec(), + confirmations: 1, + block_height: 9, mined_timestamp: timestamp, }, TxQueryBatchResponseProto { signature: Some(SignatureProto::from( - tx5.transaction.first_kernel_excess_sig().unwrap().clone(), + tx6.transaction.first_kernel_excess_sig().unwrap().clone(), )), location: TxLocationProto::from(TxLocation::Mined) as i32, - block_hash: block_headers.get(&9).unwrap().hash().to_vec(), - confirmations: 1, - block_height: 9, + block_hash: block_headers.get(&8).unwrap().hash().to_vec(), + confirmations: 2, + block_height: 8, mined_timestamp: timestamp, }, TxQueryBatchResponseProto { signature: Some(SignatureProto::from( - coinbase_tx2.transaction.first_kernel_excess_sig().unwrap().clone(), + tx7.transaction.first_kernel_excess_sig().unwrap().clone(), )), location: TxLocationProto::from(TxLocation::Mined) as i32, block_hash: block_headers.get(&9).unwrap().hash().to_vec(), @@ -1191,7 +1181,6 @@ async fn tx_validation_protocol_reorg() { wallet_connectivity.clone(), resources.config.clone(), resources.event_publisher.clone(), - resources.output_manager_service.clone(), ); let join_handle = task::spawn(protocol.execute()); @@ -1212,8 +1201,7 @@ async fn tx_validation_protocol_reorg() { assert_eq!(confirmed_count, 3); assert_eq!(unconfirmed_count, 4); - // Now we will reorg to new blocks 8 and 9, tx 4 will disappear and tx5 will appear in block 9, coinbase_tx2 should - // become invalid and coinbase_tx1 should return to coinbase status + // Now we will reorg to new blocks 8 and 9; tx5 will appear in block 8; tx4, tx6 and tx7 will become invalid let _block_header = block_headers.remove(&9); let _block_header = block_headers.remove(&10); @@ -1254,16 +1242,6 @@ async fn tx_validation_protocol_reorg() { block_height: 7, mined_timestamp: timestamp, }, - TxQueryBatchResponseProto { - signature: Some(SignatureProto::from( - coinbase_tx1.transaction.first_kernel_excess_sig().unwrap().clone(), - )), - location: TxLocationProto::from(TxLocation::NotStored) as i32, - block_hash: vec![], - confirmations: 0, - block_height: 0, - mined_timestamp: 0, - }, TxQueryBatchResponseProto { signature: Some(SignatureProto::from( tx5.transaction.first_kernel_excess_sig().unwrap().clone(), @@ -1276,7 +1254,17 @@ async fn tx_validation_protocol_reorg() { }, TxQueryBatchResponseProto { signature: Some(SignatureProto::from( - coinbase_tx2.transaction.first_kernel_excess_sig().unwrap().clone(), + tx6.transaction.first_kernel_excess_sig().unwrap().clone(), + )), + location: TxLocationProto::from(TxLocation::NotStored) as i32, + block_hash: vec![], + confirmations: 0, + block_height: 0, + mined_timestamp: 0, + }, + TxQueryBatchResponseProto { + signature: Some(SignatureProto::from( + tx7.transaction.first_kernel_excess_sig().unwrap().clone(), )), location: TxLocationProto::from(TxLocation::NotStored) as i32, block_hash: vec![], @@ -1303,7 +1291,6 @@ async fn tx_validation_protocol_reorg() { wallet_connectivity.clone(), resources.config.clone(), resources.event_publisher.clone(), - resources.output_manager_service.clone(), ); let join_handle = task::spawn(protocol.execute()); @@ -1318,30 +1305,24 @@ async fn tx_validation_protocol_reorg() { assert_eq!(rpc_service_state.take_get_header_by_height_calls().len(), 0); let completed_txs = resources.db.get_completed_transactions().unwrap(); - assert_eq!( - completed_txs.get(&4u64.into()).unwrap().status, - TransactionStatus::Completed - ); - assert_eq!( - completed_txs.get(&5u64.into()).unwrap().status, - TransactionStatus::MinedUnconfirmed - ); - assert_eq!( - completed_txs.get(&5u64.into()).cloned().unwrap().mined_height.unwrap(), - 8 - ); - assert_eq!( - completed_txs.get(&5u64.into()).cloned().unwrap().confirmations.unwrap(), - 1 - ); - assert_eq!( - completed_txs.get(&7u64.into()).unwrap().status, - TransactionStatus::Coinbase - ); - let cancelled_completed_txs = resources.db.get_cancelled_completed_transactions().unwrap(); + // Tx 1 + assert!(completed_txs.get(&1u64.into()).unwrap().mined_in_block.is_some()); + + // Tx 2 + assert!(completed_txs.get(&2u64.into()).unwrap().mined_in_block.is_some()); + + // Tx 3 + assert!(completed_txs.get(&3u64.into()).unwrap().mined_in_block.is_some()); + + // Tx 4 (reorged out) + assert!(completed_txs.get(&4u64.into()).unwrap().mined_in_block.is_none()); + + // Tx 5 + assert!(completed_txs.get(&5u64.into()).unwrap().mined_in_block.is_some()); + + // Tx 6 (reorged out) + assert!(completed_txs.get(&6u64.into()).unwrap().mined_in_block.is_none()); - assert!(matches!( - cancelled_completed_txs.get(&6u64.into()).unwrap().cancelled, - Some(TxCancellationReason::AbandonedCoinbase) - )); + // Tx 7 (reorged out) + assert!(completed_txs.get(&7u64.into()).unwrap().mined_in_block.is_none()); } diff --git a/base_layer/wallet/tests/utxo_scanner/mod.rs b/base_layer/wallet/tests/utxo_scanner/mod.rs index 0ad4d3ccca9..47c1fbcad3d 100644 --- a/base_layer/wallet/tests/utxo_scanner/mod.rs +++ b/base_layer/wallet/tests/utxo_scanner/mod.rs @@ -61,8 +61,8 @@ use tari_core::{ blocks::BlockHeader, proto::base_node::{ChainMetadata, TipInfoResponse}, transactions::{ + key_manager::{create_memory_db_key_manager, MemoryDbKeyManager}, tari_amount::MicroMinotari, - test_helpers::{create_test_core_key_manager_with_memory_db, TestKeyManager}, transaction_components::{OutputFeatures, WalletOutput}, CryptoFactories, }, @@ -241,7 +241,7 @@ async fn generate_block_headers_and_utxos( birthday_epoch_time: u64, birthday_offset: u64, only_coinbase: bool, - key_manager: &TestKeyManager, + key_manager: &MemoryDbKeyManager, ) -> TestBlockData { let mut block_headers = HashMap::new(); let mut utxos_by_block = Vec::new(); @@ -299,7 +299,7 @@ async fn test_utxo_scanner_recovery() { const NUM_BLOCKS: u64 = 11; const BIRTHDAY_OFFSET: u64 = 5; - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let TestBlockData { block_headers, wallet_outputs, @@ -334,7 +334,7 @@ async fn test_utxo_scanner_recovery() { output.clone(), &key_manager, None, - OutputSource::Unknown, + OutputSource::Standard, None, None, ) @@ -398,7 +398,7 @@ async fn test_utxo_scanner_recovery_with_restart() { const BIRTHDAY_OFFSET: u64 = 5; const SYNC_INTERRUPT: u64 = 6; - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let TestBlockData { block_headers, wallet_outputs, @@ -433,7 +433,7 @@ async fn test_utxo_scanner_recovery_with_restart() { output.clone(), &key_manager, None, - OutputSource::Unknown, + OutputSource::Standard, None, None, ) @@ -472,7 +472,6 @@ async fn test_utxo_scanner_recovery_with_restart() { amount: _, source_address, message, - maturity: _, import_status: _, tx_id: _, current_height: _, @@ -539,7 +538,6 @@ async fn test_utxo_scanner_recovery_with_restart() { amount: _, source_address: _, message, - maturity: _, import_status: _, tx_id: _, current_height: _, @@ -564,7 +562,7 @@ async fn test_utxo_scanner_recovery_with_restart_and_reorg() { const NUM_BLOCKS: u64 = 11; const BIRTHDAY_OFFSET: u64 = 5; const SYNC_INTERRUPT: u64 = 6; - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let TestBlockData { mut block_headers, mut wallet_outputs, @@ -597,7 +595,7 @@ async fn test_utxo_scanner_recovery_with_restart_and_reorg() { output.clone(), &key_manager, None, - OutputSource::Unknown, + OutputSource::Standard, None, None, ) @@ -634,7 +632,7 @@ async fn test_utxo_scanner_recovery_with_restart_and_reorg() { .filter(|u| u.height <= 4) .collect::>(); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let TestBlockData { block_headers: new_block_headers, wallet_outputs: new_wallet_outputs, @@ -675,7 +673,7 @@ async fn test_utxo_scanner_recovery_with_restart_and_reorg() { output.clone(), &key_manager, None, - OutputSource::Unknown, + OutputSource::Standard, None, None, ) @@ -755,7 +753,7 @@ async fn test_utxo_scanner_scanned_block_cache_clearing() { const NUM_BLOCKS: u64 = 11; const BIRTHDAY_OFFSET: u64 = 5; - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let TestBlockData { block_headers, wallet_outputs: _wallet_outputs, @@ -864,7 +862,7 @@ async fn test_utxo_scanner_one_sided_payments() { const NUM_BLOCKS: u64 = 11; const BIRTHDAY_OFFSET: u64 = 5; - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let TestBlockData { mut block_headers, wallet_outputs, @@ -899,7 +897,7 @@ async fn test_utxo_scanner_one_sided_payments() { output.clone(), &key_manager, None, - OutputSource::Unknown, + OutputSource::Standard, None, None, ) @@ -950,7 +948,6 @@ async fn test_utxo_scanner_one_sided_payments() { amount: _, source_address: _, message, - maturity: _, import_status: _, tx_id: _, current_height: _, @@ -984,7 +981,7 @@ async fn test_utxo_scanner_one_sided_payments() { block_headers.insert(NUM_BLOCKS, block_header11); db_wallet_outputs.push( - DbWalletOutput::from_wallet_output(uo, &key_manager, None, OutputSource::Unknown, None, None) + DbWalletOutput::from_wallet_output(uo, &key_manager, None, OutputSource::Standard, None, None) .await .unwrap(), ); @@ -1048,7 +1045,6 @@ async fn test_utxo_scanner_one_sided_payments() { amount: _, source_address: _, message, - maturity: _, import_status: _, tx_id: _, current_height: h, @@ -1073,7 +1069,7 @@ async fn test_birthday_timestamp_over_chain() { const NUM_BLOCKS: u64 = 10; const BIRTHDAY_OFFSET: u64 = 5; - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let TestBlockData { block_headers, utxos_by_block, diff --git a/base_layer/wallet_ffi/src/callback_handler_tests.rs b/base_layer/wallet_ffi/src/callback_handler_tests.rs index 94e52ffd7c4..9d5456dcc5d 100644 --- a/base_layer/wallet_ffi/src/callback_handler_tests.rs +++ b/base_layer/wallet_ffi/src/callback_handler_tests.rs @@ -323,8 +323,8 @@ mod test { TransactionDirection::Inbound, None, None, - None, - ); + ) + .unwrap(); db.insert_completed_transaction(2u64.into(), completed_tx.clone()) .unwrap(); @@ -389,10 +389,10 @@ mod test { "6".to_string(), Utc::now().naive_utc(), TransactionDirection::Inbound, - None, Some(2), Some(NaiveDateTime::from_timestamp_opt(0, 0).unwrap_or(NaiveDateTime::MIN)), - ); + ) + .unwrap(); db.insert_completed_transaction(6u64.into(), faux_unconfirmed_tx.clone()) .unwrap(); @@ -421,10 +421,10 @@ mod test { "7".to_string(), Utc::now().naive_utc(), TransactionDirection::Inbound, - None, Some(5), Some(NaiveDateTime::from_timestamp_opt(0, 0).unwrap()), - ); + ) + .unwrap(); db.insert_completed_transaction(7u64.into(), faux_confirmed_tx.clone()) .unwrap(); diff --git a/base_layer/wallet_ffi/src/lib.rs b/base_layer/wallet_ffi/src/lib.rs index ea3e57314f3..b26c6ee3b64 100644 --- a/base_layer/wallet_ffi/src/lib.rs +++ b/base_layer/wallet_ffi/src/lib.rs @@ -317,8 +317,7 @@ impl From for TariUtxo { OutputStatus::ShortTermEncumberedToBeReceived => 7, OutputStatus::ShortTermEncumberedToBeSpent => 8, OutputStatus::SpentMinedUnconfirmed => 9, - OutputStatus::AbandonedCoinbase => 10, - OutputStatus::NotStored => 11, + OutputStatus::NotStored => 10, }, } } @@ -8582,13 +8581,8 @@ mod test { use tari_core::{ covenant, transactions::{ - key_manager::SecretTransactionKeyManagerInterface, - test_helpers::{ - create_test_core_key_manager_with_memory_db, - create_test_input, - create_wallet_output_with_data, - TestParams, - }, + key_manager::{create_memory_db_key_manager, SecretTransactionKeyManagerInterface}, + test_helpers::{create_test_input, create_wallet_output_with_data, TestParams}, }, }; use tari_key_manager::{mnemonic::MnemonicLanguage, mnemonic_wordlists}; @@ -9899,7 +9893,7 @@ mod test { #[allow(clippy::too_many_lines)] fn test_wallet_get_utxos() { unsafe { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let mut error = 0; let error_ptr = &mut error as *mut c_int; let mut recovery_in_progress = true; @@ -10109,7 +10103,7 @@ mod test { ); assert_eq!(error, 0); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); for i in 0..10 { let uout = (*alice_wallet) .runtime @@ -10164,7 +10158,7 @@ mod test { #[allow(clippy::too_many_lines, clippy::needless_collect)] fn test_wallet_coin_join() { unsafe { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let mut error = 0; let error_ptr = &mut error as *mut c_int; let mut recovery_in_progress = true; @@ -10365,7 +10359,7 @@ mod test { #[allow(clippy::too_many_lines, clippy::needless_collect)] fn test_wallet_coin_split() { unsafe { - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let mut error = 0; let error_ptr = &mut error as *mut c_int; let mut recovery_in_progress = true; @@ -10633,7 +10627,7 @@ mod test { ); assert_eq!(error, 0); - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); for i in 1..=5 { (*alice_wallet) .runtime @@ -10755,7 +10749,7 @@ mod test { let mut error = 0; let error_ptr = &mut error as *mut c_int; // Test the consistent features case - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let utxo_1 = runtime .block_on(create_wallet_output_with_data( script!(Nop), @@ -10896,7 +10890,7 @@ mod test { ); // Test the consistent features case - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let utxo_1 = runtime .block_on(create_wallet_output_with_data( script!(Nop), @@ -10992,7 +10986,7 @@ mod test { let mut error = 0; let error_ptr = &mut error as *mut c_int; - let key_manager = create_test_core_key_manager_with_memory_db(); + let key_manager = create_memory_db_key_manager(); let utxo_1 = runtime .block_on(create_wallet_output_with_data( script!(Nop), diff --git a/common/config/presets/f_merge_mining_proxy.toml b/common/config/presets/f_merge_mining_proxy.toml index ea9d59cec03..5d62042522c 100644 --- a/common/config/presets/f_merge_mining_proxy.toml +++ b/common/config/presets/f_merge_mining_proxy.toml @@ -45,9 +45,6 @@ monerod_url = [# stagenet # The Minotari wallet's GRPC address. (default = "/ip4/127.0.0.1/tcp/18143") #console_wallet_grpc_address = "/ip4/127.0.0.1/tcp/18143" -# GRPC authentication for the Minotari wallet (default = "none") -#wallet_grpc_authentication = { username = "miner", password = "xxxx" } - # Address of the minotari_merge_mining_proxy application. (default = "/ip4/127.0.0.1/tcp/18081") #listener_address = "/ip4/127.0.0.1/tcp/18081" diff --git a/common/config/presets/g_miner.toml b/common/config/presets/g_miner.toml index f0d3d63b167..35170b0c16d 100644 --- a/common/config/presets/g_miner.toml +++ b/common/config/presets/g_miner.toml @@ -12,11 +12,6 @@ # GRPC authentication for the base node (default = "none") #base_node_grpc_authentication = { username = "miner", password = "xxxx" } -# GRPC address of console wallet (default = "/ip4/127.0.0.1/tcp/18143") -#wallet_grpc_address = "/ip4/127.0.0.1/tcp/18143" -# GRPC authentication for the console wallet (default = "none") -#wallet_grpc_authentication = { username = "miner", password = "xxxx" } - # Number of mining threads (default: number of logical CPU cores) #num_mining_threads = 8 diff --git a/common/src/exit_codes.rs b/common/src/exit_codes.rs index 84e3900f5bc..9b002640fb1 100644 --- a/common/src/exit_codes.rs +++ b/common/src/exit_codes.rs @@ -120,6 +120,12 @@ pub enum ExitCode { TorAuthConfiguration = 118, #[error("Unable to read Tor cookie file")] TorAuthUnreadableCookie = 119, + #[error("Tokio runtime error")] + TokioRuntimeError = 120, + #[error("Key manager service error")] + KeyManagerServiceError = 121, + #[error("Consensus manager builder error")] + ConsensusManagerBuilderError = 122, } impl From for ExitError { diff --git a/comms/core/src/net_address/mutliaddresses_with_stats.rs b/comms/core/src/net_address/mutliaddresses_with_stats.rs index f8d18e6022d..9d7c9d9e4b5 100644 --- a/comms/core/src/net_address/mutliaddresses_with_stats.rs +++ b/comms/core/src/net_address/mutliaddresses_with_stats.rs @@ -327,15 +327,15 @@ mod test { let mut net_addresses: MultiaddressesWithStats = MultiaddressesWithStats::from_addresses_with_source( vec![ net_address1.clone(), - net_address2.clone(), - net_address3.clone(), - net_address4.clone(), - net_address5.clone(), - net_address6.clone(), - net_address7.clone(), - net_address8.clone(), - net_address9.clone(), - net_address10.clone(), + net_address2, + net_address3, + net_address4, + net_address5, + net_address6, + net_address7, + net_address8, + net_address9, + net_address10, net_address11.clone(), ], &PeerAddressSource::Config, diff --git a/integration_tests/Cargo.toml b/integration_tests/Cargo.toml index a0d6104a95b..ecfa79e0df1 100644 --- a/integration_tests/Cargo.toml +++ b/integration_tests/Cargo.toml @@ -30,6 +30,7 @@ tari_utilities = { version = "0.6" } minotari_wallet = { path = "../base_layer/wallet" } minotari_wallet_ffi = { path = "../base_layer/wallet_ffi" } minotari_wallet_grpc_client = { path = "../clients/rust/wallet_grpc_client" } +tari_key_manager = { path = "../base_layer/key_manager" } anyhow = "1.0.53" async-trait = "0.1.50" diff --git a/integration_tests/src/miner.rs b/integration_tests/src/miner.rs index 73494a7b0c0..c343ccaf4fa 100644 --- a/integration_tests/src/miner.rs +++ b/integration_tests/src/miner.rs @@ -20,47 +20,35 @@ // 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. -use std::{convert::TryInto, str::FromStr, time::Duration}; - -use minotari_app_grpc::{ - authentication::ClientAuthenticationInterceptor, - tari_rpc::{ - pow_algo::PowAlgos, - wallet_client::WalletClient, - Block, - GetCoinbaseRequest, - GetCoinbaseResponse, - NewBlockTemplate, - NewBlockTemplateRequest, - NewBlockTemplateResponse, - PowAlgo, - TransactionKernel, - TransactionOutput, - }, +use std::{convert::TryFrom, time::Duration}; + +use minotari_app_grpc::tari_rpc::{ + pow_algo::PowAlgos, + Block, + NewBlockTemplate, + NewBlockTemplateRequest, + PowAlgo, + TransactionOutput as GrpcTransactionOutput, }; use minotari_app_utilities::common_cli_args::CommonCliArgs; use minotari_miner::{run_miner, Cli}; use minotari_node_grpc_client::BaseNodeGrpcClient; use tari_common::configuration::Network; -use tari_common_types::grpc_authentication::GrpcAuthentication; +use tari_common_types::tari_address::TariAddress; use tari_core::{ consensus::ConsensusManager, transactions::{ - key_manager::TransactionKeyManagerInterface, - test_helpers::TestKeyManager, + generate_coinbase, + key_manager::{MemoryDbKeyManager, TariKeyId}, + tari_amount::MicroMinotari, transaction_components::WalletOutput, - CoinbaseBuilder, }, }; -use tonic::{ - codegen::InterceptedService, - transport::{Channel, Endpoint}, -}; +use tonic::transport::Channel; use crate::TariWorld; type BaseNodeClient = BaseNodeGrpcClient; -type WalletGrpcClient = WalletClient>; #[derive(Clone, Debug)] pub struct MinerProcess { @@ -90,7 +78,6 @@ impl MinerProcess { miner_max_diff: Option, ) { let node = world.get_node(&self.base_node_name).unwrap().grpc_port; - let wallet = world.get_wallet(&self.wallet_name).unwrap().grpc_port; let temp_dir = world .current_base_dir .as_ref() @@ -112,10 +99,6 @@ impl MinerProcess { "miner.base_node_grpc_address".to_string(), format!("/ip4/127.0.0.1/tcp/{}", node), ), - ( - "miner.wallet_grpc_address".to_string(), - format!("/ip4/127.0.0.1/tcp/{}", wallet), - ), ("miner.num_mining_threads".to_string(), "1".to_string()), ("miner.mine_on_tip_only".to_string(), "false".to_string()), ], @@ -130,28 +113,27 @@ impl MinerProcess { } } -#[allow(dead_code)] -pub async fn mine_blocks(world: &mut TariWorld, miner_name: String, num_blocks: u64) { - let mut base_client = create_base_node_client(world, &miner_name).await; - let mut wallet_client = create_wallet_client(world, &miner_name).await; - - for _ in 0..num_blocks { - mine_block(&mut base_client, &mut wallet_client).await; - tokio::time::sleep(Duration::from_millis(100)).await; - } - - // Give some time for the base node and wallet to sync the new blocks - tokio::time::sleep(Duration::from_secs(5)).await; -} - pub async fn mine_blocks_without_wallet( base_client: &mut BaseNodeClient, num_blocks: u64, weight: u64, - key_manager: &TestKeyManager, + key_manager: &MemoryDbKeyManager, + miner_node_script_key_id: &TariKeyId, + wallet_payment_address: &TariAddress, + stealth_payment: bool, + consensus_manager: &ConsensusManager, ) { for _ in 0..num_blocks { - mine_block_without_wallet(base_client, weight, key_manager).await; + mine_block_without_wallet( + base_client, + weight, + key_manager, + miner_node_script_key_id, + wallet_payment_address, + stealth_payment, + consensus_manager, + ) + .await; tokio::time::sleep(Duration::from_millis(100)).await; } @@ -159,28 +141,24 @@ pub async fn mine_blocks_without_wallet( tokio::time::sleep(Duration::from_secs(5)).await; } -async fn create_base_node_client(world: &TariWorld, miner_name: &String) -> BaseNodeClient { - let miner = world.miners.get(miner_name).unwrap(); - let base_node_grpc_port = world.base_nodes.get(&miner.base_node_name).unwrap().grpc_port; - let base_node_grpc_url = format!("http://127.0.0.1:{}", base_node_grpc_port); - eprintln!("Base node GRPC at {}", base_node_grpc_url); - BaseNodeClient::connect(base_node_grpc_url).await.unwrap() -} - -async fn create_wallet_client(world: &TariWorld, miner_name: &String) -> WalletGrpcClient { - let miner = world.miners.get(miner_name).unwrap(); - let wallet_grpc_port = world.wallets.get(&miner.wallet_name).unwrap().grpc_port; - let wallet_addr = format!("http://127.0.0.1:{}", wallet_grpc_port); - eprintln!("Wallet GRPC at {}", wallet_addr); - let channel = Endpoint::from_str(&wallet_addr).unwrap().connect().await.unwrap(); - WalletClient::with_interceptor( - channel, - ClientAuthenticationInterceptor::create(&GrpcAuthentication::default()).unwrap(), +pub async fn mine_block( + base_client: &mut BaseNodeClient, + key_manager: &MemoryDbKeyManager, + miner_node_script_key_id: &TariKeyId, + wallet_payment_address: &TariAddress, + stealth_payment: bool, + consensus_manager: &ConsensusManager, +) { + let (block_template, _wallet_output) = create_block_template_with_coinbase( + base_client, + 0, + key_manager, + miner_node_script_key_id, + wallet_payment_address, + stealth_payment, + consensus_manager, ) -} - -pub async fn mine_block(base_client: &mut BaseNodeClient, wallet_client: &mut WalletGrpcClient) { - let block_template = create_block_template_with_coinbase(base_client, wallet_client).await; + .await; // Ask the base node for a valid block using the template let block_result = base_client @@ -198,10 +176,26 @@ pub async fn mine_block(base_client: &mut BaseNodeClient, wallet_client: &mut Wa ); } -async fn mine_block_without_wallet(base_client: &mut BaseNodeClient, weight: u64, key_manager: &TestKeyManager) { - let (block_template, _wallet_output) = - create_block_template_with_coinbase_without_wallet(base_client, weight, key_manager).await; - mine_block_without_wallet_with_template(base_client, block_template.new_block_template.unwrap()).await; +async fn mine_block_without_wallet( + base_client: &mut BaseNodeClient, + weight: u64, + key_manager: &MemoryDbKeyManager, + miner_node_script_key_id: &TariKeyId, + wallet_payment_address: &TariAddress, + stealth_payment: bool, + consensus_manager: &ConsensusManager, +) { + let (block_template, _wallet_output) = create_block_template_with_coinbase( + base_client, + weight, + key_manager, + miner_node_script_key_id, + wallet_payment_address, + stealth_payment, + consensus_manager, + ) + .await; + mine_block_without_wallet_with_template(base_client, block_template).await; } async fn mine_block_without_wallet_with_template(base_client: &mut BaseNodeClient, block_template: NewBlockTemplate) { @@ -222,40 +216,14 @@ async fn mine_block_without_wallet_with_template(base_client: &mut BaseNodeClien } async fn create_block_template_with_coinbase( - base_client: &mut BaseNodeClient, - wallet_client: &mut WalletGrpcClient, -) -> NewBlockTemplate { - // get the block template from the base node - let template_req = NewBlockTemplateRequest { - algo: Some(PowAlgo { - pow_algo: PowAlgos::Sha3x.into(), - }), - max_weight: 0, - }; - - let template_res = base_client - .get_new_block_template(template_req) - .await - .unwrap() - .into_inner(); - - let mut block_template = template_res.new_block_template.clone().unwrap(); - - // add the coinbase outputs and kernels to the block template - let (output, kernel) = get_coinbase_outputs_and_kernels(wallet_client, template_res).await; - let body = block_template.body.as_mut().unwrap(); - - body.outputs.push(output); - body.kernels.push(kernel); - - block_template -} - -async fn create_block_template_with_coinbase_without_wallet( base_client: &mut BaseNodeClient, weight: u64, - key_manager: &TestKeyManager, -) -> (NewBlockTemplateResponse, WalletOutput) { + key_manager: &MemoryDbKeyManager, + miner_node_script_key_id: &TariKeyId, + wallet_payment_address: &TariAddress, + stealth_payment: bool, + consensus_manager: &ConsensusManager, +) -> (NewBlockTemplate, WalletOutput) { // get the block template from the base node let template_req = NewBlockTemplateRequest { algo: Some(PowAlgo { @@ -264,106 +232,41 @@ async fn create_block_template_with_coinbase_without_wallet( max_weight: weight, }; - let mut template_res = base_client + let template_response = base_client .get_new_block_template(template_req) .await .unwrap() .into_inner(); - // let mut block_template = template_res.new_block_template.clone().unwrap(); - - // add the coinbase outputs and kernels to the block template - let (output, kernel, wallet_output) = get_coinbase_without_wallet_client(template_res.clone(), key_manager).await; - // let body = block_template.body.as_mut().unwrap(); - - template_res - .new_block_template - .as_mut() - .unwrap() - .body - .as_mut() - .unwrap() - .outputs - .push(output); - template_res - .new_block_template - .as_mut() - .unwrap() - .body - .as_mut() - .unwrap() - .kernels - .push(kernel); - - (template_res, wallet_output) -} - -async fn get_coinbase_outputs_and_kernels( - wallet_client: &mut WalletGrpcClient, - template_res: NewBlockTemplateResponse, -) -> (TransactionOutput, TransactionKernel) { - let coinbase_req = coinbase_request(&template_res); - let coinbase_res = wallet_client.get_coinbase(coinbase_req).await.unwrap().into_inner(); - extract_outputs_and_kernels(coinbase_res) -} - -async fn get_coinbase_without_wallet_client( - template_res: NewBlockTemplateResponse, - key_manager: &TestKeyManager, -) -> (TransactionOutput, TransactionKernel, WalletOutput) { - let coinbase_req = coinbase_request(&template_res); - generate_coinbase(coinbase_req, key_manager).await -} - -async fn generate_coinbase( - coinbase_req: GetCoinbaseRequest, - key_manager: &TestKeyManager, -) -> (TransactionOutput, TransactionKernel, WalletOutput) { - let reward = coinbase_req.reward; - let height = coinbase_req.height; - let fee = coinbase_req.fee; - let extra = coinbase_req.extra; - - let (spending_key_id, _, script_key_id, _) = key_manager.get_next_spend_and_script_key_ids().await.unwrap(); + let mut block_template = template_response.new_block_template.clone().unwrap(); - let consensus_manager = ConsensusManager::builder(Network::LocalNet).build().unwrap(); - let consensus_constants = consensus_manager.consensus_constants(height); - - let (tx, ubutxo) = CoinbaseBuilder::new(key_manager.clone()) - .with_block_height(height) - .with_fees(fee.into()) - .with_spend_key_id(spending_key_id) - .with_script_key_id(script_key_id) - .with_extra(extra) - .build_with_reward(consensus_constants, reward.into()) - .await - .unwrap(); - - let tx_out = tx.body().outputs().first().unwrap().clone(); - let tx_krnl = tx.body().kernels().first().unwrap().clone(); - - (tx_out.try_into().unwrap(), tx_krnl.into(), ubutxo) -} - -fn coinbase_request(template_response: &NewBlockTemplateResponse) -> GetCoinbaseRequest { let template = template_response.new_block_template.as_ref().unwrap(); let miner_data = template_response.miner_data.as_ref().unwrap(); let fee = miner_data.total_fees; let reward = miner_data.reward; let height = template.header.as_ref().unwrap().height; - GetCoinbaseRequest { - reward, - fee, + + // add the coinbase outputs and kernels to the block template + let (_, output, kernel, wallet_output) = generate_coinbase( + MicroMinotari::from(fee), + MicroMinotari::from(reward), height, - extra: vec![], - } -} + &[], + key_manager, + miner_node_script_key_id, + wallet_payment_address, + stealth_payment, + consensus_manager.consensus_constants(height), + ) + .await + .unwrap(); + let body = block_template.body.as_mut().unwrap(); -fn extract_outputs_and_kernels(coinbase: GetCoinbaseResponse) -> (TransactionOutput, TransactionKernel) { - let transaction_body = coinbase.transaction.unwrap().body.unwrap(); - let output = transaction_body.outputs.get(0).cloned().unwrap(); - let kernel = transaction_body.kernels.get(0).cloned().unwrap(); - (output, kernel) + let grpc_output = GrpcTransactionOutput::try_from(output).unwrap(); + body.outputs.push(grpc_output); + body.kernels.push(kernel.into()); + + (block_template, wallet_output) } pub async fn mine_block_with_coinbase_on_node(world: &mut TariWorld, base_node: String, coinbase_name: String) { @@ -374,20 +277,40 @@ pub async fn mine_block_with_coinbase_on_node(world: &mut TariWorld, base_node: .get_grpc_client() .await .unwrap(); - let (template, wallet_output) = - create_block_template_with_coinbase_without_wallet(&mut client, 0, &world.key_manager).await; + let (template, wallet_output) = create_block_template_with_coinbase( + &mut client, + 0, + &world.key_manager, + &world.miner_node_script_key_id.clone(), + &world.default_payment_address.clone(), + false, + &world.consensus_manager.clone(), + ) + .await; world.utxos.insert(coinbase_name, wallet_output); - mine_block_without_wallet_with_template(&mut client, template.new_block_template.unwrap()).await; + mine_block_without_wallet_with_template(&mut client, template).await; } -pub async fn mine_block_before_submit(client: &mut BaseNodeClient, key_manager: &TestKeyManager) -> Block { - let (template, _wallet_output) = create_block_template_with_coinbase_without_wallet(client, 0, key_manager).await; +pub async fn mine_block_before_submit( + client: &mut BaseNodeClient, + key_manager: &MemoryDbKeyManager, + miner_node_script_key_id: &TariKeyId, + wallet_payment_address: &TariAddress, + stealth_payment: bool, + consensus_manager: &ConsensusManager, +) -> Block { + let (template, _wallet_output) = create_block_template_with_coinbase( + client, + 0, + key_manager, + miner_node_script_key_id, + wallet_payment_address, + stealth_payment, + consensus_manager, + ) + .await; - let new_block = client - .get_new_block(template.new_block_template.unwrap()) - .await - .unwrap() - .into_inner(); + let new_block = client.get_new_block(template).await.unwrap().into_inner(); new_block.block.unwrap() } diff --git a/integration_tests/src/transaction.rs b/integration_tests/src/transaction.rs index ad1b2e18ec6..d358d9f63b3 100644 --- a/integration_tests/src/transaction.rs +++ b/integration_tests/src/transaction.rs @@ -26,9 +26,9 @@ use tari_core::{ borsh::SerializedSize, covenants::Covenant, transactions::{ - key_manager::TariKeyId, + key_manager::{MemoryDbKeyManager, TariKeyId}, tari_amount::MicroMinotari, - test_helpers::{create_transaction_with, TestKeyManager, TestParams}, + test_helpers::{create_transaction_with, TestParams}, transaction_components::{ OutputFeatures, Transaction, @@ -54,7 +54,7 @@ struct TestTransactionBuilder { } impl TestTransactionBuilder { - pub async fn new(key_manager: &TestKeyManager) -> Self { + pub async fn new(key_manager: &MemoryDbKeyManager) -> Self { Self { amount: MicroMinotari(0), fee_per_gram: MicroMinotari(1), @@ -80,7 +80,7 @@ impl TestTransactionBuilder { self.amount += amount } - pub async fn add_input(&mut self, u: WalletOutput, key_manager: &TestKeyManager) -> &mut Self { + pub async fn add_input(&mut self, u: WalletOutput, key_manager: &MemoryDbKeyManager) -> &mut Self { self.update_amount(u.value); if u.features.maturity > self.inputs_max_height { @@ -97,7 +97,7 @@ impl TestTransactionBuilder { self } - pub async fn build(mut self, key_manager: &TestKeyManager) -> (Transaction, WalletOutput) { + pub async fn build(mut self, key_manager: &MemoryDbKeyManager) -> (Transaction, WalletOutput) { self.create_utxo(key_manager, self.inputs.len()).await; let inputs = self.inputs.iter().map(|f| f.1.clone()).collect(); @@ -107,7 +107,7 @@ impl TestTransactionBuilder { (tx, self.output.clone().unwrap().1) } - async fn create_utxo(&mut self, key_manager: &TestKeyManager, num_inputs: usize) { + async fn create_utxo(&mut self, key_manager: &MemoryDbKeyManager, num_inputs: usize) { let script = script!(Nop); let features = OutputFeatures::default(); let covenant = Covenant::default(); @@ -153,7 +153,7 @@ impl TestTransactionBuilder { pub async fn build_transaction_with_output_and_fee_per_gram( utxos: Vec, fee_per_gram: u64, - key_manager: &TestKeyManager, + key_manager: &MemoryDbKeyManager, ) -> (Transaction, WalletOutput) { let mut builder = TestTransactionBuilder::new(key_manager).await; for wallet_output in utxos { @@ -167,7 +167,7 @@ pub async fn build_transaction_with_output_and_fee_per_gram( pub async fn build_transaction_with_output_and_lockheight( utxos: Vec, lockheight: u64, - key_manager: &TestKeyManager, + key_manager: &MemoryDbKeyManager, ) -> (Transaction, WalletOutput) { let mut builder = TestTransactionBuilder::new(key_manager).await; for wallet_output in utxos { @@ -180,7 +180,7 @@ pub async fn build_transaction_with_output_and_lockheight( pub async fn build_transaction_with_output( utxos: Vec, - key_manager: &TestKeyManager, + key_manager: &MemoryDbKeyManager, ) -> (Transaction, WalletOutput) { let mut builder = TestTransactionBuilder::new(key_manager).await; for wallet_output in utxos { diff --git a/integration_tests/src/world.rs b/integration_tests/src/world.rs index 1ff90585882..6eb47e8c8bd 100644 --- a/integration_tests/src/world.rs +++ b/integration_tests/src/world.rs @@ -28,15 +28,24 @@ use std::{ use cucumber::gherkin::{Feature, Scenario}; use indexmap::IndexMap; +use rand::rngs::OsRng; use serde_json::Value; use tari_chat_client::ChatClient; +use tari_common::configuration::Network; +use tari_common_types::{ + tari_address::TariAddress, + types::{PrivateKey, PublicKey}, +}; use tari_core::{ blocks::Block, + consensus::ConsensusManager, transactions::{ - test_helpers::{create_test_core_key_manager_with_memory_db, TestKeyManager}, + key_manager::{create_memory_db_key_manager, MemoryDbKeyManager, TariKeyId}, transaction_components::{Transaction, WalletOutput}, }, }; +use tari_crypto::keys::{PublicKey as PK, SecretKey}; +use tari_key_manager::key_manager_service::KeyManagerInterface; use tari_utilities::hex::Hex; use thiserror::Error; @@ -91,12 +100,26 @@ pub struct TariWorld { pub last_imported_tx_ids: Vec, // We need to store this for the merge mining proxy steps. The checks are get and check are done on separate steps. pub last_merge_miner_response: Value, - pub key_manager: TestKeyManager, + pub key_manager: MemoryDbKeyManager, + // This will be used for all one-sided coinbase payments + pub miner_node_script_key_id: TariKeyId, + // This receiver wallet address will be used for default one-sided coinbase payments + pub default_payment_address: TariAddress, + pub consensus_manager: ConsensusManager, } impl Default for TariWorld { fn default() -> Self { println!("\nWorld initialized - remove this line when called!\n"); + let key_manager = create_memory_db_key_manager(); + let wallet_private_key = PrivateKey::random(&mut OsRng); + let miner_node_script_key_id = tokio::runtime::Runtime::new() + .unwrap() + .block_on(key_manager.import_key(wallet_private_key)) + .unwrap(); + let payment_private_key = PrivateKey::random(&mut OsRng); + let default_payment_address = + TariAddress::new(PublicKey::from_secret_key(&payment_private_key), Network::LocalNet); Self { current_scenario_name: None, current_feature_name: None, @@ -119,7 +142,10 @@ impl Default for TariWorld { errors: Default::default(), last_imported_tx_ids: vec![], last_merge_miner_response: Default::default(), - key_manager: create_test_core_key_manager_with_memory_db(), + key_manager: create_memory_db_key_manager(), + miner_node_script_key_id, + default_payment_address, + consensus_manager: ConsensusManager::builder(Network::LocalNet).build().unwrap(), } } } diff --git a/integration_tests/tests/steps/mining_steps.rs b/integration_tests/tests/steps/mining_steps.rs index bbc5d12f715..229cfb4601c 100644 --- a/integration_tests/tests/steps/mining_steps.rs +++ b/integration_tests/tests/steps/mining_steps.rs @@ -65,7 +65,17 @@ async fn mine_blocks_on(world: &mut TariWorld, blocks: u64, base_node: String) { .get_node_client(&base_node) .await .expect("Couldn't get the node client to mine with"); - mine_blocks_without_wallet(&mut client, blocks, 0, &world.key_manager).await; + mine_blocks_without_wallet( + &mut client, + blocks, + 0, + &world.key_manager, + &world.miner_node_script_key_id.clone(), + &world.default_payment_address.clone(), + false, + &world.consensus_manager.clone(), + ) + .await; } #[when(expr = "mining node {word} mines {int} blocks with min difficulty {int} and max difficulty {int}")] @@ -94,7 +104,17 @@ async fn mine_custom_weight_blocks_with_height(world: &mut TariWorld, num_blocks .get_node_client(&node_name) .await .expect("Couldn't get the node client to mine with"); - mine_blocks_without_wallet(&mut client, num_blocks, weight, &world.key_manager).await; + mine_blocks_without_wallet( + &mut client, + num_blocks, + weight, + &world.key_manager, + &world.miner_node_script_key_id.clone(), + &world.default_payment_address.clone(), + false, + &world.consensus_manager.clone(), + ) + .await; } #[then(expr = "I have a SHA3 miner {word} connected to node {word}")] @@ -200,7 +220,15 @@ async fn while_mining_in_node_all_txs_in_wallet_are_mined_confirmed( } println!("Mine a block for tx_id {} to have status Mined_Confirmed", tx_id); - mine_block(&mut node_client, &mut wallet_client).await; + mine_block( + &mut node_client, + &world.key_manager, + &world.miner_node_script_key_id.clone(), + &world.default_payment_address.clone(), + false, + &world.consensus_manager.clone(), + ) + .await; tokio::time::sleep(Duration::from_secs(5)).await; } @@ -281,8 +309,18 @@ async fn mining_node_mine_blocks(world: &mut TariWorld, blocks: u64) { async fn mine_without_submit(world: &mut TariWorld, block: String, node: String) { let mut client = world.get_node_client(&node).await.unwrap(); - let unmined_block: Block = - Block::try_from(mine_block_before_submit(&mut client, &world.key_manager).await).unwrap(); + let unmined_block: Block = Block::try_from( + mine_block_before_submit( + &mut client, + &world.key_manager, + &world.miner_node_script_key_id.clone(), + &world.default_payment_address.clone(), + false, + &world.consensus_manager.clone(), + ) + .await, + ) + .unwrap(); world.blocks.insert(block, unmined_block); } diff --git a/integration_tests/tests/steps/node_steps.rs b/integration_tests/tests/steps/node_steps.rs index a99b8c0b207..9a36b720186 100644 --- a/integration_tests/tests/steps/node_steps.rs +++ b/integration_tests/tests/steps/node_steps.rs @@ -645,7 +645,15 @@ async fn no_meddling_with_data(world: &mut TariWorld, node: String) { // No meddling let chain_tip = client.get_tip_info(Empty {}).await.unwrap().into_inner(); let current_height = chain_tip.metadata.unwrap().height_of_longest_chain; - let block = mine_block_before_submit(&mut client, &world.key_manager).await; + let block = mine_block_before_submit( + &mut client, + &world.key_manager, + &world.miner_node_script_key_id.clone(), + &world.default_payment_address.clone(), + false, + &world.consensus_manager.clone(), + ) + .await; let _sumbmit_res = client.submit_block(block).await.unwrap(); let chain_tip = client.get_tip_info(Empty {}).await.unwrap().into_inner(); @@ -660,7 +668,18 @@ async fn no_meddling_with_data(world: &mut TariWorld, node: String) { ); // Meddle with kernal_mmr_size - let mut block: Block = Block::try_from(mine_block_before_submit(&mut client, &world.key_manager).await).unwrap(); + let mut block: Block = Block::try_from( + mine_block_before_submit( + &mut client, + &world.key_manager, + &world.miner_node_script_key_id.clone(), + &world.default_payment_address.clone(), + false, + &world.consensus_manager.clone(), + ) + .await, + ) + .unwrap(); block.header.kernel_mmr_size += 1; match client.submit_block(grpc::Block::try_from(block).unwrap()).await { Ok(_) => panic!("The block should not have been valid"), @@ -673,7 +692,18 @@ async fn no_meddling_with_data(world: &mut TariWorld, node: String) { } // Meddle with output_mmr_size - let mut block: Block = Block::try_from(mine_block_before_submit(&mut client, &world.key_manager).await).unwrap(); + let mut block: Block = Block::try_from( + mine_block_before_submit( + &mut client, + &world.key_manager, + &world.miner_node_script_key_id.clone(), + &world.default_payment_address.clone(), + false, + &world.consensus_manager.clone(), + ) + .await, + ) + .unwrap(); block.header.output_smt_size += 1; match client.submit_block(grpc::Block::try_from(block).unwrap()).await { Ok(_) => panic!("The block should not have been valid"), diff --git a/integration_tests/tests/steps/wallet_steps.rs b/integration_tests/tests/steps/wallet_steps.rs index f3577bc8ae6..628437c1145 100644 --- a/integration_tests/tests/steps/wallet_steps.rs +++ b/integration_tests/tests/steps/wallet_steps.rs @@ -41,10 +41,8 @@ use grpc::{ use minotari_app_grpc::tari_rpc::{self as grpc}; use minotari_console_wallet::{CliCommands, ExportUtxosArgs}; use minotari_wallet::transaction_service::config::TransactionRoutingMechanism; -use tari_common::configuration::Network; use tari_common_types::types::{ComAndPubSignature, Commitment, PrivateKey, PublicKey}; use tari_core::{ - consensus::ConsensusManager, covenants::Covenant, transactions::{ tari_amount::MicroMinotari, @@ -1530,12 +1528,11 @@ async fn wallet_with_tari_connected_to_base_node( let mut num_blocks = 0; let mut reward = 0; - let consensus_manager = ConsensusManager::builder(Network::LocalNet).build().unwrap(); - while reward < amount { current_height += 1; num_blocks += 1; - reward += consensus_manager.get_block_reward_at(current_height).as_u64() / 1_000_000; // 1 T = 1_000_000 uT + reward += world.consensus_manager.get_block_reward_at(current_height).as_u64() / 1_000_000; // 1 T = 1_000_000 + // uT } println!("Creating miner...");