Update to librustzcash c45d3aed8a

This commit is contained in:
Kris Nuttycombe 2024-03-22 16:54:40 -06:00
parent 159ec41a71
commit 14d6fe18de
10 changed files with 344 additions and 101 deletions

173
Cargo.lock generated
View File

@ -520,6 +520,15 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0"
[[package]]
name = "document-features"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef5282ad69563b5fc40319526ba27e0e7363d552a896f0297d54f767717f9b95"
dependencies = [
"litrs",
]
[[package]]
name = "either"
version = "1.9.0"
@ -529,7 +538,7 @@ checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
[[package]]
name = "equihash"
version = "0.2.0"
source = "git+https://github.com/zcash/librustzcash.git?rev=236cd569ee4a824d98920d1a61b8cc2b90ceba1d#236cd569ee4a824d98920d1a61b8cc2b90ceba1d"
source = "git+https://github.com/zcash/librustzcash.git?rev=c45d3aed8ae2ac5ab41878df864eb4889793ac1b#c45d3aed8ae2ac5ab41878df864eb4889793ac1b"
dependencies = [
"blake2b_simd",
"byteorder",
@ -554,7 +563,7 @@ dependencies = [
[[package]]
name = "f4jumble"
version = "0.1.0"
source = "git+https://github.com/zcash/librustzcash.git?rev=236cd569ee4a824d98920d1a61b8cc2b90ceba1d#236cd569ee4a824d98920d1a61b8cc2b90ceba1d"
source = "git+https://github.com/zcash/librustzcash.git?rev=c45d3aed8ae2ac5ab41878df864eb4889793ac1b#c45d3aed8ae2ac5ab41878df864eb4889793ac1b"
dependencies = [
"blake2b_simd",
]
@ -934,8 +943,7 @@ dependencies = [
[[package]]
name = "incrementalmerkletree"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "361c467824d4d9d4f284be4b2608800839419dccc4d4608f28345237fe354623"
source = "git+https://github.com/zcash/incrementalmerkletree?rev=e1a7a80212c22e5a8912d05860f7eb6899c56a7c#e1a7a80212c22e5a8912d05860f7eb6899c56a7c"
dependencies = [
"either",
]
@ -1045,6 +1053,12 @@ version = "0.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f"
[[package]]
name = "litrs"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5"
[[package]]
name = "log"
version = "0.4.20"
@ -1227,9 +1241,8 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
[[package]]
name = "orchard"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d31e68534df32024dcc89a8390ec6d7bef65edd87d91b45cfb481a2eb2d77c5"
version = "0.7.1"
source = "git+https://github.com/zcash/orchard?rev=33474bdbfd7268e1f84718078d47f63d01a879d5#33474bdbfd7268e1f84718078d47f63d01a879d5"
dependencies = [
"aes",
"bitvec",
@ -1251,6 +1264,8 @@ dependencies = [
"subtle",
"tracing",
"zcash_note_encryption",
"zcash_spec",
"zip32",
]
[[package]]
@ -1709,6 +1724,37 @@ version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
[[package]]
name = "sapling-crypto"
version = "0.1.2"
source = "git+https://github.com/zcash/sapling-crypto?rev=22412ae07644813253feb064d1692b0823242853#22412ae07644813253feb064d1692b0823242853"
dependencies = [
"aes",
"bellman",
"bitvec",
"blake2b_simd",
"blake2s_simd",
"bls12_381",
"byteorder",
"document-features",
"ff",
"fpe",
"group",
"hex",
"incrementalmerkletree",
"jubjub",
"lazy_static",
"memuse",
"rand",
"rand_core",
"redjubjub",
"subtle",
"tracing",
"zcash_note_encryption",
"zcash_spec",
"zip32",
]
[[package]]
name = "schemer"
version = "0.2.1"
@ -1841,8 +1887,7 @@ dependencies = [
[[package]]
name = "shardtree"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbf20c7a2747d9083092e3a3eeb9a7ed75577ae364896bebbc5e0bdcd4e97735"
source = "git+https://github.com/zcash/incrementalmerkletree?rev=e1a7a80212c22e5a8912d05860f7eb6899c56a7c#e1a7a80212c22e5a8912d05860f7eb6899c56a7c"
dependencies = [
"bitflags 2.4.1",
"either",
@ -2608,19 +2653,20 @@ checksum = "213b7324336b53d2414b2db8537e56544d981803139155afa84f76eeebb7a546"
[[package]]
name = "zcash_address"
version = "0.3.0"
source = "git+https://github.com/zcash/librustzcash.git?rev=236cd569ee4a824d98920d1a61b8cc2b90ceba1d#236cd569ee4a824d98920d1a61b8cc2b90ceba1d"
version = "0.3.2"
source = "git+https://github.com/zcash/librustzcash.git?rev=c45d3aed8ae2ac5ab41878df864eb4889793ac1b#c45d3aed8ae2ac5ab41878df864eb4889793ac1b"
dependencies = [
"bech32",
"bs58",
"f4jumble",
"zcash_encoding",
"zcash_protocol",
]
[[package]]
name = "zcash_client_backend"
version = "0.10.0"
source = "git+https://github.com/zcash/librustzcash.git?rev=236cd569ee4a824d98920d1a61b8cc2b90ceba1d#236cd569ee4a824d98920d1a61b8cc2b90ceba1d"
version = "0.11.1"
source = "git+https://github.com/zcash/librustzcash.git?rev=c45d3aed8ae2ac5ab41878df864eb4889793ac1b#c45d3aed8ae2ac5ab41878df864eb4889793ac1b"
dependencies = [
"base64",
"bech32",
@ -2628,6 +2674,7 @@ dependencies = [
"bs58",
"byteorder",
"crossbeam-channel",
"document-features",
"group",
"hex",
"incrementalmerkletree",
@ -2637,7 +2684,9 @@ dependencies = [
"orchard",
"percent-encoding",
"prost",
"rand_core",
"rayon",
"sapling-crypto",
"secrecy",
"shardtree",
"subtle",
@ -2648,44 +2697,83 @@ dependencies = [
"which",
"zcash_address",
"zcash_encoding",
"zcash_keys",
"zcash_note_encryption",
"zcash_primitives",
"zcash_protocol",
"zip32",
]
[[package]]
name = "zcash_client_sqlite"
version = "0.8.1"
source = "git+https://github.com/zcash/librustzcash.git?rev=236cd569ee4a824d98920d1a61b8cc2b90ceba1d#236cd569ee4a824d98920d1a61b8cc2b90ceba1d"
version = "0.9.1"
source = "git+https://github.com/zcash/librustzcash.git?rev=c45d3aed8ae2ac5ab41878df864eb4889793ac1b#c45d3aed8ae2ac5ab41878df864eb4889793ac1b"
dependencies = [
"bs58",
"byteorder",
"document-features",
"group",
"incrementalmerkletree",
"jubjub",
"maybe-rayon",
"nonempty",
"orchard",
"prost",
"rusqlite",
"sapling-crypto",
"schemer",
"schemer-rusqlite",
"secrecy",
"shardtree",
"subtle",
"time 0.3.30",
"tracing",
"uuid",
"zcash_address",
"zcash_client_backend",
"zcash_encoding",
"zcash_keys",
"zcash_primitives",
"zcash_protocol",
"zip32",
]
[[package]]
name = "zcash_encoding"
version = "0.2.0"
source = "git+https://github.com/zcash/librustzcash.git?rev=236cd569ee4a824d98920d1a61b8cc2b90ceba1d#236cd569ee4a824d98920d1a61b8cc2b90ceba1d"
source = "git+https://github.com/zcash/librustzcash.git?rev=c45d3aed8ae2ac5ab41878df864eb4889793ac1b#c45d3aed8ae2ac5ab41878df864eb4889793ac1b"
dependencies = [
"byteorder",
"nonempty",
]
[[package]]
name = "zcash_keys"
version = "0.1.1"
source = "git+https://github.com/zcash/librustzcash.git?rev=c45d3aed8ae2ac5ab41878df864eb4889793ac1b#c45d3aed8ae2ac5ab41878df864eb4889793ac1b"
dependencies = [
"bech32",
"blake2b_simd",
"bls12_381",
"bs58",
"byteorder",
"document-features",
"group",
"memuse",
"nonempty",
"orchard",
"rand_core",
"sapling-crypto",
"secrecy",
"subtle",
"tracing",
"zcash_address",
"zcash_encoding",
"zcash_primitives",
"zcash_protocol",
"zip32",
]
[[package]]
name = "zcash_note_encryption"
version = "0.4.0"
@ -2701,17 +2789,14 @@ dependencies = [
[[package]]
name = "zcash_primitives"
version = "0.13.0"
source = "git+https://github.com/zcash/librustzcash.git?rev=236cd569ee4a824d98920d1a61b8cc2b90ceba1d#236cd569ee4a824d98920d1a61b8cc2b90ceba1d"
version = "0.14.0"
source = "git+https://github.com/zcash/librustzcash.git?rev=c45d3aed8ae2ac5ab41878df864eb4889793ac1b#c45d3aed8ae2ac5ab41878df864eb4889793ac1b"
dependencies = [
"aes",
"bellman",
"bip0039",
"bitvec",
"blake2b_simd",
"blake2s_simd",
"bls12_381",
"byteorder",
"document-features",
"equihash",
"ff",
"fpe",
@ -2719,29 +2804,33 @@ dependencies = [
"hex",
"incrementalmerkletree",
"jubjub",
"lazy_static",
"memuse",
"nonempty",
"orchard",
"rand",
"rand_core",
"redjubjub",
"sapling-crypto",
"sha2",
"subtle",
"tracing",
"zcash_address",
"zcash_encoding",
"zcash_note_encryption",
"zcash_protocol",
"zcash_spec",
"zip32",
]
[[package]]
name = "zcash_proofs"
version = "0.13.0"
source = "git+https://github.com/zcash/librustzcash.git?rev=236cd569ee4a824d98920d1a61b8cc2b90ceba1d#236cd569ee4a824d98920d1a61b8cc2b90ceba1d"
version = "0.14.0"
source = "git+https://github.com/zcash/librustzcash.git?rev=c45d3aed8ae2ac5ab41878df864eb4889793ac1b#c45d3aed8ae2ac5ab41878df864eb4889793ac1b"
dependencies = [
"bellman",
"blake2b_simd",
"bls12_381",
"document-features",
"group",
"home",
"jubjub",
@ -2749,11 +2838,30 @@ dependencies = [
"lazy_static",
"rand_core",
"redjubjub",
"sapling-crypto",
"tracing",
"xdg",
"zcash_primitives",
]
[[package]]
name = "zcash_protocol"
version = "0.1.0"
source = "git+https://github.com/zcash/librustzcash.git?rev=c45d3aed8ae2ac5ab41878df864eb4889793ac1b#c45d3aed8ae2ac5ab41878df864eb4889793ac1b"
dependencies = [
"document-features",
"memuse",
]
[[package]]
name = "zcash_spec"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7a3bf58b673cb3dacd8ae09ba345998923a197ab0da70d6239d8e8838949e9b"
dependencies = [
"blake2b_simd",
]
[[package]]
name = "zec-sqlite-cli"
version = "0.1.0"
@ -2761,9 +2869,11 @@ dependencies = [
"anyhow",
"futures-util",
"gumdrop",
"orchard",
"prost",
"rayon",
"rusqlite",
"sapling-crypto",
"schemer",
"secrecy",
"time 0.2.27",
@ -2773,8 +2883,10 @@ dependencies = [
"tracing-subscriber",
"zcash_client_backend",
"zcash_client_sqlite",
"zcash_keys",
"zcash_primitives",
"zcash_proofs",
"zcash_protocol",
]
[[package]]
@ -2816,3 +2928,14 @@ dependencies = [
"quote",
"syn 2.0.38",
]
[[package]]
name = "zip32"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4226d0aee9c9407c27064dfeec9d7b281c917de3374e1e5a2e2cfad9e09de19e"
dependencies = [
"blake2b_simd",
"memuse",
"subtle",
]

View File

@ -13,6 +13,8 @@ gumdrop = "0.8"
prost = "0.12"
rayon = "1.7"
rusqlite = { version = "0.29", features = ["time"] }
orchard = { version = "0.7.1", default-features = false }
sapling = { package = "sapling-crypto", version = "0.1.2" }
schemer = "0.2"
secrecy = "0.8"
time = "0.2"
@ -20,13 +22,21 @@ tokio = { version = "1.21.0", features = ["fs", "macros", "rt-multi-thread"] }
tonic = { version = "0.10", features = ["gzip", "tls-webpki-roots"] }
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter", "fmt"] }
zcash_client_backend = { version = "0.10", features = ["lightwalletd-tonic"] }
zcash_client_sqlite = { version = "0.8", features = ["unstable"] }
zcash_primitives = "0.13"
zcash_proofs = "0.13"
zcash_client_backend = { version = "0.11", features = ["lightwalletd-tonic", "orchard"] }
zcash_client_sqlite = { version = "0.9", features = ["unstable", "orchard"] }
zcash_keys = { version = "0.1", features = ["unstable", "orchard"] }
zcash_primitives = "0.14"
zcash_proofs = "0.14"
zcash_protocol = "0.1"
[patch.crates-io]
zcash_primitives = { git = "https://github.com/zcash/librustzcash.git", rev = "236cd569ee4a824d98920d1a61b8cc2b90ceba1d" }
zcash_proofs = { git = "https://github.com/zcash/librustzcash.git", rev = "236cd569ee4a824d98920d1a61b8cc2b90ceba1d" }
zcash_client_backend = { git = "https://github.com/zcash/librustzcash.git", rev = "236cd569ee4a824d98920d1a61b8cc2b90ceba1d" }
zcash_client_sqlite = { git = "https://github.com/zcash/librustzcash.git", rev = "236cd569ee4a824d98920d1a61b8cc2b90ceba1d" }
zcash_keys = { git = "https://github.com/zcash/librustzcash.git", rev = "c45d3aed8ae2ac5ab41878df864eb4889793ac1b" }
zcash_primitives = { git = "https://github.com/zcash/librustzcash.git", rev = "c45d3aed8ae2ac5ab41878df864eb4889793ac1b" }
zcash_protocol = { git = "https://github.com/zcash/librustzcash.git", rev = "c45d3aed8ae2ac5ab41878df864eb4889793ac1b" }
zcash_proofs = { git = "https://github.com/zcash/librustzcash.git", rev = "c45d3aed8ae2ac5ab41878df864eb4889793ac1b" }
zcash_client_backend = { git = "https://github.com/zcash/librustzcash.git", rev = "c45d3aed8ae2ac5ab41878df864eb4889793ac1b" }
zcash_client_sqlite = { git = "https://github.com/zcash/librustzcash.git", rev = "c45d3aed8ae2ac5ab41878df864eb4889793ac1b" }
orchard = { git = "https://github.com/zcash/orchard", rev = "33474bdbfd7268e1f84718078d47f63d01a879d5" }
incrementalmerkletree = { git = "https://github.com/zcash/incrementalmerkletree", rev = "e1a7a80212c22e5a8912d05860f7eb6899c56a7c" }
sapling = { git = "https://github.com/zcash/sapling-crypto", package = "sapling-crypto", rev = "22412ae07644813253feb064d1692b0823242853" }
shardtree = { git = "https://github.com/zcash/incrementalmerkletree", rev = "e1a7a80212c22e5a8912d05860f7eb6899c56a7c" }

View File

@ -3,7 +3,6 @@ use gumdrop::Options;
use zcash_client_backend::data_api::WalletRead;
use zcash_client_sqlite::WalletDb;
use zcash_primitives::zip32::AccountId;
use crate::{
data::{get_db_paths, get_wallet_network},
@ -20,18 +19,21 @@ impl Command {
pub(crate) fn run(self, wallet_dir: Option<String>) -> Result<(), anyhow::Error> {
let params = get_wallet_network(wallet_dir.as_ref())?;
let account = AccountId::from(0);
let (_, db_data) = get_db_paths(wallet_dir);
let db_data = WalletDb::for_path(db_data, params)?;
let account_id = *db_data
.get_account_ids()?
.first()
.ok_or(anyhow!("Wallet has no accounts"))?;
let address = db_data
.get_current_address(account)?
.get_current_address(account_id)?
.ok_or(error::Error::InvalidRecipient)?;
if let Some(wallet_summary) = db_data.get_wallet_summary(MIN_CONFIRMATIONS.into())? {
let balance = wallet_summary
.account_balances()
.get(&account)
.get(&account_id)
.ok_or_else(|| anyhow!("Missing account 0"))?;
println!("{:#?}", wallet_summary);
@ -45,8 +47,12 @@ impl Command {
}
println!(" Balance: {}", format_zec(balance.total()));
println!(
" Spendable: {}",
format_zec(balance.sapling_balance.spendable_value)
" Sapling Spendable: {}",
format_zec(balance.sapling_balance().spendable_value())
);
println!(
" Orchard Spendable: {}",
format_zec(balance.orchard_balance().spendable_value())
);
} else {
println!("Insufficient information to build a wallet summary.");

View File

@ -11,7 +11,6 @@ use zcash_client_sqlite::{
};
use zcash_primitives::{
consensus::{self, Parameters},
zip32::AccountId,
zip339::{Count, Mnemonic},
};
@ -102,8 +101,7 @@ impl Command {
};
// Add one account.
let (account, _) = db_data.create_account(seed, birthday)?;
assert_eq!(account, AccountId::from(0));
db_data.create_account(seed, &birthday)?;
Ok(())
}

View File

@ -112,9 +112,9 @@ impl WalletTx {
txid: TxId::from_bytes(txid.try_into().map_err(|_| anyhow!("Invalid TxId"))?),
expiry_height: expiry_height.map(BlockHeight::from_u32),
account_balance_delta: Amount::from_i64(account_balance_delta)
.map_err(|()| anyhow!("Amount out of range"))?,
.map_err(|_| anyhow!("Amount out of range"))?,
fee_paid: fee_paid
.map(|v| NonNegativeAmount::from_u64(v).map_err(|()| anyhow!("Fee out of range")))
.map(|v| NonNegativeAmount::from_u64(v).map_err(|_| anyhow!("Fee out of range")))
.transpose()?,
sent_note_count,
received_note_count,

View File

@ -1,15 +1,12 @@
use anyhow::anyhow;
use gumdrop::Options;
use zcash_client_backend::data_api::{SaplingInputSource, WalletRead};
use zcash_client_sqlite::WalletDb;
use zcash_primitives::{
transaction::components::{
amount::{Amount, MAX_MONEY},
sapling::fees::InputView,
},
zip32::AccountId,
use zcash_client_backend::{
data_api::{InputSource, WalletRead},
ShieldedProtocol,
};
use zcash_client_sqlite::WalletDb;
use zcash_protocol::value::{Zatoshis, MAX_MONEY};
use crate::{
data::{get_db_paths, get_wallet_network},
@ -25,9 +22,12 @@ impl Command {
pub(crate) fn run(self, wallet_dir: Option<String>) -> Result<(), anyhow::Error> {
let params = get_wallet_network(wallet_dir.as_ref())?;
let account = AccountId::from(0);
let (_, db_data) = get_db_paths(wallet_dir);
let db_data = WalletDb::for_path(db_data, params)?;
let account = *db_data
.get_account_ids()?
.first()
.ok_or(anyhow!("Wallet has no accounts"))?;
// Use the height of the maximum scanned block as the anchor height, to emulate a
// zero-conf transaction in order to select every note in the wallet.
@ -37,15 +37,28 @@ impl Command {
.map_err(|e| anyhow!("{:?}", e))?
.block_height();
let notes = db_data.select_spendable_sapling_notes(
let notes = db_data.select_spendable_notes(
account,
Amount::const_from_i64(MAX_MONEY),
Zatoshis::const_from_u64(MAX_MONEY),
&[ShieldedProtocol::Sapling, ShieldedProtocol::Orchard],
anchor_height,
&[],
)?;
for note in notes {
println!("{}: {}", note.note_id(), format_zec(note.value()));
for note in notes.sapling() {
println!(
"Sapling {}: {}",
note.internal_note_id(),
format_zec(note.note_value()?)
);
}
for note in notes.orchard() {
println!(
"Orchard {}: {}",
note.internal_note_id(),
format_zec(note.note_value()?)
);
}
Ok(())

View File

@ -1,16 +1,18 @@
use anyhow::anyhow;
use gumdrop::Options;
use zcash_client_backend::{
address::RecipientAddress,
data_api::wallet::{input_selection::GreedyInputSelector, propose_transfer},
data_api::{
wallet::{input_selection::GreedyInputSelector, propose_transfer},
WalletRead,
},
fees::standard::SingleOutputChangeStrategy,
zip321::{Payment, TransactionRequest},
ShieldedProtocol,
};
use zcash_client_sqlite::WalletDb;
use zcash_primitives::{
transaction::{components::amount::NonNegativeAmount, fees::StandardFeeRule},
zip32::AccountId,
};
use zcash_keys::address::Address;
use zcash_primitives::transaction::{components::amount::NonNegativeAmount, fees::StandardFeeRule};
use crate::{
data::{get_db_paths, get_wallet_network},
@ -71,17 +73,20 @@ impl Command {
pub(crate) async fn run(self, wallet_dir: Option<String>) -> Result<(), anyhow::Error> {
let params = get_wallet_network(wallet_dir.as_ref())?;
let account = AccountId::from(0);
let (_, db_data) = get_db_paths(wallet_dir.as_ref());
let mut db_data = WalletDb::for_path(db_data, params)?;
let account = *db_data
.get_account_ids()?
.first()
.ok_or_else(|| anyhow!("Wallet has no accounts."))?;
let input_selector = GreedyInputSelector::new(
SingleOutputChangeStrategy::new(self.fee_rule.into(), None),
SingleOutputChangeStrategy::new(self.fee_rule.into(), None, ShieldedProtocol::Orchard),
Default::default(),
);
let request = TransactionRequest::new(vec![Payment {
recipient_address: RecipientAddress::decode(&params, &self.address)
recipient_address: Address::decode(&params, &self.address)
.ok_or(error::Error::InvalidRecipient)?,
amount: NonNegativeAmount::from_u64(self.value)
.map_err(|_| error::Error::InvalidAmount)?,

View File

@ -1,21 +1,24 @@
#![allow(deprecated)]
use anyhow::anyhow;
use gumdrop::Options;
use secrecy::ExposeSecret;
use zcash_client_backend::{
address::RecipientAddress,
data_api::{
wallet::{input_selection::GreedyInputSelector, spend},
WalletRead,
Account, AccountSource, WalletRead,
},
fees::standard::SingleOutputChangeStrategy,
keys::UnifiedSpendingKey,
proto::service,
wallet::OvkPolicy,
zip321::{Payment, TransactionRequest},
ShieldedProtocol,
};
use zcash_client_sqlite::WalletDb;
use zcash_primitives::{transaction::components::amount::NonNegativeAmount, zip32::AccountId};
use zcash_keys::address::Address;
use zcash_proofs::prover::LocalTxProver;
use zcash_protocol::value::Zatoshis;
use crate::{
commands::propose::{parse_fee_rule, FeeRule},
@ -28,7 +31,10 @@ use crate::{
// Options accepted for the `send` command
#[derive(Debug, Options)]
pub(crate) struct Command {
#[options(required, help = "the recipient's Sapling or transparent address")]
#[options(
required,
help = "the recipient's Unified, Sapling or transparent address"
)]
address: String,
#[options(required, help = "the amount in zatoshis")]
@ -47,12 +53,23 @@ impl Command {
let keys = read_keys(wallet_dir.as_ref())?;
let params = keys.network();
let account = AccountId::from(0);
let (_, db_data) = get_db_paths(wallet_dir);
let mut db_data = WalletDb::for_path(db_data, params)?;
let account_id = *db_data
.get_account_ids()?
.first()
.ok_or(anyhow!("Wallet has no accounts"))?;
let account = db_data
.get_account(account_id)?
.ok_or(anyhow!("Account missing: {:?}", account_id))?;
let account_index = match account.source() {
AccountSource::Derived { account_index, .. } => account_index,
AccountSource::Imported => unreachable!("Imported accounts are not yet supported."),
};
let usk = UnifiedSpendingKey::from_seed(&params, keys.seed().expose_secret(), account)
.map_err(error::Error::from)?;
let usk =
UnifiedSpendingKey::from_seed(&params, keys.seed().expose_secret(), account_index)
.map_err(error::Error::from)?;
let mut client = connect_to_lightwalletd(&params).await?;
@ -61,15 +78,14 @@ impl Command {
let prover =
LocalTxProver::with_default_location().ok_or(error::Error::MissingParameters)?;
let input_selector = GreedyInputSelector::new(
SingleOutputChangeStrategy::new(self.fee_rule.into(), None),
SingleOutputChangeStrategy::new(self.fee_rule.into(), None, ShieldedProtocol::Orchard),
Default::default(),
);
let request = TransactionRequest::new(vec![Payment {
recipient_address: RecipientAddress::decode(&params, &self.address)
recipient_address: Address::decode(&params, &self.address)
.ok_or(error::Error::InvalidRecipient)?,
amount: NonNegativeAmount::from_u64(self.value)
.map_err(|_| error::Error::InvalidAmount)?,
amount: Zatoshis::from_u64(self.value).map_err(|_| error::Error::InvalidAmount)?,
memo: None,
label: None,
message: None,
@ -77,7 +93,7 @@ impl Command {
}])
.map_err(error::Error::from)?;
let id_tx = spend(
let txids = spend(
&mut db_data,
&params,
&prover,
@ -90,13 +106,24 @@ impl Command {
)
.map_err(error::Error::from)?;
if txids.len() > 1 {
return Err(anyhow!(
"Multi-transaction proposals are not yet supported."
));
}
let txid = *txids.first();
// Send the transaction.
println!("Sending transaction...");
let (txid, raw_tx) = db_data.get_transaction(id_tx).map(|tx| {
let mut raw_tx = service::RawTransaction::default();
tx.write(&mut raw_tx.data).unwrap();
(tx.txid(), raw_tx)
})?;
let (txid, raw_tx) = db_data
.get_transaction(txid)?
.map(|tx| {
let mut raw_tx = service::RawTransaction::default();
tx.write(&mut raw_tx.data).unwrap();
(tx.txid(), raw_tx)
})
.ok_or(anyhow!("Transaction not found for id {:?}", txid))?;
let response = client.send_transaction(raw_tx).await?.into_inner();
if response.error_code != 0 {

View File

@ -3,6 +3,7 @@ use std::path::Path;
use anyhow::anyhow;
use futures_util::TryStreamExt;
use gumdrop::Options;
use orchard::tree::MerkleHashOrchard;
use prost::Message;
use tokio::{fs::File, io::AsyncWriteExt, task::JoinHandle};
@ -10,18 +11,18 @@ use tonic::transport::Channel;
use tracing::{debug, error, info};
use zcash_client_backend::{
data_api::{
chain::{error::Error as ChainError, scan_cached_blocks, BlockSource, CommitmentTreeRoot},
chain::{
error::Error as ChainError, scan_cached_blocks, BlockSource, ChainState,
CommitmentTreeRoot,
},
scanning::{ScanPriority, ScanRange},
WalletCommitmentTrees, WalletRead, WalletWrite,
},
proto::service::{self, compact_tx_streamer_client::CompactTxStreamerClient},
proto::service::{self, compact_tx_streamer_client::CompactTxStreamerClient, BlockId},
};
use zcash_client_sqlite::{chain::BlockMeta, FsBlockDb, FsBlockDbError, WalletDb};
use zcash_primitives::{
consensus::{BlockHeight, Parameters},
merkle_tree::HashSer,
sapling,
};
use zcash_primitives::merkle_tree::HashSer;
use zcash_protocol::consensus::{BlockHeight, Parameters};
use crate::{
data::{get_block_path, get_db_paths, get_wallet_network},
@ -79,11 +80,21 @@ impl Command {
let block_meta =
download_blocks(client, fsblockdb_root, db_cache, scan_range).await?;
let chain_state =
download_chain_state(client, scan_range.block_range().start - 1)
.await?;
// Scan the downloaded blocks and check for scanning errors that
// indicate the wallet's chain tip is out of sync with blockchain
// history.
let scan_ranges_updated =
scan_blocks(params, fsblockdb_root, db_cache, db_data, scan_range)?;
let scan_ranges_updated = scan_blocks(
params,
fsblockdb_root,
db_cache,
db_data,
&chain_state,
scan_range,
)?;
// Delete the now-scanned blocks, because keeping the entire chain
// in CompactBlock files on disk is horrendous for the filesystem.
@ -134,9 +145,18 @@ impl Command {
let block_meta =
download_blocks(client, fsblockdb_root, db_cache, &scan_range).await?;
let chain_state =
download_chain_state(client, scan_range.block_range().start - 1).await?;
// Scan the downloaded blocks.
let scan_ranges_updated =
scan_blocks(params, fsblockdb_root, db_cache, db_data, &scan_range)?;
let scan_ranges_updated = scan_blocks(
params,
fsblockdb_root,
db_cache,
db_data,
&chain_state,
&scan_range,
)?;
// Delete the now-scanned blocks.
block_deletions.push(delete_cached_blocks(fsblockdb_root, block_meta));
@ -181,8 +201,7 @@ async fn update_subtree_roots<P: Parameters>(
request.set_shielded_protocol(service::ShieldedProtocol::Sapling);
// Hack to work around a bug in the initial lightwalletd implementation.
request.max_entries = 65536;
let roots: Vec<CommitmentTreeRoot<sapling::Node>> = client
let sapling_roots: Vec<CommitmentTreeRoot<sapling::Node>> = client
.get_subtree_roots(request)
.await?
.into_inner()
@ -196,8 +215,29 @@ async fn update_subtree_roots<P: Parameters>(
.try_collect()
.await?;
info!("Sapling tree has {} subtrees", roots.len());
db_data.put_sapling_subtree_roots(0, &roots)?;
info!("Sapling tree has {} subtrees", sapling_roots.len());
db_data.put_sapling_subtree_roots(0, &sapling_roots)?;
let mut request = service::GetSubtreeRootsArg::default();
request.set_shielded_protocol(service::ShieldedProtocol::Orchard);
// Hack to work around a bug in the initial lightwalletd implementation.
request.max_entries = 65536;
let orchard_roots: Vec<CommitmentTreeRoot<MerkleHashOrchard>> = client
.get_subtree_roots(request)
.await?
.into_inner()
.and_then(|root| async move {
let root_hash = MerkleHashOrchard::read(&root.root_hash[..])?;
Ok(CommitmentTreeRoot::from_parts(
BlockHeight::from_u32(root.completing_block_height as u32),
root_hash,
))
})
.try_collect()
.await?;
info!("Orchard tree has {} subtrees", orchard_roots.len());
db_data.put_orchard_subtree_roots(0, &orchard_roots)?;
Ok(())
}
@ -274,6 +314,20 @@ async fn download_blocks(
Ok(block_meta)
}
async fn download_chain_state(
client: &mut CompactTxStreamerClient<Channel>,
block_height: BlockHeight,
) -> Result<ChainState, anyhow::Error> {
let tree_state = client
.get_tree_state(BlockId {
height: block_height.into(),
hash: vec![],
})
.await?;
Ok(tree_state.into_inner().to_chain_state()?)
}
fn delete_cached_blocks(fsblockdb_root: &Path, block_meta: Vec<BlockMeta>) -> JoinHandle<()> {
let fsblockdb_root = fsblockdb_root.to_owned();
tokio::spawn(async move {
@ -294,6 +348,7 @@ fn scan_blocks<P: Parameters + Send + 'static>(
fsblockdb_root: &Path,
db_cache: &mut FsBlockDb,
db_data: &mut WalletDb<rusqlite::Connection, P>,
initial_chain_state: &ChainState,
scan_range: &ScanRange,
) -> Result<bool, anyhow::Error> {
info!("Scanning {}", scan_range);
@ -302,6 +357,7 @@ fn scan_blocks<P: Parameters + Send + 'static>(
db_cache,
db_data,
scan_range.block_range().start,
initial_chain_state,
scan_range.len(),
);

View File

@ -1,9 +1,14 @@
use zcash_primitives::transaction::components::Amount;
use zcash_protocol::value::ZatBalance;
const COIN: u64 = 1_0000_0000;
pub(crate) fn format_zec(value: impl Into<Amount>) -> String {
let value = i64::from(value.into());
pub(crate) fn format_zec(value: impl TryInto<ZatBalance>) -> String {
let value = i64::from(
value
.try_into()
.map_err(|_| ())
.expect("Values are formattable"),
);
let abs_value = value.unsigned_abs();
let abs_zec = abs_value / COIN;
let frac = abs_value % COIN;