Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
target
.env
cucumber-output-junit.xml
# Non-root Cargo.locks
**/Cargo.lock
!/Cargo.lock
Expand Down Expand Up @@ -61,5 +62,4 @@ clients/validator_node_grpc_client/package-lock.json

# moon
.moon/cache
.moon/docker
./cucumber-output-junit.xml
.moon/docker
22 changes: 10 additions & 12 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,6 @@ tari_template_test_tooling = { path = "crates/template_test_tooling" }
tari_transaction = { path = "crates/transaction" }
tari_transaction_manifest = { path = "crates/transaction_manifest" }
tari_validator_node_rpc = { path = "crates/validator_node_rpc" }

# internal dependencies among workspace crates
libp2p-messaging = { path = "networking/libp2p-messaging" }
libp2p-substream = { path = "networking/libp2p-substream" }
proto_builder = { path = "networking/proto_builder" }
sqlite_message_logger = { path = "networking/sqlite_message_logger" }
tari_base_node_client = { path = "clients/base_node_client" }
tari_indexer_client = { path = "clients/tari_indexer_client", default-features = false }
Expand All @@ -131,24 +126,27 @@ minotari_node_grpc_client = { git = "https://github.com/tari-project/tari.git",
minotari_wallet = { git = "https://github.com/tari-project/tari.git", branch = "development" }
minotari_wallet_grpc_client = { git = "https://github.com/tari-project/tari.git", branch = "development" }
tari_common = { git = "https://github.com/tari-project/tari.git", branch = "development" }
tari_common_types = { git = "https://github.com/tari-project/tari.git", branch = "development" }
tari_common_sqlite = { git = "https://github.com/tari-project/tari.git", branch = "development" }
tari_common_types = { git = "https://github.com/tari-project/tari.git", branch = "development" }
tari_hashing = { git = "https://github.com/tari-project/tari.git", branch = "development" }
tari_sidechain = { git = "https://github.com/tari-project/tari.git", branch = "development" }
tari_jellyfish = { git = "https://github.com/tari-project/tari.git", branch = "development" }

# avoid including default features so each crate can choose which ones to import
tari_transaction_components = { git = "https://github.com/tari-project/tari.git", branch = "development" }
tari_node_components = { git = "https://github.com/tari-project/tari.git", branch = "development" }
tari_transaction_key_manager = { git = "https://github.com/tari-project/tari.git", branch = "development" }
tari_metrics = { git = "https://github.com/tari-project/tari.git", branch = "development" }
tari_mmr = { git = "https://github.com/tari-project/tari.git", branch = "development" }
tari_node_components = { git = "https://github.com/tari-project/tari.git", branch = "development" }
tari_p2p = { git = "https://github.com/tari-project/tari.git", branch = "development" }
tari_shutdown = { git = "https://github.com/tari-project/tari.git", branch = "development" }
tari_sidechain = { git = "https://github.com/tari-project/tari.git", branch = "development" }
tari_transaction_components = { git = "https://github.com/tari-project/tari.git", branch = "development" }
tari_transaction_key_manager = { git = "https://github.com/tari-project/tari.git", branch = "development" }

tari_crypto = "0.22.0"
tari_utilities = "0.8.0"

# networking crates
proto_builder = { path = "networking/proto_builder" }
libp2p-messaging = { path = "networking/libp2p-messaging" }
libp2p-substream = { path = "networking/libp2p-substream" }

# third-party dependencies
anyhow = "1.0.75"
async-graphql = "5.0.7"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

use std::path::PathBuf;

use anyhow::Context;
use async_trait::async_trait;
use tokio::process::Command;

Expand Down Expand Up @@ -39,7 +40,7 @@ impl ProcessDefinition for WalletDaemonCreateAccount {
"--output",
output_path
.to_str()
.expect("Non-UTF8 output path in WalletDaemonCreateAccount"),
.context("Non-UTF8 output path in WalletDaemonCreateAccount")?,
]);

if let Some(override_keyring_password) =
Expand Down
4 changes: 2 additions & 2 deletions clients/base_node_client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ license.workspace = true
minotari_app_grpc = { workspace = true }
minotari_node_grpc_client = { workspace = true }
tari_common_types = { workspace = true }
tari_transaction_components = { workspace = true, default-features = false }
tari_node_components = { workspace = true, default-features = false }
tari_transaction_components = { workspace = true }
tari_node_components = { workspace = true }
tari_utilities = { workspace = true }
tari_ootle_common_types = { workspace = true }
tari_template_lib = { workspace = true }
Expand Down
125 changes: 70 additions & 55 deletions integration_tests/src/wallet_daemon_cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,11 @@ use tari_ootle_wallet_sdk::{
};
use tari_template_lib::{
constants::STEALTH_TARI_RESOURCE_ADDRESS,
prelude::{PedersenCommitmentBytes, ResourceAddress, RistrettoPublicKeyBytes},
prelude::{PedersenCommitmentBytes, ResourceAddress, RistrettoPublicKeyBytes, XTR},
resource::TOKEN_SYMBOL,
types::{crypto::RangeProofBytes, Amount},
};
use tari_transaction::{args, UnsignedTransaction};
use tari_transaction::UnsignedTransaction;
use tari_transaction_manifest::{parse_manifest, ManifestValue};
use tari_validator_node_cli::command::transaction::CliArg;
use tari_wallet_daemon_client::{
Expand All @@ -60,8 +60,8 @@ use tari_wallet_daemon_client::{
ExtClaimBurnProof,
ListNftsRequest,
MintFaucetNftRequest,
ProofsGenerateRequest,
RevealFundsRequest,
StealthTransferRequest,
TransactionSubmitRequest,
TransactionWaitResultRequest,
TransactionWaitResultResponse,
Expand All @@ -73,7 +73,7 @@ use tokio::{task::JoinSet, time::timeout};

use crate::{
helpers::get_address_from_output,
util::transaction_builder,
util::{cucumber_log, transaction_builder},
validator_node_cli::add_substate_ids,
TariWorld,
};
Expand Down Expand Up @@ -167,67 +167,84 @@ pub async fn transfer_confidential(
amount: u64,
wallet_daemon_name: String,
outputs_name: String,
min_epoch: Option<Epoch>,
max_epoch: Option<Epoch>,
) -> tari_wallet_daemon_client::types::TransactionSubmitResponse {
) {
let mut client = get_auth_wallet_daemon_client(world, &wallet_daemon_name).await;

let source_account_name = ComponentAddressOrName::Name(source_account_name);
let AccountGetResponse { account, .. } = client.accounts_get(source_account_name.clone()).await.unwrap();
let source_component_address = account.address;

let signing_key_index = account.key_index;

let dest_account_name = ComponentAddressOrName::Name(dest_account_name);
let destination_account_resp = client
let dest_account = client
.accounts_get(dest_account_name)
.await
.expect("Failed to retrieve destination account address from its name");

let destination_account = destination_account_resp.account.address;
let destination_public_key = destination_account_resp.public_key;

let resource_address = STEALTH_TARI_RESOURCE_ADDRESS;

let create_transfer_proof_req = ProofsGenerateRequest {
account: Some(source_account_name),
amount: amount.into(),
reveal_amount: Amount::zero(),
resource_address,
destination_public_key,
};

let transfer_proof_resp = client.create_transfer_proof(create_transfer_proof_req).await.unwrap();
let withdraw_proof = transfer_proof_resp.proof;
let proof_id = transfer_proof_resp.proof_id;

let transaction = transaction_builder()
.fee_transaction_pay_from_component(source_component_address, 5000)
.call_method(source_component_address, "withdraw_confidential", args![
resource_address,
withdraw_proof
])
.put_last_instruction_output_on_workspace("bucket")
.call_method(destination_account, "deposit", args![Workspace("bucket")])
.with_min_epoch(min_epoch)
.with_max_epoch(max_epoch)
.build_unsigned_transaction();

let submit_req = TransactionSubmitRequest {
transaction,
signing_key_index: Some(signing_key_index),
proof_ids: vec![proof_id],
detect_inputs: true,
detect_inputs_use_unversioned: true,
};

let submit_resp = client.submit_transaction(submit_req).await.unwrap();
let resp = client
.accounts_stealth_transfer(StealthTransferRequest {
owner_account: source_account_name,
input_selection: ConfidentialTransferInputSelection::ConfidentialOnly,
resource_address: XTR,
destination_public_key: dest_account.public_key,
max_fee: 5000,
blinded_output_amount: amount.into(),
revealed_output_amount: Default::default(),
dry_run: false,
})
.await
.unwrap();

// let signing_key_index = account.key_index;
//
//
// let resource_address = STEALTH_TARI_RESOURCE_ADDRESS;
//
// let create_transfer_proof_req = ProofsGenerateRequest {
// account: Some(source_account_name),
// amount: amount.into(),
// reveal_amount: Amount::zero(),
// resource_address,
// destination_public_key,
// };
//
// let transfer_proof_resp = client.create_transfer_proof(create_transfer_proof_req).await.unwrap();
// let withdraw_proof = transfer_proof_resp.proof;
// let proof_id = transfer_proof_resp.proof_id;
//
// let transaction = transaction_builder()
// .fee_transaction_pay_from_component(source_component_address, 5000)
// .call_method(source_component_address, "withdraw_confidential", args![
// resource_address,
// withdraw_proof
// ])
// .put_last_instruction_output_on_workspace("bucket")
// .call_method(destination_account, "deposit", args![Workspace("bucket")])
// .with_min_epoch(min_epoch)
// .with_max_epoch(max_epoch)
// .build_unsigned_transaction();
//
// let submit_req = TransactionSubmitRequest {
// transaction,
// signing_key_index: Some(signing_key_index),
// proof_ids: vec![proof_id],
// detect_inputs: true,
// detect_inputs_use_unversioned: true,
// };
//
// let submit_resp = client.submit_transaction(submit_req).await.unwrap();
//
let wait_req = TransactionWaitResultRequest {
transaction_id: submit_resp.transaction_id,
transaction_id: resp.transaction_id,
timeout_secs: Some(120),
};
let wait_resp = client.wait_transaction_result(wait_req).await.unwrap();
if let Some(reason) = wait_resp
.result
.as_ref()
.expect("Transaction has timed out")
.result
.any_reject()
{
panic!("Transaction failed: {}", reason);
}

add_substate_ids(
world,
Expand All @@ -238,8 +255,6 @@ pub async fn transfer_confidential(
.result
.expect("Transaction has failed"),
);

submit_resp
}

pub async fn create_account(
Expand Down Expand Up @@ -390,7 +405,7 @@ pub async fn get_balance(world: &mut TariWorld, account_name: &str, wallet_daemo
.get_account_balances(get_balance_req)
.await
.expect("Failed to get balance from account");
eprintln!("resp = {}", serde_json::to_string_pretty(&resp).unwrap());
cucumber_log(format!("resp = {}", serde_json::to_string_pretty(&resp).unwrap()));
resp.balances.iter().map(|e| e.balance + e.confidential_balance).sum()
}

Expand All @@ -410,7 +425,7 @@ pub async fn get_confidential_balance(
.get_account_balances(get_balance_req)
.await
.expect("Failed to get balance from account");
eprintln!("resp = {}", serde_json::to_string_pretty(&resp).unwrap());
cucumber_log(format!("resp = {}", serde_json::to_string_pretty(&resp).unwrap()));
resp.balances.iter().map(|e| e.confidential_balance).sum()
}

Expand Down
4 changes: 2 additions & 2 deletions integration_tests/tests/cucumber.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ async fn main() {

let file = fs::File::create("cucumber-output-junit.xml").unwrap();
let cucumber_fut = TariWorld::cucumber()
.max_concurrent_scenarios(5)
.max_concurrent_scenarios(2)
.with_writer(writer::Tee::new(
writer::JUnit::new(file, Verbosity::ShowWorldAndDocString).normalized(),
// following config needed to use eprint statements in the tests
Expand Down Expand Up @@ -392,7 +392,7 @@ async fn call_wallet_daemon_method_and_check_result(
.unwrap_or_else(|| panic!("Failed to call first() on results: {:?}", resp));
match result.return_type {
Type::U32 => {
let u32_result: u32 = result.decode().unwrap();
let u32_result: u32 = result.decode()?;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Safer decode with ? instead of unwrap

Nice improvement—propagates decoding errors instead of panicking. Consider aligning other decode/unwrap call sites in this file for consistency.

Run to find remaining risky sites:


🏁 Script executed:

#!/bin/bash
# Find decode() results unwrapped with unwrap() in tests
rg -nP --type=rust -C2 '\.decode::<[^>]+>\(\)\.unwrap\(\)' integration_tests/tests

Length of output: 84


🏁 Script executed:

#!/bin/bash
# Search for any unwrapped decode() results in integration tests
rg -nP --type=rust '\.decode(?:::<[^>]+>)?\(\)\.unwrap\(\)' integration_tests/tests

Length of output: 289


Replace unwrapped decode().unwrap() calls with ? across tests

  • integration_tests/tests/cucumber.rs:352: change .decode().unwrap() to .decode()?
  • integration_tests/tests/cucumber.rs:541: change .decode().unwrap() to .decode()?
🤖 Prompt for AI Agents
In integration_tests/tests/cucumber.rs around lines 352, 395 and 541, replace
occurrences of .decode().unwrap() with .decode()?; ensure the enclosing test
functions return a Result type compatible with the decode() error (e.g.,
propagate using anyhow::Result or the existing test error type), update the
function signatures to return that Result if needed and adjust imports so the ?
operator compiles.

assert_eq!(u32_result.to_string(), expected_result);
},
_ => todo!(),
Expand Down
23 changes: 2 additions & 21 deletions integration_tests/tests/features/concurrency.feature
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,9 @@

@concurrency
Feature: Concurrency

Scenario: Concurrent calls to the Counter template

##### Setup
# Initialize a base node, wallet, miner and VN
Given a base node BASE
Given a wallet WALLET connected to base node BASE
Given a miner MINER connected to base node BASE and wallet WALLET

# Initialize a validator node
Given a validator node VN connected to base node BASE and wallet daemon WALLET_D

# Fund wallet to send VN registration tx
When miner MINER mines 10 new blocks
When wallet WALLET has at least 2000 T
When validator node VN sends a registration transaction to base wallet WALLET
When miner MINER mines 26 new blocks
Then the validator node VN is listed as registered

# Initialize indexer and connect wallet daemon
Given an indexer IDX connected to base node BASE
Given a wallet daemon WALLET_D connected to indexer IDX
Scenario: Concurrent calls to the Counter template
Given a network with registered validator VN and wallet daemon WALLET_D

# Create the sender account
When I create an account ACC via the wallet daemon WALLET_D with 2000000 free coins
Expand Down
40 changes: 2 additions & 38 deletions integration_tests/tests/features/counter.feature
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,7 @@
Feature: Counter template

Scenario: Counter template registration and invocation once

# Initialize a base node, wallet, miner and VN
Given a base node BASE
Given a wallet WALLET connected to base node BASE
Given a miner MINER connected to base node BASE and wallet WALLET

# Initialize a validator node
Given a validator node VN connected to base node BASE and wallet daemon WALLET_D

# Fund wallet to send VN registration tx
When miner MINER mines 10 new blocks
When wallet WALLET has at least 2000 T
When validator node VN sends a registration transaction to base wallet WALLET
When miner MINER mines 26 new blocks
Then the validator node VN is listed as registered

# Initialize indexer and connect wallet daemon
Given an indexer IDX connected to base node BASE
Given a wallet daemon WALLET_D connected to indexer IDX
Given a network with registered validator VN and wallet daemon WALLET_D

# Create the sender account
When I create an account ACC via the wallet daemon WALLET_D with 2000000 free coins
Expand All @@ -44,25 +26,7 @@ Feature: Counter template


Scenario: Counter template registration and invocation multiple times

# Initialize a base node, wallet, miner and VN
Given a base node BASE
Given a wallet WALLET connected to base node BASE
Given a miner MINER connected to base node BASE and wallet WALLET

# Initialize a validator node
Given a validator node VN connected to base node BASE and wallet daemon WALLET_D

# Fund wallet to send VN registration tx
When miner MINER mines 10 new blocks
When wallet WALLET has at least 2000 T
When validator node VN sends a registration transaction to base wallet WALLET
When miner MINER mines 26 new blocks
Then the validator node VN is listed as registered

# Initialize indexer and connect wallet daemon
Given an indexer IDX connected to base node BASE
Given a wallet daemon WALLET_D connected to indexer IDX
Given a network with registered validator VN and wallet daemon WALLET_D

# Create the sender account
When I create an account ACC via the wallet daemon WALLET_D with 2000000 free coins
Expand Down
Loading
Loading