Update to use data access API in librustzcash. (#172)

* Refactor to updated data access API.

* Update to latest librustzcash/data_access_api.

Co-authored-by: Kevin Gorham <kevin.gorham@electriccoin.co>
This commit is contained in:
Kris Nuttycombe 2021-03-10 11:31:55 -07:00 committed by GitHub
parent 794a9f99b8
commit 4bcf74d871
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 402 additions and 340 deletions

396
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -56,6 +56,12 @@ zcash_proofs = { git = 'https://github.com/zcash/librustzcash.git', rev='04a2bd4
#zcash_primitives = { path = '../../clones/librustzcash/zcash_primitives' } #zcash_primitives = { path = '../../clones/librustzcash/zcash_primitives' }
#zcash_proofs = { path = '../../clones/librustzcash/zcash_proofs' } #zcash_proofs = { path = '../../clones/librustzcash/zcash_proofs' }
[patch.crates-io]
zcash_client_backend = {git = "https://github.com/nuttycom/librustzcash", branch = "data_access_api"}
zcash_client_sqlite = {git = "https://github.com/nuttycom/librustzcash", branch = "data_access_api"}
zcash_primitives = {git = "https://github.com/nuttycom/librustzcash", branch = "data_access_api"}
zcash_proofs = {git = "https://github.com/nuttycom/librustzcash", branch = "data_access_api"}
[features] [features]
mainnet = ["zcash_client_sqlite/mainnet"] mainnet = ["zcash_client_sqlite/mainnet"]
updater = ["bls12_381", "futures", "grpc", "grpc-protobuf", "httpbis", "tls-api", "tls-api-rustls"] updater = ["bls12_381", "futures", "grpc", "grpc-protobuf", "httpbis", "tls-api", "tls-api-rustls"]

View File

@ -11,64 +11,49 @@ use jni::{
sys::{jboolean, jbyteArray, jint, jlong, JNI_FALSE, JNI_TRUE, jobjectArray, jstring}, sys::{jboolean, jbyteArray, jint, jlong, JNI_FALSE, JNI_TRUE, jobjectArray, jstring},
}; };
use log::Level; use log::Level;
use protobuf::{Message, parse_from_bytes}; use std::convert::{TryFrom, TryInto};
use secp256k1::{PublicKey, Secp256k1}; use std::panic;
use sha2::{Digest, Sha256}; use std::path::Path;
use std::ptr;
use zcash_client_backend::{ use zcash_client_backend::{
address::RecipientAddress, address::RecipientAddress,
data_api::{
chain::{scan_cached_blocks, validate_chain},
error::Error,
wallet::{create_spend_to_address, decrypt_and_store_transaction},
WalletRead, WalletWrite,
},
encoding::{ encoding::{
decode_extended_full_viewing_key, decode_extended_spending_key, decode_extended_full_viewing_key, decode_extended_spending_key,
encode_extended_full_viewing_key, encode_extended_spending_key, encode_payment_address, encode_extended_full_viewing_key, encode_extended_spending_key, encode_payment_address,
}, },
keys::spending_key, keys::spending_key,
wallet::{AccountId, OvkPolicy},
}; };
use zcash_client_sqlite::{ use zcash_client_sqlite::{
chain::{rewind_to_height, validate_combined_chain}, wallet::init::{init_accounts_table, init_blocks_table, init_data_database},
error::ErrorKind, BlockDB, NoteId, WalletDB,
init::{init_accounts_table, init_blocks_table, init_data_database},
query::{
get_address, get_balance, get_received_memo_as_utf8, get_sent_memo_as_utf8,
get_verified_balance,
},
scan::{decrypt_and_store_transaction, scan_cached_blocks},
transact::{create_to_address, OvkPolicy},
}; };
use zcash_primitives::{ use zcash_primitives::{
block::BlockHash, block::BlockHash,
consensus::{BlockHeight, BranchId}, consensus::{BlockHeight, BranchId, Parameters},
legacy::TransparentAddress,
note_encryption::Memo, note_encryption::Memo,
transaction::{components::Amount, Transaction}, transaction::{components::Amount, Transaction},
zip32::ExtendedFullViewingKey, zip32::ExtendedFullViewingKey,
}; };
#[cfg(feature = "mainnet")] #[cfg(feature = "mainnet")]
use zcash_primitives::consensus::MainNetwork as Network; use zcash_primitives::consensus::{MainNetwork, MAIN_NETWORK};
#[cfg(not(feature = "mainnet"))] #[cfg(not(feature = "mainnet"))]
use zcash_primitives::consensus::TestNetwork as Network; use zcash_primitives::consensus::{TestNetwork, TEST_NETWORK};
#[cfg(feature = "mainnet")]
use zcash_primitives::constants::mainnet::{
COIN_TYPE, HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY, HRP_SAPLING_EXTENDED_SPENDING_KEY,
HRP_SAPLING_PAYMENT_ADDRESS,
};
#[cfg(feature = "mainnet")]
use zcash_primitives::constants::mainnet::B58_PUBKEY_ADDRESS_PREFIX;
#[cfg(not(feature = "mainnet"))]
use zcash_primitives::constants::testnet::{
COIN_TYPE, HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY, HRP_SAPLING_EXTENDED_SPENDING_KEY,
HRP_SAPLING_PAYMENT_ADDRESS,
};
#[cfg(not(feature = "mainnet"))]
use zcash_primitives::constants::testnet::B58_PUBKEY_ADDRESS_PREFIX;
use zcash_primitives::legacy::TransparentAddress;
use zcash_proofs::prover::LocalTxProver;
use local_rpc_types::{TransactionDataList, TransparentTransaction, TransparentTransactionList}; use local_rpc_types::{TransactionDataList, TransparentTransaction, TransparentTransactionList};
use std::convert::TryFrom; use protobuf::{parse_from_bytes, Message};
use std::convert::TryInto; use sha2::{Digest, Sha256};
use std::panic;
use std::path::Path;
use std::ptr;
use crate::utils::exception::unwrap_exc_or; use hdwallet::{ExtendedPrivKey, KeyIndex};
use secp256k1::{PublicKey, Secp256k1};
mod utils; mod utils;
@ -88,6 +73,22 @@ fn print_debug_state() {
debug!("Release enabled (congrats, this is NOT a debug build)."); debug!("Release enabled (congrats, this is NOT a debug build).");
} }
#[cfg(feature = "mainnet")]
pub const NETWORK: MainNetwork = MAIN_NETWORK;
#[cfg(not(feature = "mainnet"))]
pub const NETWORK: TestNetwork = TEST_NETWORK;
fn wallet_db(env: &JNIEnv<'_>, db_data: JString<'_>) -> Result<WalletDB, failure::Error> {
WalletDB::for_path(utils::java_string_to_rust(&env, db_data))
.map_err(|e| format_err!("Error opening wallet database connection: {}", e))
}
fn block_db(env: &JNIEnv<'_>, db_data: JString<'_>) -> Result<BlockDB, failure::Error> {
BlockDB::for_path(utils::java_string_to_rust(&env, db_data))
.map_err(|e| format_err!("Error opening block source database connection: {}", e))
}
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_initLogs( pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_initLogs(
_env: JNIEnv<'_>, _env: JNIEnv<'_>,
@ -112,9 +113,9 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_initDataDb(
db_data: JString<'_>, db_data: JString<'_>,
) -> jboolean { ) -> jboolean {
let res = panic::catch_unwind(|| { let res = panic::catch_unwind(|| {
let db_data = utils::java_string_to_rust(&env, db_data); let db_path = utils::java_string_to_rust(&env, db_data);
WalletDB::for_path(db_path)
init_data_database(&db_data) .and_then(|db| init_data_database(&db))
.map(|()| JNI_TRUE) .map(|()| JNI_TRUE)
.map_err(|e| format_err!("Error while initializing data DB: {}", e)) .map_err(|e| format_err!("Error while initializing data DB: {}", e))
}); });
@ -130,7 +131,7 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_initAccount
accounts: jint, accounts: jint,
) -> jobjectArray { ) -> jobjectArray {
let res = panic::catch_unwind(|| { let res = panic::catch_unwind(|| {
let db_data = utils::java_string_to_rust(&env, db_data); let db_data = wallet_db(&env, db_data)?;
let seed = env.convert_byte_array(seed).unwrap(); let seed = env.convert_byte_array(seed).unwrap();
let accounts = if accounts >= 0 { let accounts = if accounts >= 0 {
accounts as u32 accounts as u32
@ -139,29 +140,29 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_initAccount
}; };
let extsks: Vec<_> = (0..accounts) let extsks: Vec<_> = (0..accounts)
.map(|account| spending_key(&seed, COIN_TYPE, account)) .map(|account| spending_key(&seed, NETWORK.coin_type(), account))
.collect(); .collect();
let extfvks: Vec<_> = extsks.iter().map(ExtendedFullViewingKey::from).collect(); let extfvks: Vec<_> = extsks.iter().map(ExtendedFullViewingKey::from).collect();
match init_accounts_table(&db_data, &Network, &extfvks) { init_accounts_table(&db_data, &NETWORK, &extfvks)
Ok(()) => { .map(|_| {
// Return the ExtendedSpendingKeys for the created accounts // Return the ExtendedSpendingKeys for the created accounts
Ok(utils::rust_vec_to_java( utils::rust_vec_to_java(
&env, &env,
extsks, extsks,
"java/lang/String", "java/lang/String",
|env, extsk| { |env, extsk| {
env.new_string(encode_extended_spending_key( env.new_string(encode_extended_spending_key(
HRP_SAPLING_EXTENDED_SPENDING_KEY, NETWORK.hrp_sapling_extended_spending_key(),
&extsk, &extsk,
)) ))
}, },
|env| env.new_string(""), |env| env.new_string(""),
)) )
} })
Err(e) => Err(format_err!("Error while initializing accounts: {}", e)), .map_err(|e| format_err!("Error while initializing accounts: {}", e))
}
}); });
unwrap_exc_or(&env, res, ptr::null_mut()) unwrap_exc_or(&env, res, ptr::null_mut())
} }
@ -173,20 +174,23 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_initAccount
extfvks_arr: jobjectArray, extfvks_arr: jobjectArray,
) -> jboolean { ) -> jboolean {
let res = panic::catch_unwind(|| { let res = panic::catch_unwind(|| {
let db_data = utils::java_string_to_rust(&env, db_data); let db_data = wallet_db(&env, db_data)?;
// TODO: avoid all this unwrapping and also surface errors, better // TODO: avoid all this unwrapping and also surface errors, better
let count = env.get_array_length(extfvks_arr).unwrap(); let count = env.get_array_length(extfvks_arr).unwrap();
let extfvks = (0..count) let extfvks = (0..count)
.map(|i| env.get_object_array_element(extfvks_arr, i)) .map(|i| env.get_object_array_element(extfvks_arr, i))
.map(|jstr| utils::java_string_to_rust(&env, jstr.unwrap().into())) .map(|jstr| utils::java_string_to_rust(&env, jstr.unwrap().into()))
.map(|vkstr| { .map(|vkstr| {
decode_extended_full_viewing_key(HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY, &vkstr) decode_extended_full_viewing_key(
.unwrap() NETWORK.hrp_sapling_extended_full_viewing_key(),
.unwrap() &vkstr,
)
.unwrap()
.unwrap()
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
match init_accounts_table(&db_data, &Network, &extfvks) { match init_accounts_table(&db_data, &NETWORK, &extfvks) {
Ok(()) => Ok(JNI_TRUE), Ok(()) => Ok(JNI_TRUE),
Err(e) => Err(format_err!("Error while initializing accounts: {}", e)), Err(e) => Err(format_err!("Error while initializing accounts: {}", e)),
} }
@ -210,7 +214,7 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_tool_DerivationTool_deriveE
}; };
let extsks: Vec<_> = (0..accounts) let extsks: Vec<_> = (0..accounts)
.map(|account| spending_key(&seed, COIN_TYPE, account)) .map(|account| spending_key(&seed, NETWORK.coin_type(), account))
.collect(); .collect();
Ok(utils::rust_vec_to_java( Ok(utils::rust_vec_to_java(
@ -219,7 +223,7 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_tool_DerivationTool_deriveE
"java/lang/String", "java/lang/String",
|env, extsk| { |env, extsk| {
env.new_string(encode_extended_spending_key( env.new_string(encode_extended_spending_key(
HRP_SAPLING_EXTENDED_SPENDING_KEY, NETWORK.hrp_sapling_extended_spending_key(),
&extsk, &extsk,
)) ))
}, },
@ -245,7 +249,9 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_tool_DerivationTool_deriveE
}; };
let extfvks: Vec<_> = (0..accounts) let extfvks: Vec<_> = (0..accounts)
.map(|account| ExtendedFullViewingKey::from(&spending_key(&seed, COIN_TYPE, account))) .map(|account| {
ExtendedFullViewingKey::from(&spending_key(&seed, NETWORK.coin_type(), account))
})
.collect(); .collect();
Ok(utils::rust_vec_to_java( Ok(utils::rust_vec_to_java(
@ -254,7 +260,7 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_tool_DerivationTool_deriveE
"java/lang/String", "java/lang/String",
|env, extfvk| { |env, extfvk| {
env.new_string(encode_extended_full_viewing_key( env.new_string(encode_extended_full_viewing_key(
HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY, NETWORK.hrp_sapling_extended_full_viewing_key(),
&extfvk, &extfvk,
)) ))
}, },
@ -279,11 +285,11 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_tool_DerivationTool_deriveS
return Err(format_err!("accountIndex argument must be positive")); return Err(format_err!("accountIndex argument must be positive"));
}; };
let address = spending_key(&seed, COIN_TYPE, account_index) let address = spending_key(&seed, NETWORK.coin_type(), account_index)
.default_address() .default_address()
.unwrap() .unwrap()
.1; .1;
let address_str = encode_payment_address(HRP_SAPLING_PAYMENT_ADDRESS, &address); let address_str = encode_payment_address(NETWORK.hrp_sapling_payment_address(), &address);
let output = env let output = env
.new_string(address_str) .new_string(address_str)
.expect("Couldn't create Java string!"); .expect("Couldn't create Java string!");
@ -301,7 +307,7 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_tool_DerivationTool_deriveS
let res = panic::catch_unwind(|| { let res = panic::catch_unwind(|| {
let extfvk_string = utils::java_string_to_rust(&env, extfvk_string); let extfvk_string = utils::java_string_to_rust(&env, extfvk_string);
let extfvk = match decode_extended_full_viewing_key( let extfvk = match decode_extended_full_viewing_key(
HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY, NETWORK.hrp_sapling_extended_full_viewing_key(),
&extfvk_string, &extfvk_string,
) { ) {
Ok(Some(extfvk)) => extfvk, Ok(Some(extfvk)) => extfvk,
@ -317,7 +323,7 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_tool_DerivationTool_deriveS
}; };
let address = extfvk.default_address().unwrap().1; let address = extfvk.default_address().unwrap().1;
let address_str = encode_payment_address(HRP_SAPLING_PAYMENT_ADDRESS, &address); let address_str = encode_payment_address(NETWORK.hrp_sapling_payment_address(), &address);
let output = env let output = env
.new_string(address_str) .new_string(address_str)
.expect("Couldn't create Java string!"); .expect("Couldn't create Java string!");
@ -335,7 +341,7 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_tool_DerivationTool_deriveE
let res = panic::catch_unwind(|| { let res = panic::catch_unwind(|| {
let extsk_string = utils::java_string_to_rust(&env, extsk_string); let extsk_string = utils::java_string_to_rust(&env, extsk_string);
let extfvk = match decode_extended_spending_key( let extfvk = match decode_extended_spending_key(
HRP_SAPLING_EXTENDED_SPENDING_KEY, NETWORK.hrp_sapling_extended_spending_key(),
&extsk_string, &extsk_string,
) { ) {
Ok(Some(extsk)) => ExtendedFullViewingKey::from(&extsk), Ok(Some(extsk)) => ExtendedFullViewingKey::from(&extsk),
@ -352,7 +358,7 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_tool_DerivationTool_deriveE
let output = env let output = env
.new_string(encode_extended_full_viewing_key( .new_string(encode_extended_full_viewing_key(
HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY, NETWORK.hrp_sapling_extended_full_viewing_key(),
&extfvk, &extfvk,
)) ))
.expect("Couldn't create Java string!"); .expect("Couldn't create Java string!");
@ -373,7 +379,7 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_initBlocksT
sapling_tree_string: JString<'_>, sapling_tree_string: JString<'_>,
) -> jboolean { ) -> jboolean {
let res = panic::catch_unwind(|| { let res = panic::catch_unwind(|| {
let db_data = utils::java_string_to_rust(&env, db_data); let db_data = wallet_db(&env, db_data)?;
let hash = { let hash = {
let mut hash = hex::decode(utils::java_string_to_rust(&env, hash_string)).unwrap(); let mut hash = hex::decode(utils::java_string_to_rust(&env, hash_string)).unwrap();
hash.reverse(); hash.reverse();
@ -388,7 +394,7 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_initBlocksT
hex::decode(utils::java_string_to_rust(&env, sapling_tree_string)).unwrap(); hex::decode(utils::java_string_to_rust(&env, sapling_tree_string)).unwrap();
debug!("initializing blocks table with height {}", height); debug!("initializing blocks table with height {}", height);
match init_blocks_table(&db_data, height, hash, time, &sapling_tree) { match init_blocks_table(&db_data, height.try_into()?, hash, time, &sapling_tree) {
Ok(()) => Ok(JNI_TRUE), Ok(()) => Ok(JNI_TRUE),
Err(e) => Err(format_err!("Error while initializing blocks table: {}", e)), Err(e) => Err(format_err!("Error while initializing blocks table: {}", e)),
} }
@ -404,21 +410,25 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_getAddress(
account: jint, account: jint,
) -> jstring { ) -> jstring {
let res = panic::catch_unwind(|| { let res = panic::catch_unwind(|| {
let db_data = utils::java_string_to_rust(&env, db_data); let db_data = wallet_db(&env, db_data)?;
let account = if account >= 0 { let account = AccountId(account.try_into()?);
account as u32
} else {
return Err(format_err!("account argument must be positive"));
};
match get_address(&db_data, account) { match (&db_data).get_address(&NETWORK, account) {
Ok(addr) => { Ok(Some(addr)) => {
let output = env.new_string(addr).expect("Couldn't create Java string!"); let addr_str = encode_payment_address(NETWORK.hrp_sapling_payment_address(), &addr);
let output = env
.new_string(addr_str)
.expect("Couldn't create Java string!");
Ok(output.into_inner()) Ok(output.into_inner())
} }
Ok(None) => Err(format_err!(
"No payment address was available for account {:?}",
account
)),
Err(e) => Err(format_err!("Error while fetching address: {}", e)), Err(e) => Err(format_err!("Error while fetching address: {}", e)),
} }
}); });
unwrap_exc_or(&env, res, ptr::null_mut()) unwrap_exc_or(&env, res, ptr::null_mut())
} }
@ -431,7 +441,7 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_isValidShie
let res = panic::catch_unwind(|| { let res = panic::catch_unwind(|| {
let addr = utils::java_string_to_rust(&env, addr); let addr = utils::java_string_to_rust(&env, addr);
match RecipientAddress::decode(&Network, &addr) { match RecipientAddress::decode(&NETWORK, &addr) {
Some(addr) => match addr { Some(addr) => match addr {
RecipientAddress::Shielded(_) => Ok(JNI_TRUE), RecipientAddress::Shielded(_) => Ok(JNI_TRUE),
RecipientAddress::Transparent(_) => Ok(JNI_FALSE), RecipientAddress::Transparent(_) => Ok(JNI_FALSE),
@ -451,7 +461,7 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_isValidTran
let res = panic::catch_unwind(|| { let res = panic::catch_unwind(|| {
let addr = utils::java_string_to_rust(&env, addr); let addr = utils::java_string_to_rust(&env, addr);
match RecipientAddress::decode(&Network, &addr) { match RecipientAddress::decode(&NETWORK, &addr) {
Some(addr) => match addr { Some(addr) => match addr {
RecipientAddress::Shielded(_) => Ok(JNI_FALSE), RecipientAddress::Shielded(_) => Ok(JNI_FALSE),
RecipientAddress::Transparent(_) => Ok(JNI_TRUE), RecipientAddress::Transparent(_) => Ok(JNI_TRUE),
@ -470,14 +480,10 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_getBalance(
account: jint, account: jint,
) -> jlong { ) -> jlong {
let res = panic::catch_unwind(|| { let res = panic::catch_unwind(|| {
let db_data = utils::java_string_to_rust(&env, db_data); let db_data = wallet_db(&env, db_data)?;
let account = if account >= 0 { let account = AccountId(account.try_into()?);
account as u32
} else {
return Err(format_err!("account argument must be positive"));
};
match get_balance(&db_data, account) { match (&db_data).get_balance(account) {
Ok(balance) => Ok(balance.into()), Ok(balance) => Ok(balance.into()),
Err(e) => Err(format_err!("Error while fetching balance: {}", e)), Err(e) => Err(format_err!("Error while fetching balance: {}", e)),
} }
@ -493,18 +499,25 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_getVerified
account: jint, account: jint,
) -> jlong { ) -> jlong {
let res = panic::catch_unwind(|| { let res = panic::catch_unwind(|| {
let db_data = utils::java_string_to_rust(&env, db_data); let db_data = wallet_db(&env, db_data)?;
let account = if account >= 0 { let account = AccountId(account.try_into()?);
account as u32
} else {
return Err(format_err!("account argument must be positive"));
};
match get_verified_balance(&db_data, account) { (&db_data)
Ok(balance) => Ok(balance.into()), .get_target_and_anchor_heights()
Err(e) => Err(format_err!("Error while fetching verified balance: {}", e)), .map_err(|e| format_err!("Error while fetching anchor height: {}", e))
} .and_then(|opt_anchor| {
opt_anchor
.map(|(_, a)| a)
.ok_or(format_err!("Anchor height not available; scan required."))
})
.and_then(|anchor| {
(&db_data)
.get_verified_balance(account, anchor)
.map_err(|e| format_err!("Error while fetching verified balance: {}", e))
})
.map(|amount| amount.into())
}); });
unwrap_exc_or(&env, res, -1) unwrap_exc_or(&env, res, -1)
} }
@ -516,9 +529,9 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_getReceived
id_note: jlong, id_note: jlong,
) -> jstring { ) -> jstring {
let res = panic::catch_unwind(|| { let res = panic::catch_unwind(|| {
let db_data = utils::java_string_to_rust(&env, db_data); let db_data = wallet_db(&env, db_data)?;
let memo = match get_received_memo_as_utf8(db_data, id_note) { let memo = match (&db_data).get_received_memo_as_utf8(NoteId(id_note)) {
Ok(memo) => memo.unwrap_or_default(), Ok(memo) => memo.unwrap_or_default(),
Err(e) => return Err(format_err!("Error while fetching memo: {}", e)), Err(e) => return Err(format_err!("Error while fetching memo: {}", e)),
}; };
@ -537,16 +550,17 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_getSentMemo
id_note: jlong, id_note: jlong,
) -> jstring { ) -> jstring {
let res = panic::catch_unwind(|| { let res = panic::catch_unwind(|| {
let db_data = utils::java_string_to_rust(&env, db_data); let db_data = wallet_db(&env, db_data)?;
let memo = match get_sent_memo_as_utf8(db_data, id_note) { let memo = (&db_data)
Ok(memo) => memo.unwrap_or_default(), .get_sent_memo_as_utf8(NoteId(id_note))
Err(e) => return Err(format_err!("Error while fetching memo: {}", e)), .map(|memo| memo.unwrap_or_default())
}; .map_err(|e| format_err!("Error while fetching memo: {}", e))?;
let output = env.new_string(memo).expect("Couldn't create Java string!"); let output = env.new_string(memo).expect("Couldn't create Java string!");
Ok(output.into_inner()) Ok(output.into_inner())
}); });
unwrap_exc_or(&env, res, ptr::null_mut()) unwrap_exc_or(&env, res, ptr::null_mut())
} }
@ -558,13 +572,19 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_validateCom
db_data: JString<'_>, db_data: JString<'_>,
) -> jint { ) -> jint {
let res = panic::catch_unwind(|| { let res = panic::catch_unwind(|| {
let db_cache = utils::java_string_to_rust(&env, db_cache); let block_db = block_db(&env, db_cache)?;
let db_data = utils::java_string_to_rust(&env, db_data); let db_data = wallet_db(&env, db_data)?;
if let Err(e) = validate_combined_chain(Network, &db_cache, &db_data) { let validate_from = (&db_data)
match e.kind() { .get_max_height_hash()
ErrorKind::InvalidChain(upper_bound, _) => { .map_err(|e| format_err!("Error while validating chain: {}", e))?;
let upper_bound_u32 = u32::from(*upper_bound);
let val_res = validate_chain(&NETWORK, &block_db, validate_from);
if let Err(e) = val_res {
match e.0 {
Error::InvalidChain(upper_bound, _) => {
let upper_bound_u32 = u32::from(upper_bound);
Ok(upper_bound_u32 as i32) Ok(upper_bound_u32 as i32)
} }
_ => Err(format_err!("Error while validating chain: {}", e)), _ => Err(format_err!("Error while validating chain: {}", e)),
@ -574,6 +594,7 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_validateCom
Ok(-1) Ok(-1)
} }
}); });
unwrap_exc_or(&env, res, 0) unwrap_exc_or(&env, res, 0)
} }
@ -585,17 +606,18 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_rewindToHei
height: jint, height: jint,
) -> jboolean { ) -> jboolean {
let res = panic::catch_unwind(|| { let res = panic::catch_unwind(|| {
let db_data = utils::java_string_to_rust(&env, db_data); let db_data = wallet_db(&env, db_data)?;
let mut update_ops = (&db_data)
.get_update_ops()
.map_err(|e| format_err!("Could not obtain a writable database connection: {}", e))?;
match rewind_to_height(Network, &db_data, BlockHeight::from(height as u32)) { let height = BlockHeight::try_from(height)?;
Ok(()) => Ok(JNI_TRUE), (&mut update_ops)
Err(e) => Err(format_err!( .transactionally(|ops| ops.rewind_to_height(&NETWORK, height))
"Error while rewinding data DB to height {}: {}", .map(|_| JNI_TRUE)
height, .map_err(|e| format_err!("Error while rewinding data DB to height {}: {}", height, e))
e
)),
}
}); });
unwrap_exc_or(&env, res, JNI_FALSE) unwrap_exc_or(&env, res, JNI_FALSE)
} }
@ -607,10 +629,10 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_scanBlocks(
db_data: JString<'_>, db_data: JString<'_>,
) -> jboolean { ) -> jboolean {
let res = panic::catch_unwind(|| { let res = panic::catch_unwind(|| {
let db_cache = utils::java_string_to_rust(&env, db_cache); let db_cache = block_db(&env, db_cache)?;
let db_data = utils::java_string_to_rust(&env, db_data); let db_data = wallet_db(&env, db_data)?;
match scan_cached_blocks(&Network, &db_cache, &db_data, None) { match scan_cached_blocks(&NETWORK, &db_cache, &db_data, None) {
Ok(()) => Ok(JNI_TRUE), Ok(()) => Ok(JNI_TRUE),
Err(e) => Err(format_err!("Error while scanning blocks: {}", e)), Err(e) => Err(format_err!("Error while scanning blocks: {}", e)),
} }
@ -628,10 +650,10 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_scanBlockBa
limit: jint, limit: jint,
) -> jboolean { ) -> jboolean {
let res = panic::catch_unwind(|| { let res = panic::catch_unwind(|| {
let db_cache = utils::java_string_to_rust(&env, db_cache); let db_cache = block_db(&env, db_cache)?;
let db_data = utils::java_string_to_rust(&env, db_data); let db_data = wallet_db(&env, db_data)?;
match scan_cached_blocks(&Network, &db_cache, &db_data, Some(limit.try_into().unwrap())) { match scan_cached_blocks(&NETWORK, &db_cache, &db_data, Some(limit as u32)) {
Ok(()) => Ok(JNI_TRUE), Ok(()) => Ok(JNI_TRUE),
Err(e) => Err(format_err!("Error while scanning blocks: {}", e)), Err(e) => Err(format_err!("Error while scanning blocks: {}", e)),
} }
@ -658,7 +680,7 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_parseTransa
for data in input_tx_data.data.iter() { for data in input_tx_data.data.iter() {
let mut tx = TransparentTransaction::new(); let mut tx = TransparentTransaction::new();
let parsed = Transaction::read(&data[..])?; let parsed = Transaction::read(&data[..])?;
tx.set_expiryHeight(u32::from(parsed.expiry_height)); tx.set_expiryHeight(parsed.expiry_height.into());
// Note: the wrong value is returned here (negative numbers) // Note: the wrong value is returned here (negative numbers)
tx.set_value(i64::from(parsed.value_balance)); tx.set_value(i64::from(parsed.value_balance));
tx.set_hasShieldedSpends(parsed.shielded_spends.len() > 0); tx.set_hasShieldedSpends(parsed.shielded_spends.len() > 0);
@ -668,7 +690,9 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_parseTransa
match vout.script_pubkey.address() { match vout.script_pubkey.address() {
// NOTE : this logic below doesn't work. No address is parsed. // NOTE : this logic below doesn't work. No address is parsed.
Some(TransparentAddress::PublicKey(hash)) => { Some(TransparentAddress::PublicKey(hash)) => {
tx.set_toAddress(hash.to_base58check(&B58_PUBKEY_ADDRESS_PREFIX, &[])); tx.set_toAddress(
hash.to_base58check(&NETWORK.b58_pubkey_address_prefix(), &[]),
);
} }
_ => {} _ => {}
} }
@ -701,7 +725,9 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_tool_DerivationTool_deriveT
let address_sk = ext_t_key let address_sk = ext_t_key
.derive_private_key(KeyIndex::hardened_from_normalize_index(44).unwrap()) .derive_private_key(KeyIndex::hardened_from_normalize_index(44).unwrap())
.unwrap() .unwrap()
.derive_private_key(KeyIndex::hardened_from_normalize_index(COIN_TYPE).unwrap()) .derive_private_key(
KeyIndex::hardened_from_normalize_index(NETWORK.coin_type()).unwrap(),
)
.unwrap() .unwrap()
.derive_private_key(KeyIndex::hardened_from_normalize_index(0).unwrap()) .derive_private_key(KeyIndex::hardened_from_normalize_index(0).unwrap())
.unwrap() .unwrap()
@ -716,7 +742,7 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_tool_DerivationTool_deriveT
hash160.update(Sha256::digest(&pk.serialize()[..].to_vec())); hash160.update(Sha256::digest(&pk.serialize()[..].to_vec()));
let address_string = hash160 let address_string = hash160
.finalize() .finalize()
.to_base58check(&B58_PUBKEY_ADDRESS_PREFIX, &[]); .to_base58check(&NETWORK.b58_pubkey_address_prefix(), &[]);
let output = env let output = env
.new_string(address_string) .new_string(address_string)
@ -734,15 +760,16 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_decryptAndS
tx: jbyteArray, tx: jbyteArray,
) -> jboolean { ) -> jboolean {
let res = panic::catch_unwind(|| { let res = panic::catch_unwind(|| {
let db_data = utils::java_string_to_rust(&env, db_data); let db_data = wallet_db(&env, db_data)?;
let tx_bytes = env.convert_byte_array(tx).unwrap(); let tx_bytes = env.convert_byte_array(tx).unwrap();
let tx = Transaction::read(&tx_bytes[..])?; let tx = Transaction::read(&tx_bytes[..])?;
match decrypt_and_store_transaction(&db_data, &Network, &tx) { match decrypt_and_store_transaction(&NETWORK, &db_data, &tx) {
Ok(()) => Ok(JNI_TRUE), Ok(()) => Ok(JNI_TRUE),
Err(e) => Err(format_err!("Error while decrypting transaction: {}", e)), Err(e) => Err(format_err!("Error while decrypting transaction: {}", e)),
} }
}); });
unwrap_exc_or(&env, res, JNI_FALSE) unwrap_exc_or(&env, res, JNI_FALSE)
} }
@ -751,7 +778,7 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_createToAdd
env: JNIEnv<'_>, env: JNIEnv<'_>,
_: JClass<'_>, _: JClass<'_>,
db_data: JString<'_>, db_data: JString<'_>,
consensus_branch_id: jlong, _: jlong, // was: consensus_branch_id; this is now derived from target/anchor height
account: jint, account: jint,
extsk: JString<'_>, extsk: JString<'_>,
to: JString<'_>, to: JString<'_>,
@ -761,7 +788,7 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_createToAdd
output_params: JString<'_>, output_params: JString<'_>,
) -> jlong { ) -> jlong {
let res = panic::catch_unwind(|| { let res = panic::catch_unwind(|| {
let db_data = utils::java_string_to_rust(&env, db_data); let db_data = wallet_db(&env, db_data)?;
let account = if account >= 0 { let account = if account >= 0 {
account as u32 account as u32
} else { } else {
@ -778,17 +805,19 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_createToAdd
let spend_params = utils::java_string_to_rust(&env, spend_params); let spend_params = utils::java_string_to_rust(&env, spend_params);
let output_params = utils::java_string_to_rust(&env, output_params); let output_params = utils::java_string_to_rust(&env, output_params);
let extsk = match decode_extended_spending_key(HRP_SAPLING_EXTENDED_SPENDING_KEY, &extsk) { let extsk =
Ok(Some(extsk)) => extsk, match decode_extended_spending_key(NETWORK.hrp_sapling_extended_spending_key(), &extsk)
Ok(None) => { {
return Err(format_err!("ExtendedSpendingKey is for the wrong network")); Ok(Some(extsk)) => extsk,
} Ok(None) => {
Err(e) => { return Err(format_err!("ExtendedSpendingKey is for the wrong network"));
return Err(format_err!("Invalid ExtendedSpendingKey: {}", e)); }
} Err(e) => {
}; return Err(format_err!("Invalid ExtendedSpendingKey: {}", e));
}
};
let to = match RecipientAddress::decode(&Network, &to) { let to = match RecipientAddress::decode(&NETWORK, &to) {
Some(to) => to, Some(to) => to,
None => { None => {
return Err(format_err!("Address is for the wrong network")); return Err(format_err!("Address is for the wrong network"));
@ -799,20 +828,13 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_createToAdd
let prover = LocalTxProver::new(Path::new(&spend_params), Path::new(&output_params)); let prover = LocalTxProver::new(Path::new(&spend_params), Path::new(&output_params));
let branch_id = match BranchId::try_from(consensus_branch_id as u32) {
Ok(branch) => branch,
Err(e) => {
return Err(format_err!("Invalid consensus branch id: {}", e));
}
};
// let branch = if // let branch = if
create_to_address( create_spend_to_address(
&db_data, &db_data,
&Network, &NETWORK,
branch_id,
prover, prover,
(account, &extsk), AccountId(account),
&extsk,
&to, &to,
value, value,
memo, memo,
@ -830,7 +852,7 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_branchIdFor
height: jint, height: jint,
) -> jint { ) -> jint {
let res = panic::catch_unwind(|| { let res = panic::catch_unwind(|| {
let branch: BranchId = BranchId::for_height::<Network>(&Network, BlockHeight::from(height as u32)); let branch: BranchId = BranchId::for_height(&NETWORK, BlockHeight::from(height as u32));
let branch_id: u32 = u32::from(branch); let branch_id: u32 = u32::from(branch);
debug!("For height {} found consensus branch {:?}", height, branch); debug!("For height {} found consensus branch {:?}", height, branch);
Ok(branch_id as i32) Ok(branch_id as i32)

View File

@ -1,4 +1,4 @@
// This file is generated by rust-protobuf 2.17.0. Do not edit // This file is generated by rust-protobuf 2.18.1. Do not edit
// @generated // @generated
// https://github.com/rust-lang/rust-clippy/issues/702 // https://github.com/rust-lang/rust-clippy/issues/702
@ -21,7 +21,7 @@
/// Generated files are compatible only with the same version /// Generated files are compatible only with the same version
/// of protobuf runtime. /// of protobuf runtime.
// const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_2_17_0; // const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_2_18_1;
#[derive(PartialEq,Clone,Default)] #[derive(PartialEq,Clone,Default)]
pub struct TransactionDataList { pub struct TransactionDataList {

View File

@ -44,10 +44,10 @@ pub fn unwrap_exc_or<T>(env: &JNIEnv, res: ExceptionResult<T>, error_val: T) ->
} }
} }
// Same as `unwrap_exc_or` but returns default value. // // Same as `unwrap_exc_or` but returns default value.
pub fn unwrap_exc_or_default<T: Default>(env: &JNIEnv, res: ExceptionResult<T>) -> T { // pub fn unwrap_exc_or_default<T: Default>(env: &JNIEnv, res: ExceptionResult<T>) -> T {
unwrap_exc_or(env, res, T::default()) // unwrap_exc_or(env, res, T::default())
} // }
// Calls a corresponding `JNIEnv` method, so exception will be thrown when execution returns to // Calls a corresponding `JNIEnv` method, so exception will be thrown when execution returns to
// the Java side. // the Java side.