2018-11-28 09:19:43 -08:00
#[ macro_use ]
extern crate log ;
2020-09-22 08:14:56 -07:00
use android_logger ::Config ;
2020-12-17 23:26:48 -08:00
use base58 ::ToBase58 ;
2019-02-11 18:56:17 -08:00
use failure ::format_err ;
2020-12-17 23:26:48 -08:00
use hdwallet ::{ ExtendedPrivKey , KeyIndex } ;
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 ;
2021-03-10 10:31:55 -08:00
use std ::convert ::{ TryFrom , TryInto } ;
use std ::panic ;
use std ::path ::Path ;
use std ::ptr ;
2019-02-07 04:56:04 -08:00
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 } ,
WalletRead , WalletWrite ,
} ,
2019-11-17 20:45:05 -08:00
encoding ::{
2020-07-27 11:39:43 -07:00
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
} ,
2019-04-10 10:39:06 -07:00
keys ::spending_key ,
2021-03-10 10:31:55 -08:00
wallet ::{ AccountId , OvkPolicy } ,
2019-02-07 04:56:04 -08:00
} ;
2019-04-10 10:39:06 -07:00
use zcash_client_sqlite ::{
2021-03-10 10:31:55 -08:00
wallet ::init ::{ init_accounts_table , init_blocks_table , init_data_database } ,
BlockDB , NoteId , WalletDB ,
2019-04-10 10:39:06 -07:00
} ;
use zcash_primitives ::{
2019-11-17 20:45:05 -08:00
block ::BlockHash ,
2021-03-10 10:31:55 -08:00
consensus ::{ BlockHeight , BranchId , Parameters } ,
legacy ::TransparentAddress ,
2019-11-17 20:45:05 -08:00
note_encryption ::Memo ,
2020-03-12 21:41:17 -07:00
transaction ::{ components ::Amount , Transaction } ,
2020-09-22 07:51:13 -07:00
zip32 ::ExtendedFullViewingKey ,
2019-04-10 10:39:06 -07:00
} ;
2020-06-09 19:14:22 -07:00
#[ cfg(feature = " mainnet " ) ]
2021-03-10 10:31:55 -08:00
use zcash_primitives ::consensus ::{ MainNetwork , MAIN_NETWORK } ;
2020-12-17 23:26:48 -08:00
#[ cfg(not(feature = " mainnet " )) ]
2021-03-10 10:31:55 -08:00
use zcash_primitives ::consensus ::{ TestNetwork , TEST_NETWORK } ;
2019-04-10 10:43:24 -07:00
2020-09-22 07:44:31 -07:00
use local_rpc_types ::{ TransactionDataList , TransparentTransaction , TransparentTransactionList } ;
2021-03-10 10:31:55 -08:00
use protobuf ::{ parse_from_bytes , Message } ;
use sha2 ::{ Digest , Sha256 } ;
2020-08-13 18:03:19 -07:00
2021-03-10 10:31:55 -08:00
use hdwallet ::{ ExtendedPrivKey , KeyIndex } ;
use secp256k1 ::{ PublicKey , Secp256k1 } ;
2020-08-13 18:03:19 -07:00
2020-12-17 23:26:48 -08:00
mod utils ;
// /////////////////////////////////////////////////////////////////////////////////////////////////
// Temporary Imports
mod local_rpc_types ;
2020-08-13 18:03:19 -07:00
// use crate::extended_key::{key_index::KeyIndex, ExtendedPrivKey, ExtendedPubKey, KeySeed};
// /////////////////////////////////////////////////////////////////////////////////////////////////
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 ;
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 ) )
}
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 ) ;
WalletDB ::for_path ( db_path )
. and_then ( | db | init_data_database ( & 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-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_initAccountsTable (
2019-02-11 07:11:09 -08:00
env : JNIEnv < '_ > ,
_ : JClass < '_ > ,
db_data : JString < '_ > ,
2019-02-07 04:56:04 -08:00
seed : jbyteArray ,
accounts : jint ,
) -> jobjectArray {
2019-02-11 18:56:17 -08:00
let res = panic ::catch_unwind ( | | {
2021-03-10 10:31:55 -08:00
let db_data = wallet_db ( & env , db_data ) ? ;
2019-02-11 18:56:17 -08:00
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 positive " ) ) ;
} ;
let extsks : Vec < _ > = ( 0 .. accounts )
2021-03-10 10:31:55 -08:00
. map ( | account | spending_key ( & seed , NETWORK . coin_type ( ) , account ) )
2019-02-07 04:56:04 -08:00
. collect ( ) ;
2019-02-07 05:01:54 -08:00
let extfvks : Vec < _ > = extsks . iter ( ) . map ( ExtendedFullViewingKey ::from ) . collect ( ) ;
2019-02-07 04:56:04 -08:00
2021-03-10 10:31:55 -08:00
init_accounts_table ( & db_data , & NETWORK , & extfvks )
. map ( | _ | {
2019-02-07 04:56:04 -08:00
// Return the ExtendedSpendingKeys for the created accounts
2021-03-10 10:31:55 -08:00
utils ::rust_vec_to_java (
2019-02-11 18:56:17 -08:00
& 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-02-11 18:56:17 -08:00
& extsk ,
) )
} ,
| env | env . new_string ( " " ) ,
2021-03-10 10:31:55 -08:00
)
} )
. map_err ( | e | format_err! ( " Error while initializing accounts: {} " , e ) )
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
}
2019-01-29 17:41:50 -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 ,
) -> jboolean {
let res = panic ::catch_unwind ( | | {
2021-03-10 10:31:55 -08:00
let db_data = wallet_db ( & env , 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-10 10:31:55 -08:00
match init_accounts_table ( & db_data , & NETWORK , & extfvks ) {
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 ]
2020-09-11 00:33:25 -07:00
pub unsafe extern " C " fn Java_cash_z_ecc_android_sdk_tool_DerivationTool_deriveExtendedFullViewingKeys (
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 | {
ExtendedFullViewingKey ::from ( & spending_key ( & seed , NETWORK . coin_type ( ) , account ) )
} )
2019-11-17 20:45:05 -08:00
. collect ( ) ;
Ok ( utils ::rust_vec_to_java (
& env ,
extfvks ,
" java/lang/String " ,
| env , extfvk | {
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 ,
) )
} ,
| 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-03-10 10:31:55 -08:00
let db_data = wallet_db ( & env , 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 ]
2020-06-10 00:08:19 -07:00
pub unsafe extern " C " fn Java_cash_z_ecc_android_sdk_jni_RustBackend_getAddress (
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-03-10 10:31:55 -08:00
let db_data = wallet_db ( & env , db_data ) ? ;
let account = AccountId ( account . try_into ( ) ? ) ;
match ( & db_data ) . get_address ( & NETWORK , account ) {
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-03-10 10:31:55 -08:00
let db_data = wallet_db ( & env , db_data ) ? ;
let account = AccountId ( account . try_into ( ) ? ) ;
2019-02-11 18:56:17 -08:00
2021-03-10 10:31:55 -08:00
match ( & db_data ) . get_balance ( account ) {
2019-08-29 10:04:53 -07:00
Ok ( balance ) = > Ok ( balance . into ( ) ) ,
2019-02-11 18:56:17 -08:00
Err ( e ) = > Err ( format_err! ( " Error while fetching balance: {} " , e ) ) ,
2018-12-04 08:46:24 -08:00
}
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
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-03-10 10:31:55 -08:00
let db_data = wallet_db ( & env , db_data ) ? ;
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 )
. get_verified_balance ( account , anchor )
. 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-03-10 10:31:55 -08:00
let db_data = wallet_db ( & env , db_data ) ? ;
2019-02-11 18:56:17 -08:00
2021-03-10 10:31:55 -08:00
let memo = match ( & db_data ) . get_received_memo_as_utf8 ( NoteId ( id_note ) ) {
2019-02-11 18:56:17 -08:00
Ok ( memo ) = > memo . unwrap_or_default ( ) ,
Err ( e ) = > return Err ( format_err! ( " Error while fetching memo: {} " , e ) ) ,
} ;
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-03-10 10:31:55 -08:00
let db_data = wallet_db ( & env , db_data ) ? ;
2019-02-11 18:56:17 -08:00
2021-03-10 10:31:55 -08:00
let memo = ( & db_data )
. get_sent_memo_as_utf8 ( NoteId ( id_note ) )
. map ( | memo | memo . unwrap_or_default ( ) )
. map_err ( | e | format_err! ( " Error while fetching memo: {} " , e ) ) ? ;
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 ) ? ;
let db_data = wallet_db ( & env , db_data ) ? ;
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 {
match e . 0 {
Error ::InvalidChain ( upper_bound , _ ) = > {
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-03-10 10:31:55 -08:00
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 ) ) ? ;
let height = BlockHeight ::try_from ( height ) ? ;
( & mut update_ops )
. transactionally ( | ops | ops . rewind_to_height ( & NETWORK , height ) )
. map ( | _ | JNI_TRUE )
. map_err ( | e | format_err! ( " Error while rewinding data DB to height {}: {} " , height , e ) )
2019-05-02 15:40:58 -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 ) ? ;
let db_data = wallet_db ( & env , db_data ) ? ;
2019-02-11 18:56:17 -08:00
2021-03-10 10:31:55 -08:00
match scan_cached_blocks ( & NETWORK , & db_cache , & 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
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 ) ? ;
let db_data = wallet_db ( & env , db_data ) ? ;
2020-01-14 09:56:03 -08:00
2021-03-10 10:31:55 -08:00
match scan_cached_blocks ( & NETWORK , & db_cache , & 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
// ////////////////////////////////////////////////////////////////////////////////////////////////
// PROOF-OF-CONCEPT FOR PROTOBUF COMMUNICATION WITH SDK
// ////////////////////////////////////////////////////////////////////////////////////////////////
#[ no_mangle ]
pub unsafe extern " C " fn Java_cash_z_ecc_android_sdk_jni_RustBackend_parseTransactionDataList (
env : JNIEnv < '_ > ,
_ : JClass < '_ > ,
tx_data_list : jbyteArray ,
) -> jbyteArray {
2020-09-22 07:51:13 -07:00
let err_val : Vec < u8 > = Vec ::new ( ) ;
let res_err = env . byte_array_from_slice ( & err_val ) . unwrap ( ) ;
2020-08-13 18:03:19 -07:00
let res = panic ::catch_unwind ( | | {
let tx_data_bytes = env . convert_byte_array ( tx_data_list ) ? ;
let input_tx_data = parse_from_bytes ::< TransactionDataList > ( & tx_data_bytes ) ? ;
let mut tx_list = TransparentTransactionList ::new ( ) ;
let mut txs = protobuf ::RepeatedField ::< TransparentTransaction > ::new ( ) ;
for data in input_tx_data . data . iter ( ) {
let mut tx = TransparentTransaction ::new ( ) ;
let parsed = Transaction ::read ( & data [ .. ] ) ? ;
2021-03-10 10:31:55 -08:00
tx . set_expiryHeight ( parsed . expiry_height . into ( ) ) ;
2020-08-13 18:03:19 -07:00
// Note: the wrong value is returned here (negative numbers)
tx . set_value ( i64 ::from ( parsed . value_balance ) ) ;
tx . set_hasShieldedSpends ( parsed . shielded_spends . len ( ) > 0 ) ;
tx . set_hasShieldedOutputs ( parsed . shielded_outputs . len ( ) > 0 ) ;
2020-09-22 07:51:13 -07:00
for ( _n , vout ) in parsed . vout . iter ( ) . enumerate ( ) {
2020-08-13 18:03:19 -07:00
match vout . script_pubkey . address ( ) {
// NOTE : this logic below doesn't work. No address is parsed.
Some ( TransparentAddress ::PublicKey ( hash ) ) = > {
2021-03-10 10:31:55 -08:00
tx . set_toAddress (
hash . to_base58check ( & NETWORK . b58_pubkey_address_prefix ( ) , & [ ] ) ,
) ;
2020-09-22 07:44:31 -07:00
}
2020-08-13 18:03:19 -07:00
_ = > { }
}
}
txs . push ( tx ) ;
}
tx_list . set_transactions ( txs ) ;
match env . byte_array_from_slice ( & tx_list . write_to_bytes ( ) ? ) {
Ok ( result ) = > Ok ( result ) ,
Err ( e ) = > Err ( format_err! ( " Error while parsing transaction: {} " , e ) ) ,
}
} ) ;
unwrap_exc_or ( & env , res , res_err )
}
#[ 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 ,
) -> jstring {
let res = panic ::catch_unwind ( | | {
let seed = env . convert_byte_array ( seed ) . unwrap ( ) ;
// modified from: https://github.com/adityapk00/zecwallet-light-cli/blob/master/lib/src/lightwallet.rs
let ext_t_key = ExtendedPrivKey ::with_seed ( & seed ) . unwrap ( ) ;
let address_sk = ext_t_key
2020-09-22 07:44:31 -07:00
. derive_private_key ( KeyIndex ::hardened_from_normalize_index ( 44 ) . unwrap ( ) )
. unwrap ( )
2021-03-10 10:31:55 -08:00
. derive_private_key (
KeyIndex ::hardened_from_normalize_index ( NETWORK . coin_type ( ) ) . unwrap ( ) ,
)
2020-09-22 07:44:31 -07:00
. unwrap ( )
. derive_private_key ( KeyIndex ::hardened_from_normalize_index ( 0 ) . unwrap ( ) )
. unwrap ( )
. derive_private_key ( KeyIndex ::Normal ( 0 ) )
. unwrap ( )
. derive_private_key ( KeyIndex ::Normal ( 0 ) )
. unwrap ( )
2020-08-13 18:03:19 -07:00
. private_key ;
let secp = Secp256k1 ::new ( ) ;
let pk = PublicKey ::from_secret_key ( & secp , & address_sk ) ;
let mut hash160 = ripemd160 ::Ripemd160 ::new ( ) ;
2020-09-25 06:59:55 -07:00
hash160 . update ( Sha256 ::digest ( & pk . serialize ( ) [ .. ] . to_vec ( ) ) ) ;
2020-09-22 07:44:31 -07:00
let address_string = hash160
2020-09-25 06:59:55 -07:00
. finalize ( )
2021-03-10 10:31:55 -08:00
. to_base58check ( & NETWORK . b58_pubkey_address_prefix ( ) , & [ ] ) ;
2020-08-13 18:03:19 -07:00
2020-09-22 07:44:31 -07:00
let output = env
. new_string ( address_string )
. expect ( " Couldn't create Java string! " ) ;
2020-08-13 18:03:19 -07:00
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-03-10 10:31:55 -08:00
let db_data = wallet_db ( & env , db_data ) ? ;
2020-03-12 21:41:17 -07:00
let tx_bytes = env . convert_byte_array ( tx ) . unwrap ( ) ;
let tx = Transaction ::read ( & tx_bytes [ .. ] ) ? ;
2021-03-10 10:31:55 -08:00
match decrypt_and_store_transaction ( & NETWORK , & 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-03-10 10:31:55 -08:00
let db_data = wallet_db ( & env , db_data ) ? ;
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
} ;
2019-11-12 08:58:15 -08:00
let memo = Memo ::from_bytes ( & memo_bytes ) ;
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 (
2019-02-11 18:56:17 -08:00
& 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 ,
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
#[ 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
}
2020-08-13 18:03:19 -07:00
//
// Helper code from: https://github.com/adityapk00/zecwallet-light-cli/blob/master/lib/src/lightwallet.rs
//
/// A trait for converting a [u8] to base58 encoded string.
pub trait ToBase58Check {
/// Converts a value of `self` to a base58 value, returning the owned string.
/// The version is a coin-specific prefix that is added.
/// The suffix is any bytes that we want to add at the end (like the "iscompressed" flag for
/// Secret key encoding)
fn to_base58check ( & self , version : & [ u8 ] , suffix : & [ u8 ] ) -> String ;
}
impl ToBase58Check for [ u8 ] {
fn to_base58check ( & self , version : & [ u8 ] , suffix : & [ u8 ] ) -> String {
let mut payload : Vec < u8 > = Vec ::new ( ) ;
payload . extend_from_slice ( version ) ;
payload . extend_from_slice ( self ) ;
payload . extend_from_slice ( suffix ) ;
let mut checksum = double_sha256 ( & payload ) ;
payload . append ( & mut checksum [ .. 4 ] . to_vec ( ) ) ;
payload . to_base58 ( )
}
}
pub fn double_sha256 ( payload : & [ u8 ] ) -> Vec < u8 > {
let h1 = Sha256 ::digest ( & payload ) ;
let h2 = Sha256 ::digest ( & h1 ) ;
h2 . to_vec ( )
2020-09-22 07:44:31 -07:00
}