From 2f2b1391284f4a6ffcacb7a6d5e880f6c51cc8a3 Mon Sep 17 00:00:00 2001 From: Hansie Odendaal <39146854+hansieodendaal@users.noreply.github.com> Date: Thu, 7 Mar 2024 11:22:36 +0200 Subject: [PATCH] feat: expose extra_data field to wallet ffi (#6191) Description --- Added `extra_data` to wallet FFI for method `wallet_get_utxos` Motivation and Context --- The `extra_data` field is needed for display purposes in the client. How Has This Been Tested? --- Expanded test case `fn test_wallet_get_utxos()` What process can a PR reviewer use to test or verify this change? --- Review code and the test case Breaking Changes --- - [x] None - [ ] Requires data directory on base node to be deleted - [ ] Requires hard fork - [ ] Other - Please specify Co-authored-by: SW van Heerden --- .../core/src/transactions/test_helpers.rs | 8 ++- .../transaction_components/output_features.rs | 2 +- .../transaction_protocol/sender.rs | 18 +++--- .../transaction_initializer.rs | 13 ++-- base_layer/wallet_ffi/src/lib.rs | 62 ++++++++++++++----- base_layer/wallet_ffi/wallet.h | 3 + 6 files changed, 72 insertions(+), 34 deletions(-) diff --git a/base_layer/core/src/transactions/test_helpers.rs b/base_layer/core/src/transactions/test_helpers.rs index 1716225a5f..586f6c7e3b 100644 --- a/base_layer/core/src/transactions/test_helpers.rs +++ b/base_layer/core/src/transactions/test_helpers.rs @@ -72,6 +72,7 @@ pub async fn create_test_input< amount: MicroMinotari, maturity: u64, key_manager: &TransactionKeyManagerWrapper>, + coinbase_extra: Vec, ) -> WalletOutput { let params = TestParams::new(key_manager).await; params @@ -80,6 +81,7 @@ pub async fn create_test_input< value: amount, features: OutputFeatures { maturity, + coinbase_extra, ..Default::default() }, ..Default::default() @@ -354,12 +356,14 @@ pub async fn create_coinbase_wallet_output( .unwrap() } -pub async fn create_wallet_output_with_data( +pub async fn create_wallet_output_with_data< + TKeyManagerDbConnection: PooledDbConnection + Clone + 'static, +>( script: TariScript, output_features: OutputFeatures, test_params: &TestParams, value: MicroMinotari, - key_manager: &MemoryDbKeyManager, + key_manager: &TransactionKeyManagerWrapper>, ) -> Result { test_params .create_output( diff --git a/base_layer/core/src/transactions/transaction_components/output_features.rs b/base_layer/core/src/transactions/transaction_components/output_features.rs index 8b685a6b7f..0db451450b 100644 --- a/base_layer/core/src/transactions/transaction_components/output_features.rs +++ b/base_layer/core/src/transactions/transaction_components/output_features.rs @@ -59,7 +59,7 @@ pub struct OutputFeatures { /// transaction. This is enforced in [AggregatedBody::check_output_features]. /// /// For coinbase outputs, the maximum length of this field is determined by the consensus constant, - /// `coinbase_output_features_metadata_max_length`. + /// `coinbase_output_features_extra_max_length`. pub coinbase_extra: Vec, /// Features that are specific to a side chain pub sidechain_feature: Option, diff --git a/base_layer/core/src/transactions/transaction_protocol/sender.rs b/base_layer/core/src/transactions/transaction_protocol/sender.rs index 776fe40e28..2e6ae88294 100644 --- a/base_layer/core/src/transactions/transaction_protocol/sender.rs +++ b/base_layer/core/src/transactions/transaction_protocol/sender.rs @@ -1043,7 +1043,7 @@ mod test { let key_manager = create_memory_db_key_manager(); let p1 = TestParams::new(&key_manager).await; let p2 = TestParams::new(&key_manager).await; - let input = create_test_input(MicroMinotari(1200), 0, &key_manager).await; + let input = create_test_input(MicroMinotari(1200), 0, &key_manager, vec![]).await; let mut builder = SenderTransactionProtocol::builder(create_consensus_constants(0), key_manager.clone()); let script = TariScript::default(); let output_features = OutputFeatures::default(); @@ -1106,7 +1106,7 @@ mod test { let a_change_key = TestParams::new(&key_manager).await; // Bob's parameters let bob_key = TestParams::new(&key_manager).await; - let input = create_test_input(MicroMinotari(1200), 0, &key_manager).await; + let input = create_test_input(MicroMinotari(1200), 0, &key_manager, vec![]).await; let utxo = input.to_transaction_input(&key_manager).await.unwrap(); let script = script!(Nop); let consensus_constants = create_consensus_constants(0); @@ -1213,7 +1213,7 @@ mod test { let alice_key = TestParams::new(&key_manager).await; // Bob's parameters let bob_key = TestParams::new(&key_manager).await; - let input = create_test_input(MicroMinotari(25000), 0, &key_manager).await; + let input = create_test_input(MicroMinotari(25000), 0, &key_manager, vec![]).await; let consensus_constants = create_consensus_constants(0); let mut builder = SenderTransactionProtocol::builder(consensus_constants.clone(), key_manager.clone()); let script = script!(Nop); @@ -1324,9 +1324,9 @@ mod test { let factories = CryptoFactories::default(); // Bob's parameters let bob_key = TestParams::new(&key_manager).await; - let input = create_test_input(MicroMinotari(10000), 0, &key_manager).await; - let input2 = create_test_input(MicroMinotari(2000), 0, &key_manager).await; - let input3 = create_test_input(MicroMinotari(15000), 0, &key_manager).await; + let input = create_test_input(MicroMinotari(10000), 0, &key_manager, vec![]).await; + let input2 = create_test_input(MicroMinotari(2000), 0, &key_manager, vec![]).await; + let input3 = create_test_input(MicroMinotari(15000), 0, &key_manager, vec![]).await; let consensus_constants = create_consensus_constants(0); let mut builder = SenderTransactionProtocol::builder(consensus_constants.clone(), key_manager.clone()); let script = script!(Nop); @@ -1431,7 +1431,7 @@ mod test { // Alice's parameters let key_manager = create_memory_db_key_manager(); let (utxo_amount, fee_per_gram, amount) = (MicroMinotari(2500), MicroMinotari(10), MicroMinotari(500)); - let input = create_test_input(utxo_amount, 0, &key_manager).await; + let input = create_test_input(utxo_amount, 0, &key_manager, vec![]).await; let script = script!(Nop); let mut builder = SenderTransactionProtocol::builder(create_consensus_constants(0), key_manager.clone()); let change = TestParams::new(&key_manager).await; @@ -1469,7 +1469,7 @@ mod test { // Alice's parameters let key_manager = create_memory_db_key_manager(); let (utxo_amount, fee_per_gram, amount) = (MicroMinotari(2500), MicroMinotari(10), MicroMinotari(500)); - let input = create_test_input(utxo_amount, 0, &key_manager).await; + let input = create_test_input(utxo_amount, 0, &key_manager, vec![]).await; let script = script!(Nop); let mut builder = SenderTransactionProtocol::builder(create_consensus_constants(0), key_manager.clone()); let change = TestParams::new(&key_manager).await; @@ -1511,7 +1511,7 @@ mod test { // Bob's parameters let bob_test_params = TestParams::new(&key_manager_bob).await; let alice_value = MicroMinotari(25000); - let input = create_test_input(alice_value, 0, &key_manager_alice).await; + let input = create_test_input(alice_value, 0, &key_manager_alice, vec![]).await; let script = script!(Nop); let consensus_constants = create_consensus_constants(0); diff --git a/base_layer/core/src/transactions/transaction_protocol/transaction_initializer.rs b/base_layer/core/src/transactions/transaction_protocol/transaction_initializer.rs index 4bdb2e36df..400d040ddc 100644 --- a/base_layer/core/src/transactions/transaction_protocol/transaction_initializer.rs +++ b/base_layer/core/src/transactions/transaction_protocol/transaction_initializer.rs @@ -691,7 +691,7 @@ mod test { // Create some inputs let key_manager = create_memory_db_key_manager(); let p = TestParams::new(&key_manager).await; - let input = create_test_input(MicroMinotari(5000), 0, &key_manager).await; + let input = create_test_input(MicroMinotari(5000), 0, &key_manager, vec![]).await; let constants = create_consensus_constants(0); let expected_fee = Fee::from(*constants.transaction_weight_params()).calculate( MicroMinotari(4), @@ -755,6 +755,7 @@ mod test { 2000 * uT + tx_fee + fee_for_change_output - 1 * uT, 0, &key_manager, + vec![], ) .await; let output = p @@ -815,7 +816,7 @@ mod test { .await .unwrap() .with_fee_per_gram(MicroMinotari(2)); - let input_base = create_test_input(MicroMinotari(50), 0, &key_manager).await; + let input_base = create_test_input(MicroMinotari(50), 0, &key_manager, vec![]).await; for _ in 0..=MAX_TRANSACTION_INPUTS { builder.with_input(input_base.clone()).await.unwrap(); } @@ -836,7 +837,7 @@ mod test { p.get_size_for_default_features_and_scripts(1) .expect("Failed to borsh serialized size"), ); - let input = create_test_input(500 * uT + tx_fee, 0, &key_manager).await; + let input = create_test_input(500 * uT + tx_fee, 0, &key_manager, vec![]).await; let script = script!(Nop); // Start the builder let constants = create_consensus_constants(0); @@ -873,7 +874,7 @@ mod test { // Create some inputs let key_manager = create_memory_db_key_manager(); let p = TestParams::new(&key_manager).await; - let input = create_test_input(MicroMinotari(400), 0, &key_manager).await; + let input = create_test_input(MicroMinotari(400), 0, &key_manager, vec![]).await; let script = script!(Nop); let output = create_wallet_output_with_data( script.clone(), @@ -925,8 +926,8 @@ mod test { // Create some inputs let key_manager = create_memory_db_key_manager(); let p = TestParams::new(&key_manager).await; - let input1 = create_test_input(MicroMinotari(2000), 0, &key_manager).await; - let input2 = create_test_input(MicroMinotari(3000), 0, &key_manager).await; + let input1 = create_test_input(MicroMinotari(2000), 0, &key_manager, vec![]).await; + let input2 = create_test_input(MicroMinotari(3000), 0, &key_manager, vec![]).await; let fee_per_gram = MicroMinotari(6); let script = script!(Nop); diff --git a/base_layer/wallet_ffi/src/lib.rs b/base_layer/wallet_ffi/src/lib.rs index df57762c7b..9a7ee76877 100644 --- a/base_layer/wallet_ffi/src/lib.rs +++ b/base_layer/wallet_ffi/src/lib.rs @@ -293,6 +293,7 @@ pub struct TariUtxo { pub mined_timestamp: u64, pub lock_height: u64, pub status: u8, + pub coinbase_extra: Vec, } impl From for TariUtxo { @@ -321,6 +322,7 @@ impl From for TariUtxo { OutputStatus::SpentMinedUnconfirmed => 9, OutputStatus::NotStored => 10, }, + coinbase_extra: x.wallet_output.features.coinbase_extra, } } } @@ -10073,7 +10075,6 @@ mod test { #[allow(clippy::too_many_lines)] fn test_wallet_get_utxos() { unsafe { - let key_manager = create_memory_db_key_manager(); let mut error = 0; let error_ptr = &mut error as *mut c_int; let mut recovery_in_progress = true; @@ -10136,14 +10137,20 @@ mod test { recovery_in_progress_ptr, error_ptr, ); + let alice_wallet_runtime = &(*alice_wallet).runtime; + let key_manager = &(*alice_wallet).wallet.key_manager_service; assert_eq!(error, 0); - for i in 0..10 { - let uout = (*alice_wallet) - .runtime - .block_on(create_test_input((1000 * i).into(), 0, &key_manager)); - (*alice_wallet) - .runtime + let mut test_outputs = Vec::with_capacity(10); + for i in 0..10u8 { + let uout = alice_wallet_runtime.block_on(create_test_input( + (1000u64 * u64::from(i)).into(), + 0, + key_manager, + vec![i, i + 1, i + 2, i + 3, i + 4], + )); + test_outputs.push(uout.clone()); + alice_wallet_runtime .block_on((*alice_wallet).wallet.output_manager_service.add_output(uout, None)) .unwrap(); } @@ -10158,7 +10165,7 @@ mod test { 3000, error_ptr, ); - let utxos: &[TariUtxo] = slice::from_raw_parts_mut((*outputs).ptr as *mut TariUtxo, (*outputs).len); + let utxos: &[TariUtxo] = slice::from_raw_parts((*outputs).ptr as *mut TariUtxo, (*outputs).len); assert_eq!(error, 0); assert_eq!((*outputs).len, 6); assert_eq!(utxos.len(), 6); @@ -10169,6 +10176,22 @@ mod test { .fold((true, utxos[0].value), |acc, x| { (acc.0 && x.value > acc.1, x.value) }) .0 ); + for utxo in utxos { + let output = test_outputs + .iter() + .find(|val| { + alice_wallet_runtime + .block_on(val.commitment(key_manager)) + .unwrap() + .to_hex() == + CStr::from_ptr(utxo.commitment).to_str().unwrap() + }) + .unwrap(); + assert_eq!(output.value.as_u64(), utxo.value); + assert_eq!(output.features.maturity, utxo.lock_height); + assert_eq!(output.features.coinbase_extra, utxo.coinbase_extra); + } + println!(); destroy_tari_vector(outputs); // descending order @@ -10181,7 +10204,7 @@ mod test { 3000, error_ptr, ); - let utxos: &[TariUtxo] = slice::from_raw_parts_mut((*outputs).ptr as *mut TariUtxo, (*outputs).len); + let utxos: &[TariUtxo] = slice::from_raw_parts((*outputs).ptr as *mut TariUtxo, (*outputs).len); assert_eq!(error, 0); assert_eq!((*outputs).len, 6); assert_eq!(utxos.len(), 6); @@ -10294,6 +10317,7 @@ mod test { (1000 * i).into(), 0, &(*alice_wallet).wallet.key_manager_service, + vec![], )); (*alice_wallet) .runtime @@ -10430,6 +10454,7 @@ mod test { (15000 * i).into(), 0, &(*alice_wallet).wallet.key_manager_service, + vec![], )); (*alice_wallet) .runtime @@ -10645,6 +10670,7 @@ mod test { (15000 * i).into(), 0, &(*alice_wallet).wallet.key_manager_service, + vec![], )); (*alice_wallet) .runtime @@ -10865,15 +10891,18 @@ mod test { ); assert_eq!(error, 0); - let key_manager = create_memory_db_key_manager(); + let key_manager = &(*alice_wallet).wallet.key_manager_service; for i in 1..=5 { (*alice_wallet) .runtime .block_on( (*alice_wallet).wallet.output_manager_service.add_output( - (*alice_wallet) - .runtime - .block_on(create_test_input((15000 * i).into(), 0, &key_manager)), + (*alice_wallet).runtime.block_on(create_test_input( + (15000 * i).into(), + 0, + key_manager, + vec![], + )), None, ), ) @@ -11118,6 +11147,8 @@ mod test { error_ptr, ); assert_eq!(error, 0); + let key_manager = &(*wallet_ptr).wallet.key_manager_service; + let node_identity = NodeIdentity::random(&mut OsRng, get_next_memory_address(), PeerFeatures::COMMUNICATION_NODE); let base_node_peer_public_key_ptr = Box::into_raw(Box::new(node_identity.public_key().clone())); @@ -11132,14 +11163,13 @@ mod test { ); // Test the consistent features case - let key_manager = create_memory_db_key_manager(); let utxo_1 = runtime .block_on(create_wallet_output_with_data( script!(Nop), OutputFeatures::default(), - &runtime.block_on(TestParams::new(&key_manager)), + &runtime.block_on(TestParams::new(key_manager)), MicroMinotari(1234u64), - &key_manager, + key_manager, )) .unwrap(); let amount = utxo_1.value.as_u64(); diff --git a/base_layer/wallet_ffi/wallet.h b/base_layer/wallet_ffi/wallet.h index e3ac32b65b..4588864b98 100644 --- a/base_layer/wallet_ffi/wallet.h +++ b/base_layer/wallet_ffi/wallet.h @@ -196,6 +196,8 @@ struct TransportConfig; */ struct UnblindedOutput; +struct Vec_u8; + /** * -------------------------------- Vector ------------------------------------------------ /// */ @@ -347,6 +349,7 @@ struct TariUtxo { uint64_t mined_timestamp; uint64_t lock_height; uint8_t status; + struct Vec_u8 coinbase_extra; }; #ifdef __cplusplus