Skip to content

Commit cf4254c

Browse files
test: add ffi cucumber wallet balance test (#7189)
Description --- - Added cucumber test to verify wallet balance with recovery into FFI wallet. - Fixed broken `As a client I want to be able to restore my ffi wallet from seed words` cucumber test. Motivation and Context --- Trying to solve various balance query inconsistencies. How Has This Been Tested? --- Cucumber test: `As a client I want to be able to check my balance from restored wallets` 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 --> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Added the ability to restore FFI wallets from seed words and verify balances in integration tests. - Introduced support for storing and checking wallet balances within the test environment. - Enhanced wallet CLI test steps to support wallet recovery from seed words and view/spend key export/import. - Added detailed logging for transaction errors in the wallet gRPC server. - Extended wallet process and world state with new fields for base node association, peer seeds, balances, and keys. - **Bug Fixes** - Improved type handling when collecting seed words during wallet recovery. - **Tests** - Added critical scenarios to test wallet restoration and balance checking for FFI wallets. - Introduced new test steps for remembering and verifying wallet balances. - Updated test scenarios and steps to explicitly specify one-sided and interactive transaction types for clarity. - Added logging support for cucumber test steps. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: SW van Heerden <swvheerden@gmail.com>
1 parent 3de58ec commit cf4254c

23 files changed

+818
-324
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

applications/minotari_console_wallet/src/grpc/wallet_grpc_server.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -830,7 +830,10 @@ impl wallet_server::Wallet for WalletGrpcServer {
830830
.get_any_transaction(tx_id)
831831
.await
832832
.map_err(|e| Status::internal(format!("{:?}", e)))?
833-
.ok_or_else(|| Status::not_found("Transaction not found".to_string()))?;
833+
.ok_or_else(|| {
834+
error!(target: LOG_TARGET, "Transaction {} not found", tx_id);
835+
Status::not_found(format!("Transaction {} not found", tx_id))
836+
})?;
834837
let final_tx = convert_wallet_transaction_into_transaction_info(
835838
wallet_tx,
836839
&wallet_address,

applications/minotari_console_wallet/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ pub use cli::{
4040
CoinSplitArgs,
4141
DiscoverPeerArgs,
4242
ExportUtxosArgs,
43+
ExportViewKeyAndSpendKeyArgs,
4344
MakeItRainArgs,
4445
SendMinotariArgs,
4546
SetBaseNodeArgs,

integration_tests/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ tari_common_sqlite = { path = "../common_sqlite" }
1717
tari_common_types = { path = "../base_layer/common_types" }
1818
tari_comms = { path = "../comms/core" }
1919
tari_comms_dht = { path = "../comms/dht" }
20+
tari_key_manager = { path = "../base_layer/key_manager" }
2021
minotari_console_wallet = { path = "../applications/minotari_console_wallet", features = ["grpc"] }
2122
tari_core = { path = "../base_layer/core" }
2223
minotari_merge_mining_proxy = { path = "../applications/minotari_merge_mining_proxy" }

integration_tests/src/ffi/ffi_import.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,12 @@ extern "C" {
201201
) -> *mut TariSeedWords;
202202
pub fn seed_words_get_length(seed_words: *const TariSeedWords, error_out: *mut c_int) -> c_uint;
203203
pub fn seed_words_get_at(seed_words: *mut TariSeedWords, position: c_uint, error_out: *mut c_int) -> *mut c_char;
204-
pub fn seed_words_push_word(seed_words: *mut TariSeedWords, word: *const c_char, error_out: *mut c_int) -> c_uchar;
204+
pub fn seed_words_push_word(
205+
seed_words: *mut TariSeedWords,
206+
word: *const c_char,
207+
passphrase: *const c_char,
208+
error_out: *mut c_int,
209+
) -> c_uchar;
205210
pub fn seed_words_destroy(seed_words: *mut TariSeedWords);
206211
pub fn contact_create(
207212
alias: *const c_char,
@@ -412,7 +417,7 @@ extern "C" {
412417
context: *mut c_void,
413418
config: *mut TariCommsConfig,
414419
log_path: *const c_char,
415-
log_level: c_int,
420+
log_verbosity: c_int,
416421
num_rolling_log_files: c_uint,
417422
size_per_log_file_bytes: c_uint,
418423
passphrase: *const c_char,
@@ -422,6 +427,7 @@ extern "C" {
422427
dns_seeds_str: *const c_char,
423428
dns_seed_name_servers_str: *const c_char,
424429
use_dns_sec: bool,
430+
425431
callback_received_transaction: unsafe extern "C" fn(context: *mut c_void, *mut TariPendingInboundTransaction),
426432
callback_received_transaction_reply: unsafe extern "C" fn(context: *mut c_void, *mut TariCompletedTransaction),
427433
callback_received_finalized_transaction: unsafe extern "C" fn(
@@ -461,7 +467,7 @@ extern "C" {
461467
callback_saf_messages_received: unsafe extern "C" fn(context: *mut c_void),
462468
callback_connectivity_status: unsafe extern "C" fn(context: *mut c_void, u64),
463469
callback_wallet_scanned_height: unsafe extern "C" fn(context: *mut c_void, u64),
464-
callback_base_node_state_updated: unsafe extern "C" fn(context: *mut c_void, *mut TariBaseNodeState),
470+
callback_base_node_state: unsafe extern "C" fn(context: *mut c_void, *mut TariBaseNodeState),
465471
recovery_in_progress: *mut bool,
466472
error_out: *mut c_int,
467473
) -> *mut TariWallet;

integration_tests/src/ffi/seed_words.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,15 @@
2020
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
2121
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2222

23-
use std::{ffi::CString, ptr::null_mut};
23+
use std::{ffi::CString, ptr, ptr::null_mut};
2424

25-
use libc::c_void;
25+
use libc::{c_char, c_void};
2626

2727
use super::{ffi_import, FFIString};
28+
use crate::ffi::ffi_import::TariSeedWords;
2829

2930
pub struct SeedWords {
30-
ptr: *mut c_void,
31+
ptr: *mut TariSeedWords,
3132
}
3233

3334
impl Drop for SeedWords {
@@ -38,7 +39,7 @@ impl Drop for SeedWords {
3839
}
3940

4041
impl SeedWords {
41-
pub fn create() -> Self {
42+
pub fn create_empty_seed_words() -> Self {
4243
let ptr;
4344
unsafe {
4445
ptr = ffi_import::seed_words_create();
@@ -96,7 +97,9 @@ impl SeedWords {
9697
let mut error = 0;
9798
let result;
9899
unsafe {
99-
result = ffi_import::seed_words_push_word(self.ptr, CString::new(word).unwrap().into_raw(), &mut error);
100+
let w = CString::new(word).unwrap();
101+
let w_str: *const c_char = CString::into_raw(w) as *const c_char;
102+
result = ffi_import::seed_words_push_word(self.ptr, w_str, ptr::null(), &mut error);
100103
if error > 0 {
101104
println!("seed_words_push_word error {}", error);
102105
panic!("seed_words_push_word error");

integration_tests/src/wallet_ffi.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ pub fn create_contact(alias: String, address: String) -> ffi::Contact {
226226
}
227227

228228
pub fn create_seed_words(words: Vec<&str>) -> ffi::SeedWords {
229-
let seed_words = ffi::SeedWords::create();
229+
let seed_words = ffi::SeedWords::create_empty_seed_words();
230230
for word in words {
231231
seed_words.push_word(word.to_string());
232232
}

integration_tests/src/wallet_process.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ pub struct WalletProcess {
4949
pub name: String,
5050
pub port: u64,
5151
pub temp_dir_path: PathBuf,
52+
pub base_node_name: Option<String>,
53+
pub peer_seeds: Vec<String>,
5254
}
5355

5456
impl Drop for WalletProcess {
@@ -99,7 +101,7 @@ pub async fn spawn_wallet(
99101
.base_node_monitor_max_refresh_interval = Duration::from_secs(5);
100102
};
101103

102-
let base_node = base_node_name.map(|name| {
104+
let base_node = base_node_name.clone().map(|name| {
103105
let pubkey = world.base_nodes.get(&name).unwrap().identity.public_key().clone();
104106
let port = world.base_nodes.get(&name).unwrap().port;
105107
let set_base_node_request = SetBaseNodeRequest {
@@ -192,7 +194,9 @@ pub async fn spawn_wallet(
192194
port,
193195
grpc_port,
194196
temp_dir_path: temp_dir,
197+
base_node_name,
195198
kill_signal: shutdown,
199+
peer_seeds,
196200
});
197201

198202
tokio::time::sleep(Duration::from_secs(5)).await;

integration_tests/src/world.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ use std::{
2828

2929
use cucumber::gherkin::{Feature, Scenario};
3030
use indexmap::IndexMap;
31+
use minotari_app_grpc::tari_rpc::GetBalanceResponse;
3132
use rand::rngs::OsRng;
3233
use serde_json::Value;
3334
use tari_common::configuration::Network;
@@ -86,6 +87,8 @@ pub struct TariWorld {
8687
pub miners: IndexMap<String, MinerProcess>,
8788
pub ffi_wallets: IndexMap<String, WalletFFI>,
8889
pub wallets: IndexMap<String, WalletProcess>,
90+
pub balance: IndexMap<String, GetBalanceResponse>,
91+
pub view_and_spend_keys: IndexMap<String, PathBuf>,
8992
pub merge_mining_proxies: IndexMap<String, MergeMiningProxyProcess>,
9093
pub transactions: IndexMap<String, Transaction>,
9194
pub wallet_addresses: IndexMap<String, String>, // values are strings representing tari addresses
@@ -128,6 +131,8 @@ impl Default for TariWorld {
128131
miners: Default::default(),
129132
ffi_wallets: Default::default(),
130133
wallets: Default::default(),
134+
balance: Default::default(),
135+
view_and_spend_keys: Default::default(),
131136
merge_mining_proxies: Default::default(),
132137
transactions: Default::default(),
133138
wallet_addresses: Default::default(),

integration_tests/tests/features/BlockTemplate.feature

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -85,18 +85,18 @@ Scenario: Verify UTXO and kernel MMR size in header
8585
When I wait for wallet WALLET_11 to have at least 18462050000 uT
8686
When I wait for wallet WALLET_12 to have at least 18462050000 uT
8787

88-
Then I send 18462000000 uT from wallet WALLET_01 to wallet WALLET_DEFAULT at fee 1
89-
Then I send 18462000000 uT from wallet WALLET_02 to wallet WALLET_DEFAULT at fee 1
90-
Then I send 18462000000 uT from wallet WALLET_03 to wallet WALLET_DEFAULT at fee 1
91-
Then I send 18462000000 uT from wallet WALLET_04 to wallet WALLET_DEFAULT at fee 1
92-
Then I send 18462000000 uT from wallet WALLET_05 to wallet WALLET_DEFAULT at fee 1
93-
Then I send 18462000000 uT from wallet WALLET_06 to wallet WALLET_DEFAULT at fee 1
94-
Then I send 18462000000 uT from wallet WALLET_07 to wallet WALLET_DEFAULT at fee 1
95-
Then I send 18462000000 uT from wallet WALLET_08 to wallet WALLET_DEFAULT at fee 1
96-
Then I send 18462000000 uT from wallet WALLET_09 to wallet WALLET_DEFAULT at fee 1
97-
Then I send 18462000000 uT from wallet WALLET_10 to wallet WALLET_DEFAULT at fee 1
98-
Then I send 18462000000 uT from wallet WALLET_11 to wallet WALLET_DEFAULT at fee 1
99-
Then I send 18462000000 uT from wallet WALLET_12 to wallet WALLET_DEFAULT at fee 1
88+
Then I send a one-sided transaction of 18462000000 uT from wallet WALLET_01 to wallet WALLET_DEFAULT at fee 1
89+
Then I send a one-sided transaction of 18462000000 uT from wallet WALLET_02 to wallet WALLET_DEFAULT at fee 1
90+
Then I send a one-sided transaction of 18462000000 uT from wallet WALLET_03 to wallet WALLET_DEFAULT at fee 1
91+
Then I send a one-sided transaction of 18462000000 uT from wallet WALLET_04 to wallet WALLET_DEFAULT at fee 1
92+
Then I send a one-sided transaction of 18462000000 uT from wallet WALLET_05 to wallet WALLET_DEFAULT at fee 1
93+
Then I send a one-sided transaction of 18462000000 uT from wallet WALLET_06 to wallet WALLET_DEFAULT at fee 1
94+
Then I send a one-sided transaction of 18462000000 uT from wallet WALLET_07 to wallet WALLET_DEFAULT at fee 1
95+
Then I send a one-sided transaction of 18462000000 uT from wallet WALLET_08 to wallet WALLET_DEFAULT at fee 1
96+
Then I send a one-sided transaction of 18462000000 uT from wallet WALLET_09 to wallet WALLET_DEFAULT at fee 1
97+
Then I send a one-sided transaction of 18462000000 uT from wallet WALLET_10 to wallet WALLET_DEFAULT at fee 1
98+
Then I send a one-sided transaction of 18462000000 uT from wallet WALLET_11 to wallet WALLET_DEFAULT at fee 1
99+
Then I send a one-sided transaction of 18462000000 uT from wallet WALLET_12 to wallet WALLET_DEFAULT at fee 1
100100

101101
# Mempool now has 12 transactions, each with 1000 coinbases as inputs, so we can create a big block
102102
Then I generate a block BLOCK_18 with 1000 coinbases from node NODE_01 for wallet WALLET_DEFAULT

0 commit comments

Comments
 (0)