From 7f3ccc1fc756abda9c36f2987e0dd44de6298ff2 Mon Sep 17 00:00:00 2001 From: Hansie Odendaal Date: Tue, 1 Oct 2024 11:51:57 +0200 Subject: [PATCH] add pre-mine input from file --- .../src/automation/commands.rs | 142 +++++++++++++++--- .../src/automation/mod.rs | 1 + .../minotari_console_wallet/src/cli.rs | 8 + .../src/wallet_modes.rs | 5 +- base_layer/core/src/blocks/genesis_block.rs | 17 ++- 5 files changed, 139 insertions(+), 34 deletions(-) diff --git a/applications/minotari_console_wallet/src/automation/commands.rs b/applications/minotari_console_wallet/src/automation/commands.rs index 8d403f3410..f14225dd51 100644 --- a/applications/minotari_console_wallet/src/automation/commands.rs +++ b/applications/minotari_console_wallet/src/automation/commands.rs @@ -27,7 +27,7 @@ use std::{ fs, fs::File, io, - io::{LineWriter, Write}, + io::{BufRead, BufReader, LineWriter, Write}, path::{Path, PathBuf}, str::FromStr, time::{Duration, Instant}, @@ -84,6 +84,7 @@ use tari_core::{ Transaction, TransactionInput, TransactionInputVersion, + TransactionKernel, TransactionOutput, TransactionOutputVersion, UnblindedOutput, @@ -860,16 +861,16 @@ pub async fn command_runner( let mut recipient_info = Vec::new(); for item in args_recipient_info { - let embedded_outputs = match get_embedded_pre_mine_outputs(item.output_indexes.clone()) { - Ok(outputs) => outputs, - Err(e) => { - eprintln!("\nError: {}\n", e); - break; - }, - }; - let output_hashes = embedded_outputs.iter().map(|v| v.hash()).collect::>(); + if args.verify_unspent_outputs && !args.use_pre_mine_input_file { + let embedded_outputs = match get_embedded_pre_mine_outputs(item.output_indexes.clone(), None) { + Ok(outputs) => outputs, + Err(e) => { + eprintln!("\nError: {}\n", e); + break; + }, + }; + let output_hashes = embedded_outputs.iter().map(|v| v.hash()).collect::>(); - if args.verify_unspent_outputs { let unspent_outputs = transaction_service.fetch_unspent_outputs(output_hashes.clone()).await?; if unspent_outputs.len() != output_hashes.len() { let unspent_output_hashes = unspent_outputs.iter().map(|v| v.hash()).collect::>(); @@ -904,6 +905,7 @@ pub async fn command_runner( session_id: session_id.clone(), fee_per_gram: args.fee_per_gram, recipient_info, + use_pre_mine_input_file: args.use_pre_mine_input_file, }; let out_file = out_dir.join(get_file_name(SPEND_SESSION_INFO, None)); @@ -928,7 +930,7 @@ pub async fn command_runner( }, } - let embedded_output = match get_embedded_pre_mine_outputs(vec![args.output_index]) { + let embedded_output = match get_embedded_pre_mine_outputs(vec![args.output_index], None) { Ok(outputs) => outputs[0].clone(), Err(e) => { eprintln!("\nError: {}\n", e); @@ -1013,10 +1015,22 @@ pub async fn command_runner( break; } + let pre_mine_from_file = + match read_genesis_file_outputs(session_info.use_pre_mine_input_file, args.pre_mine_file_path) { + Ok(outputs) => outputs, + Err(e) => { + eprintln!("\nError: {}\n", e); + break; + }, + }; + let mut outputs_for_leader = Vec::with_capacity(args_recipient_info.len()); let mut outputs_for_self = Vec::with_capacity(args_recipient_info.len()); for recipient_info in &args_recipient_info { - let embedded_outputs = match get_embedded_pre_mine_outputs(recipient_info.output_indexes.clone()) { + let embedded_outputs = match get_embedded_pre_mine_outputs( + recipient_info.output_indexes.clone(), + pre_mine_from_file.clone(), + ) { Ok(outputs) => outputs, Err(e) => { eprintln!("\nError: {}\n", e); @@ -1175,6 +1189,15 @@ pub async fn command_runner( party_info_per_index.push(outputs_per_index); } + let pre_mine_from_file = + match read_genesis_file_outputs(session_info.use_pre_mine_input_file, args.pre_mine_file_path) { + Ok(outputs) => outputs, + Err(e) => { + eprintln!("\nError: {}\n", e); + break; + }, + }; + // Encumber outputs let mut outputs_for_parties = Vec::with_capacity(party_info_per_index.len()); let mut outputs_for_self = Vec::with_capacity(party_info_per_index.len()); @@ -1217,13 +1240,14 @@ pub async fn command_runner( } let original_maturity = pre_mine_items[current_index].original_maturity; - let embedded_output = match get_embedded_pre_mine_outputs(vec![current_index]) { - Ok(outputs) => outputs[0].clone(), - Err(e) => { - eprintln!("\nError: {}\n", e); - break; - }, - }; + let embedded_output = + match get_embedded_pre_mine_outputs(vec![current_index], pre_mine_from_file.clone()) { + Ok(outputs) => outputs[0].clone(), + Err(e) => { + eprintln!("\nError: {}\n", e); + break; + }, + }; match encumber_aggregate_utxo( transaction_service.clone(), @@ -1345,13 +1369,25 @@ pub async fn command_runner( break; } + let pre_mine_from_file = + match read_genesis_file_outputs(session_info.use_pre_mine_input_file, args.pre_mine_file_path) { + Ok(outputs) => outputs, + Err(e) => { + eprintln!("\nError: {}\n", e); + break; + }, + }; + let mut outputs_for_leader = Vec::with_capacity(party_info_indexed.outputs_for_self.len()); for (leader_info, party_info) in leader_info_indexed .outputs_for_parties .iter() .zip(party_info_indexed.outputs_for_self.iter()) { - let embedded_output = match get_embedded_pre_mine_outputs(vec![party_info.output_index]) { + let embedded_output = match get_embedded_pre_mine_outputs( + vec![party_info.output_index], + pre_mine_from_file.clone(), + ) { Ok(outputs) => outputs[0].clone(), Err(e) => { eprintln!("\nError: {}\n", e); @@ -1598,7 +1634,7 @@ pub async fn command_runner( } if args.save_to_file { - let file_name = get_pre_mine_file_name(); + let file_name = get_pre_mine_addition_file_name(); let out_dir_path = out_dir(&args.session_id)?; let out_file = out_dir_path.join(&file_name); let mut file_stream = match File::create(&out_file) { @@ -2352,7 +2388,58 @@ pub async fn command_runner( Ok(()) } +fn read_genesis_file_outputs( + use_pre_mine_input_file: bool, + pre_mine_file_path: Option, +) -> Result>, String> { + if use_pre_mine_input_file { + let file_path = if let Some(path) = pre_mine_file_path { + let file = path.join(get_pre_mine_file_name()); + if !file.exists() { + return Err(format!("Pre-mine file '{}' does not exist!", file.display())); + } + file + } else { + return Err("Missing pre-mine file!".to_string()); + }; + + let file = File::open(file_path.clone()) + .map_err(|e| format!("Problem opening file '{}' ({})", file_path.display(), e))?; + let reader = BufReader::new(file); + + let mut outputs = Vec::new(); + for line in reader.lines() { + let line = line.map_err(|e| format!("Problem reading line in file '{}' ({})", file_path.display(), e))?; + if let Ok(output) = serde_json::from_str::(&line) { + outputs.push(output); + } else if serde_json::from_str::(&line).is_ok() { + // Do nothing here + } else { + return Err(format!("Error: Could not deserialize line: {}", line)); + } + } + if outputs.is_empty() { + return Err(format!("No outputs found in '{}'", file_path.display())); + } + + Ok(Some(outputs)) + } else { + Ok(None) + } +} + fn get_pre_mine_file_name() -> String { + match Network::get_current_or_user_setting_or_default() { + Network::MainNet => "mainnet_pre_mine.json".to_string(), + Network::StageNet => "stagenet_pre_mine.json".to_string(), + Network::NextNet => "nextnet_pre_mine.json".to_string(), + Network::LocalNet => "esmeralda_pre_mine.json".to_string(), + Network::Igor => "igor_pre_mine.json".to_string(), + Network::Esmeralda => "esmeralda_pre_mine.json".to_string(), + } +} + +fn get_pre_mine_addition_file_name() -> String { match Network::get_current_or_user_setting_or_default() { Network::MainNet => "mainnet_pre_mine_addition.json".to_string(), Network::StageNet => "stagenet_pre_mine_addition.json".to_string(), @@ -2388,14 +2475,21 @@ fn sort_args_recipient_info(recipient_info: Vec) -> Vec) -> Result, CommandError> { - let utxos = get_all_embedded_pre_mine_outputs()?; +fn get_embedded_pre_mine_outputs( + output_indexes: Vec, + utxos: Option>, +) -> Result, CommandError> { + let utxos = if let Some(val) = utxos { + val + } else { + get_all_embedded_pre_mine_outputs()? + }; let mut fetched_outputs = Vec::with_capacity(output_indexes.len()); for index in output_indexes { if index >= utxos.len() { return Err(CommandError::PreMine(format!( - "Error: Invalid 'output_index' {} provided pre-mine outputs only number {}!", + "Error: Invalid 'output_index' {} provided, pre-mine outputs only number {}!", index, utxos.len() ))); diff --git a/applications/minotari_console_wallet/src/automation/mod.rs b/applications/minotari_console_wallet/src/automation/mod.rs index bba470a7be..8bb67bc39e 100644 --- a/applications/minotari_console_wallet/src/automation/mod.rs +++ b/applications/minotari_console_wallet/src/automation/mod.rs @@ -45,6 +45,7 @@ struct PreMineSpendStep1SessionInfo { session_id: String, fee_per_gram: MicroMinotari, recipient_info: Vec, + use_pre_mine_input_file: bool, } #[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq)] diff --git a/applications/minotari_console_wallet/src/cli.rs b/applications/minotari_console_wallet/src/cli.rs index ae0baddbc9..6710ebb0ad 100644 --- a/applications/minotari_console_wallet/src/cli.rs +++ b/applications/minotari_console_wallet/src/cli.rs @@ -194,6 +194,8 @@ pub struct PreMineSpendSessionInfoArgs { pub recipient_info: Vec, #[clap(long)] pub verify_unspent_outputs: bool, + #[clap(long)] + pub use_pre_mine_input_file: bool, } #[derive(Debug, Args, Clone)] @@ -248,6 +250,8 @@ pub struct PreMineSpendPartyDetailsArgs { #[clap(long)] pub input_file: PathBuf, #[clap(long)] + pub pre_mine_file_path: Option, + #[clap(long)] pub recipient_info: Vec, #[clap(long)] pub alias: String, @@ -259,12 +263,16 @@ pub struct PreMineSpendEncumberAggregateUtxoArgs { pub session_id: String, #[clap(long)] pub input_file_names: Vec, + #[clap(long)] + pub pre_mine_file_path: Option, } #[derive(Debug, Args, Clone)] pub struct PreMineSpendInputOutputSigArgs { #[clap(long)] pub session_id: String, + #[clap(long)] + pub pre_mine_file_path: Option, } #[derive(Debug, Args, Clone)] diff --git a/applications/minotari_console_wallet/src/wallet_modes.rs b/applications/minotari_console_wallet/src/wallet_modes.rs index 5ff229b273..d1370c584d 100644 --- a/applications/minotari_console_wallet/src/wallet_modes.rs +++ b/applications/minotari_console_wallet/src/wallet_modes.rs @@ -546,11 +546,12 @@ mod test { pre-mine-spend-session-info --fee-per-gram 2 \ --recipient-info=[1,123,313]:\ f4LR9f6WwwcPiKJjK5ciTkU1ocNhANa3FPw1wkyVUwbuKpgiihawCXy6PFszunUWQ4Te8KVFnyWVHHwsk9x5Cg7ZQiA \ - --verify-unspent-outputs + --verify-unspent-outputs --use-pre-mine-input-file pre-mine-spend-party-details --input-file ./step_1_session_info.txt --alias alice \ --recipient-info=[1,123,313]:\ - f4LR9f6WwwcPiKJjK5ciTkU1ocNhANa3FPw1wkyVUwbuKpgiihawCXy6PFszunUWQ4Te8KVFnyWVHHwsk9x5Cg7ZQiA + f4LR9f6WwwcPiKJjK5ciTkU1ocNhANa3FPw1wkyVUwbuKpgiihawCXy6PFszunUWQ4Te8KVFnyWVHHwsk9x5Cg7ZQiA \ + --pre-mine-file-path ./pre_mine_file.txt pre-mine-spend-encumber-aggregate-utxo --session-id ee1643655c \ --input-file-names=step_2_for_leader_from_alice.txt --input-file-names=step_2_for_leader_from_bob.txt \ diff --git a/base_layer/core/src/blocks/genesis_block.rs b/base_layer/core/src/blocks/genesis_block.rs index ff0ffff376..cbf6b93f86 100644 --- a/base_layer/core/src/blocks/genesis_block.rs +++ b/base_layer/core/src/blocks/genesis_block.rs @@ -32,7 +32,10 @@ use tari_utilities::ByteArray; use crate::{ blocks::{block::Block, BlockHeader, BlockHeaderAccumulatedData, ChainBlock}, proof_of_work::{AccumulatedDifficulty, Difficulty, PowAlgorithm, PowData, ProofOfWork}, - transactions::{aggregated_body::AggregateBody, transaction_components::TransactionOutput}, + transactions::{ + aggregated_body::AggregateBody, + transaction_components::{TransactionKernel, TransactionOutput}, + }, OutputSmt, }; @@ -51,17 +54,15 @@ pub fn get_genesis_block(network: Network) -> ChainBlock { fn add_pre_mine_utxos_to_genesis_block(file: &str, block: &mut Block) { let mut utxos = Vec::new(); - let mut counter = 1; - let lines_count = file.lines().count(); for line in file.lines() { - if counter < lines_count { - let utxo: TransactionOutput = serde_json::from_str(line).unwrap(); + if let Ok(utxo) = serde_json::from_str::(line) { utxos.push(utxo); - } else { - block.body.add_kernel(serde_json::from_str(line).unwrap()); + } else if let Ok(kernel) = serde_json::from_str::(line) { + block.body.add_kernel(kernel); block.header.kernel_mmr_size += 1; + } else { + panic!("Error: Could not deserialize line: {} in file: {}", line, file); } - counter += 1; } block.header.output_smt_size += utxos.len() as u64; block.body.add_outputs(utxos);