Add address retrieval.
This commit is contained in:
parent
b72251ee28
commit
70de11dd32
|
@ -1,6 +1,7 @@
|
|||
use zcash_primitives::{
|
||||
block::BlockHash,
|
||||
consensus::{self, BlockHeight},
|
||||
primitives::PaymentAddress,
|
||||
//merkle_tree::{CommitmentTree, IncrementalWitness},
|
||||
//sapling::Node,
|
||||
//transaction::{
|
||||
|
@ -18,23 +19,25 @@ pub mod error;
|
|||
|
||||
pub trait DBOps {
|
||||
type Error;
|
||||
type Account;
|
||||
// type TxRef; // Backend-specific transaction handle
|
||||
// type NoteRef; // Backend-specific note identifier`
|
||||
|
||||
fn init_db(&self) -> Result<(), Self::Error>;
|
||||
|
||||
fn init_accounts<P: consensus::Parameters>(
|
||||
fn init_account_storage<P: consensus::Parameters>(
|
||||
&self,
|
||||
params: &P,
|
||||
extfvks: &[ExtendedFullViewingKey],
|
||||
) -> Result<(), Self::Error>;
|
||||
|
||||
// fn init_blocks(
|
||||
// height: i32,
|
||||
// hash: BlockHash,
|
||||
// time: u32,
|
||||
// sapling_tree: &[u8],
|
||||
// ) -> Result<(), Self::Error>;
|
||||
fn init_block_storage(
|
||||
&self,
|
||||
height: BlockHeight,
|
||||
hash: BlockHash,
|
||||
time: u32, //TODO: Newtype!
|
||||
sapling_tree: &[u8], //TODO: Newtype!
|
||||
) -> Result<(), Self::Error>;
|
||||
|
||||
fn block_height_extrema(&self) -> Result<Option<(BlockHeight, BlockHeight)>, Self::Error>;
|
||||
|
||||
|
@ -46,8 +49,12 @@ pub trait DBOps {
|
|||
block_height: BlockHeight,
|
||||
) -> Result<(), Self::Error>;
|
||||
|
||||
// fn get_address(account: Account) -> Result<String, Self::Error>;
|
||||
//
|
||||
fn get_address<P: consensus::Parameters>(
|
||||
&self,
|
||||
params: &P,
|
||||
account: Self::Account,
|
||||
) -> Result<Option<PaymentAddress>, Self::Error>;
|
||||
|
||||
// fn get_balance(account: Account) -> Result<Amount, Self::Error>;
|
||||
//
|
||||
// fn get_verified_balance(account: Account) -> Result<Amount, Self::Error>;
|
||||
|
|
|
@ -158,8 +158,8 @@ pub fn block_height_extrema(
|
|||
Ok(Some((min_height.into(), max_height.into())))
|
||||
},
|
||||
)
|
||||
// cannot use .optional() here because the result of a failed group
|
||||
// operation is an error, not an empty row.
|
||||
//.optional() doesn't work here because a failed aggregate function
|
||||
//produces a runtime error, not an empty set of rows.
|
||||
.or(Ok(None))
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
//! Functions for initializing the various databases.
|
||||
|
||||
use rusqlite::{types::ToSql, NO_PARAMS};
|
||||
use zcash_client_backend::encoding::encode_extended_full_viewing_key;
|
||||
|
||||
use zcash_primitives::{block::BlockHash, consensus, zip32::ExtendedFullViewingKey};
|
||||
use zcash_primitives::{
|
||||
block::BlockHash,
|
||||
consensus::{self, BlockHeight},
|
||||
zip32::ExtendedFullViewingKey,
|
||||
};
|
||||
|
||||
use zcash_client_backend::data_api::error::Error;
|
||||
use zcash_client_backend::{data_api::error::Error, encoding::encode_extended_full_viewing_key};
|
||||
|
||||
use crate::{address_from_extfvk, error::SqliteClientError, CacheConnection, DataConnection};
|
||||
|
||||
|
@ -178,18 +181,20 @@ pub fn init_accounts_table<P: consensus::Parameters>(
|
|||
// Insert accounts atomically
|
||||
data.0.execute("BEGIN IMMEDIATE", NO_PARAMS)?;
|
||||
for (account, extfvk) in extfvks.iter().enumerate() {
|
||||
let address = address_from_extfvk(params, extfvk);
|
||||
let extfvk = encode_extended_full_viewing_key(
|
||||
let extfvk_str = encode_extended_full_viewing_key(
|
||||
params.hrp_sapling_extended_full_viewing_key(),
|
||||
extfvk,
|
||||
);
|
||||
|
||||
let address_str = address_from_extfvk(params, extfvk);
|
||||
|
||||
data.0.execute(
|
||||
"INSERT INTO accounts (account, extfvk, address)
|
||||
VALUES (?, ?, ?)",
|
||||
&[
|
||||
(account as u32).to_sql()?,
|
||||
extfvk.to_sql()?,
|
||||
address.to_sql()?,
|
||||
extfvk_str.to_sql()?,
|
||||
address_str.to_sql()?,
|
||||
],
|
||||
)?;
|
||||
}
|
||||
|
@ -207,14 +212,17 @@ pub fn init_accounts_table<P: consensus::Parameters>(
|
|||
///
|
||||
/// ```
|
||||
/// use tempfile::NamedTempFile;
|
||||
/// use zcash_primitives::block::BlockHash;
|
||||
/// use zcash_primitives::{
|
||||
/// block::BlockHash,
|
||||
/// consensus::BlockHeight,
|
||||
/// };
|
||||
/// use zcash_client_sqlite::{
|
||||
/// DataConnection,
|
||||
/// init::init_blocks_table,
|
||||
/// };
|
||||
///
|
||||
/// // The block height.
|
||||
/// let height = 500_000;
|
||||
/// let height = BlockHeight(500_000);
|
||||
/// // The hash of the block header.
|
||||
/// let hash = BlockHash([0; 32]);
|
||||
/// // The nTime field from the block header.
|
||||
|
@ -229,7 +237,7 @@ pub fn init_accounts_table<P: consensus::Parameters>(
|
|||
/// ```
|
||||
pub fn init_blocks_table(
|
||||
data: &DataConnection,
|
||||
height: i32,
|
||||
height: BlockHeight,
|
||||
hash: BlockHash,
|
||||
time: u32,
|
||||
sapling_tree: &[u8],
|
||||
|
@ -243,7 +251,7 @@ pub fn init_blocks_table(
|
|||
"INSERT INTO blocks (height, hash, time, sapling_tree)
|
||||
VALUES (?, ?, ?, ?)",
|
||||
&[
|
||||
height.to_sql()?,
|
||||
u32::from(height).to_sql()?,
|
||||
hash.0.to_sql()?,
|
||||
time.to_sql()?,
|
||||
sapling_tree.to_sql()?,
|
||||
|
@ -260,13 +268,11 @@ mod tests {
|
|||
|
||||
use zcash_primitives::{
|
||||
block::BlockHash,
|
||||
consensus::Parameters,
|
||||
consensus::BlockHeight,
|
||||
zip32::{ExtendedFullViewingKey, ExtendedSpendingKey},
|
||||
};
|
||||
|
||||
use zcash_client_backend::encoding::decode_payment_address;
|
||||
|
||||
use crate::{query::get_address, tests, DataConnection};
|
||||
use crate::{query::get_address, tests, Account, DataConnection};
|
||||
|
||||
use super::{init_accounts_table, init_blocks_table, init_data_database};
|
||||
|
||||
|
@ -298,10 +304,24 @@ mod tests {
|
|||
init_data_database(&db_data).unwrap();
|
||||
|
||||
// First call with data should initialise the blocks table
|
||||
init_blocks_table(&db_data, 1, BlockHash([1; 32]), 1, &[]).unwrap();
|
||||
init_blocks_table(
|
||||
&db_data,
|
||||
BlockHeight::from(1u32),
|
||||
BlockHash([1; 32]),
|
||||
1,
|
||||
&[],
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// Subsequent calls should return an error
|
||||
init_blocks_table(&db_data, 2, BlockHash([2; 32]), 2, &[]).unwrap_err();
|
||||
init_blocks_table(
|
||||
&db_data,
|
||||
BlockHeight::from(2u32),
|
||||
BlockHash([2; 32]),
|
||||
2,
|
||||
&[],
|
||||
)
|
||||
.unwrap_err();
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -316,9 +336,7 @@ mod tests {
|
|||
init_accounts_table(&db_data, &tests::network(), &extfvks).unwrap();
|
||||
|
||||
// The account's address should be in the data DB
|
||||
let addr = get_address(&db_data, 0).unwrap();
|
||||
let pa =
|
||||
decode_payment_address(tests::network().hrp_sapling_payment_address(), &addr).unwrap();
|
||||
let pa = get_address(&db_data, &tests::network(), Account(0)).unwrap();
|
||||
assert_eq!(pa.unwrap(), extsk.default_address().unwrap().1);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ use std::path::Path;
|
|||
use zcash_primitives::{
|
||||
block::BlockHash,
|
||||
consensus::{self, BlockHeight},
|
||||
primitives::PaymentAddress,
|
||||
zip32::ExtendedFullViewingKey,
|
||||
};
|
||||
|
||||
|
@ -46,7 +47,7 @@ pub mod query;
|
|||
pub mod scan;
|
||||
pub mod transact;
|
||||
|
||||
pub struct Account(u32);
|
||||
pub struct Account(pub u32);
|
||||
|
||||
pub struct DataConnection(Connection);
|
||||
|
||||
|
@ -58,12 +59,13 @@ impl DataConnection {
|
|||
|
||||
impl DBOps for DataConnection {
|
||||
type Error = Error<rusqlite::Error>;
|
||||
type Account = Account;
|
||||
|
||||
fn init_db(&self) -> Result<(), Self::Error> {
|
||||
init::init_data_database(self).map_err(Error::Database)
|
||||
}
|
||||
|
||||
fn init_accounts<P: consensus::Parameters>(
|
||||
fn init_account_storage<P: consensus::Parameters>(
|
||||
&self,
|
||||
params: &P,
|
||||
extfvks: &[ExtendedFullViewingKey],
|
||||
|
@ -71,6 +73,16 @@ impl DBOps for DataConnection {
|
|||
init::init_accounts_table(self, params, extfvks).map_err(|e| e.0)
|
||||
}
|
||||
|
||||
fn init_block_storage(
|
||||
&self,
|
||||
height: BlockHeight,
|
||||
hash: BlockHash,
|
||||
time: u32,
|
||||
sapling_tree: &[u8],
|
||||
) -> Result<(), Self::Error> {
|
||||
init::init_blocks_table(self, height, hash, time, sapling_tree).map_err(|e| e.0)
|
||||
}
|
||||
|
||||
fn block_height_extrema(&self) -> Result<Option<(BlockHeight, BlockHeight)>, Self::Error> {
|
||||
chain::block_height_extrema(self).map_err(Error::Database)
|
||||
}
|
||||
|
@ -86,6 +98,14 @@ impl DBOps for DataConnection {
|
|||
) -> Result<(), Self::Error> {
|
||||
chain::rewind_to_height(self, parameters, block_height).map_err(|e| e.0)
|
||||
}
|
||||
|
||||
fn get_address<P: consensus::Parameters>(
|
||||
&self,
|
||||
params: &P,
|
||||
account: Self::Account,
|
||||
) -> Result<Option<PaymentAddress>, Self::Error> {
|
||||
query::get_address(self, params, account).map_err(|e| e.0)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CacheConnection(Connection);
|
||||
|
|
|
@ -1,10 +1,18 @@
|
|||
//! Functions for querying information in the data database.
|
||||
|
||||
use zcash_primitives::{note_encryption::Memo, transaction::components::Amount};
|
||||
use zcash_primitives::{
|
||||
consensus::{self},
|
||||
note_encryption::Memo,
|
||||
primitives::PaymentAddress,
|
||||
transaction::components::Amount,
|
||||
};
|
||||
|
||||
use zcash_client_backend::data_api::{chain::get_target_and_anchor_heights, error::Error};
|
||||
use zcash_client_backend::{
|
||||
data_api::{chain::get_target_and_anchor_heights, error::Error},
|
||||
encoding::decode_payment_address,
|
||||
};
|
||||
|
||||
use crate::{error::SqliteClientError, DataConnection};
|
||||
use crate::{error::SqliteClientError, Account, DataConnection};
|
||||
|
||||
/// Returns the address for the account.
|
||||
///
|
||||
|
@ -12,24 +20,33 @@ use crate::{error::SqliteClientError, DataConnection};
|
|||
///
|
||||
/// ```
|
||||
/// use tempfile::NamedTempFile;
|
||||
/// use zcash_primitives::{
|
||||
/// consensus::{self, Network},
|
||||
/// };
|
||||
/// use zcash_client_sqlite::{
|
||||
/// Account,
|
||||
/// DataConnection,
|
||||
/// query::get_address,
|
||||
/// };
|
||||
///
|
||||
/// let data_file = NamedTempFile::new().unwrap();
|
||||
/// let db = DataConnection::for_path(data_file).unwrap();
|
||||
/// let addr = get_address(&db, 0);
|
||||
/// let addr = get_address(&db, &Network::TestNetwork, Account(0));
|
||||
/// ```
|
||||
pub fn get_address(data: &DataConnection, account: u32) -> Result<String, rusqlite::Error> {
|
||||
let addr = data.0.query_row(
|
||||
pub fn get_address<P: consensus::Parameters>(
|
||||
data: &DataConnection,
|
||||
params: &P,
|
||||
account: Account,
|
||||
) -> Result<Option<PaymentAddress>, SqliteClientError> {
|
||||
let addr: String = data.0.query_row(
|
||||
"SELECT address FROM accounts
|
||||
WHERE account = ?",
|
||||
&[account],
|
||||
&[account.0],
|
||||
|row| row.get(0),
|
||||
)?;
|
||||
|
||||
Ok(addr)
|
||||
decode_payment_address(params.hrp_sapling_payment_address(), &addr)
|
||||
.map_err(|e| SqliteClientError(e.into()))
|
||||
}
|
||||
|
||||
/// Returns the balance for the account, including all mined unspent notes that we know
|
||||
|
@ -200,7 +217,7 @@ mod tests {
|
|||
|
||||
use crate::{
|
||||
init::{init_accounts_table, init_data_database},
|
||||
tests, DataConnection,
|
||||
tests, Account, DataConnection,
|
||||
};
|
||||
|
||||
use super::{get_address, get_balance, get_verified_balance};
|
||||
|
@ -227,7 +244,7 @@ mod tests {
|
|||
}
|
||||
|
||||
// An invalid account has zero balance
|
||||
assert!(get_address(&db_data, 1).is_err());
|
||||
assert!(get_address(&db_data, &tests::network(), Account(1)).is_err());
|
||||
assert_eq!(get_balance(&db_data, 1).unwrap(), Amount::zero());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -377,7 +377,7 @@ mod tests {
|
|||
|
||||
use zcash_primitives::{
|
||||
block::BlockHash,
|
||||
consensus,
|
||||
consensus::{self, BlockHeight},
|
||||
note_encryption::try_sapling_output_recovery,
|
||||
prover::TxProver,
|
||||
transaction::{components::Amount, Transaction},
|
||||
|
@ -487,7 +487,14 @@ mod tests {
|
|||
let data_file = NamedTempFile::new().unwrap();
|
||||
let db_data = DataConnection(Connection::open(data_file.path()).unwrap());
|
||||
init_data_database(&db_data).unwrap();
|
||||
init_blocks_table(&db_data, 1, BlockHash([1; 32]), 1, &[]).unwrap();
|
||||
init_blocks_table(
|
||||
&db_data,
|
||||
BlockHeight::from(1u32),
|
||||
BlockHash([1; 32]),
|
||||
1,
|
||||
&[],
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// Add an account to the wallet
|
||||
let extsk = ExtendedSpendingKey::master(&[]);
|
||||
|
|
Loading…
Reference in New Issue