Skip to content

Commit

Permalink
feat: added FFI function wallet_get_network_and_version #5252 (#5263)
Browse files Browse the repository at this point in the history
Description
---
- Network and client APP_VERSION_NUMBER is now stored when wallet is
initialized.
- Added FFI function `wallet_get_network_and_version` that returns the
`network` and `version` of the client that has last accessed the wallet
database.

Motivation and Context
---
For debugging purposes on the client (e.g. Mobile)

How Has This Been Tested?
---
manually

---------

Co-authored-by: SW van Heerden <[email protected]>
Co-authored-by: stringhandler <[email protected]>
  • Loading branch information
3 people authored Mar 24, 2023
1 parent 1bec437 commit 4b09b59
Show file tree
Hide file tree
Showing 10 changed files with 282 additions and 5 deletions.
3 changes: 3 additions & 0 deletions base_layer/wallet/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ itertools = "0.10.3"
chacha20poly1305 = "0.10.1"
zeroize = "1"

[build-dependencies]
tari_common = { path = "../../common", features = ["build", "static-application-info"] }

[dev-dependencies]
tari_p2p = { path = "../p2p", features = ["test-mocks"] }
tari_comms_dht = { path = "../../comms/dht", features = ["test-mocks"] }
Expand Down
10 changes: 10 additions & 0 deletions base_layer/wallet/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Copyright 2022. The Tari Project
// SPDX-License-Identifier: BSD-3-Clause

use tari_common::build::StaticApplicationInfo;

fn main() {
// generate version info
let gen = StaticApplicationInfo::initialize().unwrap();
gen.write_consts_to_outdir("consts.rs").unwrap();
}
5 changes: 5 additions & 0 deletions base_layer/wallet/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ use crate::{
transaction_service::storage::sqlite_db::TransactionServiceSqliteDatabase,
};

mod consts {
// Import the auto-generated const values from the Manifest and Git
include!(concat!(env!("OUT_DIR"), "/consts.rs"));
}

pub type WalletSqlite = Wallet<
WalletSqliteDatabase,
TransactionServiceSqliteDatabase,
Expand Down
17 changes: 17 additions & 0 deletions base_layer/wallet/src/storage/database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ pub enum DbKey {
SecondaryKeyVersion, // the parameter version for the secondary derivation key
SecondaryKeyHash, // a hash commitment to the secondary derivation key
WalletBirthday,
LastAccessedNetwork,
LastAccessedVersion,
}

impl DbKey {
Expand All @@ -94,6 +96,8 @@ impl DbKey {
DbKey::SecondaryKeyHash => "SecondaryKeyHash".to_string(),
DbKey::WalletBirthday => "WalletBirthday".to_string(),
DbKey::CommsIdentitySignature => "CommsIdentitySignature".to_string(),
DbKey::LastAccessedNetwork => "LastAccessedNetwork".to_string(),
DbKey::LastAccessedVersion => "LastAccessedVersion".to_string(),
}
}
}
Expand All @@ -112,6 +116,8 @@ pub enum DbValue {
SecondaryKeyVersion(String),
SecondaryKeyHash(String),
WalletBirthday(String),
LastAccessedNetwork(String),
LastAccessedVersion(String),
}

#[derive(Clone)]
Expand All @@ -123,6 +129,7 @@ pub enum DbKeyValuePair {
CommsAddress(Multiaddr),
CommsFeatures(PeerFeatures),
CommsIdentitySignature(Box<IdentitySignature>),
NetworkAndVersion((String, String)),
}

pub enum WriteOperation {
Expand Down Expand Up @@ -255,6 +262,14 @@ where T: WalletBackend + 'static
Ok(())
}

pub fn set_last_network_and_version(&self, network: String, version: String) -> Result<(), WalletStorageError> {
self.db
.write(WriteOperation::Insert(DbKeyValuePair::NetworkAndVersion((
network, version,
))))?;
Ok(())
}

pub fn get_client_key_value(&self, key: String) -> Result<Option<String>, WalletStorageError> {
let c = match self.db.fetch(&DbKey::ClientKey(key.clone())) {
Ok(None) => Ok(None),
Expand Down Expand Up @@ -354,6 +369,8 @@ impl Display for DbValue {
DbValue::SecondaryKeyHash(h) => f.write_str(&format!("SecondaryKeyHash: {}", h)),
DbValue::WalletBirthday(b) => f.write_str(&format!("WalletBirthday: {}", b)),
DbValue::CommsIdentitySignature(_) => f.write_str("CommsIdentitySignature"),
DbValue::LastAccessedNetwork(network) => f.write_str(&format!("LastAccessedNetwork: {}", network)),
DbValue::LastAccessedVersion(version) => f.write_str(&format!("LastAccessedVersion: {}", version)),
}
}
}
Expand Down
13 changes: 12 additions & 1 deletion base_layer/wallet/src/storage/sqlite_db/wallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,14 @@ impl WalletSqliteDatabase {
WalletSettingSql::new(DbKey::CommsIdentitySignature, identity_sig.to_bytes().to_hex())
.set(&mut conn)?;
},
DbKeyValuePair::NetworkAndVersion((network, version)) => {
kvp_text = "NetworkAndVersion";

WalletSettingSql::new(DbKey::LastAccessedNetwork, network).set(&mut conn)?;
WalletSettingSql::new(DbKey::LastAccessedVersion, version).set(&mut conn)?;
},
}

if start.elapsed().as_millis() > 0 {
trace!(
target: LOG_TARGET,
Expand Down Expand Up @@ -452,7 +459,9 @@ impl WalletSqliteDatabase {
DbKey::SecondaryKeySalt |
DbKey::SecondaryKeyHash |
DbKey::WalletBirthday |
DbKey::CommsIdentitySignature => {
DbKey::CommsIdentitySignature |
DbKey::LastAccessedNetwork |
DbKey::LastAccessedVersion => {
return Err(WalletStorageError::OperationNotSupported);
},
};
Expand Down Expand Up @@ -499,6 +508,8 @@ impl WalletBackend for WalletSqliteDatabase {
DbKey::SecondaryKeySalt => WalletSettingSql::get(key, &mut conn)?.map(DbValue::SecondaryKeySalt),
DbKey::SecondaryKeyHash => WalletSettingSql::get(key, &mut conn)?.map(DbValue::SecondaryKeyHash),
DbKey::WalletBirthday => WalletSettingSql::get(key, &mut conn)?.map(DbValue::WalletBirthday),
DbKey::LastAccessedNetwork => WalletSettingSql::get(key, &mut conn)?.map(DbValue::LastAccessedNetwork),
DbKey::LastAccessedVersion => WalletSettingSql::get(key, &mut conn)?.map(DbValue::LastAccessedVersion),
DbKey::CommsIdentitySignature => WalletSettingSql::get(key, &mut conn)?
.and_then(|s| from_hex(&s).ok())
.and_then(|bytes| IdentitySignature::from_bytes(&bytes).ok())
Expand Down
31 changes: 29 additions & 2 deletions base_layer/wallet/src/storage/sqlite_utilities/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

use std::{fs::File, path::Path, time::Duration};
use std::{fs::File, ops::DerefMut, path::Path, time::Duration};

use diesel_migrations::{EmbeddedMigrations, MigrationHarness};
use fs2::FileExt;
Expand All @@ -34,7 +34,10 @@ use crate::{
error::WalletStorageError,
key_manager_service::storage::sqlite_db::KeyManagerSqliteDatabase,
output_manager_service::storage::sqlite_db::OutputManagerSqliteDatabase,
storage::sqlite_db::wallet::WalletSqliteDatabase,
storage::{
database::DbKey,
sqlite_db::wallet::{WalletSettingSql, WalletSqliteDatabase},
},
transaction_service::storage::sqlite_db::TransactionServiceSqliteDatabase,
};

Expand Down Expand Up @@ -142,3 +145,27 @@ pub fn initialize_sqlite_database_backends<P: AsRef<Path>>(
key_manager_backend,
))
}

pub fn get_last_version<P: AsRef<Path>>(db_path: P) -> Result<Option<String>, WalletStorageError> {
let path_str = db_path
.as_ref()
.to_str()
.ok_or(WalletStorageError::InvalidUnicodePath)?;

let mut pool = SqliteConnectionPool::new(String::from(path_str), 1, true, true, Duration::from_secs(60));
pool.create_pool()?;

WalletSettingSql::get(&DbKey::LastAccessedVersion, pool.get_pooled_connection()?.deref_mut())
}

pub fn get_last_network<P: AsRef<Path>>(db_path: P) -> Result<Option<String>, WalletStorageError> {
let path_str = db_path
.as_ref()
.to_str()
.ok_or(WalletStorageError::InvalidUnicodePath)?;

let mut pool = SqliteConnectionPool::new(String::from(path_str), 1, true, true, Duration::from_secs(60));
pool.create_pool()?;

WalletSettingSql::get(&DbKey::LastAccessedNetwork, pool.get_pooled_connection()?.deref_mut())
}
8 changes: 8 additions & 0 deletions base_layer/wallet/src/wallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ use crate::{
base_node_service::{handle::BaseNodeServiceHandle, BaseNodeServiceInitializer},
config::{WalletConfig, KEY_MANAGER_COMMS_SECRET_KEY_BRANCH_KEY},
connectivity_service::{WalletConnectivityHandle, WalletConnectivityInitializer, WalletConnectivityInterface},
consts,
error::{WalletError, WalletStorageError},
key_manager_service::{storage::database::KeyManagerBackend, KeyManagerHandle, KeyManagerInitializer},
output_manager_service::{
Expand Down Expand Up @@ -279,6 +280,13 @@ where
wallet_database.set_comms_identity_signature(identity_sig)?;
}

// storing current network and version
if let Err(e) = wallet_database
.set_last_network_and_version(config.network.to_string(), consts::APP_VERSION_NUMBER.to_string())
{
warn!("failed to store network and version: {:#?}", e);
}

Ok(Self {
network: config.network.into(),
comms,
Expand Down
166 changes: 165 additions & 1 deletion base_layer/wallet_ffi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ use tari_wallet::{
storage::{
database::WalletDatabase,
sqlite_db::wallet::WalletSqliteDatabase,
sqlite_utilities::initialize_sqlite_database_backends,
sqlite_utilities::{get_last_network, get_last_version, initialize_sqlite_database_backends},
},
transaction_service::{
config::TransactionServiceConfig,
Expand Down Expand Up @@ -5447,6 +5447,84 @@ pub unsafe extern "C" fn wallet_create(
}
}

/// Retrieves the version of an app that last accessed the wallet database
///
/// ## Arguments
/// `config` - The TariCommsConfig pointer
/// `error_out` - Pointer to an int which will be modified to an error code should one occur, may not be null. Functions
/// as an out parameter.
/// ## Returns
/// `*mut c_char` - Returns the pointer to the hexadecimal representation of the signature and
///
/// # Safety
/// The ```string_destroy``` method must be called when finished with a string coming from rust to prevent a memory leak
#[no_mangle]
pub unsafe extern "C" fn wallet_get_last_version(config: *mut TariCommsConfig, error_out: *mut c_int) -> *mut c_char {
let mut error = 0;
ptr::swap(error_out, &mut error as *mut c_int);
if config.is_null() {
error = LibWalletError::from(InterfaceError::NullError("config".to_string())).code;
ptr::swap(error_out, &mut error as *mut c_int);
return ptr::null_mut();
}

let sql_database_path = (*config)
.datastore_path
.join((*config).peer_database_name.clone())
.with_extension("sqlite3");
match get_last_version(sql_database_path) {
Ok(None) => ptr::null_mut(),
Ok(Some(version)) => {
let version = CString::new(version).expect("failed to initialize CString");
version.into_raw()
},
Err(e) => {
error = LibWalletError::from(WalletError::WalletStorageError(e)).code;
ptr::swap(error_out, &mut error as *mut c_int);
ptr::null_mut()
},
}
}

/// Retrieves the network of an app that last accessed the wallet database
///
/// ## Arguments
/// `config` - The TariCommsConfig pointer
/// `error_out` - Pointer to an int which will be modified to an error code should one occur, may not be null. Functions
/// as an out parameter.
/// ## Returns
/// `*mut c_char` - Returns the pointer to the hexadecimal representation of the signature and
///
/// # Safety
/// The ```string_destroy``` method must be called when finished with a string coming from rust to prevent a memory leak
#[no_mangle]
pub unsafe extern "C" fn wallet_get_last_network(config: *mut TariCommsConfig, error_out: *mut c_int) -> *mut c_char {
let mut error = 0;
ptr::swap(error_out, &mut error as *mut c_int);
if config.is_null() {
error = LibWalletError::from(InterfaceError::NullError("config".to_string())).code;
ptr::swap(error_out, &mut error as *mut c_int);
return ptr::null_mut();
}

let sql_database_path = (*config)
.datastore_path
.join((*config).peer_database_name.clone())
.with_extension("sqlite3");
match get_last_network(sql_database_path) {
Ok(None) => ptr::null_mut(),
Ok(Some(network)) => {
let network = CString::new(network).expect("failed to initialize CString");
network.into_raw()
},
Err(e) => {
error = LibWalletError::from(WalletError::WalletStorageError(e)).code;
ptr::swap(error_out, &mut error as *mut c_int);
ptr::null_mut()
},
}
}

/// Retrieves the balance from a wallet
///
/// ## Arguments
Expand Down Expand Up @@ -10356,6 +10434,92 @@ mod test {
}
}

#[test]
#[allow(clippy::too_many_lines, clippy::needless_collect)]
fn test_wallet_get_network_and_version() {
unsafe {
let mut error = 0;
let error_ptr = &mut error as *mut c_int;
let mut recovery_in_progress = true;
let recovery_in_progress_ptr = &mut recovery_in_progress as *mut bool;

let secret_key_alice = private_key_generate();
let db_name_alice = CString::new(random::string(8).as_str()).unwrap();
let db_name_alice_str: *const c_char = CString::into_raw(db_name_alice) as *const c_char;
let alice_temp_dir = tempdir().unwrap();
let db_path_alice = CString::new(alice_temp_dir.path().to_str().unwrap()).unwrap();
let db_path_alice_str: *const c_char = CString::into_raw(db_path_alice) as *const c_char;
let transport_config_alice = transport_memory_create();
let address_alice = transport_memory_get_address(transport_config_alice, error_ptr);
let address_alice_str = CStr::from_ptr(address_alice).to_str().unwrap().to_owned();
let address_alice_str: *const c_char = CString::new(address_alice_str).unwrap().into_raw() as *const c_char;
let network = CString::new(NETWORK_STRING).unwrap();
let network_str: *const c_char = CString::into_raw(network) as *const c_char;

let alice_config = comms_config_create(
address_alice_str,
transport_config_alice,
db_name_alice_str,
db_path_alice_str,
20,
10800,
error_ptr,
);

let passphrase: *const c_char = CString::into_raw(CString::new("niao").unwrap()) as *const c_char;

let alice_wallet = wallet_create(
alice_config,
ptr::null(),
0,
0,
passphrase,
ptr::null(),
network_str,
received_tx_callback,
received_tx_reply_callback,
received_tx_finalized_callback,
broadcast_callback,
mined_callback,
mined_unconfirmed_callback,
scanned_callback,
scanned_unconfirmed_callback,
transaction_send_result_callback,
tx_cancellation_callback,
txo_validation_complete_callback,
contacts_liveness_data_updated_callback,
balance_updated_callback,
transaction_validation_complete_callback,
saf_messages_received_callback,
connectivity_status_callback,
recovery_in_progress_ptr,
error_ptr,
);
assert_eq!(error, 0);
(1..=5).for_each(|i| {
(*alice_wallet)
.runtime
.block_on((*alice_wallet).wallet.output_manager_service.add_output(
create_test_input((15000 * i).into(), 0, &ExtendedPedersenCommitmentFactory::default()).1,
None,
))
.unwrap();
});

// obtaining network and version
let _ = wallet_get_last_version(alice_config, &mut error as *mut c_int);
let _ = wallet_get_last_network(alice_config, &mut error as *mut c_int);

string_destroy(db_name_alice_str as *mut c_char);
string_destroy(db_path_alice_str as *mut c_char);
string_destroy(address_alice_str as *mut c_char);
private_key_destroy(secret_key_alice);
transport_config_destroy(transport_config_alice);
comms_config_destroy(alice_config);
wallet_destroy(alice_wallet);
}
}

#[test]
fn test_tari_vector() {
let mut error = 0;
Expand Down
Loading

0 comments on commit 4b09b59

Please sign in to comment.