From 886017a4f5a2c5fe1d89bd952c2b09d750a03268 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Mon, 11 Feb 2019 15:11:09 +0000 Subject: [PATCH 1/4] Migrate to Rust 2018 edition Requires a minimum of Rust 1.31. --- Cargo.toml | 1 + src/main/rust/lib.rs | 90 ++++++++++++++++++-------------------------- 2 files changed, 38 insertions(+), 53 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4f543d3a..6651f24a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ authors = [ ] description = "JNI backend for the Android wallet SDK" publish = false +edition = "2018" [dependencies] android_logger = "0.6" diff --git a/src/main/rust/lib.rs b/src/main/rust/lib.rs index 6dadc715..db50e0cd 100644 --- a/src/main/rust/lib.rs +++ b/src/main/rust/lib.rs @@ -1,25 +1,6 @@ -extern crate failure; - #[macro_use] extern crate log; -extern crate android_logger; -extern crate ff; -extern crate jni; -extern crate log_panics; -extern crate pairing; -extern crate protobuf; -extern crate rand; -extern crate rusqlite; -extern crate sapling_crypto; -extern crate time; -extern crate zcash_client_backend; -extern crate zcash_primitives; -extern crate zip32; - -#[cfg(test)] -extern crate tempfile; - mod sql; const SAPLING_CONSENSUS_BRANCH_ID: u32 = 0x76b8_09bb; @@ -49,7 +30,10 @@ use crate::sql::{ }; #[no_mangle] -pub unsafe extern "C" fn Java_cash_z_wallet_sdk_jni_JniConverter_initLogs(_env: JNIEnv, _: JClass) { +pub unsafe extern "C" fn Java_cash_z_wallet_sdk_jni_JniConverter_initLogs( + _env: JNIEnv<'_>, + _: JClass<'_>, +) { android_logger::init_once( Filter::default().with_min_level(Level::Trace), Some("cash.z.rust.logs"), @@ -62,9 +46,9 @@ pub unsafe extern "C" fn Java_cash_z_wallet_sdk_jni_JniConverter_initLogs(_env: #[no_mangle] pub unsafe extern "C" fn Java_cash_z_wallet_sdk_jni_JniConverter_initDataDb( - env: JNIEnv, - _: JClass, - db_data: JString, + env: JNIEnv<'_>, + _: JClass<'_>, + db_data: JString<'_>, ) -> jboolean { let db_data: String = env .get_string(db_data) @@ -82,9 +66,9 @@ pub unsafe extern "C" fn Java_cash_z_wallet_sdk_jni_JniConverter_initDataDb( #[no_mangle] pub unsafe extern "C" fn Java_cash_z_wallet_sdk_jni_JniConverter_initAccountsTable( - env: JNIEnv, - _: JClass, - db_data: JString, + env: JNIEnv<'_>, + _: JClass<'_>, + db_data: JString<'_>, seed: jbyteArray, accounts: jint, ) -> jobjectArray { @@ -146,9 +130,9 @@ pub unsafe extern "C" fn Java_cash_z_wallet_sdk_jni_JniConverter_initAccountsTab #[no_mangle] pub unsafe extern "C" fn Java_cash_z_wallet_sdk_jni_JniConverter_initBlocksTable( - env: JNIEnv, - _: JClass, - db_data: JString, + env: JNIEnv<'_>, + _: JClass<'_>, + db_data: JString<'_>, height: jint, time: jlong, sapling_tree: jbyteArray, @@ -176,9 +160,9 @@ pub unsafe extern "C" fn Java_cash_z_wallet_sdk_jni_JniConverter_initBlocksTable #[no_mangle] pub unsafe extern "C" fn Java_cash_z_wallet_sdk_jni_JniConverter_getAddress( - env: JNIEnv, - _: JClass, - db_data: JString, + env: JNIEnv<'_>, + _: JClass<'_>, + db_data: JString<'_>, account: jint, ) -> jstring { let db_data: String = env @@ -208,9 +192,9 @@ pub unsafe extern "C" fn Java_cash_z_wallet_sdk_jni_JniConverter_getAddress( #[no_mangle] pub unsafe extern "C" fn Java_cash_z_wallet_sdk_jni_JniConverter_getBalance( - env: JNIEnv, - _: JClass, - db_data: JString, + env: JNIEnv<'_>, + _: JClass<'_>, + db_data: JString<'_>, account: jint, ) -> jlong { let db_data: String = env @@ -235,9 +219,9 @@ pub unsafe extern "C" fn Java_cash_z_wallet_sdk_jni_JniConverter_getBalance( #[no_mangle] pub unsafe extern "C" fn Java_cash_z_wallet_sdk_jni_JniConverter_getReceivedMemoAsUtf8( - env: JNIEnv, - _: JClass, - db_data: JString, + env: JNIEnv<'_>, + _: JClass<'_>, + db_data: JString<'_>, id_note: jlong, ) -> jstring { let db_data: String = env @@ -260,9 +244,9 @@ pub unsafe extern "C" fn Java_cash_z_wallet_sdk_jni_JniConverter_getReceivedMemo #[no_mangle] pub unsafe extern "C" fn Java_cash_z_wallet_sdk_jni_JniConverter_getSentMemoAsUtf8( - env: JNIEnv, - _: JClass, - db_data: JString, + env: JNIEnv<'_>, + _: JClass<'_>, + db_data: JString<'_>, id_note: jlong, ) -> jstring { let db_data: String = env @@ -285,10 +269,10 @@ pub unsafe extern "C" fn Java_cash_z_wallet_sdk_jni_JniConverter_getSentMemoAsUt #[no_mangle] pub unsafe extern "C" fn Java_cash_z_wallet_sdk_jni_JniConverter_scanBlocks( - env: JNIEnv, - _: JClass, - db_cache: JString, - db_data: JString, + env: JNIEnv<'_>, + _: JClass<'_>, + db_cache: JString<'_>, + db_data: JString<'_>, ) -> jboolean { let db_cache: String = env .get_string(db_cache) @@ -310,16 +294,16 @@ pub unsafe extern "C" fn Java_cash_z_wallet_sdk_jni_JniConverter_scanBlocks( #[no_mangle] pub unsafe extern "C" fn Java_cash_z_wallet_sdk_jni_JniConverter_sendToAddress( - env: JNIEnv, - _: JClass, - db_data: JString, + env: JNIEnv<'_>, + _: JClass<'_>, + db_data: JString<'_>, account: jint, - extsk: JString, - to: JString, + extsk: JString<'_>, + to: JString<'_>, value: jlong, - memo: JString, - spend_params: JString, - output_params: JString, + memo: JString<'_>, + spend_params: JString<'_>, + output_params: JString<'_>, ) -> jlong { let db_data: String = env .get_string(db_data) From 1163c557a85b0b8ab0167d1fa63330b0b7a41ee7 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Mon, 11 Feb 2019 15:36:34 +0000 Subject: [PATCH 2/4] Use spending_key helper instead of manually constructing account path --- src/main/rust/lib.rs | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/src/main/rust/lib.rs b/src/main/rust/lib.rs index db50e0cd..e2f87a0c 100644 --- a/src/main/rust/lib.rs +++ b/src/main/rust/lib.rs @@ -18,11 +18,12 @@ use zcash_client_backend::{ encoding::{ decode_extended_spending_key, decode_payment_address, encode_extended_spending_key, }, + keystore::spending_key, note_encryption::Memo, prover::LocalTxProver, }; use zcash_primitives::transaction::components::Amount; -use zip32::{ChildIndex, ExtendedFullViewingKey, ExtendedSpendingKey}; +use zip32::ExtendedFullViewingKey; use crate::sql::{ get_address, get_balance, init_accounts_table, init_blocks_table, init_data_database, @@ -79,18 +80,8 @@ pub unsafe extern "C" fn Java_cash_z_wallet_sdk_jni_JniConverter_initAccountsTab let seed = env.convert_byte_array(seed).unwrap(); let ret = if accounts >= 0 { - let master = ExtendedSpendingKey::master(&seed); let extsks: Vec<_> = (0..accounts as u32) - .map(|account| { - ExtendedSpendingKey::from_path( - &master, - &[ - ChildIndex::Hardened(32), - ChildIndex::Hardened(1), - ChildIndex::Hardened(account), - ], - ) - }) + .map(|account| spending_key(&seed, 1, account)) .collect(); let extfvks: Vec<_> = extsks.iter().map(ExtendedFullViewingKey::from).collect(); From 5dfadd439320745f324268a3d8ac74e33503d798 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Mon, 11 Feb 2019 15:44:49 +0000 Subject: [PATCH 3/4] Extract java_string_to_rust() utility function --- src/main/rust/lib.rs | 76 +++++++++--------------------------------- src/main/rust/utils.rs | 7 ++++ 2 files changed, 23 insertions(+), 60 deletions(-) create mode 100644 src/main/rust/utils.rs diff --git a/src/main/rust/lib.rs b/src/main/rust/lib.rs index e2f87a0c..a2a34040 100644 --- a/src/main/rust/lib.rs +++ b/src/main/rust/lib.rs @@ -2,6 +2,7 @@ extern crate log; mod sql; +mod utils; const SAPLING_CONSENSUS_BRANCH_ID: u32 = 0x76b8_09bb; @@ -51,10 +52,7 @@ pub unsafe extern "C" fn Java_cash_z_wallet_sdk_jni_JniConverter_initDataDb( _: JClass<'_>, db_data: JString<'_>, ) -> jboolean { - let db_data: String = env - .get_string(db_data) - .expect("Couldn't get Java string!") - .into(); + let db_data = utils::java_string_to_rust(&env, db_data); match init_data_database(&db_data) { Ok(()) => JNI_TRUE, @@ -73,10 +71,7 @@ pub unsafe extern "C" fn Java_cash_z_wallet_sdk_jni_JniConverter_initAccountsTab seed: jbyteArray, accounts: jint, ) -> jobjectArray { - let db_data: String = env - .get_string(db_data) - .expect("Couldn't get Java string!") - .into(); + let db_data = utils::java_string_to_rust(&env, db_data); let seed = env.convert_byte_array(seed).unwrap(); let ret = if accounts >= 0 { @@ -128,10 +123,7 @@ pub unsafe extern "C" fn Java_cash_z_wallet_sdk_jni_JniConverter_initBlocksTable time: jlong, sapling_tree: jbyteArray, ) -> jboolean { - let db_data: String = env - .get_string(db_data) - .expect("Couldn't get Java string!") - .into(); + let db_data = utils::java_string_to_rust(&env, db_data); let time = if time >= 0 && time <= jlong::from(u32::max_value()) { time as u32 } else { @@ -156,10 +148,7 @@ pub unsafe extern "C" fn Java_cash_z_wallet_sdk_jni_JniConverter_getAddress( db_data: JString<'_>, account: jint, ) -> jstring { - let db_data: String = env - .get_string(db_data) - .expect("Couldn't get Java string!") - .into(); + let db_data = utils::java_string_to_rust(&env, db_data); let addr = match account { acc if acc >= 0 => match get_address(&db_data, acc as u32) { @@ -188,10 +177,7 @@ pub unsafe extern "C" fn Java_cash_z_wallet_sdk_jni_JniConverter_getBalance( db_data: JString<'_>, account: jint, ) -> jlong { - let db_data: String = env - .get_string(db_data) - .expect("Couldn't get Java string!") - .into(); + let db_data = utils::java_string_to_rust(&env, db_data); let account = if account >= 0 { account as u32 } else { @@ -215,10 +201,7 @@ pub unsafe extern "C" fn Java_cash_z_wallet_sdk_jni_JniConverter_getReceivedMemo db_data: JString<'_>, id_note: jlong, ) -> jstring { - let db_data: String = env - .get_string(db_data) - .expect("Couldn't get Java string!") - .into(); + let db_data = utils::java_string_to_rust(&env, db_data); let memo = match crate::sql::get_received_memo_as_utf8(db_data, id_note) { Ok(memo) => memo.unwrap_or_default(), @@ -240,10 +223,7 @@ pub unsafe extern "C" fn Java_cash_z_wallet_sdk_jni_JniConverter_getSentMemoAsUt db_data: JString<'_>, id_note: jlong, ) -> jstring { - let db_data: String = env - .get_string(db_data) - .expect("Couldn't get Java string!") - .into(); + let db_data = utils::java_string_to_rust(&env, db_data); let memo = match crate::sql::get_sent_memo_as_utf8(db_data, id_note) { Ok(memo) => memo.unwrap_or_default(), @@ -265,14 +245,8 @@ pub unsafe extern "C" fn Java_cash_z_wallet_sdk_jni_JniConverter_scanBlocks( db_cache: JString<'_>, db_data: JString<'_>, ) -> jboolean { - let db_cache: String = env - .get_string(db_cache) - .expect("Couldn't get Java string!") - .into(); - let db_data: String = env - .get_string(db_data) - .expect("Couldn't get Java string!") - .into(); + let db_cache = utils::java_string_to_rust(&env, db_cache); + let db_data = utils::java_string_to_rust(&env, db_data); match scan_cached_blocks(&db_cache, &db_data) { Ok(()) => JNI_TRUE, @@ -296,37 +270,19 @@ pub unsafe extern "C" fn Java_cash_z_wallet_sdk_jni_JniConverter_sendToAddress( spend_params: JString<'_>, output_params: JString<'_>, ) -> jlong { - let db_data: String = env - .get_string(db_data) - .expect("Couldn't get Java string!") - .into(); + let db_data = utils::java_string_to_rust(&env, db_data); let account = if account >= 0 { account as u32 } else { error!("account argument must be positive"); return -1; }; - let extsk: String = env - .get_string(extsk) - .expect("Couldn't get Java string!") - .into(); - let to: String = env - .get_string(to) - .expect("Couldn't get Java string!") - .into(); + let extsk = utils::java_string_to_rust(&env, extsk); + let to = utils::java_string_to_rust(&env, to); let value = Amount(value); - let memo: String = env - .get_string(memo) - .expect("Couldn't get Java string!") - .into(); - let spend_params: String = env - .get_string(spend_params) - .expect("Couldn't get Java string!") - .into(); - let output_params: String = env - .get_string(output_params) - .expect("Couldn't get Java string!") - .into(); + let memo = utils::java_string_to_rust(&env, memo); + let spend_params = utils::java_string_to_rust(&env, spend_params); + let output_params = utils::java_string_to_rust(&env, output_params); let extsk = match decode_extended_spending_key(HRP_SAPLING_EXTENDED_SPENDING_KEY_TEST, &extsk) { Ok(extsk) => extsk, diff --git a/src/main/rust/utils.rs b/src/main/rust/utils.rs new file mode 100644 index 00000000..b519be74 --- /dev/null +++ b/src/main/rust/utils.rs @@ -0,0 +1,7 @@ +use jni::{objects::JString, JNIEnv}; + +pub(crate) fn java_string_to_rust(env: &JNIEnv<'_>, jstring: JString<'_>) -> String { + env.get_string(jstring) + .expect("Couldn't get Java string!") + .into() +} From 6d86b2cf16f0e316e52ec1293b5fcad391ad6bff Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Mon, 11 Feb 2019 16:20:11 +0000 Subject: [PATCH 4/4] Extract rust_vec_to_java() utility function --- src/main/rust/lib.rs | 23 ++++++++++------------- src/main/rust/utils.rs | 34 +++++++++++++++++++++++++++++++++- 2 files changed, 43 insertions(+), 14 deletions(-) diff --git a/src/main/rust/lib.rs b/src/main/rust/lib.rs index a2a34040..c3a574b4 100644 --- a/src/main/rust/lib.rs +++ b/src/main/rust/lib.rs @@ -9,7 +9,7 @@ const SAPLING_CONSENSUS_BRANCH_ID: u32 = 0x76b8_09bb; use android_logger::Filter; use jni::{ objects::{JClass, JString}, - sys::{jboolean, jbyteArray, jint, jlong, jobjectArray, jsize, jstring, JNI_FALSE, JNI_TRUE}, + sys::{jboolean, jbyteArray, jint, jlong, jobjectArray, jstring, JNI_FALSE, JNI_TRUE}, JNIEnv, }; use log::Level; @@ -97,21 +97,18 @@ pub unsafe extern "C" fn Java_cash_z_wallet_sdk_jni_JniConverter_initAccountsTab vec![] }; - let jempty = env.new_string("").expect("Couldn't create Java string!"); - let jret = env - .new_object_array(ret.len() as jsize, "java/lang/String", *jempty) - .expect("Couldn't create Java array!"); - for (i, extsk) in ret.into_iter().enumerate() { - let jextsk = env - .new_string(encode_extended_spending_key( + utils::rust_vec_to_java( + &env, + ret, + "java/lang/String", + |env, extsk| { + env.new_string(encode_extended_spending_key( HRP_SAPLING_EXTENDED_SPENDING_KEY_TEST, &extsk, )) - .expect("Couldn't create Java string!"); - env.set_object_array_element(jret, i as jsize, *jextsk) - .expect("Couldn't set Java array element!"); - } - jret + }, + |env| env.new_string(""), + ) } #[no_mangle] diff --git a/src/main/rust/utils.rs b/src/main/rust/utils.rs index b519be74..6e4f7b91 100644 --- a/src/main/rust/utils.rs +++ b/src/main/rust/utils.rs @@ -1,7 +1,39 @@ -use jni::{objects::JString, JNIEnv}; +use jni::{ + descriptors::Desc, + errors::Result as JNIResult, + objects::{JClass, JObject, JString}, + sys::{jobjectArray, jsize}, + JNIEnv, +}; +use std::ops::Deref; pub(crate) fn java_string_to_rust(env: &JNIEnv<'_>, jstring: JString<'_>) -> String { env.get_string(jstring) .expect("Couldn't get Java string!") .into() } + +pub(crate) fn rust_vec_to_java<'a, T, U, V, F, G>( + env: &JNIEnv<'a>, + data: Vec, + element_class: U, + element_map: F, + empty_element: G, +) -> jobjectArray +where + U: Desc<'a, JClass<'a>>, + V: Deref>, + F: Fn(&JNIEnv<'a>, T) -> JNIResult, + G: Fn(&JNIEnv<'a>) -> JNIResult, +{ + let jempty = empty_element(env).expect("Couldn't create Java string!"); + let jret = env + .new_object_array(data.len() as jsize, element_class, *jempty) + .expect("Couldn't create Java array!"); + for (i, elem) in data.into_iter().enumerate() { + let jelem = element_map(env, elem).expect("Couldn't map element to Java!"); + env.set_object_array_element(jret, i as jsize, *jelem) + .expect("Couldn't set Java array element!"); + } + jret +}