Skip to content

Commit

Permalink
feat: update pre-mine specification and allow multiple spends (#6590)
Browse files Browse the repository at this point in the history
Description
---
- Updated the pre-mine specification to cater for different upfront
release strategies.
- Update pre-mine spending to consider spending multiples of multiple
outputs to a single wallet.
- Updated pre-mine spend to output immediate genesis block spends to
json for inclusion in the genesis block.
- Added reading pre-mine input from file as an option for immediate
genesis block spends, instead of reading the embedded pre-mine file.

Motivation and Context
---
Catering for new requirements.

How Has This Been Tested?
---
System-level testing [**TBD**]

What process can a PR reviewer use to test or verify this change?
---
Code review

<!-- Checklist -->
<!-- 1. Is the title of your PR in the form that would make nice release
notes? The title, excluding the conventional commit
tag, will be included exactly as is in the CHANGELOG, so please think
about it carefully. -->


Breaking Changes
---

- [x] None
- [ ] Requires data directory on base node to be deleted
- [ ] Requires hard fork
- [ ] Other - Please specify

<!-- Does this include a breaking change? If so, include this line as a
footer -->
<!-- BREAKING CHANGE: Description what the user should do, e.g. delete a
database, resync the chain -->
  • Loading branch information
hansieodendaal authored Oct 1, 2024
1 parent c9b95c1 commit 6d998c7
Show file tree
Hide file tree
Showing 11 changed files with 1,655 additions and 426 deletions.
1,037 changes: 750 additions & 287 deletions applications/minotari_console_wallet/src/automation/commands.rs

Large diffs are not rendered by default.

45 changes: 41 additions & 4 deletions applications/minotari_console_wallet/src/automation/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,14 @@ use tari_script::{CheckSigSchnorrSignature, ExecutionStack, TariScript};
struct PreMineSpendStep1SessionInfo {
session_id: String,
fee_per_gram: MicroMinotari,
commitment_to_spend: String,
output_hash: String,
recipient_info: Vec<RecipientInfo>,
use_pre_mine_input_file: bool,
}

#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq)]
struct RecipientInfo {
output_to_be_spend: usize,
recipient_address: TariAddress,
output_index: usize,
}

impl SessionId for PreMineSpendStep1SessionInfo {
Expand All @@ -59,8 +63,14 @@ impl SessionId for PreMineSpendStep1SessionInfo {
// Step 2 outputs for self with `PreMineSpendPartyDetails`
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq)]
struct PreMineSpendStep2OutputsForSelf {
outputs_for_self: Vec<Step2OutputsForSelf>,
alias: String,
wallet_spend_key_id: TariKeyId,
}

#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq)]
pub struct Step2OutputsForSelf {
output_index: usize,
recipient_address: TariAddress,
script_nonce_key_id: TariKeyId,
sender_offset_key_id: TariKeyId,
sender_offset_nonce_key_id: TariKeyId,
Expand All @@ -70,6 +80,14 @@ struct PreMineSpendStep2OutputsForSelf {
// Step 2 outputs for leader with `PreMineSpendPartyDetails`
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq)]
struct PreMineSpendStep2OutputsForLeader {
outputs_for_leader: Vec<Step2OutputsForLeader>,
alias: String,
}

#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq)]
pub struct Step2OutputsForLeader {
output_index: usize,
recipient_address: TariAddress,
script_input_signature: CheckSigSchnorrSignature,
public_script_nonce_key: PublicKey,
public_sender_offset_key: PublicKey,
Expand All @@ -81,12 +99,24 @@ struct PreMineSpendStep2OutputsForLeader {
// Step 3 outputs for self with `PreMineSpendEncumberAggregateUtxo`
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq)]
struct PreMineSpendStep3OutputsForSelf {
outputs_for_self: Vec<Step3OutputsForSelf>,
}

#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq)]
struct Step3OutputsForSelf {
output_index: usize,
tx_id: TxId,
}

// Step 3 outputs for parties with `PreMineSpendEncumberAggregateUtxo`
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq)]
struct PreMineSpendStep3OutputsForParties {
outputs_for_parties: Vec<Step3OutputsForParties>,
}

#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq)]
struct Step3OutputsForParties {
output_index: usize,
input_stack: ExecutionStack,
input_script: TariScript,
total_script_key: PublicKey,
Expand All @@ -103,6 +133,13 @@ struct PreMineSpendStep3OutputsForParties {
// Step 4 outputs for leader with `PreMineSpendInputOutputSigs`
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq)]
struct PreMineSpendStep4OutputsForLeader {
outputs_for_leader: Vec<Step4OutputsForLeader>,
alias: String,
}

#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq)]
struct Step4OutputsForLeader {
output_index: usize,
script_signature: Signature,
metadata_signature: Signature,
script_offset: PrivateKey,
Expand Down
66 changes: 62 additions & 4 deletions applications/minotari_console_wallet/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
use std::{
fmt::{Debug, Display, Formatter},
path::PathBuf,
str::FromStr,
time::Duration,
};

Expand Down Expand Up @@ -190,19 +191,68 @@ pub struct PreMineSpendSessionInfoArgs {
#[clap(long)]
pub fee_per_gram: MicroMinotari,
#[clap(long)]
pub output_index: usize,
#[clap(long)]
pub recipient_address: TariAddress,
pub recipient_info: Vec<CliRecipientInfo>,
#[clap(long)]
pub verify_unspent_outputs: bool,
#[clap(long)]
pub use_pre_mine_input_file: bool,
}

#[derive(Debug, Args, Clone)]
pub struct CliRecipientInfo {
pub output_indexes: Vec<usize>,
pub recipient_address: TariAddress,
}

impl FromStr for CliRecipientInfo {
type Err = String;

fn from_str(s: &str) -> Result<Self, Self::Err> {
// Parse 'RecipientInfo' from "[<v1>,<v2>,<v3>]:<recipient_address>"
if !s.contains(':') {
return Err("Invalid 'recipient-info', could not find address separator ':'".to_string());
}
let parts: Vec<&str> = s.split(':').collect();
if parts.len() != 2 {
return Err(format!(
"Invalid 'recipient-info', needs exactly 2 parts, found {}",
parts.len()
));
}

// Parse output indexes
if !parts[0].starts_with('[') && !parts[0].ends_with(']') {
return Err("Invalid 'recipient-info' part 1; array bounds must be indicated with '[' and ']'".to_string());
}
let binding = parts[0].replace("[", "").replace("]", "");
let parts_0 = binding.split(',').collect::<Vec<&str>>();
let output_indexes = parts_0
.iter()
.map(|v| {
v.parse()
.map_err(|e| format!("'recipient_info' - invalid output_index: {}", e))
})
.collect::<Result<Vec<usize>, String>>()?;

// Parse recipient address
let recipient_address = TariAddress::from_base58(parts[1])
.map_err(|e| format!("'recipient_info' - invalid recipient address: {}", e))?;

Ok(CliRecipientInfo {
output_indexes,
recipient_address,
})
}
}

#[derive(Debug, Args, Clone)]
pub struct PreMineSpendPartyDetailsArgs {
#[clap(long)]
pub input_file: PathBuf,
#[clap(long)]
pub output_index: usize,
pub pre_mine_file_path: Option<PathBuf>,
#[clap(long)]
pub recipient_info: Vec<CliRecipientInfo>,
#[clap(long)]
pub alias: String,
}
Expand All @@ -213,12 +263,16 @@ pub struct PreMineSpendEncumberAggregateUtxoArgs {
pub session_id: String,
#[clap(long)]
pub input_file_names: Vec<String>,
#[clap(long)]
pub pre_mine_file_path: Option<PathBuf>,
}

#[derive(Debug, Args, Clone)]
pub struct PreMineSpendInputOutputSigArgs {
#[clap(long)]
pub session_id: String,
#[clap(long)]
pub pre_mine_file_path: Option<PathBuf>,
}

#[derive(Debug, Args, Clone)]
Expand All @@ -227,6 +281,10 @@ pub struct PreMineSpendAggregateTransactionArgs {
pub session_id: String,
#[clap(long)]
pub input_file_names: Vec<String>,
#[clap(long)]
pub save_to_file: bool,
#[clap(long)]
pub print_to_console: bool,
}

#[derive(Debug, Args, Clone)]
Expand Down
10 changes: 7 additions & 3 deletions applications/minotari_console_wallet/src/wallet_modes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -543,11 +543,15 @@ mod test {
pre-mine-spend-get-output-status
pre-mine-spend-session-info --fee-per-gram 2 --output-index 123 --recipient-address \
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 --output-index 123 --alias alice
pre-mine-spend-party-details --input-file ./step_1_session_info.txt --alias alice \
--recipient-info=[1,123,313]:\
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 \
Expand Down
17 changes: 9 additions & 8 deletions base_layer/core/src/blocks/genesis_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};

Expand All @@ -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::<TransactionOutput>(line) {
utxos.push(utxo);
} else {
block.body.add_kernel(serde_json::from_str(line).unwrap());
} else if let Ok(kernel) = serde_json::from_str::<TransactionKernel>(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);
Expand Down
Loading

0 comments on commit 6d998c7

Please sign in to comment.