zcash_client_sqlite: Support sending to t-addrs
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -676,6 +676,7 @@ name = "zcash_client_sqlite"
|
|||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bech32 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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",
|
"ff 0.4.0",
|
||||||
"pairing 0.14.2",
|
"pairing 0.14.2",
|
||||||
"protobuf 2.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"protobuf 2.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ edition = "2018"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bech32 = "0.7"
|
bech32 = "0.7"
|
||||||
|
bs58 = { version = "0.2", features = ["check"] }
|
||||||
ff = { path = "../ff" }
|
ff = { path = "../ff" }
|
||||||
pairing = { path = "../pairing" }
|
pairing = { path = "../pairing" }
|
||||||
protobuf = "2"
|
protobuf = "2"
|
||||||
|
|||||||
63
zcash_client_sqlite/src/address.rs
Normal file
63
zcash_client_sqlite/src/address.rs
Normal 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,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,6 +20,7 @@ pub enum ErrorKind {
|
|||||||
ScanRequired,
|
ScanRequired,
|
||||||
TableNotEmpty,
|
TableNotEmpty,
|
||||||
Bech32(bech32::Error),
|
Bech32(bech32::Error),
|
||||||
|
Base58(bs58::decode::DecodeError),
|
||||||
Builder(builder::Error),
|
Builder(builder::Error),
|
||||||
Database(rusqlite::Error),
|
Database(rusqlite::Error),
|
||||||
Io(std::io::Error),
|
Io(std::io::Error),
|
||||||
@@ -65,6 +66,7 @@ impl fmt::Display for Error {
|
|||||||
ErrorKind::ScanRequired => write!(f, "Must scan blocks first"),
|
ErrorKind::ScanRequired => write!(f, "Must scan blocks first"),
|
||||||
ErrorKind::TableNotEmpty => write!(f, "Table is not empty"),
|
ErrorKind::TableNotEmpty => write!(f, "Table is not empty"),
|
||||||
ErrorKind::Bech32(e) => write!(f, "{}", e),
|
ErrorKind::Bech32(e) => write!(f, "{}", e),
|
||||||
|
ErrorKind::Base58(e) => write!(f, "{}", e),
|
||||||
ErrorKind::Builder(e) => write!(f, "{:?}", e),
|
ErrorKind::Builder(e) => write!(f, "{:?}", e),
|
||||||
ErrorKind::Database(e) => write!(f, "{}", e),
|
ErrorKind::Database(e) => write!(f, "{}", e),
|
||||||
ErrorKind::Io(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 {
|
impl From<builder::Error> for Error {
|
||||||
fn from(e: builder::Error) -> Self {
|
fn from(e: builder::Error) -> Self {
|
||||||
Error(ErrorKind::Builder(e))
|
Error(ErrorKind::Builder(e))
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ use zcash_client_backend::constants::testnet::{
|
|||||||
HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY, HRP_SAPLING_PAYMENT_ADDRESS,
|
HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY, HRP_SAPLING_PAYMENT_ADDRESS,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub mod address;
|
||||||
pub mod chain;
|
pub mod chain;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod init;
|
pub mod init;
|
||||||
|
|||||||
@@ -4,12 +4,12 @@ use ff::{PrimeField, PrimeFieldRepr};
|
|||||||
use pairing::bls12_381::Bls12;
|
use pairing::bls12_381::Bls12;
|
||||||
use rusqlite::{types::ToSql, Connection, NO_PARAMS};
|
use rusqlite::{types::ToSql, Connection, NO_PARAMS};
|
||||||
use std::path::Path;
|
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::{
|
use zcash_primitives::{
|
||||||
jubjub::fs::{Fs, FsRepr},
|
jubjub::fs::{Fs, FsRepr},
|
||||||
merkle_tree::IncrementalWitness,
|
merkle_tree::IncrementalWitness,
|
||||||
note_encryption::Memo,
|
note_encryption::Memo,
|
||||||
primitives::{Diversifier, Note, PaymentAddress},
|
primitives::{Diversifier, Note},
|
||||||
prover::TxProver,
|
prover::TxProver,
|
||||||
sapling::Node,
|
sapling::Node,
|
||||||
transaction::{
|
transaction::{
|
||||||
@@ -21,9 +21,9 @@ use zcash_primitives::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
address::RecipientAddress,
|
||||||
error::{Error, ErrorKind},
|
error::{Error, ErrorKind},
|
||||||
get_target_and_anchor_heights, HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY,
|
get_target_and_anchor_heights, HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY,
|
||||||
HRP_SAPLING_PAYMENT_ADDRESS,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SelectedNoteRow {
|
struct SelectedNoteRow {
|
||||||
@@ -61,7 +61,7 @@ struct SelectedNoteRow {
|
|||||||
///
|
///
|
||||||
/// let account = 0;
|
/// let account = 0;
|
||||||
/// let extsk = spending_key(&[0; 32][..], COIN_TYPE, account);
|
/// 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(
|
/// match create_to_address(
|
||||||
/// "/path/to/data.db",
|
/// "/path/to/data.db",
|
||||||
/// SAPLING_CONSENSUS_BRANCH_ID,
|
/// SAPLING_CONSENSUS_BRANCH_ID,
|
||||||
@@ -80,7 +80,7 @@ pub fn create_to_address<P: AsRef<Path>>(
|
|||||||
consensus_branch_id: u32,
|
consensus_branch_id: u32,
|
||||||
prover: impl TxProver,
|
prover: impl TxProver,
|
||||||
(account, extsk): (u32, &ExtendedSpendingKey),
|
(account, extsk): (u32, &ExtendedSpendingKey),
|
||||||
to: &PaymentAddress<Bls12>,
|
to: &RecipientAddress,
|
||||||
value: Amount,
|
value: Amount,
|
||||||
memo: Option<Memo>,
|
memo: Option<Memo>,
|
||||||
) -> Result<i64, Error> {
|
) -> Result<i64, Error> {
|
||||||
@@ -221,7 +221,12 @@ pub fn create_to_address<P: AsRef<Path>>(
|
|||||||
selected.witness,
|
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)?;
|
let (tx, tx_metadata) = builder.build(consensus_branch_id, prover)?;
|
||||||
// We only called add_sapling_output() once.
|
// We only called add_sapling_output() once.
|
||||||
let output_index = match tx_metadata.output_index(0) {
|
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.
|
// 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 {
|
if let Some(memo) = memo {
|
||||||
let mut stmt_insert_sent_note = data.prepare(
|
let mut stmt_insert_sent_note = data.prepare(
|
||||||
"INSERT INTO sent_notes (tx, output_index, from_account, address, value, memo)
|
"INSERT INTO sent_notes (tx, output_index, from_account, address, value, memo)
|
||||||
@@ -340,7 +346,7 @@ mod tests {
|
|||||||
ExtendedFullViewingKey::from(&extsk1),
|
ExtendedFullViewingKey::from(&extsk1),
|
||||||
];
|
];
|
||||||
init_accounts_table(&db_data, &extfvks).unwrap();
|
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
|
// Invalid extsk for the given account should cause an error
|
||||||
match create_to_address(
|
match create_to_address(
|
||||||
@@ -379,7 +385,7 @@ mod tests {
|
|||||||
let extsk = ExtendedSpendingKey::master(&[]);
|
let extsk = ExtendedSpendingKey::master(&[]);
|
||||||
let extfvks = [ExtendedFullViewingKey::from(&extsk)];
|
let extfvks = [ExtendedFullViewingKey::from(&extsk)];
|
||||||
init_accounts_table(&db_data, &extfvks).unwrap();
|
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
|
// We cannot do anything if we aren't synchronised
|
||||||
match create_to_address(
|
match create_to_address(
|
||||||
@@ -407,7 +413,7 @@ mod tests {
|
|||||||
let extsk = ExtendedSpendingKey::master(&[]);
|
let extsk = ExtendedSpendingKey::master(&[]);
|
||||||
let extfvks = [ExtendedFullViewingKey::from(&extsk)];
|
let extfvks = [ExtendedFullViewingKey::from(&extsk)];
|
||||||
init_accounts_table(&db_data, &extfvks).unwrap();
|
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
|
// Account balance should be zero
|
||||||
assert_eq!(get_balance(db_data, 0).unwrap(), Amount::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
|
// Spend fails because there are insufficient verified notes
|
||||||
let extsk2 = ExtendedSpendingKey::master(&[]);
|
let extsk2 = ExtendedSpendingKey::master(&[]);
|
||||||
let to = extsk2.default_address().unwrap().1;
|
let to = extsk2.default_address().unwrap().1.into();
|
||||||
match create_to_address(
|
match create_to_address(
|
||||||
db_data,
|
db_data,
|
||||||
1,
|
1,
|
||||||
@@ -575,7 +581,7 @@ mod tests {
|
|||||||
|
|
||||||
// Send some of the funds to another address
|
// Send some of the funds to another address
|
||||||
let extsk2 = ExtendedSpendingKey::master(&[]);
|
let extsk2 = ExtendedSpendingKey::master(&[]);
|
||||||
let to = extsk2.default_address().unwrap().1;
|
let to = extsk2.default_address().unwrap().1.into();
|
||||||
create_to_address(
|
create_to_address(
|
||||||
db_data,
|
db_data,
|
||||||
1,
|
1,
|
||||||
|
|||||||
Reference in New Issue
Block a user