Skip to content

Commit

Permalink
zcash_client_sqlite: Support sending to t-addrs
Browse files Browse the repository at this point in the history
  • Loading branch information
str4d committed May 24, 2019
1 parent b1d63ef commit ae63116
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 10 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions zcash_client_sqlite/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ edition = "2018"

[dependencies]
bech32 = "0.6"
bs58 = { version = "0.2", features = ["check"] }
ff = { path = "../ff" }
pairing = { path = "../pairing" }
protobuf = "2"
Expand Down
66 changes: 66 additions & 0 deletions zcash_client_sqlite/src/address.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
//! Structs for handling supported address types.

use pairing::bls12_381::Bls12;
use sapling_crypto::primitives::PaymentAddress;
use zcash_client_backend::encoding::{
decode_payment_address, decode_transparent_address, encode_payment_address,
encode_transparent_address,
};
use zcash_primitives::legacy::TransparentAddress;

use super::Error;

#[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) -> Result<Option<Self>, Error> {
if let Some(pa) = decode_payment_address(HRP_SAPLING_PAYMENT_ADDRESS, s)? {
Ok(Some(RecipientAddress::Shielded(pa)))
} else if let Some(addr) =
decode_transparent_address(&B58_PUBKEY_ADDRESS_PREFIX, &B58_SCRIPT_ADDRESS_PREFIX, s)?
{
Ok(Some(RecipientAddress::Transparent(addr)))
} else {
Ok(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,
),
}
}
}
35 changes: 25 additions & 10 deletions zcash_client_sqlite/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ use protobuf::parse_from_bytes;
use rusqlite::{types::ToSql, Connection, NO_PARAMS};
use sapling_crypto::{
jubjub::fs::{Fs, FsRepr},
primitives::{Diversifier, Note, PaymentAddress},
primitives::{Diversifier, Note},
};
use std::cmp;
use std::error;
Expand Down Expand Up @@ -67,6 +67,7 @@ use zcash_client_backend::constants::testnet::{
HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY, HRP_SAPLING_PAYMENT_ADDRESS,
};

pub mod address;
pub mod chain;

const ANCHOR_OFFSET: u32 = 10;
Expand All @@ -91,6 +92,7 @@ pub enum ErrorKind {
ScanRequired,
TableNotEmpty,
Bech32(bech32::Error),
Base58(bs58::decode::DecodeError),
Builder(builder::Error),
Database(rusqlite::Error),
IO(std::io::Error),
Expand Down Expand Up @@ -135,6 +137,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),
Expand All @@ -151,6 +154,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))
Expand Down Expand Up @@ -918,7 +927,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 send_to_address(
/// "/path/to/data.db",
/// SAPLING_CONSENSUS_BRANCH_ID,
Expand All @@ -937,7 +946,7 @@ pub fn send_to_address<P: AsRef<Path>>(
consensus_branch_id: u32,
prover: impl TxProver,
(account, extsk): (u32, &ExtendedSpendingKey),
to: &PaymentAddress<Bls12>,
to: &address::RecipientAddress,
value: Amount,
memo: Option<Memo>,
) -> Result<i64, Error> {
Expand Down Expand Up @@ -1068,7 +1077,12 @@ pub fn send_to_address<P: AsRef<Path>>(
selected.witness,
)?;
}
builder.add_sapling_output(ovk, to.clone(), value, memo.clone())?;
match to {
address::RecipientAddress::Shielded(to) => {
builder.add_sapling_output(ovk, to.clone(), value, memo.clone())
}
address::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) {
Expand Down Expand Up @@ -1110,7 +1124,8 @@ pub fn send_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)
Expand Down Expand Up @@ -1587,7 +1602,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 send_to_address(
Expand Down Expand Up @@ -1626,7 +1641,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 send_to_address(db_data, 1, test_prover(), (0, &extsk), &to, Amount(1), None) {
Expand All @@ -1646,7 +1661,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(0));
Expand Down Expand Up @@ -1707,7 +1722,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 send_to_address(
db_data,
1,
Expand Down Expand Up @@ -1806,7 +1821,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();
send_to_address(
db_data,
1,
Expand Down

0 comments on commit ae63116

Please sign in to comment.