zcash_client_sqlite: Support sending to t-addrs

This commit is contained in:
Jack Grigg 2019-05-24 15:59:18 +01:00
parent 1c60a79ec1
commit 1cbeac9d59
No known key found for this signature in database
GPG Key ID: 9E8255172BBF9898
6 changed files with 92 additions and 12 deletions

1
Cargo.lock generated
View File

@ -676,6 +676,7 @@ name = "zcash_client_sqlite"
version = "0.0.0"
dependencies = [
"bech32 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"bs58 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"ff 0.4.0",
"pairing 0.14.2",
"protobuf 2.8.0 (registry+https://github.com/rust-lang/crates.io-index)",

View File

@ -8,6 +8,7 @@ edition = "2018"
[dependencies]
bech32 = "0.7"
bs58 = { version = "0.2", features = ["check"] }
ff = { path = "../ff" }
pairing = { path = "../pairing" }
protobuf = "2"

View File

@ -0,0 +1,63 @@
//! Structs for handling supported address types.
use pairing::bls12_381::Bls12;
use zcash_client_backend::encoding::{
decode_payment_address, decode_transparent_address, encode_payment_address,
encode_transparent_address,
};
use zcash_primitives::{legacy::TransparentAddress, primitives::PaymentAddress};
#[cfg(feature = "mainnet")]
use zcash_client_backend::constants::mainnet::{
B58_PUBKEY_ADDRESS_PREFIX, B58_SCRIPT_ADDRESS_PREFIX, HRP_SAPLING_PAYMENT_ADDRESS,
};
#[cfg(not(feature = "mainnet"))]
use zcash_client_backend::constants::testnet::{
B58_PUBKEY_ADDRESS_PREFIX, B58_SCRIPT_ADDRESS_PREFIX, HRP_SAPLING_PAYMENT_ADDRESS,
};
/// An address that funds can be sent to.
pub enum RecipientAddress {
Shielded(PaymentAddress<Bls12>),
Transparent(TransparentAddress),
}
impl From<PaymentAddress<Bls12>> for RecipientAddress {
fn from(addr: PaymentAddress<Bls12>) -> Self {
RecipientAddress::Shielded(addr)
}
}
impl From<TransparentAddress> for RecipientAddress {
fn from(addr: TransparentAddress) -> Self {
RecipientAddress::Transparent(addr)
}
}
impl RecipientAddress {
pub fn from_str(s: &str) -> Option<Self> {
if let Ok(Some(pa)) = decode_payment_address(HRP_SAPLING_PAYMENT_ADDRESS, s) {
Some(pa.into())
} else if let Ok(Some(addr)) =
decode_transparent_address(&B58_PUBKEY_ADDRESS_PREFIX, &B58_SCRIPT_ADDRESS_PREFIX, s)
{
Some(addr.into())
} else {
None
}
}
pub fn to_string(&self) -> String {
match self {
RecipientAddress::Shielded(pa) => {
encode_payment_address(HRP_SAPLING_PAYMENT_ADDRESS, pa)
}
RecipientAddress::Transparent(addr) => encode_transparent_address(
&B58_PUBKEY_ADDRESS_PREFIX,
&B58_SCRIPT_ADDRESS_PREFIX,
addr,
),
}
}
}

View File

@ -20,6 +20,7 @@ pub enum ErrorKind {
ScanRequired,
TableNotEmpty,
Bech32(bech32::Error),
Base58(bs58::decode::DecodeError),
Builder(builder::Error),
Database(rusqlite::Error),
Io(std::io::Error),
@ -65,6 +66,7 @@ impl fmt::Display for Error {
ErrorKind::ScanRequired => write!(f, "Must scan blocks first"),
ErrorKind::TableNotEmpty => write!(f, "Table is not empty"),
ErrorKind::Bech32(e) => write!(f, "{}", e),
ErrorKind::Base58(e) => write!(f, "{}", e),
ErrorKind::Builder(e) => write!(f, "{:?}", e),
ErrorKind::Database(e) => write!(f, "{}", e),
ErrorKind::Io(e) => write!(f, "{}", e),
@ -93,6 +95,12 @@ impl From<bech32::Error> for Error {
}
}
impl From<bs58::decode::DecodeError> for Error {
fn from(e: bs58::decode::DecodeError) -> Self {
Error(ErrorKind::Base58(e))
}
}
impl From<builder::Error> for Error {
fn from(e: builder::Error) -> Self {
Error(ErrorKind::Builder(e))

View File

@ -39,6 +39,7 @@ use zcash_client_backend::constants::testnet::{
HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY, HRP_SAPLING_PAYMENT_ADDRESS,
};
pub mod address;
pub mod chain;
pub mod error;
pub mod init;

View File

@ -4,12 +4,12 @@ use ff::{PrimeField, PrimeFieldRepr};
use pairing::bls12_381::Bls12;
use rusqlite::{types::ToSql, Connection, NO_PARAMS};
use std::path::Path;
use zcash_client_backend::encoding::{encode_extended_full_viewing_key, encode_payment_address};
use zcash_client_backend::encoding::encode_extended_full_viewing_key;
use zcash_primitives::{
jubjub::fs::{Fs, FsRepr},
merkle_tree::IncrementalWitness,
note_encryption::Memo,
primitives::{Diversifier, Note, PaymentAddress},
primitives::{Diversifier, Note},
prover::TxProver,
sapling::Node,
transaction::{
@ -21,9 +21,9 @@ use zcash_primitives::{
};
use crate::{
address::RecipientAddress,
error::{Error, ErrorKind},
get_target_and_anchor_heights, HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY,
HRP_SAPLING_PAYMENT_ADDRESS,
};
struct SelectedNoteRow {
@ -61,7 +61,7 @@ struct SelectedNoteRow {
///
/// let account = 0;
/// let extsk = spending_key(&[0; 32][..], COIN_TYPE, account);
/// let to = extsk.default_address().unwrap().1;
/// let to = extsk.default_address().unwrap().1.into();
/// match create_to_address(
/// "/path/to/data.db",
/// SAPLING_CONSENSUS_BRANCH_ID,
@ -80,7 +80,7 @@ pub fn create_to_address<P: AsRef<Path>>(
consensus_branch_id: u32,
prover: impl TxProver,
(account, extsk): (u32, &ExtendedSpendingKey),
to: &PaymentAddress<Bls12>,
to: &RecipientAddress,
value: Amount,
memo: Option<Memo>,
) -> Result<i64, Error> {
@ -221,7 +221,12 @@ pub fn create_to_address<P: AsRef<Path>>(
selected.witness,
)?;
}
builder.add_sapling_output(ovk, to.clone(), value, memo.clone())?;
match to {
RecipientAddress::Shielded(to) => {
builder.add_sapling_output(ovk, to.clone(), value, memo.clone())
}
RecipientAddress::Transparent(to) => builder.add_transparent_output(&to, value),
}?;
let (tx, tx_metadata) = builder.build(consensus_branch_id, prover)?;
// We only called add_sapling_output() once.
let output_index = match tx_metadata.output_index(0) {
@ -263,7 +268,8 @@ pub fn create_to_address<P: AsRef<Path>>(
}
// Save the sent note in the database.
let to_str = encode_payment_address(HRP_SAPLING_PAYMENT_ADDRESS, to);
// TODO: Decide how to save transparent output information.
let to_str = to.to_string();
if let Some(memo) = memo {
let mut stmt_insert_sent_note = data.prepare(
"INSERT INTO sent_notes (tx, output_index, from_account, address, value, memo)
@ -340,7 +346,7 @@ mod tests {
ExtendedFullViewingKey::from(&extsk1),
];
init_accounts_table(&db_data, &extfvks).unwrap();
let to = extsk0.default_address().unwrap().1;
let to = extsk0.default_address().unwrap().1.into();
// Invalid extsk for the given account should cause an error
match create_to_address(
@ -379,7 +385,7 @@ mod tests {
let extsk = ExtendedSpendingKey::master(&[]);
let extfvks = [ExtendedFullViewingKey::from(&extsk)];
init_accounts_table(&db_data, &extfvks).unwrap();
let to = extsk.default_address().unwrap().1;
let to = extsk.default_address().unwrap().1.into();
// We cannot do anything if we aren't synchronised
match create_to_address(
@ -407,7 +413,7 @@ mod tests {
let extsk = ExtendedSpendingKey::master(&[]);
let extfvks = [ExtendedFullViewingKey::from(&extsk)];
init_accounts_table(&db_data, &extfvks).unwrap();
let to = extsk.default_address().unwrap().1;
let to = extsk.default_address().unwrap().1.into();
// Account balance should be zero
assert_eq!(get_balance(db_data, 0).unwrap(), Amount::zero());
@ -476,7 +482,7 @@ mod tests {
// Spend fails because there are insufficient verified notes
let extsk2 = ExtendedSpendingKey::master(&[]);
let to = extsk2.default_address().unwrap().1;
let to = extsk2.default_address().unwrap().1.into();
match create_to_address(
db_data,
1,
@ -575,7 +581,7 @@ mod tests {
// Send some of the funds to another address
let extsk2 = ExtendedSpendingKey::master(&[]);
let to = extsk2.default_address().unwrap().1;
let to = extsk2.default_address().unwrap().1.into();
create_to_address(
db_data,
1,