Feature-flag transparent functionality in zcash_client_sqlite
This fixes the wasm32-wasi build issues by excluding the hdwallet dependencies which are not wasm32-wasi compatible.
This commit is contained in:
parent
86da9434ad
commit
cc58a21ad7
|
@ -2,15 +2,18 @@
|
||||||
|
|
||||||
use zcash_primitives::zip32::{ChildIndex, ExtendedSpendingKey};
|
use zcash_primitives::zip32::{ChildIndex, ExtendedSpendingKey};
|
||||||
|
|
||||||
|
use crate::wallet::AccountId;
|
||||||
|
|
||||||
|
use zcash_primitives::{legacy::TransparentAddress, zip32::ExtendedFullViewingKey};
|
||||||
|
|
||||||
#[cfg(feature = "transparent-inputs")]
|
#[cfg(feature = "transparent-inputs")]
|
||||||
use {
|
use {
|
||||||
crate::wallet::AccountId,
|
|
||||||
bs58::{self, decode::Error as Bs58Error},
|
bs58::{self, decode::Error as Bs58Error},
|
||||||
hdwallet::{ExtendedPrivKey, ExtendedPubKey, KeyIndex},
|
hdwallet::{ExtendedPrivKey, ExtendedPubKey, KeyIndex},
|
||||||
secp256k1::{key::PublicKey, key::SecretKey, Secp256k1},
|
secp256k1::{key::PublicKey, key::SecretKey, Secp256k1},
|
||||||
sha2::{Digest, Sha256},
|
sha2::{Digest, Sha256},
|
||||||
std::convert::TryInto,
|
std::convert::TryInto,
|
||||||
zcash_primitives::{consensus, legacy::TransparentAddress},
|
zcash_primitives::consensus,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Derives the ZIP 32 [`ExtendedSpendingKey`] for a given coin type and account from the
|
/// Derives the ZIP 32 [`ExtendedSpendingKey`] for a given coin type and account from the
|
||||||
|
@ -138,9 +141,57 @@ impl<'a> TryInto<SecretKey> for &'a Wif {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A set of viewing keys that are all associated with a single
|
||||||
|
/// ZIP-0032 account identifier.
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct UnifiedFullViewingKey {
|
||||||
|
account: AccountId,
|
||||||
|
transparent: Option<TransparentAddress>,
|
||||||
|
sapling: Option<ExtendedFullViewingKey>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UnifiedFullViewingKey {
|
||||||
|
/// Construct a new unified full viewing key, if the required components are present.
|
||||||
|
pub fn new(
|
||||||
|
account: AccountId,
|
||||||
|
transparent: Option<TransparentAddress>,
|
||||||
|
sapling: Option<ExtendedFullViewingKey>,
|
||||||
|
) -> Option<UnifiedFullViewingKey> {
|
||||||
|
if sapling.is_none() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(UnifiedFullViewingKey {
|
||||||
|
account,
|
||||||
|
transparent,
|
||||||
|
sapling,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the ZIP32 account identifier to which all component
|
||||||
|
/// keys are related.
|
||||||
|
pub fn account(&self) -> AccountId {
|
||||||
|
self.account
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the transparent component of the unified key.
|
||||||
|
// TODO: make this the pubkey rather than the address to
|
||||||
|
// permit child derivation
|
||||||
|
pub fn transparent(&self) -> Option<&TransparentAddress> {
|
||||||
|
self.transparent.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the Sapling extended full viewing key component of this
|
||||||
|
/// unified key.
|
||||||
|
pub fn sapling(&self) -> Option<&ExtendedFullViewingKey> {
|
||||||
|
self.sapling.as_ref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::spending_key;
|
use super::spending_key;
|
||||||
|
use crate::wallet::AccountId;
|
||||||
|
|
||||||
#[cfg(feature = "transparent-inputs")]
|
#[cfg(feature = "transparent-inputs")]
|
||||||
use {
|
use {
|
||||||
|
@ -149,12 +200,13 @@ mod tests {
|
||||||
derive_transparent_address_from_public_key, derive_transparent_address_from_secret_key,
|
derive_transparent_address_from_public_key, derive_transparent_address_from_secret_key,
|
||||||
Wif,
|
Wif,
|
||||||
},
|
},
|
||||||
crate::{encoding::AddressCodec, wallet::AccountId},
|
crate::encoding::AddressCodec,
|
||||||
secp256k1::key::SecretKey,
|
secp256k1::key::SecretKey,
|
||||||
std::convert::TryInto,
|
std::convert::TryInto,
|
||||||
zcash_primitives::consensus::MAIN_NETWORK,
|
zcash_primitives::consensus::MAIN_NETWORK,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(feature = "transparent-inputs")]
|
||||||
fn seed() -> Vec<u8> {
|
fn seed() -> Vec<u8> {
|
||||||
let seed_hex = "6ef5f84def6f4b9d38f466586a8380a38593bd47c8cda77f091856176da47f26b5bd1c8d097486e5635df5a66e820d28e1d73346f499801c86228d43f390304f";
|
let seed_hex = "6ef5f84def6f4b9d38f466586a8380a38593bd47c8cda77f091856176da47f26b5bd1c8d097486e5635df5a66e820d28e1d73346f499801c86228d43f390304f";
|
||||||
hex::decode(&seed_hex).unwrap()
|
hex::decode(&seed_hex).unwrap()
|
||||||
|
|
|
@ -23,8 +23,8 @@ rand_core = "0.6"
|
||||||
rusqlite = { version = "0.24", features = ["bundled", "time"] }
|
rusqlite = { version = "0.24", features = ["bundled", "time"] }
|
||||||
secp256k1 = { version = "0.20" }
|
secp256k1 = { version = "0.20" }
|
||||||
time = "0.2"
|
time = "0.2"
|
||||||
zcash_client_backend = { version = "0.5", path = "../zcash_client_backend", features = ["transparent-inputs"] }
|
zcash_client_backend = { version = "0.5", path = "../zcash_client_backend"}
|
||||||
zcash_primitives = { version = "0.5", path = "../zcash_primitives", features = ["transparent-inputs"] }
|
zcash_primitives = { version = "0.5", path = "../zcash_primitives"}
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tempfile = "3"
|
tempfile = "3"
|
||||||
|
@ -33,6 +33,7 @@ zcash_proofs = { version = "0.5", path = "../zcash_proofs" }
|
||||||
[features]
|
[features]
|
||||||
mainnet = []
|
mainnet = []
|
||||||
test-dependencies = ["zcash_client_backend/test-dependencies"]
|
test-dependencies = ["zcash_client_backend/test-dependencies"]
|
||||||
|
transparent-inputs = ["zcash_client_backend/transparent-inputs", "zcash_primitives/transparent-inputs"]
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
bench = false
|
bench = false
|
||||||
|
|
|
@ -60,6 +60,7 @@ use zcash_client_backend::{
|
||||||
|
|
||||||
use crate::error::SqliteClientError;
|
use crate::error::SqliteClientError;
|
||||||
|
|
||||||
|
#[cfg(feature = "transparent-inputs")]
|
||||||
use {
|
use {
|
||||||
zcash_client_backend::wallet::WalletTransparentOutput,
|
zcash_client_backend::wallet::WalletTransparentOutput,
|
||||||
zcash_primitives::legacy::TransparentAddress,
|
zcash_primitives::legacy::TransparentAddress,
|
||||||
|
@ -148,6 +149,7 @@ impl<P: consensus::Parameters> WalletDb<P> {
|
||||||
WHERE prevout_txid = :prevout_txid
|
WHERE prevout_txid = :prevout_txid
|
||||||
AND prevout_idx = :prevout_idx"
|
AND prevout_idx = :prevout_idx"
|
||||||
)?,
|
)?,
|
||||||
|
#[cfg(feature = "transparent-inputs")]
|
||||||
stmt_insert_received_transparent_utxo: self.conn.prepare(
|
stmt_insert_received_transparent_utxo: self.conn.prepare(
|
||||||
"INSERT INTO utxos (address, prevout_txid, prevout_idx, script, value_zat, height)
|
"INSERT INTO utxos (address, prevout_txid, prevout_idx, script, value_zat, height)
|
||||||
VALUES (:address, :prevout_txid, :prevout_idx, :script, :value_zat, :height)"
|
VALUES (:address, :prevout_txid, :prevout_idx, :script, :value_zat, :height)"
|
||||||
|
@ -299,6 +301,7 @@ impl<P: consensus::Parameters> WalletRead for WalletDb<P> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "transparent-inputs")]
|
||||||
fn get_unspent_transparent_outputs(
|
fn get_unspent_transparent_outputs(
|
||||||
&self,
|
&self,
|
||||||
address: &TransparentAddress,
|
address: &TransparentAddress,
|
||||||
|
@ -329,6 +332,7 @@ pub struct DataConnStmtCache<'a, P> {
|
||||||
stmt_mark_sapling_note_spent: Statement<'a>,
|
stmt_mark_sapling_note_spent: Statement<'a>,
|
||||||
stmt_mark_transparent_utxo_spent: Statement<'a>,
|
stmt_mark_transparent_utxo_spent: Statement<'a>,
|
||||||
|
|
||||||
|
#[cfg(feature = "transparent-inputs")]
|
||||||
stmt_insert_received_transparent_utxo: Statement<'a>,
|
stmt_insert_received_transparent_utxo: Statement<'a>,
|
||||||
stmt_delete_utxos: Statement<'a>,
|
stmt_delete_utxos: Statement<'a>,
|
||||||
stmt_insert_received_note: Statement<'a>,
|
stmt_insert_received_note: Statement<'a>,
|
||||||
|
@ -436,6 +440,7 @@ impl<'a, P: consensus::Parameters> WalletRead for DataConnStmtCache<'a, P> {
|
||||||
.select_spendable_sapling_notes(account, target_value, anchor_height)
|
.select_spendable_sapling_notes(account, target_value, anchor_height)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "transparent-inputs")]
|
||||||
fn get_unspent_transparent_outputs(
|
fn get_unspent_transparent_outputs(
|
||||||
&self,
|
&self,
|
||||||
address: &TransparentAddress,
|
address: &TransparentAddress,
|
||||||
|
@ -694,15 +699,17 @@ mod tests {
|
||||||
use protobuf::Message;
|
use protobuf::Message;
|
||||||
use rand_core::{OsRng, RngCore};
|
use rand_core::{OsRng, RngCore};
|
||||||
use rusqlite::params;
|
use rusqlite::params;
|
||||||
use secp256k1::key::SecretKey;
|
|
||||||
|
|
||||||
use zcash_client_backend::{
|
use zcash_client_backend::{
|
||||||
keys::{
|
keys::{spending_key, UnifiedFullViewingKey},
|
||||||
derive_secret_key_from_seed, derive_transparent_address_from_secret_key, spending_key,
|
|
||||||
},
|
|
||||||
proto::compact_formats::{CompactBlock, CompactOutput, CompactSpend, CompactTx},
|
proto::compact_formats::{CompactBlock, CompactOutput, CompactSpend, CompactTx},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(feature = "transparent-inputs")]
|
||||||
|
use zcash_client_backend::keys::{
|
||||||
|
derive_secret_key_from_seed, derive_transparent_address_from_secret_key,
|
||||||
|
};
|
||||||
|
|
||||||
use zcash_primitives::{
|
use zcash_primitives::{
|
||||||
block::BlockHash,
|
block::BlockHash,
|
||||||
consensus::{BlockHeight, Network, NetworkUpgrade, Parameters},
|
consensus::{BlockHeight, Network, NetworkUpgrade, Parameters},
|
||||||
|
@ -713,7 +720,7 @@ mod tests {
|
||||||
PaymentAddress,
|
PaymentAddress,
|
||||||
},
|
},
|
||||||
transaction::components::Amount,
|
transaction::components::Amount,
|
||||||
zip32::{ExtendedFullViewingKey, ExtendedSpendingKey},
|
zip32::ExtendedFullViewingKey,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{wallet::init::init_accounts_table, AccountId, WalletDb};
|
use crate::{wallet::init::init_accounts_table, AccountId, WalletDb};
|
||||||
|
@ -744,22 +751,26 @@ mod tests {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn derive_test_keys_from_seed(
|
|
||||||
seed: &[u8],
|
|
||||||
account: AccountId,
|
|
||||||
) -> (ExtendedSpendingKey, SecretKey) {
|
|
||||||
let extsk = spending_key(seed, network().coin_type(), account);
|
|
||||||
let tsk = derive_secret_key_from_seed(&network(), seed, account, 0).unwrap();
|
|
||||||
(extsk, tsk)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn init_test_accounts_table(
|
pub(crate) fn init_test_accounts_table(
|
||||||
db_data: &WalletDb<Network>,
|
db_data: &WalletDb<Network>,
|
||||||
) -> (ExtendedFullViewingKey, TransparentAddress) {
|
) -> (ExtendedFullViewingKey, Option<TransparentAddress>) {
|
||||||
let (extsk, tsk) = derive_test_keys_from_seed(&[0u8; 32], AccountId(0));
|
let seed = [0u8; 32];
|
||||||
|
|
||||||
|
let extsk = spending_key(&seed, network().coin_type(), AccountId(0));
|
||||||
let extfvk = ExtendedFullViewingKey::from(&extsk);
|
let extfvk = ExtendedFullViewingKey::from(&extsk);
|
||||||
let taddr = derive_transparent_address_from_secret_key(&tsk);
|
|
||||||
init_accounts_table(db_data, &[extfvk.clone()], &[taddr.clone()]).unwrap();
|
#[cfg(feature = "transparent-inputs")]
|
||||||
|
let taddr = {
|
||||||
|
let tsk = derive_secret_key_from_seed(&network(), &seed, AccountId(0), 0).unwrap();
|
||||||
|
Some(derive_transparent_address_from_secret_key(&tsk))
|
||||||
|
};
|
||||||
|
|
||||||
|
#[cfg(not(feature = "transparent-inputs"))]
|
||||||
|
let taddr = None;
|
||||||
|
|
||||||
|
let ufvk =
|
||||||
|
UnifiedFullViewingKey::new(AccountId(0), taddr.clone(), Some(extfvk.clone())).unwrap();
|
||||||
|
init_accounts_table(db_data, &[ufvk]).unwrap();
|
||||||
(extfvk, taddr)
|
(extfvk, taddr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,13 +37,13 @@ use zcash_client_backend::{
|
||||||
|
|
||||||
use crate::{error::SqliteClientError, DataConnStmtCache, NoteId, WalletDb, PRUNING_HEIGHT};
|
use crate::{error::SqliteClientError, DataConnStmtCache, NoteId, WalletDb, PRUNING_HEIGHT};
|
||||||
|
|
||||||
|
use {zcash_client_backend::encoding::AddressCodec, zcash_primitives::legacy::TransparentAddress};
|
||||||
|
|
||||||
|
#[cfg(feature = "transparent-inputs")]
|
||||||
use {
|
use {
|
||||||
crate::UtxoId,
|
crate::UtxoId,
|
||||||
zcash_client_backend::{encoding::AddressCodec, wallet::WalletTransparentOutput},
|
zcash_client_backend::wallet::WalletTransparentOutput,
|
||||||
zcash_primitives::{
|
zcash_primitives::{legacy::Script, transaction::components::TxOut},
|
||||||
legacy::{Script, TransparentAddress},
|
|
||||||
transaction::components::TxOut,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub mod init;
|
pub mod init;
|
||||||
|
@ -704,6 +704,7 @@ pub fn get_all_nullifiers<P>(
|
||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "transparent-inputs")]
|
||||||
pub fn get_unspent_transparent_outputs<P: consensus::Parameters>(
|
pub fn get_unspent_transparent_outputs<P: consensus::Parameters>(
|
||||||
wdb: &WalletDb<P>,
|
wdb: &WalletDb<P>,
|
||||||
address: &TransparentAddress,
|
address: &TransparentAddress,
|
||||||
|
@ -867,6 +868,7 @@ pub fn mark_transparent_utxo_spent<'a, P>(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "transparent-inputs")]
|
||||||
pub fn put_received_transparent_utxo<'a, P: consensus::Parameters>(
|
pub fn put_received_transparent_utxo<'a, P: consensus::Parameters>(
|
||||||
stmts: &mut DataConnStmtCache<'a, P>,
|
stmts: &mut DataConnStmtCache<'a, P>,
|
||||||
output: &WalletTransparentOutput,
|
output: &WalletTransparentOutput,
|
||||||
|
|
|
@ -1,15 +1,16 @@
|
||||||
//! Functions for initializing the various databases.
|
//! Functions for initializing the various databases.
|
||||||
|
|
||||||
use rusqlite::{types::ToSql, NO_PARAMS};
|
use rusqlite::{params, types::ToSql, NO_PARAMS};
|
||||||
|
|
||||||
use zcash_primitives::{
|
use zcash_primitives::{
|
||||||
block::BlockHash,
|
block::BlockHash,
|
||||||
consensus::{self, BlockHeight},
|
consensus::{self, BlockHeight},
|
||||||
legacy::TransparentAddress,
|
|
||||||
zip32::ExtendedFullViewingKey,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use zcash_client_backend::encoding::{encode_extended_full_viewing_key, AddressCodec};
|
use zcash_client_backend::{
|
||||||
|
encoding::{encode_extended_full_viewing_key, AddressCodec},
|
||||||
|
keys::UnifiedFullViewingKey,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{address_from_extfvk, error::SqliteClientError, WalletDb};
|
use crate::{address_from_extfvk, error::SqliteClientError, WalletDb};
|
||||||
|
|
||||||
|
@ -33,9 +34,9 @@ pub fn init_wallet_db<P>(wdb: &WalletDb<P>) -> Result<(), rusqlite::Error> {
|
||||||
wdb.conn.execute(
|
wdb.conn.execute(
|
||||||
"CREATE TABLE IF NOT EXISTS accounts (
|
"CREATE TABLE IF NOT EXISTS accounts (
|
||||||
account INTEGER PRIMARY KEY,
|
account INTEGER PRIMARY KEY,
|
||||||
extfvk TEXT NOT NULL,
|
extfvk TEXT,
|
||||||
address TEXT NOT NULL,
|
address TEXT,
|
||||||
transparent_address TEXT NOT NULL
|
transparent_address TEXT
|
||||||
)",
|
)",
|
||||||
NO_PARAMS,
|
NO_PARAMS,
|
||||||
)?;
|
)?;
|
||||||
|
@ -126,11 +127,11 @@ pub fn init_wallet_db<P>(wdb: &WalletDb<P>) -> Result<(), rusqlite::Error> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initialises the data database with the given [`ExtendedFullViewingKey`]s.
|
/// Initialises the data database with the given [`UnifiedFullViewingKey`]s.
|
||||||
///
|
///
|
||||||
/// The [`ExtendedFullViewingKey`]s are stored internally and used by other APIs such as
|
/// The [`UnifiedFullViewingKey`]s are stored internally and used by other APIs such as
|
||||||
/// [`get_address`], [`scan_cached_blocks`], and [`create_spend_to_address`]. `extfvks` **MUST**
|
/// [`get_address`], [`scan_cached_blocks`], and [`create_spend_to_address`]. `extfvks` **MUST**
|
||||||
/// be arranged in account-order; that is, the [`ExtendedFullViewingKey`] for ZIP 32
|
/// be arranged in account-order; that is, the [`UnifiedFullViewingKey`] for ZIP 32
|
||||||
/// account `i` **MUST** be at `extfvks[i]`.
|
/// account `i` **MUST** be at `extfvks[i]`.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
|
@ -144,7 +145,10 @@ pub fn init_wallet_db<P>(wdb: &WalletDb<P>) -> Result<(), rusqlite::Error> {
|
||||||
/// };
|
/// };
|
||||||
///
|
///
|
||||||
/// use zcash_client_backend::{
|
/// use zcash_client_backend::{
|
||||||
/// keys::{spending_key, derive_transparent_address_from_secret_key, derive_secret_key_from_seed},
|
/// keys::{
|
||||||
|
/// spending_key,
|
||||||
|
/// UnifiedFullViewingKey
|
||||||
|
/// },
|
||||||
/// wallet::AccountId,
|
/// wallet::AccountId,
|
||||||
/// };
|
/// };
|
||||||
///
|
///
|
||||||
|
@ -160,10 +164,9 @@ pub fn init_wallet_db<P>(wdb: &WalletDb<P>) -> Result<(), rusqlite::Error> {
|
||||||
/// let seed = [0u8; 32];
|
/// let seed = [0u8; 32];
|
||||||
/// let account = AccountId(0);
|
/// let account = AccountId(0);
|
||||||
/// let extsk = spending_key(&seed, Network::TestNetwork.coin_type(), account);
|
/// let extsk = spending_key(&seed, Network::TestNetwork.coin_type(), account);
|
||||||
/// let tsk = derive_secret_key_from_seed(&Network::TestNetwork, &seed, account, 0).unwrap();
|
|
||||||
/// let extfvk = ExtendedFullViewingKey::from(&extsk);
|
/// let extfvk = ExtendedFullViewingKey::from(&extsk);
|
||||||
/// let taddr = derive_transparent_address_from_secret_key(&tsk);
|
/// let ufvk = UnifiedFullViewingKey::new(account, None, Some(extfvk)).unwrap();
|
||||||
/// init_accounts_table(&db_data, &[extfvk], &[taddr]).unwrap();
|
/// init_accounts_table(&db_data, &[ufvk]).unwrap();
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// [`get_address`]: crate::wallet::get_address
|
/// [`get_address`]: crate::wallet::get_address
|
||||||
|
@ -171,12 +174,8 @@ pub fn init_wallet_db<P>(wdb: &WalletDb<P>) -> Result<(), rusqlite::Error> {
|
||||||
/// [`create_spend_to_address`]: zcash_client_backend::data_api::wallet::create_spend_to_address
|
/// [`create_spend_to_address`]: zcash_client_backend::data_api::wallet::create_spend_to_address
|
||||||
pub fn init_accounts_table<P: consensus::Parameters>(
|
pub fn init_accounts_table<P: consensus::Parameters>(
|
||||||
wdb: &WalletDb<P>,
|
wdb: &WalletDb<P>,
|
||||||
extfvks: &[ExtendedFullViewingKey],
|
keys: &[UnifiedFullViewingKey],
|
||||||
taddrs: &[TransparentAddress],
|
|
||||||
) -> Result<(), SqliteClientError> {
|
) -> Result<(), SqliteClientError> {
|
||||||
//TODO: make this a proper error?
|
|
||||||
assert!(extfvks.len() == taddrs.len());
|
|
||||||
|
|
||||||
let mut empty_check = wdb.conn.prepare("SELECT * FROM accounts LIMIT 1")?;
|
let mut empty_check = wdb.conn.prepare("SELECT * FROM accounts LIMIT 1")?;
|
||||||
if empty_check.exists(NO_PARAMS)? {
|
if empty_check.exists(NO_PARAMS)? {
|
||||||
return Err(SqliteClientError::TableNotEmpty);
|
return Err(SqliteClientError::TableNotEmpty);
|
||||||
|
@ -184,24 +183,23 @@ pub fn init_accounts_table<P: consensus::Parameters>(
|
||||||
|
|
||||||
// Insert accounts atomically
|
// Insert accounts atomically
|
||||||
wdb.conn.execute("BEGIN IMMEDIATE", NO_PARAMS)?;
|
wdb.conn.execute("BEGIN IMMEDIATE", NO_PARAMS)?;
|
||||||
for (account, (extfvk, taddr)) in extfvks.iter().zip(taddrs.iter()).enumerate() {
|
for key in keys.iter() {
|
||||||
let extfvk_str = encode_extended_full_viewing_key(
|
let extfvk_str: Option<String> = key.sapling().map(|extfvk| {
|
||||||
wdb.params.hrp_sapling_extended_full_viewing_key(),
|
encode_extended_full_viewing_key(
|
||||||
extfvk,
|
wdb.params.hrp_sapling_extended_full_viewing_key(),
|
||||||
);
|
extfvk,
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
let address_str = address_from_extfvk(&wdb.params, extfvk);
|
let address_str: Option<String> = key
|
||||||
let taddress_str: String = taddr.encode(&wdb.params);
|
.sapling()
|
||||||
|
.map(|extfvk| address_from_extfvk(&wdb.params, extfvk));
|
||||||
|
let taddress_str: Option<String> = key.transparent().map(|taddr| taddr.encode(&wdb.params));
|
||||||
|
|
||||||
wdb.conn.execute(
|
wdb.conn.execute(
|
||||||
"INSERT INTO accounts (account, extfvk, address, transparent_address)
|
"INSERT INTO accounts (account, extfvk, address, transparent_address)
|
||||||
VALUES (?, ?, ?, ?)",
|
VALUES (?, ?, ?, ?)",
|
||||||
&[
|
params![key.account().0, extfvk_str, address_str, taddress_str,],
|
||||||
(account as u32).to_sql()?,
|
|
||||||
extfvk_str.to_sql()?,
|
|
||||||
address_str.to_sql()?,
|
|
||||||
taddress_str.to_sql()?,
|
|
||||||
],
|
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
wdb.conn.execute("COMMIT", NO_PARAMS)?;
|
wdb.conn.execute("COMMIT", NO_PARAMS)?;
|
||||||
|
@ -271,13 +269,24 @@ pub fn init_blocks_table<P>(
|
||||||
mod tests {
|
mod tests {
|
||||||
use tempfile::NamedTempFile;
|
use tempfile::NamedTempFile;
|
||||||
|
|
||||||
use zcash_client_backend::keys::derive_transparent_address_from_secret_key;
|
use zcash_client_backend::keys::{spending_key, UnifiedFullViewingKey};
|
||||||
|
|
||||||
use zcash_primitives::{
|
#[cfg(feature = "transparent-inputs")]
|
||||||
block::BlockHash, consensus::BlockHeight, zip32::ExtendedFullViewingKey,
|
use zcash_client_backend::keys::{
|
||||||
|
derive_secret_key_from_seed, derive_transparent_address_from_secret_key,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{tests, wallet::get_address, AccountId, WalletDb};
|
use zcash_primitives::{
|
||||||
|
block::BlockHash,
|
||||||
|
consensus::{BlockHeight, Parameters},
|
||||||
|
zip32::ExtendedFullViewingKey,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
tests::{self, network},
|
||||||
|
wallet::get_address,
|
||||||
|
AccountId, WalletDb,
|
||||||
|
};
|
||||||
|
|
||||||
use super::{init_accounts_table, init_blocks_table, init_wallet_db};
|
use super::{init_accounts_table, init_blocks_table, init_wallet_db};
|
||||||
|
|
||||||
|
@ -288,18 +297,34 @@ mod tests {
|
||||||
init_wallet_db(&db_data).unwrap();
|
init_wallet_db(&db_data).unwrap();
|
||||||
|
|
||||||
// We can call the function as many times as we want with no data
|
// We can call the function as many times as we want with no data
|
||||||
init_accounts_table(&db_data, &[], &[]).unwrap();
|
init_accounts_table(&db_data, &[]).unwrap();
|
||||||
init_accounts_table(&db_data, &[], &[]).unwrap();
|
init_accounts_table(&db_data, &[]).unwrap();
|
||||||
|
|
||||||
|
let seed = [0u8; 32];
|
||||||
|
let account = AccountId(0);
|
||||||
|
|
||||||
// First call with data should initialise the accounts table
|
// First call with data should initialise the accounts table
|
||||||
let (extsk, tsk) = tests::derive_test_keys_from_seed(&[0u8; 32], AccountId(0));
|
let extsk = spending_key(&seed, network().coin_type(), account);
|
||||||
let extfvk = ExtendedFullViewingKey::from(&extsk);
|
let extfvk = ExtendedFullViewingKey::from(&extsk);
|
||||||
let taddr = derive_transparent_address_from_secret_key(&tsk);
|
|
||||||
init_accounts_table(&db_data, &[extfvk.clone()], &[taddr.clone()]).unwrap();
|
#[cfg(feature = "transparent-inputs")]
|
||||||
|
let ufvk = {
|
||||||
|
let tsk = derive_secret_key_from_seed(&network(), &seed, account, 0).unwrap();
|
||||||
|
UnifiedFullViewingKey::new(
|
||||||
|
account,
|
||||||
|
Some(derive_transparent_address_from_secret_key(&tsk)),
|
||||||
|
Some(extfvk),
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
};
|
||||||
|
#[cfg(not(feature = "transparent-inputs"))]
|
||||||
|
let ufvk = UnifiedFullViewingKey::new(account, None, Some(extfvk)).unwrap();
|
||||||
|
|
||||||
|
init_accounts_table(&db_data, &[ufvk.clone()]).unwrap();
|
||||||
|
|
||||||
// Subsequent calls should return an error
|
// Subsequent calls should return an error
|
||||||
init_accounts_table(&db_data, &[], &[]).unwrap_err();
|
init_accounts_table(&db_data, &[]).unwrap_err();
|
||||||
init_accounts_table(&db_data, &[extfvk], &[taddr]).unwrap_err();
|
init_accounts_table(&db_data, &[ufvk]).unwrap_err();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -335,11 +360,13 @@ mod tests {
|
||||||
let db_data = WalletDb::for_path(data_file.path(), tests::network()).unwrap();
|
let db_data = WalletDb::for_path(data_file.path(), tests::network()).unwrap();
|
||||||
init_wallet_db(&db_data).unwrap();
|
init_wallet_db(&db_data).unwrap();
|
||||||
|
|
||||||
|
let seed = [0u8; 32];
|
||||||
|
|
||||||
// Add an account to the wallet
|
// Add an account to the wallet
|
||||||
let (extsk, tsk) = tests::derive_test_keys_from_seed(&[0u8; 32], AccountId(0));
|
let extsk = spending_key(&seed, network().coin_type(), AccountId(0));
|
||||||
let extfvk = ExtendedFullViewingKey::from(&extsk);
|
let extfvk = ExtendedFullViewingKey::from(&extsk);
|
||||||
let taddr = derive_transparent_address_from_secret_key(&tsk);
|
let ufvk = UnifiedFullViewingKey::new(AccountId(0), None, Some(extfvk)).unwrap();
|
||||||
init_accounts_table(&db_data, &[extfvk], &[taddr]).unwrap();
|
init_accounts_table(&db_data, &[ufvk]).unwrap();
|
||||||
|
|
||||||
// The account's address should be in the data DB
|
// The account's address should be in the data DB
|
||||||
let pa = get_address(&db_data, AccountId(0)).unwrap();
|
let pa = get_address(&db_data, AccountId(0)).unwrap();
|
||||||
|
|
|
@ -153,7 +153,7 @@ mod tests {
|
||||||
|
|
||||||
use zcash_primitives::{
|
use zcash_primitives::{
|
||||||
block::BlockHash,
|
block::BlockHash,
|
||||||
consensus::{BlockHeight, BranchId},
|
consensus::{BlockHeight, BranchId, Parameters},
|
||||||
legacy::TransparentAddress,
|
legacy::TransparentAddress,
|
||||||
sapling::{note_encryption::try_sapling_output_recovery, prover::TxProver},
|
sapling::{note_encryption::try_sapling_output_recovery, prover::TxProver},
|
||||||
transaction::{components::Amount, Transaction},
|
transaction::{components::Amount, Transaction},
|
||||||
|
@ -164,16 +164,18 @@ mod tests {
|
||||||
|
|
||||||
use zcash_client_backend::{
|
use zcash_client_backend::{
|
||||||
data_api::{chain::scan_cached_blocks, wallet::create_spend_to_address, WalletRead},
|
data_api::{chain::scan_cached_blocks, wallet::create_spend_to_address, WalletRead},
|
||||||
keys::derive_transparent_address_from_secret_key,
|
keys::{spending_key, UnifiedFullViewingKey},
|
||||||
wallet::OvkPolicy,
|
wallet::OvkPolicy,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(feature = "transparent-inputs")]
|
||||||
|
use zcash_client_backend::keys::{
|
||||||
|
derive_secret_key_from_seed, derive_transparent_address_from_secret_key,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
chain::init::init_cache_database,
|
chain::init::init_cache_database,
|
||||||
tests::{
|
tests::{self, fake_compact_block, insert_into_cache, network, sapling_activation_height},
|
||||||
self, derive_test_keys_from_seed, fake_compact_block, insert_into_cache,
|
|
||||||
sapling_activation_height,
|
|
||||||
},
|
|
||||||
wallet::{
|
wallet::{
|
||||||
get_balance, get_balance_at,
|
get_balance, get_balance_at,
|
||||||
init::{init_accounts_table, init_blocks_table, init_wallet_db},
|
init::{init_accounts_table, init_blocks_table, init_wallet_db},
|
||||||
|
@ -197,17 +199,39 @@ mod tests {
|
||||||
init_wallet_db(&db_data).unwrap();
|
init_wallet_db(&db_data).unwrap();
|
||||||
|
|
||||||
// Add two accounts to the wallet
|
// Add two accounts to the wallet
|
||||||
let (extsk0, tsk0) = derive_test_keys_from_seed(&[0u8; 32], AccountId(0));
|
let extsk0 = spending_key(&[0u8; 32], network().coin_type(), AccountId(0));
|
||||||
let (extsk1, tsk1) = derive_test_keys_from_seed(&[1u8; 32], AccountId(1));
|
let extsk1 = spending_key(&[1u8; 32], network().coin_type(), AccountId(1));
|
||||||
let extfvks = [
|
let extfvk0 = ExtendedFullViewingKey::from(&extsk0);
|
||||||
ExtendedFullViewingKey::from(&extsk0),
|
let extfvk1 = ExtendedFullViewingKey::from(&extsk1);
|
||||||
ExtendedFullViewingKey::from(&extsk1),
|
|
||||||
|
#[cfg(feature = "transparent-inputs")]
|
||||||
|
let ufvks = {
|
||||||
|
let tsk0 =
|
||||||
|
derive_secret_key_from_seed(&network(), &[0u8; 32], AccountId(0), 0).unwrap();
|
||||||
|
let tsk1 =
|
||||||
|
derive_secret_key_from_seed(&network(), &[1u8; 32], AccountId(1), 0).unwrap();
|
||||||
|
[
|
||||||
|
UnifiedFullViewingKey::new(
|
||||||
|
AccountId(0),
|
||||||
|
Some(derive_transparent_address_from_secret_key(&tsk0)),
|
||||||
|
Some(extfvk0),
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
UnifiedFullViewingKey::new(
|
||||||
|
AccountId(1),
|
||||||
|
Some(derive_transparent_address_from_secret_key(&tsk1)),
|
||||||
|
Some(extfvk1),
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
]
|
||||||
|
};
|
||||||
|
#[cfg(not(feature = "transparent-inputs"))]
|
||||||
|
let ufvks = [
|
||||||
|
UnifiedFullViewingKey::new(AccountId(0), None, Some(extfvk0)).unwrap(),
|
||||||
|
UnifiedFullViewingKey::new(AccountId(1), None, Some(extfvk1)).unwrap(),
|
||||||
];
|
];
|
||||||
let taddrs = [
|
|
||||||
derive_transparent_address_from_secret_key(&tsk0),
|
init_accounts_table(&db_data, &ufvks).unwrap();
|
||||||
derive_transparent_address_from_secret_key(&tsk1),
|
|
||||||
];
|
|
||||||
init_accounts_table(&db_data, &extfvks, &taddrs).unwrap();
|
|
||||||
let to = extsk0.default_address().unwrap().1.into();
|
let to = extsk0.default_address().unwrap().1.into();
|
||||||
|
|
||||||
// Invalid extsk for the given account should cause an error
|
// Invalid extsk for the given account should cause an error
|
||||||
|
@ -252,10 +276,10 @@ mod tests {
|
||||||
init_wallet_db(&db_data).unwrap();
|
init_wallet_db(&db_data).unwrap();
|
||||||
|
|
||||||
// Add an account to the wallet
|
// Add an account to the wallet
|
||||||
let (extsk, tsk) = derive_test_keys_from_seed(&[0u8; 32], AccountId(0));
|
let extsk = spending_key(&[0u8; 32], network().coin_type(), AccountId(0));
|
||||||
let extfvk = ExtendedFullViewingKey::from(&extsk);
|
let extfvk = ExtendedFullViewingKey::from(&extsk);
|
||||||
let taddr = derive_transparent_address_from_secret_key(&tsk);
|
let ufvk = UnifiedFullViewingKey::new(AccountId(0), None, Some(extfvk)).unwrap();
|
||||||
init_accounts_table(&db_data, &[extfvk], &[taddr]).unwrap();
|
init_accounts_table(&db_data, &[ufvk]).unwrap();
|
||||||
let to = extsk.default_address().unwrap().1.into();
|
let to = extsk.default_address().unwrap().1.into();
|
||||||
|
|
||||||
// We cannot do anything if we aren't synchronised
|
// We cannot do anything if we aren't synchronised
|
||||||
|
@ -292,10 +316,10 @@ mod tests {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// Add an account to the wallet
|
// Add an account to the wallet
|
||||||
let (extsk, tsk) = derive_test_keys_from_seed(&[0u8; 32], AccountId(0));
|
let extsk = spending_key(&[0u8; 32], network().coin_type(), AccountId(0));
|
||||||
let extfvk = ExtendedFullViewingKey::from(&extsk);
|
let extfvk = ExtendedFullViewingKey::from(&extsk);
|
||||||
let taddr = derive_transparent_address_from_secret_key(&tsk);
|
let ufvk = UnifiedFullViewingKey::new(AccountId(0), None, Some(extfvk)).unwrap();
|
||||||
init_accounts_table(&db_data, &[extfvk], &[taddr]).unwrap();
|
init_accounts_table(&db_data, &[ufvk]).unwrap();
|
||||||
let to = extsk.default_address().unwrap().1.into();
|
let to = extsk.default_address().unwrap().1.into();
|
||||||
|
|
||||||
// Account balance should be zero
|
// Account balance should be zero
|
||||||
|
@ -334,10 +358,10 @@ mod tests {
|
||||||
init_wallet_db(&db_data).unwrap();
|
init_wallet_db(&db_data).unwrap();
|
||||||
|
|
||||||
// Add an account to the wallet
|
// Add an account to the wallet
|
||||||
let (extsk, tsk) = derive_test_keys_from_seed(&[0u8; 32], AccountId(0));
|
let extsk = spending_key(&[0u8; 32], network().coin_type(), AccountId(0));
|
||||||
let extfvk = ExtendedFullViewingKey::from(&extsk);
|
let extfvk = ExtendedFullViewingKey::from(&extsk);
|
||||||
let taddr = derive_transparent_address_from_secret_key(&tsk);
|
let ufvk = UnifiedFullViewingKey::new(AccountId(0), None, Some(extfvk.clone())).unwrap();
|
||||||
init_accounts_table(&db_data, &[extfvk.clone()], &[taddr]).unwrap();
|
init_accounts_table(&db_data, &[ufvk]).unwrap();
|
||||||
|
|
||||||
// Add funds to the wallet in a single note
|
// Add funds to the wallet in a single note
|
||||||
let value = Amount::from_u64(50000).unwrap();
|
let value = Amount::from_u64(50000).unwrap();
|
||||||
|
@ -474,10 +498,10 @@ mod tests {
|
||||||
init_wallet_db(&db_data).unwrap();
|
init_wallet_db(&db_data).unwrap();
|
||||||
|
|
||||||
// Add an account to the wallet
|
// Add an account to the wallet
|
||||||
let (extsk, tsk) = derive_test_keys_from_seed(&[0u8; 32], AccountId(0));
|
let extsk = spending_key(&[0u8; 32], network().coin_type(), AccountId(0));
|
||||||
let extfvk = ExtendedFullViewingKey::from(&extsk);
|
let extfvk = ExtendedFullViewingKey::from(&extsk);
|
||||||
let taddr = derive_transparent_address_from_secret_key(&tsk);
|
let ufvk = UnifiedFullViewingKey::new(AccountId(0), None, Some(extfvk.clone())).unwrap();
|
||||||
init_accounts_table(&db_data, &[extfvk.clone()], &[taddr]).unwrap();
|
init_accounts_table(&db_data, &[ufvk]).unwrap();
|
||||||
|
|
||||||
// Add funds to the wallet in a single note
|
// Add funds to the wallet in a single note
|
||||||
let value = Amount::from_u64(50000).unwrap();
|
let value = Amount::from_u64(50000).unwrap();
|
||||||
|
@ -600,10 +624,10 @@ mod tests {
|
||||||
init_wallet_db(&db_data).unwrap();
|
init_wallet_db(&db_data).unwrap();
|
||||||
|
|
||||||
// Add an account to the wallet
|
// Add an account to the wallet
|
||||||
let (extsk, tsk) = derive_test_keys_from_seed(&[0u8; 32], AccountId(0));
|
let extsk = spending_key(&[0u8; 32], network.coin_type(), AccountId(0));
|
||||||
let extfvk = ExtendedFullViewingKey::from(&extsk);
|
let extfvk = ExtendedFullViewingKey::from(&extsk);
|
||||||
let taddr = derive_transparent_address_from_secret_key(&tsk);
|
let ufvk = UnifiedFullViewingKey::new(AccountId(0), None, Some(extfvk.clone())).unwrap();
|
||||||
init_accounts_table(&db_data, &[extfvk.clone()], &[taddr]).unwrap();
|
init_accounts_table(&db_data, &[ufvk]).unwrap();
|
||||||
|
|
||||||
// Add funds to the wallet in a single note
|
// Add funds to the wallet in a single note
|
||||||
let value = Amount::from_u64(50000).unwrap();
|
let value = Amount::from_u64(50000).unwrap();
|
||||||
|
@ -707,10 +731,10 @@ mod tests {
|
||||||
init_wallet_db(&db_data).unwrap();
|
init_wallet_db(&db_data).unwrap();
|
||||||
|
|
||||||
// Add an account to the wallet
|
// Add an account to the wallet
|
||||||
let (extsk, tsk) = derive_test_keys_from_seed(&[0u8; 32], AccountId(0));
|
let extsk = spending_key(&[0u8; 32], network().coin_type(), AccountId(0));
|
||||||
let extfvk = ExtendedFullViewingKey::from(&extsk);
|
let extfvk = ExtendedFullViewingKey::from(&extsk);
|
||||||
let taddr = derive_transparent_address_from_secret_key(&tsk);
|
let ufvk = UnifiedFullViewingKey::new(AccountId(0), None, Some(extfvk.clone())).unwrap();
|
||||||
init_accounts_table(&db_data, &[extfvk.clone()], &[taddr]).unwrap();
|
init_accounts_table(&db_data, &[ufvk]).unwrap();
|
||||||
|
|
||||||
// Add funds to the wallet in a single note
|
// Add funds to the wallet in a single note
|
||||||
let value = Amount::from_u64(51000).unwrap();
|
let value = Amount::from_u64(51000).unwrap();
|
||||||
|
|
Loading…
Reference in New Issue