Update accounts table create statement.

This PR makes the opinionated change that T-addrs are required
to be supported when using the zcash_client_sqlite backend.
This commit is contained in:
Kevin Gorham 2021-03-31 17:59:36 -04:00 committed by Kris Nuttycombe
parent bdf56925e9
commit 8e16d93f94
9 changed files with 140 additions and 117 deletions

View File

@ -128,7 +128,7 @@ where
/// }; /// };
/// ///
/// let account = AccountId(0); /// let account = AccountId(0);
/// let extsk = spending_key(&[0; 32][..], COIN_TYPE, account.0); /// let extsk = spending_key(&[0; 32][..], COIN_TYPE, account);
/// let to = extsk.default_address().unwrap().1.into(); /// let to = extsk.default_address().unwrap().1.into();
/// ///
/// let data_file = NamedTempFile::new().unwrap(); /// let data_file = NamedTempFile::new().unwrap();
@ -297,7 +297,7 @@ where
.and_then(|x| x.ok_or_else(|| Error::ScanRequired.into()))?; .and_then(|x| x.ok_or_else(|| Error::ScanRequired.into()))?;
// derive the corresponding t-address // derive the corresponding t-address
let taddr = derive_transparent_address_from_secret_key(*sk); let taddr = derive_transparent_address_from_secret_key(sk);
// derive own shielded address from the provided extended spending key // derive own shielded address from the provided extended spending key
let z_address = extsk.default_address().unwrap().1; let z_address = extsk.default_address().unwrap().1;

View File

@ -104,9 +104,10 @@ impl<P: consensus::Parameters> AddressCodec<P> for TransparentAddress {
/// use zcash_client_backend::{ /// use zcash_client_backend::{
/// encoding::encode_extended_spending_key, /// encoding::encode_extended_spending_key,
/// keys::spending_key, /// keys::spending_key,
/// wallet::AccountId,
/// }; /// };
/// ///
/// let extsk = spending_key(&[0; 32][..], COIN_TYPE, 0); /// let extsk = spending_key(&[0; 32][..], COIN_TYPE, AccountId(0));
/// let encoded = encode_extended_spending_key(HRP_SAPLING_EXTENDED_SPENDING_KEY, &extsk); /// let encoded = encode_extended_spending_key(HRP_SAPLING_EXTENDED_SPENDING_KEY, &extsk);
/// ``` /// ```
/// [`ExtendedSpendingKey`]: zcash_primitives::zip32::ExtendedSpendingKey /// [`ExtendedSpendingKey`]: zcash_primitives::zip32::ExtendedSpendingKey
@ -135,10 +136,11 @@ pub fn decode_extended_spending_key(
/// use zcash_client_backend::{ /// use zcash_client_backend::{
/// encoding::encode_extended_full_viewing_key, /// encoding::encode_extended_full_viewing_key,
/// keys::spending_key, /// keys::spending_key,
/// wallet::AccountId,
/// }; /// };
/// use zcash_primitives::zip32::ExtendedFullViewingKey; /// use zcash_primitives::zip32::ExtendedFullViewingKey;
/// ///
/// let extsk = spending_key(&[0; 32][..], COIN_TYPE, 0); /// let extsk = spending_key(&[0; 32][..], COIN_TYPE, AccountId(0));
/// let extfvk = ExtendedFullViewingKey::from(&extsk); /// let extfvk = ExtendedFullViewingKey::from(&extsk);
/// let encoded = encode_extended_full_viewing_key(HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY, &extfvk); /// let encoded = encode_extended_full_viewing_key(HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY, &extfvk);
/// ``` /// ```

View File

@ -24,12 +24,15 @@ use {
/// ///
/// ``` /// ```
/// use zcash_primitives::{constants::testnet::COIN_TYPE}; /// use zcash_primitives::{constants::testnet::COIN_TYPE};
/// use zcash_client_backend::{keys::spending_key}; /// use zcash_client_backend::{
/// keys::spending_key,
/// wallet::AccountId,
/// };
/// ///
/// let extsk = spending_key(&[0; 32][..], COIN_TYPE, 0); /// let extsk = spending_key(&[0; 32][..], COIN_TYPE, AccountId(0));
/// ``` /// ```
/// [`ExtendedSpendingKey`]: zcash_primitives::zip32::ExtendedSpendingKey /// [`ExtendedSpendingKey`]: zcash_primitives::zip32::ExtendedSpendingKey
pub fn spending_key(seed: &[u8], coin_type: u32, account: u32) -> ExtendedSpendingKey { pub fn spending_key(seed: &[u8], coin_type: u32, account: AccountId) -> ExtendedSpendingKey {
if seed.len() < 32 { if seed.len() < 32 {
panic!("ZIP 32 seeds MUST be at least 32 bytes"); panic!("ZIP 32 seeds MUST be at least 32 bytes");
} }
@ -39,26 +42,26 @@ pub fn spending_key(seed: &[u8], coin_type: u32, account: u32) -> ExtendedSpendi
&[ &[
ChildIndex::Hardened(32), ChildIndex::Hardened(32),
ChildIndex::Hardened(coin_type), ChildIndex::Hardened(coin_type),
ChildIndex::Hardened(account), ChildIndex::Hardened(account.0),
], ],
) )
} }
#[cfg(feature = "transparent-inputs")] #[cfg(feature = "transparent-inputs")]
pub fn derive_transparent_address_from_secret_key( pub fn derive_transparent_address_from_secret_key(
secret_key: secp256k1::key::SecretKey, secret_key: &secp256k1::key::SecretKey,
) -> TransparentAddress { ) -> TransparentAddress {
let secp = Secp256k1::new(); let secp = Secp256k1::new();
let pk = PublicKey::from_secret_key(&secp, &secret_key); let pk = PublicKey::from_secret_key(&secp, secret_key);
derive_transparent_address_from_public_key(pk) derive_transparent_address_from_public_key(&pk)
} }
#[cfg(feature = "transparent-inputs")] #[cfg(feature = "transparent-inputs")]
pub fn derive_transparent_address_from_public_key( pub fn derive_transparent_address_from_public_key(
public_key: secp256k1::key::PublicKey, public_key: &secp256k1::key::PublicKey,
) -> TransparentAddress { ) -> TransparentAddress {
let mut hash160 = ripemd160::Ripemd160::new(); let mut hash160 = ripemd160::Ripemd160::new();
hash160.update(Sha256::digest(&public_key.serialize()[..].to_vec())); hash160.update(Sha256::digest(&public_key.serialize()));
TransparentAddress::PublicKey(*hash160.finalize().as_ref()) TransparentAddress::PublicKey(*hash160.finalize().as_ref())
} }
@ -160,7 +163,7 @@ mod tests {
#[test] #[test]
#[should_panic] #[should_panic]
fn spending_key_panics_on_short_seed() { fn spending_key_panics_on_short_seed() {
let _ = spending_key(&[0; 31][..], 0, 0); let _ = spending_key(&[0; 31][..], 0, AccountId(0));
} }
#[cfg(feature = "transparent-inputs")] #[cfg(feature = "transparent-inputs")]
@ -178,7 +181,7 @@ mod tests {
#[test] #[test]
fn sk_to_taddr() { fn sk_to_taddr() {
let sk = derive_secret_key_from_seed(&MAIN_NETWORK, &seed(), AccountId(0), 0).unwrap(); let sk = derive_secret_key_from_seed(&MAIN_NETWORK, &seed(), AccountId(0), 0).unwrap();
let taddr = derive_transparent_address_from_secret_key(sk).encode(&MAIN_NETWORK); let taddr = derive_transparent_address_from_secret_key(&sk).encode(&MAIN_NETWORK);
assert_eq!(taddr, "t1PKtYdJJHhc3Pxowmznkg7vdTwnhEsCvR4".to_string()); assert_eq!(taddr, "t1PKtYdJJHhc3Pxowmznkg7vdTwnhEsCvR4".to_string());
} }
@ -187,7 +190,7 @@ mod tests {
fn sk_wif_to_taddr() { fn sk_wif_to_taddr() {
let sk_wif = Wif("L4BvDC33yLjMRxipZvdiUmdYeRfZmR8viziwsVwe72zJdGbiJPv2".to_string()); let sk_wif = Wif("L4BvDC33yLjMRxipZvdiUmdYeRfZmR8viziwsVwe72zJdGbiJPv2".to_string());
let sk: SecretKey = (&sk_wif).try_into().expect("invalid wif"); let sk: SecretKey = (&sk_wif).try_into().expect("invalid wif");
let taddr = derive_transparent_address_from_secret_key(sk).encode(&MAIN_NETWORK); let taddr = derive_transparent_address_from_secret_key(&sk).encode(&MAIN_NETWORK);
assert_eq!(taddr, "t1PKtYdJJHhc3Pxowmznkg7vdTwnhEsCvR4".to_string()); assert_eq!(taddr, "t1PKtYdJJHhc3Pxowmznkg7vdTwnhEsCvR4".to_string());
} }
@ -206,7 +209,7 @@ mod tests {
#[test] #[test]
fn pk_to_taddr() { fn pk_to_taddr() {
let pk = derive_public_key_from_seed(&MAIN_NETWORK, &seed(), AccountId(0), 0).unwrap(); let pk = derive_public_key_from_seed(&MAIN_NETWORK, &seed(), AccountId(0), 0).unwrap();
let taddr = derive_transparent_address_from_public_key(pk).encode(&MAIN_NETWORK); let taddr = derive_transparent_address_from_public_key(&pk).encode(&MAIN_NETWORK);
assert_eq!(taddr, "t1PKtYdJJHhc3Pxowmznkg7vdTwnhEsCvR4".to_string()); assert_eq!(taddr, "t1PKtYdJJHhc3Pxowmznkg7vdTwnhEsCvR4".to_string());
} }
} }

View File

@ -21,9 +21,10 @@ jubjub = "0.5.1"
protobuf = "2.20" protobuf = "2.20"
rand_core = "0.5.1" rand_core = "0.5.1"
rusqlite = { version = "0.24", features = ["bundled", "time"] } rusqlite = { version = "0.24", features = ["bundled", "time"] }
secp256k1 = { version = "0.19" }
time = "0.2" time = "0.2"
zcash_client_backend = { version = "0.5", path = "../zcash_client_backend" } zcash_client_backend = { version = "0.5", path = "../zcash_client_backend", features = ["transparent-inputs"] }
zcash_primitives = { version = "0.5", path = "../zcash_primitives" } zcash_primitives = { version = "0.5", path = "../zcash_primitives", features = ["transparent-inputs"] }
[dev-dependencies] [dev-dependencies]
rand_core = "0.5.1" rand_core = "0.5.1"
@ -32,5 +33,4 @@ zcash_proofs = { version = "0.5", path = "../zcash_proofs" }
[features] [features]
mainnet = [] mainnet = []
transparent-inputs = []
test-dependencies = ["zcash_client_backend/test-dependencies"] test-dependencies = ["zcash_client_backend/test-dependencies"]

View File

@ -69,9 +69,7 @@ mod tests {
use tempfile::NamedTempFile; use tempfile::NamedTempFile;
use zcash_primitives::{ use zcash_primitives::{
block::BlockHash, block::BlockHash, transaction::components::Amount, zip32::ExtendedSpendingKey,
transaction::components::Amount,
zip32::{ExtendedFullViewingKey, ExtendedSpendingKey},
}; };
use zcash_client_backend::data_api::WalletRead; use zcash_client_backend::data_api::WalletRead;
@ -84,14 +82,10 @@ mod tests {
chain::init::init_cache_database, chain::init::init_cache_database,
error::SqliteClientError, error::SqliteClientError,
tests::{ tests::{
self, fake_compact_block, fake_compact_block_spending, insert_into_cache, self, fake_compact_block, fake_compact_block_spending, init_test_accounts_table,
sapling_activation_height, insert_into_cache, sapling_activation_height,
},
wallet::{
get_balance,
init::{init_accounts_table, init_wallet_db},
rewind_to_height,
}, },
wallet::{get_balance, init::init_wallet_db, rewind_to_height},
AccountId, BlockDb, NoteId, WalletDb, AccountId, BlockDb, NoteId, WalletDb,
}; };
@ -106,9 +100,7 @@ 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 = ExtendedSpendingKey::master(&[]); let (extfvk, _taddr) = init_test_accounts_table(&db_data);
let extfvk = ExtendedFullViewingKey::from(&extsk);
init_accounts_table(&db_data, &[extfvk.clone()]).unwrap();
// Empty chain should be valid // Empty chain should be valid
validate_chain( validate_chain(
@ -187,9 +179,7 @@ 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 = ExtendedSpendingKey::master(&[]); let (extfvk, _taddr) = init_test_accounts_table(&db_data);
let extfvk = ExtendedFullViewingKey::from(&extsk);
init_accounts_table(&db_data, &[extfvk.clone()]).unwrap();
// Create some fake CompactBlocks // Create some fake CompactBlocks
let (cb, _) = fake_compact_block( let (cb, _) = fake_compact_block(
@ -259,9 +249,7 @@ 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 = ExtendedSpendingKey::master(&[]); let (extfvk, _taddr) = init_test_accounts_table(&db_data);
let extfvk = ExtendedFullViewingKey::from(&extsk);
init_accounts_table(&db_data, &[extfvk.clone()]).unwrap();
// Create some fake CompactBlocks // Create some fake CompactBlocks
let (cb, _) = fake_compact_block( let (cb, _) = fake_compact_block(
@ -331,9 +319,7 @@ 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 = ExtendedSpendingKey::master(&[]); let (extfvk, _taddr) = init_test_accounts_table(&db_data);
let extfvk = ExtendedFullViewingKey::from(&extsk);
init_accounts_table(&db_data, &[extfvk.clone()]).unwrap();
// Account balance should be zero // Account balance should be zero
assert_eq!(get_balance(&db_data, AccountId(0)).unwrap(), Amount::zero()); assert_eq!(get_balance(&db_data, AccountId(0)).unwrap(), Amount::zero());
@ -390,9 +376,7 @@ 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 = ExtendedSpendingKey::master(&[]); let (extfvk, _taddr) = init_test_accounts_table(&db_data);
let extfvk = ExtendedFullViewingKey::from(&extsk);
init_accounts_table(&db_data, &[extfvk.clone()]).unwrap();
// Create a block with height SAPLING_ACTIVATION_HEIGHT // Create a block with height SAPLING_ACTIVATION_HEIGHT
let value = Amount::from_u64(50000).unwrap(); let value = Amount::from_u64(50000).unwrap();
@ -451,9 +435,7 @@ 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 = ExtendedSpendingKey::master(&[]); let (extfvk, _taddr) = init_test_accounts_table(&db_data);
let extfvk = ExtendedFullViewingKey::from(&extsk);
init_accounts_table(&db_data, &[extfvk.clone()]).unwrap();
// Account balance should be zero // Account balance should be zero
assert_eq!(get_balance(&db_data, AccountId(0)).unwrap(), Amount::zero()); assert_eq!(get_balance(&db_data, AccountId(0)).unwrap(), Amount::zero());
@ -499,9 +481,7 @@ 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 = ExtendedSpendingKey::master(&[]); let (extfvk, _taddr) = init_test_accounts_table(&db_data);
let extfvk = ExtendedFullViewingKey::from(&extsk);
init_accounts_table(&db_data, &[extfvk.clone()]).unwrap();
// Account balance should be zero // Account balance should be zero
assert_eq!(get_balance(&db_data, AccountId(0)).unwrap(), Amount::zero()); assert_eq!(get_balance(&db_data, AccountId(0)).unwrap(), Amount::zero());

View File

@ -60,7 +60,6 @@ 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,
@ -89,7 +88,6 @@ impl fmt::Display for NoteId {
/// A newtype wrapper for sqlite primary key values for the utxos /// A newtype wrapper for sqlite primary key values for the utxos
/// table. /// table.
#[cfg(feature = "transparent-inputs")]
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct UtxoId(pub i64); pub struct UtxoId(pub i64);
@ -145,12 +143,10 @@ 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)"
)?, )?,
#[cfg(feature = "transparent-inputs")]
stmt_delete_utxos: self.conn.prepare( stmt_delete_utxos: self.conn.prepare(
"DELETE FROM utxos WHERE address = :address AND height > :above_height" "DELETE FROM utxos WHERE address = :address AND height > :above_height"
)?, )?,
@ -285,7 +281,6 @@ impl<P: consensus::Parameters> WalletRead for WalletDb<P> {
wallet::transact::select_unspent_sapling_notes(&self, account, target_value, anchor_height) wallet::transact::select_unspent_sapling_notes(&self, account, target_value, anchor_height)
} }
#[cfg(feature = "transparent-inputs")]
fn get_unspent_transparent_utxos( fn get_unspent_transparent_utxos(
&self, &self,
address: &TransparentAddress, address: &TransparentAddress,
@ -316,9 +311,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>,
#[cfg(feature = "transparent-inputs")]
stmt_delete_utxos: Statement<'a>, stmt_delete_utxos: Statement<'a>,
stmt_insert_received_note: Statement<'a>, stmt_insert_received_note: Statement<'a>,
stmt_update_received_note: Statement<'a>, stmt_update_received_note: Statement<'a>,
@ -417,7 +410,6 @@ impl<'a, P: consensus::Parameters> WalletRead for DataConnStmtCache<'a, P> {
.select_unspent_sapling_notes(account, target_value, anchor_height) .select_unspent_sapling_notes(account, target_value, anchor_height)
} }
#[cfg(feature = "transparent-inputs")]
fn get_unspent_transparent_utxos( fn get_unspent_transparent_utxos(
&self, &self,
address: &TransparentAddress, address: &TransparentAddress,
@ -656,23 +648,30 @@ 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::proto::compact_formats::{ use zcash_client_backend::{
CompactBlock, CompactOutput, CompactSpend, CompactTx, keys::{
derive_secret_key_from_seed, derive_transparent_address_from_secret_key, spending_key,
},
proto::compact_formats::{CompactBlock, CompactOutput, CompactSpend, CompactTx},
}; };
use zcash_primitives::{ use zcash_primitives::{
block::BlockHash, block::BlockHash,
consensus::{BlockHeight, Network, NetworkUpgrade, Parameters}, consensus::{BlockHeight, Network, NetworkUpgrade, Parameters},
legacy::TransparentAddress,
memo::MemoBytes, memo::MemoBytes,
sapling::{ sapling::{
note_encryption::sapling_note_encryption, util::generate_random_rseed, Note, Nullifier, note_encryption::sapling_note_encryption, util::generate_random_rseed, Note, Nullifier,
PaymentAddress, PaymentAddress,
}, },
transaction::components::Amount, transaction::components::Amount,
zip32::ExtendedFullViewingKey, zip32::{ExtendedFullViewingKey, ExtendedSpendingKey},
}; };
use crate::{wallet::init::init_accounts_table, AccountId, WalletDb};
use super::BlockDb; use super::BlockDb;
#[cfg(feature = "mainnet")] #[cfg(feature = "mainnet")]
@ -699,6 +698,25 @@ 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(
db_data: &WalletDb<Network>,
) -> (ExtendedFullViewingKey, TransparentAddress) {
let (extsk, tsk) = derive_test_keys_from_seed(&[0u8; 32], AccountId(0));
let extfvk = ExtendedFullViewingKey::from(&extsk);
let taddr = derive_transparent_address_from_secret_key(&tsk);
init_accounts_table(db_data, &[extfvk.clone()], &[taddr.clone()]).unwrap();
(extfvk, taddr)
}
/// Create a fake CompactBlock at the given height, containing a single output paying /// Create a fake CompactBlock at the given height, containing a single output paying
/// the given address. Returns the CompactBlock and the nullifier for the new note. /// the given address. Returns the CompactBlock and the nullifier for the new note.
pub(crate) fn fake_compact_block( pub(crate) fn fake_compact_block(

View File

@ -37,7 +37,6 @@ use zcash_client_backend::{
use crate::{error::SqliteClientError, DataConnStmtCache, NoteId, WalletDb}; use crate::{error::SqliteClientError, DataConnStmtCache, NoteId, WalletDb};
#[cfg(feature = "transparent-inputs")]
use { use {
crate::UtxoId, crate::UtxoId,
zcash_client_backend::{encoding::AddressCodec, wallet::WalletTransparentOutput}, zcash_client_backend::{encoding::AddressCodec, wallet::WalletTransparentOutput},
@ -597,7 +596,6 @@ pub fn get_nullifiers<P>(
Ok(res) Ok(res)
} }
#[cfg(feature = "transparent-inputs")]
pub fn get_unspent_transparent_utxos<P: consensus::Parameters>( pub fn get_unspent_transparent_utxos<P: consensus::Parameters>(
wdb: &WalletDb<P>, wdb: &WalletDb<P>,
address: &TransparentAddress, address: &TransparentAddress,
@ -769,7 +767,6 @@ 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,
@ -790,7 +787,6 @@ pub fn put_received_transparent_utxo<'a, P: consensus::Parameters>(
Ok(UtxoId(stmts.wallet_db.conn.last_insert_rowid())) Ok(UtxoId(stmts.wallet_db.conn.last_insert_rowid()))
} }
#[cfg(feature = "transparent-inputs")]
pub fn delete_utxos_above<'a, P: consensus::Parameters>( pub fn delete_utxos_above<'a, P: consensus::Parameters>(
stmts: &mut DataConnStmtCache<'a, P>, stmts: &mut DataConnStmtCache<'a, P>,
taddr: &TransparentAddress, taddr: &TransparentAddress,
@ -957,18 +953,11 @@ pub fn insert_sent_note<'a, P: consensus::Parameters>(
mod tests { mod tests {
use tempfile::NamedTempFile; use tempfile::NamedTempFile;
use zcash_primitives::{ use zcash_primitives::transaction::components::Amount;
transaction::components::Amount,
zip32::{ExtendedFullViewingKey, ExtendedSpendingKey},
};
use zcash_client_backend::data_api::WalletRead; use zcash_client_backend::data_api::WalletRead;
use crate::{ use crate::{tests, wallet::init::init_wallet_db, AccountId, WalletDb};
tests,
wallet::init::{init_accounts_table, init_wallet_db},
AccountId, WalletDb,
};
use super::{get_address, get_balance}; use super::{get_address, get_balance};
@ -979,9 +968,7 @@ 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 = ExtendedSpendingKey::master(&[]); tests::init_test_accounts_table(&db_data);
let extfvks = [ExtendedFullViewingKey::from(&extsk)];
init_accounts_table(&db_data, &extfvks).unwrap();
// The account should be empty // The account should be empty
assert_eq!(get_balance(&db_data, AccountId(0)).unwrap(), Amount::zero()); assert_eq!(get_balance(&db_data, AccountId(0)).unwrap(), Amount::zero());

View File

@ -2,7 +2,12 @@
use rusqlite::{types::ToSql, NO_PARAMS}; use rusqlite::{types::ToSql, NO_PARAMS};
use zcash_primitives::{block::BlockHash, consensus::{self, BlockHeight}, legacy::TransparentAddress, zip32::ExtendedFullViewingKey}; use zcash_primitives::{
block::BlockHash,
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};
@ -29,7 +34,8 @@ pub fn init_wallet_db<P>(wdb: &WalletDb<P>) -> Result<(), rusqlite::Error> {
"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 NOT NULL,
address TEXT NOT NULL address TEXT NOT NULL,
transparent_address TEXT NOT NULL
)", )",
NO_PARAMS, NO_PARAMS,
)?; )?;
@ -133,10 +139,15 @@ pub fn init_wallet_db<P>(wdb: &WalletDb<P>) -> Result<(), rusqlite::Error> {
/// use tempfile::NamedTempFile; /// use tempfile::NamedTempFile;
/// ///
/// use zcash_primitives::{ /// use zcash_primitives::{
/// consensus::Network, /// consensus::{Network, Parameters},
/// zip32::{ExtendedFullViewingKey, ExtendedSpendingKey} /// zip32::{ExtendedFullViewingKey, ExtendedSpendingKey}
/// }; /// };
/// ///
/// use zcash_client_backend::{
/// keys::{spending_key, derive_transparent_address_from_secret_key, derive_secret_key_from_seed},
/// wallet::AccountId,
/// };
///
/// use zcash_client_sqlite::{ /// use zcash_client_sqlite::{
/// WalletDb, /// WalletDb,
/// wallet::init::{init_accounts_table, init_wallet_db} /// wallet::init::{init_accounts_table, init_wallet_db}
@ -146,9 +157,13 @@ pub fn init_wallet_db<P>(wdb: &WalletDb<P>) -> Result<(), rusqlite::Error> {
/// let db_data = WalletDb::for_path(data_file.path(), Network::TestNetwork).unwrap(); /// let db_data = WalletDb::for_path(data_file.path(), Network::TestNetwork).unwrap();
/// init_wallet_db(&db_data).unwrap(); /// init_wallet_db(&db_data).unwrap();
/// ///
/// let extsk = ExtendedSpendingKey::master(&[]); /// let seed = [0u8; 32];
/// let extfvks = [ExtendedFullViewingKey::from(&extsk)]; /// let account = AccountId(0);
/// init_accounts_table(&db_data, &extfvks).unwrap(); /// 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 taddr = derive_transparent_address_from_secret_key(&tsk);
/// init_accounts_table(&db_data, &[&extfvk], &[&taddr]).unwrap();
/// ``` /// ```
/// ///
/// [`get_address`]: crate::wallet::get_address /// [`get_address`]: crate::wallet::get_address
@ -157,8 +172,11 @@ pub fn init_wallet_db<P>(wdb: &WalletDb<P>) -> Result<(), rusqlite::Error> {
pub fn init_accounts_table<P: consensus::Parameters>( pub fn init_accounts_table<P: consensus::Parameters>(
wdb: &WalletDb<P>, wdb: &WalletDb<P>,
extfvks: &[ExtendedFullViewingKey], extfvks: &[ExtendedFullViewingKey],
taddrs: &Vec<TransparentAddress>, 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);
@ -253,10 +271,10 @@ 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_primitives::{ use zcash_primitives::{
block::BlockHash, block::BlockHash, consensus::BlockHeight, zip32::ExtendedFullViewingKey,
consensus::BlockHeight,
zip32::{ExtendedFullViewingKey, ExtendedSpendingKey},
}; };
use crate::{tests, wallet::get_address, AccountId, WalletDb}; use crate::{tests, wallet::get_address, AccountId, WalletDb};
@ -270,18 +288,18 @@ 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();
// First call with data should initialise the accounts table // First call with data should initialise the accounts table
let extfvks = [ExtendedFullViewingKey::from(&ExtendedSpendingKey::master( let (extsk, tsk) = tests::derive_test_keys_from_seed(&[0u8; 32], AccountId(0));
&[], let extfvk = ExtendedFullViewingKey::from(&extsk);
))]; let taddr = derive_transparent_address_from_secret_key(&tsk);
init_accounts_table(&db_data, &extfvks).unwrap(); init_accounts_table(&db_data, &[extfvk.clone()], &[taddr.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, &extfvks).unwrap_err(); init_accounts_table(&db_data, &[extfvk], &[taddr]).unwrap_err();
} }
#[test] #[test]
@ -318,9 +336,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 = ExtendedSpendingKey::master(&[]); let (extsk, tsk) = tests::derive_test_keys_from_seed(&[0u8; 32], AccountId(0));
let extfvks = [ExtendedFullViewingKey::from(&extsk)]; let extfvk = ExtendedFullViewingKey::from(&extsk);
init_accounts_table(&db_data, &extfvks).unwrap(); let taddr = derive_transparent_address_from_secret_key(&tsk);
init_accounts_table(&db_data, &[extfvk], &[taddr]).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();

View File

@ -164,12 +164,16 @@ 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,
wallet::OvkPolicy, wallet::OvkPolicy,
}; };
use crate::{ use crate::{
chain::init::init_cache_database, chain::init::init_cache_database,
tests::{self, fake_compact_block, insert_into_cache, sapling_activation_height}, tests::{
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},
@ -193,13 +197,17 @@ 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 = ExtendedSpendingKey::master(&[]); let (extsk0, tsk0) = derive_test_keys_from_seed(&[0u8; 32], AccountId(0));
let extsk1 = ExtendedSpendingKey::master(&[0]); let (extsk1, tsk1) = derive_test_keys_from_seed(&[1u8; 32], AccountId(1));
let extfvks = [ let extfvks = [
ExtendedFullViewingKey::from(&extsk0), ExtendedFullViewingKey::from(&extsk0),
ExtendedFullViewingKey::from(&extsk1), ExtendedFullViewingKey::from(&extsk1),
]; ];
init_accounts_table(&db_data, &extfvks).unwrap(); let taddrs = [
derive_transparent_address_from_secret_key(&tsk0),
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
@ -242,9 +250,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 = ExtendedSpendingKey::master(&[]); let (extsk, tsk) = derive_test_keys_from_seed(&[0u8; 32], AccountId(0));
let extfvks = [ExtendedFullViewingKey::from(&extsk)]; let extfvk = ExtendedFullViewingKey::from(&extsk);
init_accounts_table(&db_data, &extfvks).unwrap(); let taddr = derive_transparent_address_from_secret_key(&tsk);
init_accounts_table(&db_data, &[extfvk], &[taddr]).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
@ -280,9 +289,10 @@ mod tests {
.unwrap(); .unwrap();
// Add an account to the wallet // Add an account to the wallet
let extsk = ExtendedSpendingKey::master(&[]); let (extsk, tsk) = derive_test_keys_from_seed(&[0u8; 32], AccountId(0));
let extfvks = [ExtendedFullViewingKey::from(&extsk)]; let extfvk = ExtendedFullViewingKey::from(&extsk);
init_accounts_table(&db_data, &extfvks).unwrap(); let taddr = derive_transparent_address_from_secret_key(&tsk);
init_accounts_table(&db_data, &[extfvk], &[taddr]).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
@ -320,9 +330,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 = ExtendedSpendingKey::master(&[]); let (extsk, tsk) = derive_test_keys_from_seed(&[0u8; 32], AccountId(0));
let extfvk = ExtendedFullViewingKey::from(&extsk); let extfvk = ExtendedFullViewingKey::from(&extsk);
init_accounts_table(&db_data, &[extfvk.clone()]).unwrap(); let taddr = derive_transparent_address_from_secret_key(&tsk);
init_accounts_table(&db_data, &[extfvk.clone()], &[taddr]).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();
@ -447,9 +458,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 = ExtendedSpendingKey::master(&[]); let (extsk, tsk) = derive_test_keys_from_seed(&[0u8; 32], AccountId(0));
let extfvk = ExtendedFullViewingKey::from(&extsk); let extfvk = ExtendedFullViewingKey::from(&extsk);
init_accounts_table(&db_data, &[extfvk.clone()]).unwrap(); let taddr = derive_transparent_address_from_secret_key(&tsk);
init_accounts_table(&db_data, &[extfvk.clone()], &[taddr]).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();
@ -568,9 +580,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 = ExtendedSpendingKey::master(&[]); let (extsk, tsk) = derive_test_keys_from_seed(&[0u8; 32], AccountId(0));
let extfvk = ExtendedFullViewingKey::from(&extsk); let extfvk = ExtendedFullViewingKey::from(&extsk);
init_accounts_table(&db_data, &[extfvk.clone()]).unwrap(); let taddr = derive_transparent_address_from_secret_key(&tsk);
init_accounts_table(&db_data, &[extfvk.clone()], &[taddr]).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();
@ -673,9 +686,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 = ExtendedSpendingKey::master(&[]); let (extsk, tsk) = derive_test_keys_from_seed(&[0u8; 32], AccountId(0));
let extfvk = ExtendedFullViewingKey::from(&extsk); let extfvk = ExtendedFullViewingKey::from(&extsk);
init_accounts_table(&db_data, &[extfvk.clone()]).unwrap(); let taddr = derive_transparent_address_from_secret_key(&tsk);
init_accounts_table(&db_data, &[extfvk.clone()], &[taddr]).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();