JniConverter.initAccountsTable()

This commit is contained in:
Jack Grigg 2019-01-30 01:41:50 +00:00
parent c26249373d
commit d9232c885d
No known key found for this signature in database
GPG Key ID: 1B8D649257DB0829
2 changed files with 127 additions and 7 deletions

View File

@ -4,6 +4,11 @@ class JniConverter {
external fun initDataDb(dbData: String): Boolean
external fun initAccountsTable(
dbData: String,
seed: ByteArray,
accounts: Int): Array<String>
external fun initBlocksTable(
dbData: String,
height: Int,

View File

@ -22,9 +22,13 @@ use sapling_crypto::{
primitives::{Diversifier, Note, PaymentAddress},
};
use zcash_client_backend::{
constants::HRP_SAPLING_PAYMENT_ADDRESS_TEST, encoding::encode_payment_address,
note_encryption::Memo, proto::compact_formats::CompactBlock, prover::TxProver,
transaction::Builder, welding_rig::scan_block,
constants::{HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY_TEST, HRP_SAPLING_PAYMENT_ADDRESS_TEST},
encoding::{encode_extended_full_viewing_key, encode_payment_address},
note_encryption::Memo,
proto::compact_formats::CompactBlock,
prover::TxProver,
transaction::Builder,
welding_rig::scan_block,
};
use zcash_primitives::{
merkle_tree::{CommitmentTree, IncrementalWitness},
@ -57,6 +61,14 @@ fn address_from_extfvk(extfvk: &ExtendedFullViewingKey) -> String {
fn init_data_database(db_data: &str) -> rusqlite::Result<()> {
let data = Connection::open(db_data)?;
data.execute(
"CREATE TABLE IF NOT EXISTS accounts (
account INTEGER PRIMARY KEY,
extfvk TEXT NOT NULL,
address TEXT NOT NULL
)",
NO_PARAMS,
)?;
data.execute(
"CREATE TABLE IF NOT EXISTS blocks (
height INTEGER PRIMARY KEY,
@ -90,6 +102,7 @@ fn init_data_database(db_data: &str) -> rusqlite::Result<()> {
memo BLOB,
spent INTEGER,
FOREIGN KEY (tx) REFERENCES transactions(id_tx),
FOREIGN KEY (account) REFERENCES accounts(account),
FOREIGN KEY (spent) REFERENCES transactions(id_tx),
CONSTRAINT tx_output UNIQUE (tx, output_index)
)",
@ -117,6 +130,7 @@ fn init_data_database(db_data: &str) -> rusqlite::Result<()> {
value INTEGER NOT NULL,
memo BLOB,
FOREIGN KEY (tx) REFERENCES transactions(id_tx),
FOREIGN KEY (from_account) REFERENCES accounts(account),
CONSTRAINT tx_output UNIQUE (tx, output_index)
)",
NO_PARAMS,
@ -124,6 +138,35 @@ fn init_data_database(db_data: &str) -> rusqlite::Result<()> {
Ok(())
}
fn init_accounts_table(db_data: &str, extfvks: &[ExtendedFullViewingKey]) -> Result<(), Error> {
let data = Connection::open(db_data)?;
let mut empty_check = data.prepare("SELECT * FROM accounts LIMIT 1")?;
if empty_check.exists(NO_PARAMS)? {
return Err(format_err!("accounts table is not empty"));
}
// Insert accounts atomically
data.execute("BEGIN IMMEDIATE", NO_PARAMS)?;
for (account, extfvk) in extfvks.iter().enumerate() {
let address = address_from_extfvk(extfvk);
let extfvk =
encode_extended_full_viewing_key(HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY_TEST, extfvk);
data.execute(
"INSERT INTO accounts (account, extfvk, address)
VALUES (?, ?, ?)",
&[
(account as u32).to_sql()?,
extfvk.to_sql()?,
address.to_sql()?,
],
)?;
}
data.execute("COMMIT", NO_PARAMS)?;
Ok(())
}
fn init_blocks_table(
db_data: &str,
height: i32,
@ -590,20 +633,25 @@ pub mod android {
use std::path::Path;
use zcash_client_backend::{
constants::{HRP_SAPLING_EXTENDED_SPENDING_KEY_TEST, HRP_SAPLING_PAYMENT_ADDRESS_TEST},
encoding::{decode_extended_spending_key, decode_payment_address},
encoding::{
decode_extended_spending_key, decode_payment_address, encode_extended_spending_key,
},
note_encryption::Memo,
prover::LocalTxProver,
};
use zcash_primitives::transaction::components::Amount;
use zip32::{ChildIndex, ExtendedFullViewingKey, ExtendedSpendingKey};
use self::android_logger::Filter;
use self::jni::objects::{JClass, JString};
use self::jni::sys::{jboolean, jbyteArray, jint, jlong, jstring, JNI_FALSE, JNI_TRUE};
use self::jni::sys::{
jboolean, jbyteArray, jint, jlong, jobjectArray, jsize, jstring, JNI_FALSE, JNI_TRUE,
};
use self::jni::JNIEnv;
use super::{
address_from_extfvk, extfvk_from_seed, get_balance, init_blocks_table, init_data_database,
scan_cached_blocks, send_to_address, SAPLING_CONSENSUS_BRANCH_ID,
address_from_extfvk, extfvk_from_seed, get_balance, init_accounts_table, init_blocks_table,
init_data_database, scan_cached_blocks, send_to_address, SAPLING_CONSENSUS_BRANCH_ID,
};
#[no_mangle]
@ -641,6 +689,73 @@ pub mod android {
}
}
#[no_mangle]
pub unsafe extern "C" fn Java_cash_z_wallet_sdk_jni_JniConverter_initAccountsTable(
env: JNIEnv,
_: JClass,
db_data: JString,
seed: jbyteArray,
accounts: jint,
) -> jobjectArray {
let db_data: String = env
.get_string(db_data)
.expect("Couldn't get Java string!")
.into();
let seed = env.convert_byte_array(seed).unwrap();
let ret = if accounts >= 0 {
let master = ExtendedSpendingKey::master(&seed);
let extsks: Vec<_> = (0..accounts as u32)
.map(|account| {
ExtendedSpendingKey::from_path(
&master,
&[
ChildIndex::Hardened(32),
ChildIndex::Hardened(1),
ChildIndex::Hardened(account),
],
)
})
.collect();
let extfvks: Vec<_> = extsks
.iter()
.map(|extsk| ExtendedFullViewingKey::from(extsk))
.collect();
match init_accounts_table(&db_data, &extfvks) {
Ok(()) => {
// Return the ExtendedSpendingKeys for the created accounts
extsks
}
Err(e) => {
error!("Error while initializing accounts: {}", e);
// Return an empty array to indicate an error
vec![]
}
}
} else {
error!("accounts argument must be positive");
// Return an empty array to indicate an error
vec![]
};
let jempty = env.new_string("").expect("Couldn't create Java string!");
let jret = env
.new_object_array(ret.len() as jsize, "java/lang/String", *jempty)
.expect("Couldn't create Java array!");
for (i, extsk) in ret.into_iter().enumerate() {
let jextsk = env
.new_string(encode_extended_spending_key(
HRP_SAPLING_EXTENDED_SPENDING_KEY_TEST,
&extsk,
))
.expect("Couldn't create Java string!");
env.set_object_array_element(jret, i as jsize, *jextsk)
.expect("Couldn't set Java array element!");
}
jret
}
#[no_mangle]
pub unsafe extern "C" fn Java_cash_z_wallet_sdk_jni_JniConverter_initBlocksTable(
env: JNIEnv,