2018-11-28 09:19:43 -08:00
#[ macro_use ]
extern crate log ;
2021-02-16 13:02:50 -08:00
use std ::convert ::{ TryFrom , TryInto } ;
use std ::panic ;
use std ::path ::Path ;
use std ::ptr ;
2021-03-31 23:23:41 -07:00
use std ::str ::FromStr ;
2021-02-16 13:02:50 -08:00
2020-09-22 08:14:56 -07:00
use android_logger ::Config ;
2019-02-11 18:56:17 -08:00
use failure ::format_err ;
2019-02-07 04:58:33 -08:00
use jni ::{
JNIEnv ,
2020-12-17 23:26:48 -08:00
objects ::{ JClass , JString } ,
sys ::{ jboolean , jbyteArray , jint , jlong , JNI_FALSE , JNI_TRUE , jobjectArray , jstring } ,
2019-02-07 04:58:33 -08:00
} ;
2019-02-07 04:56:04 -08:00
use log ::Level ;
use zcash_client_backend ::{
2020-12-17 23:26:48 -08:00
address ::RecipientAddress ,
2021-03-10 10:31:55 -08:00
data_api ::{
chain ::{ scan_cached_blocks , validate_chain } ,
error ::Error ,
wallet ::{ create_spend_to_address , decrypt_and_store_transaction } ,
2021-03-31 23:23:41 -07:00
WalletRead ,
2021-03-10 10:31:55 -08:00
} ,
2019-11-17 20:45:05 -08:00
encoding ::{
2021-02-16 13:02:50 -08:00
AddressCodec , decode_extended_full_viewing_key ,
decode_extended_spending_key , encode_extended_full_viewing_key , encode_extended_spending_key ,
encode_payment_address ,
2019-11-17 20:45:05 -08:00
} ,
2021-02-16 13:02:50 -08:00
keys ::{
2021-03-31 23:23:41 -07:00
derive_secret_key_from_seed , derive_public_key_from_seed ,
derive_transparent_address_from_public_key , derive_transparent_address_from_secret_key ,
2021-02-16 13:02:50 -08:00
spending_key , Wif ,
} ,
wallet ::{ AccountId , OvkPolicy , WalletTransparentOutput } ,
2019-02-07 04:56:04 -08:00
} ;
2021-02-25 10:15:09 -08:00
use zcash_client_backend ::data_api ::wallet ::{ shield_funds , ANCHOR_OFFSET } ;
2019-04-10 10:39:06 -07:00
use zcash_client_sqlite ::{
2021-02-16 13:02:50 -08:00
BlockDB ,
2021-01-26 23:19:12 -08:00
error ::SqliteClientError ,
2021-02-16 13:02:50 -08:00
NoteId ,
2021-03-31 06:36:46 -07:00
wallet ::init ::{ init_accounts_table , init_blocks_table , init_wallet_db } ,
wallet ::{ put_received_transparent_utxo , delete_utxos_above } ,
wallet ::rewind_to_height ,
WalletDB ,
2019-04-10 10:39:06 -07:00
} ;
use zcash_primitives ::{
2019-11-17 20:45:05 -08:00
block ::BlockHash ,
2021-02-16 13:02:50 -08:00
consensus ::{ BlockHeight , BranchId , Parameters } ,
2021-03-10 10:31:55 -08:00
legacy ::TransparentAddress ,
2021-02-16 13:02:50 -08:00
transaction ::{
components ::{ Amount , OutPoint } ,
Transaction
} ,
2020-09-22 07:51:13 -07:00
zip32 ::ExtendedFullViewingKey ,
2021-03-31 06:27:14 -07:00
memo ::{
Memo , MemoBytes
}
2019-04-10 10:39:06 -07:00
} ;
2020-06-09 19:14:22 -07:00
#[ cfg(feature = " mainnet " ) ]
2021-02-16 13:02:50 -08:00
use zcash_primitives ::consensus ::{ MAIN_NETWORK , MainNetwork } ;
2020-12-17 23:26:48 -08:00
#[ cfg(not(feature = " mainnet " )) ]
2021-02-16 13:02:50 -08:00
use zcash_primitives ::consensus ::{ TEST_NETWORK , TestNetwork } ;
use zcash_proofs ::prover ::LocalTxProver ;
2021-03-31 23:23:41 -07:00
use secp256k1 ::key ::{ SecretKey , PublicKey } ;
2020-08-13 18:03:19 -07:00
2021-02-16 13:02:50 -08:00
use crate ::utils ::exception ::unwrap_exc_or ;
2020-08-13 18:03:19 -07:00
2020-12-17 23:26:48 -08:00
mod utils ;
2020-07-31 23:12:15 -07:00
#[ cfg(debug_assertions) ]
fn print_debug_state ( ) {
debug! ( " WARNING! Debugging enabled! This will likely slow things down 10X! " ) ;
}
#[ cfg(not(debug_assertions)) ]
fn print_debug_state ( ) {
debug! ( " Release enabled (congrats, this is NOT a debug build). " ) ;
}
2021-03-10 10:31:55 -08:00
#[ cfg(feature = " mainnet " ) ]
pub const NETWORK : MainNetwork = MAIN_NETWORK ;
#[ cfg(not(feature = " mainnet " )) ]
pub const NETWORK : TestNetwork = TEST_NETWORK ;
2021-01-26 23:19:12 -08:00
fn wallet_db < P : Parameters > ( env : & JNIEnv < '_ > , params : P , db_data : JString < '_ > ) -> Result < WalletDB < P > , failure ::Error > {
WalletDB ::for_path ( utils ::java_string_to_rust ( & env , db_data ) , params )
2021-03-10 10:31:55 -08:00
. 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 ) )
}
2019-02-07 04:56:04 -08:00
#[ no_mangle ]
2020-06-10 00:08:19 -07:00
pub unsafe extern " C " fn Java_cash_z_ecc_android_sdk_jni_RustBackend_initLogs (
2019-02-11 07:11:09 -08:00
_env : JNIEnv < '_ > ,
_ : JClass < '_ > ,
) {
2019-02-07 04:56:04 -08:00
android_logger ::init_once (
2020-09-22 08:14:56 -07:00
Config ::default ( )
. with_min_level ( Level ::Debug )
. with_tag ( " cash.z.rust.logs " ) ,
2019-02-07 04:56:04 -08:00
) ;
log_panics ::init ( ) ;
debug! ( " logs have been initialized successfully " ) ;
2020-07-31 23:12:15 -07:00
print_debug_state ( )
2019-02-07 04:56:04 -08:00
}
2018-11-28 09:19:43 -08:00
2019-02-07 04:56:04 -08:00
#[ no_mangle ]
2020-06-10 00:08:19 -07:00
pub unsafe extern " C " fn Java_cash_z_ecc_android_sdk_jni_RustBackend_initDataDb (
2019-02-11 07:11:09 -08:00
env : JNIEnv < '_ > ,
_ : JClass < '_ > ,
db_data : JString < '_ > ,
2019-02-07 04:56:04 -08:00
) -> jboolean {
2019-02-11 18:56:17 -08:00
let res = panic ::catch_unwind ( | | {
2021-03-10 10:31:55 -08:00
let db_path = utils ::java_string_to_rust ( & env , db_data ) ;
2021-01-26 23:19:12 -08:00
WalletDB ::for_path ( db_path , NETWORK )
. and_then ( | db | init_wallet_db ( & db ) )
2019-02-11 18:56:17 -08:00
. map ( | ( ) | JNI_TRUE )
. map_err ( | e | format_err! ( " Error while initializing data DB: {} " , e ) )
} ) ;
unwrap_exc_or ( & env , res , JNI_FALSE )
2019-02-07 04:56:04 -08:00
}
2018-11-28 09:19:43 -08:00
2019-11-17 20:45:05 -08:00
#[ no_mangle ]
2020-09-11 00:23:08 -07:00
pub unsafe extern " C " fn Java_cash_z_ecc_android_sdk_jni_RustBackend_initAccountsTableWithKeys (
env : JNIEnv < '_ > ,
_ : JClass < '_ > ,
db_data : JString < '_ > ,
extfvks_arr : jobjectArray ,
2021-03-31 23:23:41 -07:00
extpubs_arr : jobjectArray ,
2020-09-11 00:23:08 -07:00
) -> jboolean {
let res = panic ::catch_unwind ( | | {
2021-01-26 23:19:12 -08:00
let db_data = wallet_db ( & env , NETWORK , db_data ) ? ;
2020-10-01 13:22:29 -07:00
// TODO: avoid all this unwrapping and also surface errors, better
2020-09-11 00:23:08 -07:00
let count = env . get_array_length ( extfvks_arr ) . unwrap ( ) ;
let extfvks = ( 0 .. count )
. map ( | i | env . get_object_array_element ( extfvks_arr , i ) )
. map ( | jstr | utils ::java_string_to_rust ( & env , jstr . unwrap ( ) . into ( ) ) )
2020-09-22 07:44:31 -07:00
. map ( | vkstr | {
2021-03-10 10:31:55 -08:00
decode_extended_full_viewing_key (
NETWORK . hrp_sapling_extended_full_viewing_key ( ) ,
& vkstr ,
)
. unwrap ( )
. unwrap ( )
2020-09-22 07:44:31 -07:00
} )
2020-09-11 00:23:08 -07:00
. collect ::< Vec < _ > > ( ) ;
2021-03-31 23:23:41 -07:00
let taddrs :Vec < _ > = ( 0 .. count )
. map ( | i | env . get_object_array_element ( extpubs_arr , i ) )
. map ( | jstr | utils ::java_string_to_rust ( & env , jstr . unwrap ( ) . into ( ) ) )
. map ( | extpub_str | PublicKey ::from_str ( & extpub_str ) . unwrap ( ) )
. map ( | pk | derive_transparent_address_from_public_key ( pk ) )
. collect ( ) ;
match init_accounts_table ( & db_data , & extfvks , & taddrs ) {
2020-09-11 00:23:08 -07:00
Ok ( ( ) ) = > Ok ( JNI_TRUE ) ,
Err ( e ) = > Err ( format_err! ( " Error while initializing accounts: {} " , e ) ) ,
}
} ) ;
unwrap_exc_or ( & env , res , JNI_FALSE )
}
2020-09-11 00:33:25 -07:00
#[ no_mangle ]
pub unsafe extern " C " fn Java_cash_z_ecc_android_sdk_tool_DerivationTool_deriveExtendedSpendingKeys (
2019-11-17 20:45:05 -08:00
env : JNIEnv < '_ > ,
_ : JClass < '_ > ,
seed : jbyteArray ,
accounts : jint ,
) -> jobjectArray {
let res = panic ::catch_unwind ( | | {
let seed = env . convert_byte_array ( seed ) . unwrap ( ) ;
let accounts = if accounts > 0 {
accounts as u32
} else {
return Err ( format_err! ( " accounts argument must be greater than zero " ) ) ;
} ;
let extsks : Vec < _ > = ( 0 .. accounts )
2021-03-10 10:31:55 -08:00
. map ( | account | spending_key ( & seed , NETWORK . coin_type ( ) , account ) )
2019-11-17 20:45:05 -08:00
. collect ( ) ;
Ok ( utils ::rust_vec_to_java (
& env ,
extsks ,
" java/lang/String " ,
| env , extsk | {
env . new_string ( encode_extended_spending_key (
2021-03-10 10:31:55 -08:00
NETWORK . hrp_sapling_extended_spending_key ( ) ,
2019-11-17 20:45:05 -08:00
& extsk ,
) )
} ,
| env | env . new_string ( " " ) ,
) )
} ) ;
unwrap_exc_or ( & env , res , ptr ::null_mut ( ) )
}
#[ no_mangle ]
2021-03-31 23:23:41 -07:00
pub unsafe extern " C " fn Java_cash_z_ecc_android_sdk_tool_DerivationTool_deriveUnifiedViewingKeysFromSeed (
2019-11-17 20:45:05 -08:00
env : JNIEnv < '_ > ,
_ : JClass < '_ > ,
seed : jbyteArray ,
accounts : jint ,
) -> jobjectArray {
let res = panic ::catch_unwind ( | | {
let seed = env . convert_byte_array ( seed ) . unwrap ( ) ;
let accounts = if accounts > 0 {
accounts as u32
} else {
return Err ( format_err! ( " accounts argument must be greater than zero " ) ) ;
} ;
let extfvks : Vec < _ > = ( 0 .. accounts )
2021-03-10 10:31:55 -08:00
. map ( | account | {
2021-03-31 23:23:41 -07:00
encode_extended_full_viewing_key (
NETWORK . hrp_sapling_extended_full_viewing_key ( ) ,
& ExtendedFullViewingKey ::from ( & spending_key ( & seed , NETWORK . coin_type ( ) , account ) )
)
2021-03-10 10:31:55 -08:00
} )
2019-11-17 20:45:05 -08:00
. collect ( ) ;
2021-03-31 23:23:41 -07:00
let extpubs : Vec < _ > = ( 0 .. accounts )
. map ( | account | {
let pk = derive_public_key_from_seed ( & NETWORK , & seed , AccountId ( account ) , 0 ) . unwrap ( ) ;
hex ::encode ( & pk . serialize ( ) )
} )
. collect ( ) ;
Ok ( utils ::rust_vec_to_java_2d (
2019-11-17 20:45:05 -08:00
& env ,
extfvks ,
2021-03-31 23:23:41 -07:00
extpubs ,
| env , extfvkstr | {
env . new_string ( extfvkstr )
2019-11-17 20:45:05 -08:00
} ,
| env | env . new_string ( " " ) ,
) )
} ) ;
unwrap_exc_or ( & env , res , ptr ::null_mut ( ) )
}
2020-02-11 16:57:57 -08:00
#[ no_mangle ]
2020-09-11 00:33:25 -07:00
pub unsafe extern " C " fn Java_cash_z_ecc_android_sdk_tool_DerivationTool_deriveShieldedAddressFromSeed (
2020-02-11 16:57:57 -08:00
env : JNIEnv < '_ > ,
_ : JClass < '_ > ,
seed : jbyteArray ,
account_index : jint ,
) -> jstring {
let res = panic ::catch_unwind ( | | {
let seed = env . convert_byte_array ( seed ) . unwrap ( ) ;
let account_index = if account_index > = 0 {
account_index as u32
} else {
return Err ( format_err! ( " accountIndex argument must be positive " ) ) ;
} ;
2021-03-10 10:31:55 -08:00
let address = spending_key ( & seed , NETWORK . coin_type ( ) , account_index )
2020-02-12 05:39:30 -08:00
. default_address ( )
. unwrap ( )
. 1 ;
2021-03-10 10:31:55 -08:00
let address_str = encode_payment_address ( NETWORK . hrp_sapling_payment_address ( ) , & address ) ;
2020-02-12 05:39:30 -08:00
let output = env
. new_string ( address_str )
. expect ( " Couldn't create Java string! " ) ;
2020-02-11 16:57:57 -08:00
Ok ( output . into_inner ( ) )
} ) ;
unwrap_exc_or ( & env , res , ptr ::null_mut ( ) )
}
#[ no_mangle ]
2020-09-11 00:33:25 -07:00
pub unsafe extern " C " fn Java_cash_z_ecc_android_sdk_tool_DerivationTool_deriveShieldedAddressFromViewingKey (
2020-02-11 16:57:57 -08:00
env : JNIEnv < '_ > ,
_ : JClass < '_ > ,
extfvk_string : JString < '_ > ,
) -> jstring {
let res = panic ::catch_unwind ( | | {
let extfvk_string = utils ::java_string_to_rust ( & env , extfvk_string ) ;
let extfvk = match decode_extended_full_viewing_key (
2021-03-10 10:31:55 -08:00
NETWORK . hrp_sapling_extended_full_viewing_key ( ) ,
2020-02-11 16:57:57 -08:00
& extfvk_string ,
) {
Ok ( Some ( extfvk ) ) = > extfvk ,
Ok ( None ) = > {
2020-07-27 11:39:43 -07:00
return Err ( format_err! ( " Failed to parse viewing key string in order to derive the address. Deriving a viewing key from the string returned no results. Encoding was valid but type was incorrect. " ) ) ;
2020-02-11 16:57:57 -08:00
}
Err ( e ) = > {
return Err ( format_err! (
" Error while deriving viewing key from string input: {} " ,
e
) ) ;
}
} ;
2020-02-12 05:39:30 -08:00
let address = extfvk . default_address ( ) . unwrap ( ) . 1 ;
2021-03-10 10:31:55 -08:00
let address_str = encode_payment_address ( NETWORK . hrp_sapling_payment_address ( ) , & address ) ;
2020-02-12 05:39:30 -08:00
let output = env
. new_string ( address_str )
. expect ( " Couldn't create Java string! " ) ;
2020-02-11 16:57:57 -08:00
Ok ( output . into_inner ( ) )
} ) ;
unwrap_exc_or ( & env , res , ptr ::null_mut ( ) )
}
2019-11-17 20:45:05 -08:00
#[ no_mangle ]
2020-09-11 00:33:25 -07:00
pub unsafe extern " C " fn Java_cash_z_ecc_android_sdk_tool_DerivationTool_deriveExtendedFullViewingKey (
2019-11-17 20:45:05 -08:00
env : JNIEnv < '_ > ,
_ : JClass < '_ > ,
extsk_string : JString < '_ > ,
) -> jobjectArray {
let res = panic ::catch_unwind ( | | {
let extsk_string = utils ::java_string_to_rust ( & env , extsk_string ) ;
let extfvk = match decode_extended_spending_key (
2021-03-10 10:31:55 -08:00
NETWORK . hrp_sapling_extended_spending_key ( ) ,
2019-11-17 20:45:05 -08:00
& extsk_string ,
) {
Ok ( Some ( extsk ) ) = > ExtendedFullViewingKey ::from ( & extsk ) ,
Ok ( None ) = > {
return Err ( format_err! ( " Deriving viewing key from spending key returned no results. Encoding was valid but type was incorrect. " ) ) ;
}
Err ( e ) = > {
return Err ( format_err! (
" Error while deriving viewing key from spending key: {} " ,
e
) ) ;
}
} ;
let output = env
. new_string ( encode_extended_full_viewing_key (
2021-03-10 10:31:55 -08:00
NETWORK . hrp_sapling_extended_full_viewing_key ( ) ,
2019-11-17 20:45:05 -08:00
& extfvk ,
) )
. expect ( " Couldn't create Java string! " ) ;
Ok ( output . into_inner ( ) )
} ) ;
unwrap_exc_or ( & env , res , ptr ::null_mut ( ) )
}
2019-02-07 04:56:04 -08:00
#[ no_mangle ]
2020-06-10 00:08:19 -07:00
pub unsafe extern " C " fn Java_cash_z_ecc_android_sdk_jni_RustBackend_initBlocksTable (
2019-02-11 07:11:09 -08:00
env : JNIEnv < '_ > ,
_ : JClass < '_ > ,
db_data : JString < '_ > ,
2019-02-07 04:56:04 -08:00
height : jint ,
2019-05-02 15:40:58 -07:00
hash_string : JString < '_ > ,
2019-02-07 04:56:04 -08:00
time : jlong ,
2019-02-22 06:52:03 -08:00
sapling_tree_string : JString < '_ > ,
2019-02-07 04:56:04 -08:00
) -> jboolean {
2019-02-11 18:56:17 -08:00
let res = panic ::catch_unwind ( | | {
2021-01-26 23:19:12 -08:00
let db_data = wallet_db ( & env , NETWORK , db_data ) ? ;
2019-05-02 15:40:58 -07:00
let hash = {
let mut hash = hex ::decode ( utils ::java_string_to_rust ( & env , hash_string ) ) . unwrap ( ) ;
hash . reverse ( ) ;
BlockHash ::from_slice ( & hash )
} ;
2019-02-11 18:56:17 -08:00
let time = if time > = 0 & & time < = jlong ::from ( u32 ::max_value ( ) ) {
time as u32
} else {
return Err ( format_err! ( " time argument must fit in a u32 " ) ) ;
} ;
2019-02-22 06:52:03 -08:00
let sapling_tree =
hex ::decode ( utils ::java_string_to_rust ( & env , sapling_tree_string ) ) . unwrap ( ) ;
2019-02-11 18:56:17 -08:00
2019-11-17 20:45:05 -08:00
debug! ( " initializing blocks table with height {} " , height ) ;
2021-03-10 10:31:55 -08:00
match init_blocks_table ( & db_data , height . try_into ( ) ? , hash , time , & sapling_tree ) {
2019-02-11 18:56:17 -08:00
Ok ( ( ) ) = > Ok ( JNI_TRUE ) ,
Err ( e ) = > Err ( format_err! ( " Error while initializing blocks table: {} " , e ) ) ,
2019-01-14 16:31:26 -08:00
}
2019-02-11 18:56:17 -08:00
} ) ;
unwrap_exc_or ( & env , res , JNI_FALSE )
2019-02-07 04:56:04 -08:00
}
2019-01-14 16:31:26 -08:00
2019-02-07 04:56:04 -08:00
#[ no_mangle ]
2021-02-16 13:02:50 -08:00
pub unsafe extern " C " fn Java_cash_z_ecc_android_sdk_jni_RustBackend_getShieldedAddress (
2019-02-11 07:11:09 -08:00
env : JNIEnv < '_ > ,
_ : JClass < '_ > ,
db_data : JString < '_ > ,
2019-02-07 04:56:04 -08:00
account : jint ,
) -> jstring {
2019-02-11 18:56:17 -08:00
let res = panic ::catch_unwind ( | | {
2021-01-26 23:19:12 -08:00
let db_data = wallet_db ( & env , NETWORK , db_data ) ? ;
2021-03-10 10:31:55 -08:00
let account = AccountId ( account . try_into ( ) ? ) ;
2021-01-26 23:19:12 -08:00
match ( & db_data ) . get_address ( account ) {
2021-03-10 10:31:55 -08:00
Ok ( Some ( addr ) ) = > {
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! " ) ;
2019-02-11 18:56:17 -08:00
Ok ( output . into_inner ( ) )
2019-01-29 18:20:53 -08:00
}
2021-03-10 10:31:55 -08:00
Ok ( None ) = > Err ( format_err! (
" No payment address was available for account {:?} " ,
account
) ) ,
2019-02-11 18:56:17 -08:00
Err ( e ) = > Err ( format_err! ( " Error while fetching address: {} " , e ) ) ,
2019-02-07 04:56:04 -08:00
}
2019-02-11 18:56:17 -08:00
} ) ;
2021-03-10 10:31:55 -08:00
2019-02-11 18:56:17 -08:00
unwrap_exc_or ( & env , res , ptr ::null_mut ( ) )
2019-02-07 04:56:04 -08:00
}
2018-11-22 05:54:25 -08:00
2019-06-04 07:15:19 -07:00
#[ no_mangle ]
2020-06-10 00:08:19 -07:00
pub unsafe extern " C " fn Java_cash_z_ecc_android_sdk_jni_RustBackend_isValidShieldedAddress (
2019-06-04 07:15:19 -07:00
env : JNIEnv < '_ > ,
_ : JClass < '_ > ,
addr : JString < '_ > ,
) -> jboolean {
let res = panic ::catch_unwind ( | | {
let addr = utils ::java_string_to_rust ( & env , addr ) ;
2021-03-10 10:31:55 -08:00
match RecipientAddress ::decode ( & NETWORK , & addr ) {
2019-07-10 11:55:38 -07:00
Some ( addr ) = > match addr {
2019-06-04 07:15:19 -07:00
RecipientAddress ::Shielded ( _ ) = > Ok ( JNI_TRUE ) ,
RecipientAddress ::Transparent ( _ ) = > Ok ( JNI_FALSE ) ,
2019-08-29 10:04:53 -07:00
} ,
None = > Err ( format_err! ( " Address is for the wrong network " ) ) ,
2019-06-04 07:15:19 -07:00
}
} ) ;
unwrap_exc_or ( & env , res , JNI_FALSE )
}
#[ no_mangle ]
2020-06-10 00:08:19 -07:00
pub unsafe extern " C " fn Java_cash_z_ecc_android_sdk_jni_RustBackend_isValidTransparentAddress (
2019-06-04 07:15:19 -07:00
env : JNIEnv < '_ > ,
_ : JClass < '_ > ,
addr : JString < '_ > ,
) -> jboolean {
let res = panic ::catch_unwind ( | | {
let addr = utils ::java_string_to_rust ( & env , addr ) ;
2021-03-10 10:31:55 -08:00
match RecipientAddress ::decode ( & NETWORK , & addr ) {
2019-07-10 11:55:38 -07:00
Some ( addr ) = > match addr {
2019-06-04 07:15:19 -07:00
RecipientAddress ::Shielded ( _ ) = > Ok ( JNI_FALSE ) ,
RecipientAddress ::Transparent ( _ ) = > Ok ( JNI_TRUE ) ,
2019-08-29 10:04:53 -07:00
} ,
None = > Err ( format_err! ( " Address is for the wrong network " ) ) ,
2019-06-04 07:15:19 -07:00
}
} ) ;
unwrap_exc_or ( & env , res , JNI_FALSE )
}
2019-02-07 04:56:04 -08:00
#[ no_mangle ]
2020-06-10 00:08:19 -07:00
pub unsafe extern " C " fn Java_cash_z_ecc_android_sdk_jni_RustBackend_getBalance (
2019-02-11 07:11:09 -08:00
env : JNIEnv < '_ > ,
_ : JClass < '_ > ,
db_data : JString < '_ > ,
2019-02-07 04:56:04 -08:00
account : jint ,
) -> jlong {
2019-02-11 18:56:17 -08:00
let res = panic ::catch_unwind ( | | {
2021-01-26 23:19:12 -08:00
let db_data = wallet_db ( & env , NETWORK , db_data ) ? ;
2021-03-10 10:31:55 -08:00
let account = AccountId ( account . try_into ( ) ? ) ;
2019-02-11 18:56:17 -08:00
2021-01-26 23:19:12 -08:00
( & db_data )
. get_target_and_anchor_heights ( )
. map_err ( | e | format_err! ( " Error while fetching anchor height: {} " , e ) )
. and_then ( | opt_anchor | {
opt_anchor
. map ( | ( h , _ ) | h )
. ok_or ( format_err! ( " height not available; scan required. " ) )
} )
2021-02-16 13:02:50 -08:00
. and_then ( | anchor | {
2021-01-26 23:19:12 -08:00
( & db_data )
2021-02-16 13:02:50 -08:00
. get_balance_at ( account , anchor )
2021-01-26 23:19:12 -08:00
. map_err ( | e | format_err! ( " Error while fetching verified balance: {} " , e ) )
} )
. map ( | amount | amount . into ( ) )
2019-02-11 18:56:17 -08:00
} ) ;
unwrap_exc_or ( & env , res , - 1 )
2019-02-07 04:56:04 -08:00
}
2018-12-04 08:46:24 -08:00
2021-02-16 13:02:50 -08:00
#[ no_mangle ]
pub unsafe extern " C " fn Java_cash_z_ecc_android_sdk_jni_RustBackend_getVerifiedTransparentBalance (
env : JNIEnv < '_ > ,
_ : JClass < '_ > ,
db_data : JString < '_ > ,
address : JString < '_ > ,
) -> jlong {
let res = panic ::catch_unwind ( | | {
let db_data = wallet_db ( & env , NETWORK , db_data ) ? ;
let addr = utils ::java_string_to_rust ( & env , address ) ;
let taddr = TransparentAddress ::decode ( & NETWORK , & addr ) . unwrap ( ) ;
let amount = ( & db_data )
. get_target_and_anchor_heights ( )
. map_err ( | e | format_err! ( " Error while fetching anchor height: {} " , e ) )
. and_then ( | opt_anchor | {
opt_anchor
. map ( | ( h , _ ) | h )
. ok_or ( format_err! ( " height not available; scan required. " ) )
} )
. and_then ( | anchor | {
( & db_data )
2021-02-25 10:15:09 -08:00
. get_unspent_transparent_utxos ( & taddr , anchor - ANCHOR_OFFSET )
2021-02-16 13:02:50 -08:00
. map_err ( | e | format_err! ( " Error while fetching verified balance: {} " , e ) )
} ) ?
. iter ( )
. map ( | utxo | utxo . value )
. sum ::< Amount > ( ) ;
Ok ( amount . into ( ) )
} ) ;
unwrap_exc_or ( & env , res , - 1 )
}
#[ no_mangle ]
pub unsafe extern " C " fn Java_cash_z_ecc_android_sdk_jni_RustBackend_getTotalTransparentBalance (
env : JNIEnv < '_ > ,
_ : JClass < '_ > ,
db_data : JString < '_ > ,
address : JString < '_ > ,
) -> jlong {
let res = panic ::catch_unwind ( | | {
let db_data = wallet_db ( & env , NETWORK , db_data ) ? ;
let addr = utils ::java_string_to_rust ( & env , address ) ;
let taddr = TransparentAddress ::decode ( & NETWORK , & addr ) . unwrap ( ) ;
let amount = ( & db_data )
. get_target_and_anchor_heights ( )
. map_err ( | e | format_err! ( " Error while fetching anchor height: {} " , e ) )
. and_then ( | opt_anchor | {
opt_anchor
. map ( | ( h , _ ) | h )
. ok_or ( format_err! ( " height not available; scan required. " ) )
} )
. and_then ( | anchor | {
( & db_data )
. get_unspent_transparent_utxos ( & taddr , anchor )
. map_err ( | e | format_err! ( " Error while fetching verified balance: {} " , e ) )
} ) ?
. iter ( )
. map ( | utxo | utxo . value )
. sum ::< Amount > ( ) ;
Ok ( amount . into ( ) )
} ) ;
unwrap_exc_or ( & env , res , - 1 )
}
2019-02-18 17:45:38 -08:00
#[ no_mangle ]
2020-06-10 00:08:19 -07:00
pub unsafe extern " C " fn Java_cash_z_ecc_android_sdk_jni_RustBackend_getVerifiedBalance (
2019-02-18 17:45:38 -08:00
env : JNIEnv < '_ > ,
_ : JClass < '_ > ,
db_data : JString < '_ > ,
account : jint ,
) -> jlong {
let res = panic ::catch_unwind ( | | {
2021-01-26 23:19:12 -08:00
let db_data = wallet_db ( & env , NETWORK , db_data ) ? ;
2021-03-10 10:31:55 -08:00
let account = AccountId ( account . try_into ( ) ? ) ;
( & db_data )
. get_target_and_anchor_heights ( )
. 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 )
2021-01-26 23:19:12 -08:00
. get_balance_at ( account , anchor )
2021-03-10 10:31:55 -08:00
. map_err ( | e | format_err! ( " Error while fetching verified balance: {} " , e ) )
} )
. map ( | amount | amount . into ( ) )
2019-02-18 17:45:38 -08:00
} ) ;
2021-03-10 10:31:55 -08:00
2019-02-18 17:45:38 -08:00
unwrap_exc_or ( & env , res , - 1 )
}
2019-02-08 07:23:21 -08:00
#[ no_mangle ]
2020-06-10 00:08:19 -07:00
pub unsafe extern " C " fn Java_cash_z_ecc_android_sdk_jni_RustBackend_getReceivedMemoAsUtf8 (
2019-02-11 07:11:09 -08:00
env : JNIEnv < '_ > ,
_ : JClass < '_ > ,
db_data : JString < '_ > ,
2019-02-08 07:23:21 -08:00
id_note : jlong ,
) -> jstring {
2019-02-11 18:56:17 -08:00
let res = panic ::catch_unwind ( | | {
2021-01-26 23:19:12 -08:00
let db_data = wallet_db ( & env , NETWORK , db_data ) ? ;
2019-02-11 18:56:17 -08:00
2021-03-31 06:27:14 -07:00
let memo = ( & db_data )
. get_memo ( NoteId ::ReceivedNoteId ( id_note ) )
. map_err ( | e | format_err! ( " An error occurred retrieving the memo, {} " , e ) )
. and_then ( | memo | {
match memo {
Memo ::Empty = > Ok ( " " . to_string ( ) ) ,
Memo ::Text ( memo ) = > Ok ( memo . into ( ) ) ,
_ = > Err ( format_err! ( " This memo does not contain UTF-8 text " ) ) ,
}
} ) ? ;
2019-02-11 18:56:17 -08:00
let output = env . new_string ( memo ) . expect ( " Couldn't create Java string! " ) ;
Ok ( output . into_inner ( ) )
} ) ;
unwrap_exc_or ( & env , res , ptr ::null_mut ( ) )
2019-02-08 07:23:21 -08:00
}
#[ no_mangle ]
2020-06-10 00:08:19 -07:00
pub unsafe extern " C " fn Java_cash_z_ecc_android_sdk_jni_RustBackend_getSentMemoAsUtf8 (
2019-02-11 07:11:09 -08:00
env : JNIEnv < '_ > ,
_ : JClass < '_ > ,
db_data : JString < '_ > ,
2019-02-08 07:23:21 -08:00
id_note : jlong ,
) -> jstring {
2019-02-11 18:56:17 -08:00
let res = panic ::catch_unwind ( | | {
2021-01-26 23:19:12 -08:00
let db_data = wallet_db ( & env , NETWORK , db_data ) ? ;
2019-02-11 18:56:17 -08:00
2021-03-10 10:31:55 -08:00
let memo = ( & db_data )
2021-03-31 06:27:14 -07:00
. get_memo ( NoteId ::SentNoteId ( id_note ) )
. map_err ( | e | format_err! ( " An error occurred retrieving the memo, {} " , e ) )
. and_then ( | memo | {
match memo {
Memo ::Empty = > Ok ( " " . to_string ( ) ) ,
Memo ::Text ( memo ) = > Ok ( memo . into ( ) ) ,
_ = > Err ( format_err! ( " This memo does not contain UTF-8 text " ) ) ,
}
} ) ? ;
2019-02-11 18:56:17 -08:00
let output = env . new_string ( memo ) . expect ( " Couldn't create Java string! " ) ;
Ok ( output . into_inner ( ) )
} ) ;
2021-03-10 10:31:55 -08:00
2019-02-11 18:56:17 -08:00
unwrap_exc_or ( & env , res , ptr ::null_mut ( ) )
2019-02-08 07:23:21 -08:00
}
2019-05-02 15:40:58 -07:00
#[ no_mangle ]
2020-06-10 00:08:19 -07:00
pub unsafe extern " C " fn Java_cash_z_ecc_android_sdk_jni_RustBackend_validateCombinedChain (
2019-05-02 15:40:58 -07:00
env : JNIEnv < '_ > ,
_ : JClass < '_ > ,
db_cache : JString < '_ > ,
db_data : JString < '_ > ,
) -> jint {
let res = panic ::catch_unwind ( | | {
2021-03-10 10:31:55 -08:00
let block_db = block_db ( & env , db_cache ) ? ;
2021-01-26 23:19:12 -08:00
let db_data = wallet_db ( & env , NETWORK , db_data ) ? ;
2021-03-10 10:31:55 -08:00
let validate_from = ( & db_data )
. get_max_height_hash ( )
. map_err ( | e | format_err! ( " Error while validating chain: {} " , e ) ) ? ;
let val_res = validate_chain ( & NETWORK , & block_db , validate_from ) ;
2019-05-02 15:40:58 -07:00
2021-03-10 10:31:55 -08:00
if let Err ( e ) = val_res {
2021-01-26 23:19:12 -08:00
match e {
SqliteClientError ::BackendError ( Error ::InvalidChain ( upper_bound , _ ) ) = > {
2021-03-10 10:31:55 -08:00
let upper_bound_u32 = u32 ::from ( upper_bound ) ;
2020-12-17 23:26:48 -08:00
Ok ( upper_bound_u32 as i32 )
}
2019-05-02 15:40:58 -07:00
_ = > Err ( format_err! ( " Error while validating chain: {} " , e ) ) ,
}
} else {
// All blocks are valid, so "highest invalid block height" is below genesis.
Ok ( - 1 )
}
} ) ;
2021-03-10 10:31:55 -08:00
2019-05-02 15:40:58 -07:00
unwrap_exc_or ( & env , res , 0 )
}
#[ no_mangle ]
2020-06-10 00:08:19 -07:00
pub unsafe extern " C " fn Java_cash_z_ecc_android_sdk_jni_RustBackend_rewindToHeight (
2019-05-02 15:40:58 -07:00
env : JNIEnv < '_ > ,
_ : JClass < '_ > ,
db_data : JString < '_ > ,
height : jint ,
) -> jboolean {
let res = panic ::catch_unwind ( | | {
2021-01-26 23:19:12 -08:00
let db_data = wallet_db ( & env , NETWORK , db_data ) ? ;
2021-03-10 10:31:55 -08:00
let height = BlockHeight ::try_from ( height ) ? ;
2021-03-31 06:27:14 -07:00
rewind_to_height ( & db_data , height )
. map ( | _ | 1 )
2021-03-10 10:31:55 -08:00
. map_err ( | e | format_err! ( " Error while rewinding data DB to height {}: {} " , height , e ) )
2021-03-31 06:27:14 -07:00
} ) ;
2021-03-10 10:31:55 -08:00
2019-05-02 15:40:58 -07:00
unwrap_exc_or ( & env , res , JNI_FALSE )
}
2019-02-07 04:56:04 -08:00
#[ no_mangle ]
2020-06-10 00:08:19 -07:00
pub unsafe extern " C " fn Java_cash_z_ecc_android_sdk_jni_RustBackend_scanBlocks (
2019-02-11 07:11:09 -08:00
env : JNIEnv < '_ > ,
_ : JClass < '_ > ,
db_cache : JString < '_ > ,
db_data : JString < '_ > ,
2019-02-07 04:56:04 -08:00
) -> jboolean {
2019-02-11 18:56:17 -08:00
let res = panic ::catch_unwind ( | | {
2021-03-10 10:31:55 -08:00
let db_cache = block_db ( & env , db_cache ) ? ;
2021-01-26 23:19:12 -08:00
let db_data = wallet_db ( & env , NETWORK , db_data ) ? ;
let mut db_data = db_data . get_update_ops ( ) ? ;
2019-02-11 18:56:17 -08:00
2021-01-26 23:19:12 -08:00
match scan_cached_blocks ( & NETWORK , & db_cache , & mut db_data , None ) {
2019-02-11 18:56:17 -08:00
Ok ( ( ) ) = > Ok ( JNI_TRUE ) ,
Err ( e ) = > Err ( format_err! ( " Error while scanning blocks: {} " , e ) ) ,
2018-11-22 05:54:25 -08:00
}
2019-02-11 18:56:17 -08:00
} ) ;
unwrap_exc_or ( & env , res , JNI_FALSE )
2019-02-07 04:56:04 -08:00
}
2018-12-04 08:36:47 -08:00
2021-02-16 13:02:50 -08:00
#[ no_mangle ]
pub unsafe extern " C " fn Java_cash_z_ecc_android_sdk_jni_RustBackend_putUtxo (
env : JNIEnv < '_ > ,
_ : JClass < '_ > ,
db_data : JString < '_ > ,
address : JString < '_ > ,
txid_bytes : jbyteArray ,
index : jint ,
script : jbyteArray ,
value : jlong ,
height : jint ,
) -> jboolean {
// debug!("For height {} found consensus branch {:?}", height, branch);
debug! ( " preparing to store UTXO in db_data " ) ;
let res = panic ::catch_unwind ( | | {
let txid_bytes = env . convert_byte_array ( txid_bytes ) . unwrap ( ) ;
let mut txid = [ 0 u8 ; 32 ] ;
txid . copy_from_slice ( & txid_bytes ) ;
let script = env . convert_byte_array ( script ) . unwrap ( ) ;
let db_data = wallet_db ( & env , NETWORK , db_data ) ? ;
let mut db_data = db_data . get_update_ops ( ) ? ;
let addr = utils ::java_string_to_rust ( & env , address ) ;
let address = TransparentAddress ::decode ( & NETWORK , & addr ) . unwrap ( ) ;
let output = WalletTransparentOutput {
address : address ,
outpoint : OutPoint ::new ( txid , index as u32 ) ,
script : script ,
value : Amount ::from_i64 ( value ) . unwrap ( ) ,
height : BlockHeight ::from ( height as u32 ) ,
} ;
debug! ( " Storing UTXO in db_data " ) ;
match put_received_transparent_utxo ( & mut db_data , & output ) {
Ok ( _ ) = > Ok ( JNI_TRUE ) ,
Err ( e ) = > Err ( format_err! ( " Error while inserting UTXO: {} " , e ) ) ,
}
} ) ;
unwrap_exc_or ( & env , res , JNI_FALSE )
}
2021-03-31 06:36:46 -07:00
#[ no_mangle ]
pub unsafe extern " C " fn Java_cash_z_ecc_android_sdk_jni_RustBackend_clearUtxos (
env : JNIEnv < '_ > ,
_ : JClass < '_ > ,
db_data : JString < '_ > ,
taddress : JString < '_ > ,
above_height : jint ,
) -> jint {
let res = panic ::catch_unwind ( | | {
let db_data = wallet_db ( & env , NETWORK , db_data ) ? ;
let mut db_data = db_data . get_update_ops ( ) ? ;
let addr = utils ::java_string_to_rust ( & env , taddress ) ;
let taddress = TransparentAddress ::decode ( & NETWORK , & addr ) . unwrap ( ) ;
let height = BlockHeight ::from ( above_height as u32 ) ;
debug! ( " clearing UTXOs that were found above height: {} " , above_height ) ;
match delete_utxos_above ( & mut db_data , & taddress , height ) {
Ok ( rows ) = > Ok ( rows as i32 ) ,
Err ( e ) = > Err ( format_err! ( " Error while clearing UTXOs: {} " , e ) ) ,
}
} ) ;
unwrap_exc_or ( & env , res , - 1 )
}
2020-01-14 09:56:03 -08:00
// ADDED BY ANDROID
#[ no_mangle ]
2020-06-10 00:08:19 -07:00
pub unsafe extern " C " fn Java_cash_z_ecc_android_sdk_jni_RustBackend_scanBlockBatch (
2020-01-14 09:56:03 -08:00
env : JNIEnv < '_ > ,
_ : JClass < '_ > ,
db_cache : JString < '_ > ,
db_data : JString < '_ > ,
2020-02-12 05:39:30 -08:00
limit : jint ,
2020-01-14 09:56:03 -08:00
) -> jboolean {
let res = panic ::catch_unwind ( | | {
2021-03-10 10:31:55 -08:00
let db_cache = block_db ( & env , db_cache ) ? ;
2021-02-10 21:42:52 -08:00
let db_data = wallet_db ( & env , NETWORK , db_data ) ? ;
let mut db_data = db_data . get_update_ops ( ) ? ;
2020-01-14 09:56:03 -08:00
2021-01-26 23:19:12 -08:00
match scan_cached_blocks ( & NETWORK , & db_cache , & mut db_data , Some ( limit as u32 ) ) {
2020-01-14 09:56:03 -08:00
Ok ( ( ) ) = > Ok ( JNI_TRUE ) ,
Err ( e ) = > Err ( format_err! ( " Error while scanning blocks: {} " , e ) ) ,
}
} ) ;
unwrap_exc_or ( & env , res , JNI_FALSE )
}
2020-08-13 18:03:19 -07:00
#[ no_mangle ]
2021-02-16 13:02:50 -08:00
pub unsafe extern " C " fn Java_cash_z_ecc_android_sdk_tool_DerivationTool_deriveTransparentSecretKeyFromSeed (
2020-08-13 18:03:19 -07:00
env : JNIEnv < '_ > ,
_ : JClass < '_ > ,
2021-02-16 13:02:50 -08:00
seed : jbyteArray ,
account : jint ,
index : jint ,
) -> jstring {
2020-08-13 18:03:19 -07:00
let res = panic ::catch_unwind ( | | {
2021-02-16 13:02:50 -08:00
let seed = env . convert_byte_array ( seed ) . unwrap ( ) ;
let account = if account > = 0 {
account as u32
} else {
return Err ( format_err! ( " account argument must be positive " ) ) ;
} ;
let index = if index > = 0 {
index as u32
} else {
return Err ( format_err! ( " index argument must be positive " ) ) ;
} ;
let sk = derive_secret_key_from_seed ( & NETWORK , & seed , AccountId ( account ) , index ) . unwrap ( ) ;
let sk_wif = Wif ::from_secret_key ( & sk , true ) ;
let output = env
. new_string ( sk_wif . 0 )
. expect ( " Couldn't create Java string for private key! " ) ;
Ok ( output . into_inner ( ) )
2020-08-13 18:03:19 -07:00
} ) ;
2021-02-16 13:02:50 -08:00
unwrap_exc_or ( & env , res , ptr ::null_mut ( ) )
2020-08-13 18:03:19 -07:00
}
#[ no_mangle ]
2020-09-11 00:33:25 -07:00
pub unsafe extern " C " fn Java_cash_z_ecc_android_sdk_tool_DerivationTool_deriveTransparentAddressFromSeed (
2020-08-13 18:03:19 -07:00
env : JNIEnv < '_ > ,
_ : JClass < '_ > ,
seed : jbyteArray ,
2021-02-16 13:02:50 -08:00
account : jint ,
index : jint ,
2020-08-13 18:03:19 -07:00
) -> jstring {
let res = panic ::catch_unwind ( | | {
let seed = env . convert_byte_array ( seed ) . unwrap ( ) ;
2021-02-16 13:02:50 -08:00
let account = if account > = 0 {
account as u32
} else {
return Err ( format_err! ( " account argument must be positive " ) ) ;
} ;
let index = if index > = 0 {
index as u32
} else {
return Err ( format_err! ( " index argument must be positive " ) ) ;
} ;
let sk = derive_secret_key_from_seed ( & NETWORK , & seed , AccountId ( account ) , index ) ;
let taddr = derive_transparent_address_from_secret_key ( sk . unwrap ( ) )
. encode ( & NETWORK ) ;
2020-08-13 18:03:19 -07:00
2021-02-16 13:02:50 -08:00
let output = env
. new_string ( taddr )
. expect ( " Couldn't create Java string for taddr! " ) ;
Ok ( output . into_inner ( ) )
} ) ;
unwrap_exc_or ( & env , res , ptr ::null_mut ( ) )
}
2020-08-13 18:03:19 -07:00
2021-02-16 13:02:50 -08:00
#[ no_mangle ]
2021-03-31 23:23:41 -07:00
pub unsafe extern " C " fn Java_cash_z_ecc_android_sdk_tool_DerivationTool_deriveTransparentAddressFromPrivKey (
2021-02-16 13:02:50 -08:00
env : JNIEnv < '_ > ,
_ : JClass < '_ > ,
secret_key : JString < '_ > ,
) -> jstring {
let res = panic ::catch_unwind ( | | {
let tsk_wif = utils ::java_string_to_rust ( & env , secret_key ) ;
let sk :SecretKey = ( & Wif ( tsk_wif ) ) . try_into ( ) . expect ( " invalid private key WIF " ) ;
let taddr =
derive_transparent_address_from_secret_key ( sk )
. encode ( & NETWORK ) ;
2020-08-13 18:03:19 -07:00
2020-09-22 07:44:31 -07:00
let output = env
2021-02-16 13:02:50 -08:00
. new_string ( taddr )
2020-09-22 07:44:31 -07:00
. expect ( " Couldn't create Java string! " ) ;
2021-02-16 13:02:50 -08:00
2020-08-13 18:03:19 -07:00
Ok ( output . into_inner ( ) )
} ) ;
unwrap_exc_or ( & env , res , ptr ::null_mut ( ) )
}
2021-03-31 23:23:41 -07:00
#[ no_mangle ]
pub unsafe extern " C " fn Java_cash_z_ecc_android_sdk_tool_DerivationTool_deriveTransparentAddressFromPubKey (
env : JNIEnv < '_ > ,
_ : JClass < '_ > ,
public_key : JString < '_ > ,
) -> jstring {
let res = panic ::catch_unwind ( | | {
let public_key_str = utils ::java_string_to_rust ( & env , public_key ) ;
let pk = PublicKey ::from_str ( & public_key_str ) ? ;
let taddr =
derive_transparent_address_from_public_key ( pk )
. encode ( & NETWORK ) ;
let output = env
. new_string ( taddr )
. expect ( " Couldn't create Java string! " ) ;
Ok ( output . into_inner ( ) )
} ) ;
unwrap_exc_or ( & env , res , ptr ::null_mut ( ) )
}
2020-03-12 21:41:17 -07:00
#[ no_mangle ]
2020-06-10 00:08:19 -07:00
pub unsafe extern " C " fn Java_cash_z_ecc_android_sdk_jni_RustBackend_decryptAndStoreTransaction (
2020-03-12 21:41:17 -07:00
env : JNIEnv < '_ > ,
_ : JClass < '_ > ,
db_data : JString < '_ > ,
tx : jbyteArray ,
) -> jboolean {
let res = panic ::catch_unwind ( | | {
2021-01-26 23:19:12 -08:00
let db_data = wallet_db ( & env , NETWORK , db_data ) ? ;
let mut db_data = db_data . get_update_ops ( ) ? ;
2020-03-12 21:41:17 -07:00
let tx_bytes = env . convert_byte_array ( tx ) . unwrap ( ) ;
let tx = Transaction ::read ( & tx_bytes [ .. ] ) ? ;
2021-01-26 23:19:12 -08:00
match decrypt_and_store_transaction ( & NETWORK , & mut db_data , & tx ) {
2020-03-12 21:41:17 -07:00
Ok ( ( ) ) = > Ok ( JNI_TRUE ) ,
Err ( e ) = > Err ( format_err! ( " Error while decrypting transaction: {} " , e ) ) ,
}
} ) ;
2021-03-10 10:31:55 -08:00
2020-03-12 21:41:17 -07:00
unwrap_exc_or ( & env , res , JNI_FALSE )
}
2019-02-07 04:56:04 -08:00
#[ no_mangle ]
2020-06-10 00:08:19 -07:00
pub unsafe extern " C " fn Java_cash_z_ecc_android_sdk_jni_RustBackend_createToAddress (
2019-02-11 07:11:09 -08:00
env : JNIEnv < '_ > ,
_ : JClass < '_ > ,
db_data : JString < '_ > ,
2021-03-10 10:31:55 -08:00
_ : jlong , // was: consensus_branch_id; this is now derived from target/anchor height
2019-02-07 04:56:04 -08:00
account : jint ,
2019-02-11 07:11:09 -08:00
extsk : JString < '_ > ,
to : JString < '_ > ,
2019-02-07 04:56:04 -08:00
value : jlong ,
2019-11-12 08:58:15 -08:00
memo : jbyteArray ,
2019-02-11 07:11:09 -08:00
spend_params : JString < '_ > ,
output_params : JString < '_ > ,
2019-02-07 04:56:04 -08:00
) -> jlong {
2019-02-11 18:56:17 -08:00
let res = panic ::catch_unwind ( | | {
2021-01-26 23:19:12 -08:00
let db_data = wallet_db ( & env , NETWORK , db_data ) ? ;
let mut db_data = db_data . get_update_ops ( ) ? ;
2019-02-11 18:56:17 -08:00
let account = if account > = 0 {
account as u32
} else {
return Err ( format_err! ( " account argument must be positive " ) ) ;
} ;
let extsk = utils ::java_string_to_rust ( & env , extsk ) ;
let to = utils ::java_string_to_rust ( & env , to ) ;
2019-11-17 20:45:05 -08:00
let value =
Amount ::from_i64 ( value ) . map_err ( | ( ) | format_err! ( " Invalid amount, out of range " ) ) ? ;
2019-08-29 10:57:05 -07:00
if value . is_negative ( ) {
2019-08-30 10:05:02 -07:00
return Err ( format_err! ( " Amount is negative " ) ) ;
2019-08-29 10:57:05 -07:00
}
2019-11-12 08:58:15 -08:00
let memo_bytes = env . convert_byte_array ( memo ) . unwrap ( ) ;
2019-02-11 18:56:17 -08:00
let spend_params = utils ::java_string_to_rust ( & env , spend_params ) ;
let output_params = utils ::java_string_to_rust ( & env , output_params ) ;
2021-03-10 10:31:55 -08:00
let extsk =
match decode_extended_spending_key ( NETWORK . hrp_sapling_extended_spending_key ( ) , & extsk )
{
Ok ( Some ( extsk ) ) = > extsk ,
Ok ( None ) = > {
return Err ( format_err! ( " ExtendedSpendingKey is for the wrong network " ) ) ;
}
Err ( e ) = > {
return Err ( format_err! ( " Invalid ExtendedSpendingKey: {} " , e ) ) ;
}
} ;
2019-04-10 10:39:06 -07:00
2021-03-10 10:31:55 -08:00
let to = match RecipientAddress ::decode ( & NETWORK , & to ) {
2019-07-10 11:55:38 -07:00
Some ( to ) = > to ,
None = > {
2019-05-24 08:06:19 -07:00
return Err ( format_err! ( " Address is for the wrong network " ) ) ;
2019-03-08 19:47:49 -08:00
}
2019-02-11 18:56:17 -08:00
} ;
2021-03-31 23:23:41 -07:00
let memo = Memo ::from_bytes ( & memo_bytes ) . map_err ( | _ | format_err! ( " Invalid memo " ) ) ? ;
2019-02-11 18:56:17 -08:00
2019-04-10 10:39:06 -07:00
let prover = LocalTxProver ::new ( Path ::new ( & spend_params ) , Path ::new ( & output_params ) ) ;
2019-02-11 18:56:17 -08:00
2020-06-09 19:14:22 -07:00
// let branch = if
2021-03-10 10:31:55 -08:00
create_spend_to_address (
2021-01-26 23:19:12 -08:00
& mut db_data ,
2021-03-10 10:31:55 -08:00
& NETWORK ,
2019-02-11 18:56:17 -08:00
prover ,
2021-03-10 10:31:55 -08:00
AccountId ( account ) ,
& extsk ,
2019-02-11 18:56:17 -08:00
& to ,
value ,
2021-03-31 06:27:14 -07:00
Some ( MemoBytes ::from ( & memo ) ) ,
2020-07-28 21:34:36 -07:00
OvkPolicy ::Sender ,
2019-02-11 18:56:17 -08:00
)
2019-12-13 07:58:20 -08:00
. map_err ( | e | format_err! ( " Error while creating transaction: {} " , e ) )
2019-02-11 18:56:17 -08:00
} ) ;
unwrap_exc_or ( & env , res , - 1 )
2018-11-20 09:59:08 -08:00
}
2020-06-09 19:14:22 -07:00
2021-02-16 13:02:50 -08:00
#[ no_mangle ]
pub unsafe extern " C " fn Java_cash_z_ecc_android_sdk_jni_RustBackend_shieldToAddress (
env : JNIEnv < '_ > ,
_ : JClass < '_ > ,
db_data : JString < '_ > ,
account : jint ,
extsk : JString < '_ > ,
tsk : JString < '_ > ,
memo : jbyteArray ,
spend_params : JString < '_ > ,
output_params : JString < '_ > ,
) -> jlong {
let res = panic ::catch_unwind ( | | {
let db_data = wallet_db ( & env , NETWORK , db_data ) ? ;
let mut db_data = db_data . get_update_ops ( ) ? ;
let account = if account = = 0 {
account as u32
} else {
return Err ( format_err! ( " account argument {} must be positive " , account ) ) ;
} ;
let extsk = utils ::java_string_to_rust ( & env , extsk ) ;
let tsk_wif = utils ::java_string_to_rust ( & env , tsk ) ;
let memo_bytes = env . convert_byte_array ( memo ) . unwrap ( ) ;
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 ( NETWORK . hrp_sapling_extended_spending_key ( ) , & extsk )
{
Ok ( Some ( extsk ) ) = > extsk ,
Ok ( None ) = > {
return Err ( format_err! ( " ExtendedSpendingKey is for the wrong network " ) ) ;
}
Err ( e ) = > {
return Err ( format_err! ( " Invalid ExtendedSpendingKey: {} " , e ) ) ;
}
} ;
let sk :SecretKey = ( & Wif ( tsk_wif ) ) . try_into ( ) . expect ( " invalid private key WIF " ) ;
let memo = Memo ::from_bytes ( & memo_bytes ) . unwrap ( ) ;
let prover = LocalTxProver ::new ( Path ::new ( & spend_params ) , Path ::new ( & output_params ) ) ;
shield_funds (
& mut db_data ,
& NETWORK ,
prover ,
AccountId ( account ) ,
& sk ,
& extsk ,
2021-03-31 06:27:14 -07:00
& MemoBytes ::from ( & memo ) ,
2021-02-16 13:02:50 -08:00
10
)
. map_err ( | e | format_err! ( " Error while shielding transaction: {} " , e ) )
} ) ;
unwrap_exc_or ( & env , res , - 1 )
}
2020-06-09 19:14:22 -07:00
#[ no_mangle ]
2020-06-10 00:08:19 -07:00
pub unsafe extern " C " fn Java_cash_z_ecc_android_sdk_jni_RustBackend_branchIdForHeight (
2020-06-09 19:14:22 -07:00
env : JNIEnv < '_ > ,
_ : JClass < '_ > ,
height : jint ,
) -> jint {
let res = panic ::catch_unwind ( | | {
2021-03-10 10:31:55 -08:00
let branch : BranchId = BranchId ::for_height ( & NETWORK , BlockHeight ::from ( height as u32 ) ) ;
2020-09-22 07:44:31 -07:00
let branch_id : u32 = u32 ::from ( branch ) ;
2020-06-09 19:14:22 -07:00
debug! ( " For height {} found consensus branch {:?} " , height , branch ) ;
Ok ( branch_id as i32 )
} ) ;
unwrap_exc_or ( & env , res , - 1 )
2020-06-09 20:28:21 -07:00
}