Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: added FFI function wallet_get_network_and_version #5252 #5263

Merged
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
170 changes: 169 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,88 @@ 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");


SWvheerden marked this conversation as resolved.
Show resolved Hide resolved
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");


SWvheerden marked this conversation as resolved.
Show resolved Hide resolved
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 +10438,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