Skip to content

Commit

Permalink
feat!: update payment id to cover all transaction types (#6744)
Browse files Browse the repository at this point in the history
Description
---
- Updated `PaymentId::Open`, `PaymentId::AddressAndData` and
`PaymentId::TransactionInfo` to reflect the transaction type for all
defined types in `pub enum TxType`.
- Fixed transaction identification for all defined types in `pub enum
TxType`.
- Added method `transaction_type_from_encrypted_data` to the wallet FFI
and a unit test to test all cases.
- Added wallet FFI test cases to ensure coin-join and coin-split
transactions are correctly flagged in the payment ID.

_**TODO:** System-level testing mobile wallet recovery into a view-only
console wallet._

Close issues #6713 and #6745

Motivation and Context
---
The payment ID did not cover all transaction types or provide sufficient
information for wallet recovery.

How Has This Been Tested?
---
- System-level testing (console wallet recovered as a view-only wallet)
- Added unit tests for the wallet FFI

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

<!-- 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
---

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

<!-- Does this include a breaking change? If so, include this line as a
footer -->
BREAKING CHANGE: 
- Added a new wallet FFI method: `fn
transaction_type_from_encrypted_data`
- Embedded `PaymentId` enum in `EncryptedData` changed:
   - `PaymentId::Open` changed
   - `PaymentId::Address` fell away
   - `PaymentId::AddressAndData` changed
   - `PaymentId::TransactionInfo` changed
- No changes to pre-mine payment IDs in the genesis block that makes use
of `PaymentId::U64`

---------

Co-authored-by: SW van Heerden <[email protected]>
  • Loading branch information
hansieodendaal and SWvheerden authored Jan 17, 2025
1 parent e5193a8 commit 5f4f95b
Show file tree
Hide file tree
Showing 35 changed files with 1,310 additions and 583 deletions.
58 changes: 41 additions & 17 deletions applications/minotari_console_wallet/src/automation/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ use tari_core::{
key_manager::TransactionKeyManagerInterface,
tari_amount::{uT, MicroMinotari, Minotari},
transaction_components::{
encrypted_data::PaymentId,
encrypted_data::{PaymentId, TxType},
EncryptedData,
OutputFeatures,
Transaction,
Expand Down Expand Up @@ -793,7 +793,7 @@ pub async fn command_runner(
transaction_service.clone(),
config.fee_per_gram,
args.amount,
PaymentId::open_from_str(&args.payment_id),
PaymentId::open(&args.payment_id, TxType::Burn),
)
.await
{
Expand Down Expand Up @@ -978,8 +978,11 @@ pub async fn command_runner(
args.fee_per_gram,
output_hash,
commitment.clone(),
args.recipient_address,
PaymentId::open_from_str(&args.payment_id),
args.recipient_address.clone(),
PaymentId::open(
&args.payment_id,
detect_tx_metadata(&wallet, args.recipient_address).await,
),
)
.await
{
Expand Down Expand Up @@ -1338,14 +1341,17 @@ pub async fn command_runner(
sender_offset_public_key_shares,
metadata_ephemeral_public_key_shares,
dh_shared_secret_shares,
current_recipient_address,
current_recipient_address.clone(),
original_maturity,
if pre_mine_from_file.is_some() {
UseOutput::AsProvided(embedded_output)
} else {
UseOutput::FromBlockchain(embedded_output.hash())
},
PaymentId::open_from_str(&args.payment_id),
PaymentId::open(
&args.payment_id,
detect_tx_metadata(&wallet, current_recipient_address).await,
),
)
.await
{
Expand Down Expand Up @@ -1987,8 +1993,8 @@ pub async fn command_runner(
transaction_service.clone(),
config.fee_per_gram,
args.amount,
args.destination,
PaymentId::open_from_str(&args.payment_id),
args.destination.clone(),
PaymentId::open(&args.payment_id, detect_tx_metadata(&wallet, args.destination).await),
)
.await
{
Expand All @@ -2005,8 +2011,8 @@ pub async fn command_runner(
config.fee_per_gram,
args.amount,
UtxoSelectionCriteria::default(),
args.destination,
PaymentId::open_from_str(&args.payment_id),
args.destination.clone(),
PaymentId::open(&args.payment_id, detect_tx_metadata(&wallet, args.destination).await),
)
.await
{
Expand All @@ -2030,9 +2036,9 @@ pub async fn command_runner(
args.start_amount,
args.increase_amount,
args.start_time.unwrap_or_else(Utc::now),
args.destination,
args.destination.clone(),
transaction_type,
PaymentId::open_from_str(&args.payment_id),
PaymentId::open(&args.payment_id, detect_tx_metadata(&wallet, args.destination).await),
)
.await
{
Expand All @@ -2044,7 +2050,7 @@ pub async fn command_runner(
args.amount_per_split,
args.num_splits,
args.fee_per_gram,
PaymentId::open_from_str(&args.payment_id),
PaymentId::open(&args.payment_id, TxType::CoinSplit),
&mut output_service,
&mut transaction_service.clone(),
)
Expand Down Expand Up @@ -2244,7 +2250,7 @@ pub async fn command_runner(
args.amount,
UtxoSelectionCriteria::default(),
args.destination,
PaymentId::open_from_str(&args.payment_id),
PaymentId::open(&args.payment_id, TxType::ClaimAtomicSwap),
)
.await
{
Expand All @@ -2267,7 +2273,7 @@ pub async fn command_runner(
hash,
args.pre_image.into(),
config.fee_per_gram.into(),
PaymentId::open_from_str(&args.payment_id),
PaymentId::open(&args.payment_id, TxType::ClaimAtomicSwap),
)
.await
{
Expand All @@ -2287,7 +2293,7 @@ pub async fn command_runner(
transaction_service.clone(),
hash,
config.fee_per_gram.into(),
PaymentId::open_from_str(&args.payment_id),
PaymentId::open(&args.payment_id, TxType::HtlcAtomicSwapRefund),
)
.await
{
Expand Down Expand Up @@ -2328,7 +2334,7 @@ pub async fn command_runner(
),
UtxoSelectionCriteria::default(),
config.fee_per_gram * uT,
PaymentId::open_from_str(&args.payment_id),
PaymentId::open(&args.payment_id, TxType::ValidatorNodeRegistration),
)
.await?;
debug!(target: LOG_TARGET, "Registering VN tx_id {}", tx_id);
Expand Down Expand Up @@ -2703,6 +2709,24 @@ pub async fn command_runner(
Ok(unban_peer_manager_peers)
}

async fn detect_tx_metadata(wallet: &WalletSqlite, destination: TariAddress) -> TxType {
if let Ok(interactive_address) = wallet.get_wallet_interactive_address().await {
if let Ok(one_sided_address) = wallet.get_wallet_one_sided_address().await {
if destination == interactive_address || destination == one_sided_address {
TxType::PaymentToSelf
} else {
TxType::PaymentToOther
}
} else if destination == interactive_address {
TxType::PaymentToSelf
} else {
TxType::PaymentToOther
}
} else {
TxType::PaymentToOther
}
}

async fn temp_ban_peers(wallet: &WalletSqlite, peer_list: &mut Vec<Peer>) {
for peer in peer_list {
let _unused = wallet
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ use tari_core::{
transactions::{
tari_amount::{MicroMinotari, T},
transaction_components::{
encrypted_data::PaymentId,
encrypted_data::{PaymentId, TxType},
CodeTemplateRegistration,
OutputFeatures,
OutputType,
Expand Down Expand Up @@ -414,7 +414,7 @@ impl wallet_server::Wallet for WalletGrpcServer {
tx_id,
tx,
amount,
PaymentId::open_from_str("Claiming HTLC transaction with pre-image"),
PaymentId::open("Claiming HTLC transaction with pre-image", TxType::ClaimAtomicSwap),
)
.await
{
Expand Down Expand Up @@ -469,7 +469,7 @@ impl wallet_server::Wallet for WalletGrpcServer {
tx_id,
tx,
amount,
PaymentId::open_from_str("Creating HTLC refund transaction"),
PaymentId::open("Creating HTLC refund transaction", TxType::HtlcAtomicSwapRefund),
)
.await
{
Expand Down Expand Up @@ -832,7 +832,7 @@ impl wallet_server::Wallet for WalletGrpcServer {
usize::try_from(message.split_count)
.map_err(|_| Status::internal("Count not convert u64 to usize".to_string()))?,
MicroMinotari::from(message.fee_per_gram),
PaymentId::Empty,
PaymentId::open("Creating coin-split transaction", TxType::CoinSplit),
)
.await
.map_err(|e| Status::internal(format!("{:?}", e)))?;
Expand Down Expand Up @@ -983,13 +983,17 @@ impl wallet_server::Wallet for WalletGrpcServer {
.map_err(|e| Status::internal(e.to_string()))?;

output = output.with_script(script![Nop].map_err(|e| Status::invalid_argument(e.to_string()))?);
let payment_id = PaymentId::open(
&format!("Template registration '{}'", template_name),
TxType::CodeTemplateRegistration,
);

let (tx_id, transaction) = output_manager
.create_send_to_self_with_output(
vec![output],
fee_per_gram.into(),
UtxoSelectionCriteria::default(),
PaymentId::open_from_str(&format!("Template registration {}", template_name)),
payment_id.clone(),
)
.await
.map_err(|e| Status::internal(e.to_string()))?;
Expand All @@ -1008,7 +1012,7 @@ impl wallet_server::Wallet for WalletGrpcServer {
let template_address = reg_output.hash();

transaction_service
.submit_transaction(tx_id, transaction, 0.into(), PaymentId::Empty)
.submit_transaction(tx_id, transaction, 0.into(), payment_id)
.await
.map_err(|e| Status::internal(e.to_string()))?;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ use std::fs;

use log::*;
use minotari_wallet::output_manager_service::UtxoSelectionCriteria;
use tari_core::transactions::{tari_amount::MicroMinotari, transaction_components::encrypted_data::PaymentId};
use tari_core::transactions::{
tari_amount::MicroMinotari,
transaction_components::encrypted_data::{PaymentId, TxType},
};
use tokio::{runtime::Handle, sync::watch};
use tui::{
backend::Backend,
Expand Down Expand Up @@ -311,11 +314,7 @@ impl BurnTab {
amount.into(),
UtxoSelectionCriteria::default(),
fee_per_gram,
if self.payment_id_field.is_empty() {
PaymentId::Empty
} else {
PaymentId::open_from_str(&self.payment_id_field)
},
PaymentId::open(&self.payment_id_field, TxType::Burn),
tx,
)) {
Err(e) => {
Expand Down
17 changes: 6 additions & 11 deletions applications/minotari_console_wallet/src/ui/components/send_tab.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
use log::*;
use minotari_wallet::output_manager_service::UtxoSelectionCriteria;
use tari_common_types::wallet_types::WalletType;
use tari_core::transactions::{tari_amount::MicroMinotari, transaction_components::encrypted_data::PaymentId};
use tari_core::transactions::{
tari_amount::MicroMinotari,
transaction_components::encrypted_data::{PaymentId, TxType},
};
use tari_utilities::hex::Hex;
use tokio::{runtime::Handle, sync::watch};
use tui::{
Expand Down Expand Up @@ -284,11 +287,7 @@ impl SendTab {
amount.into(),
UtxoSelectionCriteria::default(),
fee_per_gram,
if self.payment_id_field.is_empty() {
PaymentId::Empty
} else {
PaymentId::open_from_str(&self.payment_id_field)
},
PaymentId::open(&self.payment_id_field, TxType::PaymentToOther),
tx,
),
) {
Expand All @@ -308,11 +307,7 @@ impl SendTab {
amount.into(),
UtxoSelectionCriteria::default(),
fee_per_gram,
if self.payment_id_field.is_empty() {
PaymentId::Empty
} else {
PaymentId::open_from_str(&self.payment_id_field)
},
PaymentId::open(&self.payment_id_field, TxType::PaymentToOther),
tx,
)) {
Err(e) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,11 @@ use std::collections::HashMap;
use chrono::{DateTime, Local};
use log::*;
use minotari_wallet::transaction_service::storage::models::TxCancellationReason;
use tari_common_types::transaction::{TransactionDirection, TransactionStatus};
use tari_core::transactions::transaction_components::encrypted_data::PaymentId;
use tari_common_types::{
tari_address::TariAddress,
transaction::{TransactionDirection, TransactionStatus},
};
use tari_core::transactions::transaction_components::encrypted_data::{PaymentId, TxType};
use tokio::runtime::Handle;
use tui::{
backend::Backend,
Expand Down Expand Up @@ -211,22 +214,42 @@ impl TransactionsTab {
let cancelled = tx.cancelled.is_some();
let text_color = text_colors.get(&cancelled).unwrap_or(&Color::Reset).to_owned();

let (status, burn) = if let Some(PaymentId::TransactionInfo { burn, .. }) = tx.payment_id.clone() {
(
match tx.status {
TransactionStatus::OneSidedUnconfirmed => TransactionStatus::MinedUnconfirmed,
TransactionStatus::OneSidedConfirmed => TransactionStatus::MinedConfirmed,
_ => tx.status.clone(),
},
burn,
)
} else {
(tx.status.clone(), tx.burn)
let mut transaction_status = tx.status.clone();
let mut transaction_type = if tx.burn { TxType::Burn } else { TxType::PaymentToOther };
if let Some(
PaymentId::Open { tx_type, .. } |
PaymentId::AddressAndData { tx_type, .. } |
PaymentId::TransactionInfo { tx_type, .. },
) = tx.payment_id.clone()
{
match tx.status {
TransactionStatus::OneSidedUnconfirmed => transaction_status = TransactionStatus::MinedUnconfirmed,
TransactionStatus::OneSidedConfirmed => transaction_status = TransactionStatus::MinedConfirmed,
_ => {},
}
transaction_type = tx_type.clone();
};

let address_text = match (&tx.direction, &tx.coinbase, burn) {
if let Some(PaymentId::Open { .. } | PaymentId::AddressAndData { .. }) = tx.payment_id.clone() {
if transaction_type == TxType::PaymentToSelf && tx.source_address != tx.destination_address {
transaction_type = TxType::PaymentToOther;
}
if transaction_type == TxType::Burn && tx.destination_address != TariAddress::default() {
transaction_type = TxType::PaymentToOther;
}
}

let address_text = match (&tx.direction, &tx.coinbase, transaction_type) {
(_, true, _) => "Mining reward",
(_, _, true) => "Burned output",
(_, _, TxType::Burn) => "Burned output",
(_, _, TxType::CoinJoin) => "Coin join",
(_, _, TxType::CoinSplit) => "Coin split",
(_, _, TxType::ImportedUtxoNoneRewindable) => "Imported output",
(_, _, TxType::PaymentToSelf) => "Payment to self",
(_, _, TxType::ValidatorNodeRegistration) => "Validator node registration",
(_, _, TxType::CodeTemplateRegistration) => "Code template registration",
(_, _, TxType::HtlcAtomicSwapRefund) => "HTLC atomic swap refund",
(_, _, TxType::ClaimAtomicSwap) => "Claim atomic swap",
(TransactionDirection::Outbound, _, _) => &app_state.get_alias(tx.destination_address.to_base58()),
_ => &app_state.get_alias(tx.source_address.to_base58()),
};
Expand Down Expand Up @@ -273,7 +296,7 @@ impl TransactionsTab {
} else if tx.cancelled.is_some() {
"Rejected".to_string()
} else {
status.to_string()
transaction_status.to_string()
};
column3_items.push(ListItem::new(Span::styled(
status_display,
Expand Down
18 changes: 14 additions & 4 deletions applications/minotari_console_wallet/src/ui/state/app_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,12 @@ use tari_comms::{
use tari_contacts::contacts_service::{handle::ContactsLivenessEvent, types::Contact};
use tari_core::transactions::{
tari_amount::{uT, MicroMinotari},
transaction_components::{encrypted_data::PaymentId, OutputFeatures, TemplateType, TransactionError},
transaction_components::{
encrypted_data::{PaymentId, TxType},
OutputFeatures,
TemplateType,
TransactionError,
},
weight::TransactionWeight,
};
use tari_shutdown::ShutdownSignal;
Expand Down Expand Up @@ -1195,10 +1200,15 @@ impl CompletedTransactionInfo {
let outputs_count = tx.transaction.body.outputs().len();
let coinbase = tx.transaction.body.contains_coinbase();
// Faux transactions for scanned change outputs must correspond to the original transaction
let burn = if let PaymentId::TransactionInfo { burn, .. } = tx.payment_id {
burn
let burn = if tx.transaction.body.contains_burn() {
true
} else if let PaymentId::Open { tx_type, .. } |
PaymentId::AddressAndData { tx_type, .. } |
PaymentId::TransactionInfo { tx_type, .. } = tx.payment_id.clone()
{
tx_type == TxType::Burn
} else {
tx.transaction.body.contains_burn()
false
};

Ok(Self {
Expand Down
Loading

0 comments on commit 5f4f95b

Please sign in to comment.