From ab179b557d01763c68bba5d0b12abad7d6976d36 Mon Sep 17 00:00:00 2001 From: Hansie Odendaal Date: Sun, 6 Oct 2024 20:53:33 +0200 Subject: [PATCH] total kernel offset --- .../src/automation/commands.rs | 109 ++++++++++++++++-- base_layer/core/src/blocks/genesis_block.rs | 2 + .../src/output_manager_service/service.rs | 23 +++- 3 files changed, 124 insertions(+), 10 deletions(-) diff --git a/applications/minotari_console_wallet/src/automation/commands.rs b/applications/minotari_console_wallet/src/automation/commands.rs index 864c59500c..e6d7344f5d 100644 --- a/applications/minotari_console_wallet/src/automation/commands.rs +++ b/applications/minotari_console_wallet/src/automation/commands.rs @@ -93,9 +93,11 @@ use tari_core::{ UnblindedOutput, WalletOutput, }, + CryptoFactories, }, }; use tari_crypto::{ + commitment::HomomorphicCommitmentFactory, dhke::DiffieHellmanSharedSecret, ristretto::{pedersen::PedersenCommitment, RistrettoSecretKey}, }; @@ -1637,6 +1639,7 @@ pub async fn command_runner( let mut inputs = Vec::new(); let mut outputs = Vec::new(); let mut kernels = Vec::new(); + let mut kernel_offset = PrivateKey::default(); for (indexed_info, leader_self) in party_info_per_index.iter().zip(leader_info.outputs_for_self.iter()) { let mut metadata_signatures = Vec::with_capacity(party_info_per_index.len()); @@ -1664,17 +1667,61 @@ pub async fn command_runner( break; } + // Collect all inputs, outputs and kernels that should go into the genesis block if session_info.use_pre_mine_input_file { match transaction_service.get_any_transaction(leader_self.tx_id).await { Ok(Some(WalletTransaction::Completed(tx))) => { - for input in tx.transaction.body.inputs() { - inputs.push(input.clone()); + // Fees must be zero + match tx.transaction.body.get_total_fee() { + Ok(fee) => { + if fee != MicroMinotari::zero() { + eprintln!( + "\nError: Transaction {} fee ({}) for does not equal zero!\n", + tx.tx_id, fee + ); + break; + } + }, + Err(e) => { + eprintln!("\nError: Transaction {}! ({})\n", tx.tx_id, e); + break; + }, } + + let mut utxo_sum = Commitment::default(); for output in tx.transaction.body.outputs() { outputs.push(output.clone()); + utxo_sum = &utxo_sum + &output.commitment; + } + for input in tx.transaction.body.inputs() { + inputs.push(input.clone()); + match input.commitment() { + Ok(commitment) => utxo_sum = &utxo_sum - commitment, + Err(e) => { + eprintln!("\nError: Input commitment ({})!\n", e); + break; + }, + } } + let mut kernel_sum = Commitment::default(); for kernel in tx.transaction.body.kernels() { kernels.push(kernel.clone()); + kernel_sum = &kernel_sum + &kernel.excess; + } + kernel_offset = &kernel_offset + &tx.transaction.offset; + // Ensure that the balance equation holds: + // sum(output commitments) - sum(input commitments) = sum(kernel excesses) + + // total_offset + let offset = CryptoFactories::default() + .commitment + .commit_value(&tx.transaction.offset, 0); + if utxo_sum != &kernel_sum + &offset { + eprintln!( + "\nError: Transaction {} balance: UTXO sum {} vs. kernel sum + offset {}!\n", + tx.tx_id, + utxo_sum.to_hex(), + (&kernel_sum + &offset).to_hex() + ); } }, Ok(_) => { @@ -1692,10 +1739,38 @@ pub async fn command_runner( } } + 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); if session_info.use_pre_mine_input_file { - 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); + // Ensure that the balance equation holds: + // sum(output commitments) - sum(input commitments) = sum(kernel excesses) + kernel_offset + let mut utxo_sum = Commitment::default(); + for output in &outputs { + utxo_sum = &utxo_sum + &output.commitment; + } + for input in &inputs { + match input.commitment() { + Ok(commitment) => utxo_sum = &utxo_sum - commitment, + Err(e) => { + eprintln!("\nError: Input commitment ({})!\n", e); + break; + }, + } + } + let mut kernel_sum = Commitment::default(); + for kernel in &kernels { + kernel_sum = &kernel_sum + &kernel.excess; + } + let offset = CryptoFactories::default().commitment.commit_value(&kernel_offset, 0); + if utxo_sum != &kernel_sum + &offset { + eprintln!( + "\nError: Transactions balance: UTXO sum {} vs. kernel sum + offset {}!\n", + utxo_sum.to_hex(), + (&kernel_sum + &offset).to_hex() + ); + } + let mut file_stream = match File::create(&out_file) { Ok(file) => file, Err(e) => { @@ -1706,7 +1781,7 @@ pub async fn command_runner( let mut error = false; inputs.sort(); - for input in inputs { + for input in &inputs { let input_s = match serde_json::to_string(&input) { Ok(val) => val, Err(e) => { @@ -1725,7 +1800,7 @@ pub async fn command_runner( break; } outputs.sort(); - for output in outputs { + for output in &outputs { let utxo_s = match serde_json::to_string(&output) { Ok(val) => val, Err(e) => { @@ -1744,7 +1819,7 @@ pub async fn command_runner( break; } kernels.sort(); - for kernel in kernels { + for kernel in &kernels { let kernel_s = match serde_json::to_string(&kernel) { Ok(val) => val, Err(e) => { @@ -1761,9 +1836,27 @@ pub async fn command_runner( if error { break; } + let kernel_offset_s = match serde_json::to_string(&kernel_offset) { + Ok(val) => val, + Err(e) => { + eprintln!("\nError: Could not serialize kernel offset ({})\n", e); + break; + }, + }; + if let Err(e) = file_stream.write_all(format!("{}\n", kernel_offset_s).as_bytes()) { + eprintln!("\nError: Could not write the genesis file ({})\n", e); + break; + } } println!(); + if session_info.use_pre_mine_input_file { + println!( + "Genesis block immediate pre-mine spend information: '{}' in '{}'", + file_name, + out_dir_path.display() + ); + } println!("Concluded step 5 'pre-mine-spend-aggregate-transaction'"); println!(); }, diff --git a/base_layer/core/src/blocks/genesis_block.rs b/base_layer/core/src/blocks/genesis_block.rs index 95822c387e..7d1c98b06e 100644 --- a/base_layer/core/src/blocks/genesis_block.rs +++ b/base_layer/core/src/blocks/genesis_block.rs @@ -70,6 +70,8 @@ fn add_pre_mine_utxos_to_genesis_block(file: &str, block: &mut Block) { } else if let Ok(kernel) = serde_json::from_str::(line) { block.body.add_kernel(kernel); block.header.kernel_mmr_size += 1; + } else if let Ok(excess) = serde_json::from_str::(line) { + block.header.total_kernel_offset = &block.header.total_kernel_offset + &excess; } else { panic!("Error: Could not deserialize line: {} in file: {}", line, file); } diff --git a/base_layer/wallet/src/output_manager_service/service.rs b/base_layer/wallet/src/output_manager_service/service.rs index 5b376e4832..3b14cb59a1 100644 --- a/base_layer/wallet/src/output_manager_service/service.rs +++ b/base_layer/wallet/src/output_manager_service/service.rs @@ -66,7 +66,7 @@ use tari_core::{ SenderTransactionProtocol, }, }; -use tari_crypto::ristretto::pedersen::PedersenCommitment; +use tari_crypto::{commitment::HomomorphicCommitmentFactory, ristretto::pedersen::PedersenCommitment}; use tari_key_manager::key_manager_service::{KeyAndId, KeyId, SerializedKeyString}; use tari_script::{ inputs, @@ -1523,7 +1523,7 @@ where ) .await? .with_input_data(ExecutionStack::default()) // Just a placeholder in the wallet - .with_sender_offset_public_key(sender_offset_public_key) + .with_sender_offset_public_key(sender_offset_public_key.clone()) .with_script_key(self.resources.key_manager.get_spend_key().await?.key_id) .with_minimum_value_promise(minimum_value_promise) .sign_partial_as_sender_and_receiver( @@ -1586,6 +1586,25 @@ where let shared_secret_bytes = shared_secret.as_bytes(); let shared_secret_public_key = PublicKey::from_canonical_bytes(shared_secret_bytes)?; + // Transaction balance log + // sum(output commitments) - sum(input commitments) = sum(kernel excesses) + total_offset + let mut utxo_sum = Commitment::default(); + for output in tx.body.outputs() { + utxo_sum = &utxo_sum + &output.commitment; + } + for input in tx.body.inputs() { + utxo_sum = &utxo_sum - input.commitment()?; + } + let mut kernel_sum = Commitment::default(); + for kernel in tx.body.kernels() { + kernel_sum = &kernel_sum + &kernel.excess; + } + let total_offset = self.resources.factories.commitment.commit_value(&tx.offset, 0); + trace!(target: LOG_TARGET, "total_offset: {}", total_offset.to_hex()); + trace!(target: LOG_TARGET, "utxo_sum: {}", utxo_sum.to_hex()); + trace!(target: LOG_TARGET, "kernel_sum: {}", kernel_sum.to_hex()); + trace!(target: LOG_TARGET, "kernel_sum + sender_offset: {}", (&kernel_sum + &total_offset).to_hex()); + Ok(( tx, amount,