build(ecc):Upgrade remaining ECC dependencies (#8568)
* upgrade zcash_client_backend for zebra-scan * leave zebra-utils untouched * remove unused * upgrade zcash_primitives and orchard only for zebra-chain crate * update and use TryFrom for amounts * fix imports in serialize * leave doc as it was * leave doc as it was 2 * use `try_into` for amount * use `zip_212_enforcement` * updgrades primitives in zebra-rpc * upgrade ecc dependencies for cargo-utils * fix threading issue * remove non needed Arc * update deny.toml * update primitives for zebra-grpc * fix doc * remove non needed single thread code in test * cleanup some tests * improve a bit the `ready_scan_block_keys` function * clippy * add spawn back in `scan_height_and_store_results` * remove todo * add note comment * use a more explicit import of sapling stuff in serialize * change(scan): Refactor scanning keys (#8577) * Refactor converting dfvks to scanning keys * Simplify handling of scanning keys * Remove `test-dependencies` from the scanner reader * Add comments --------- Co-authored-by: Marek <mail@marek.onl>
This commit is contained in:
parent
f2ab3271e9
commit
dbff3b49bc
143
Cargo.lock
143
Cargo.lock
|
@ -2839,9 +2839,9 @@ checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
|
|||
|
||||
[[package]]
|
||||
name = "orchard"
|
||||
version = "0.6.0"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d31e68534df32024dcc89a8390ec6d7bef65edd87d91b45cfb481a2eb2d77c5"
|
||||
checksum = "1fb255c3ffdccd3c84fe9ebed72aef64fdc72e6a3e4180dd411002d47abaad42"
|
||||
dependencies = [
|
||||
"aes",
|
||||
"bitvec",
|
||||
|
@ -2863,13 +2863,15 @@ dependencies = [
|
|||
"subtle",
|
||||
"tracing",
|
||||
"zcash_note_encryption",
|
||||
"zcash_spec",
|
||||
"zip32",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "orchard"
|
||||
version = "0.7.1"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fb255c3ffdccd3c84fe9ebed72aef64fdc72e6a3e4180dd411002d47abaad42"
|
||||
checksum = "0462569fc8b0d1b158e4d640571867a4e4319225ebee2ab6647e60c70af19ae3"
|
||||
dependencies = [
|
||||
"aes",
|
||||
"bitvec",
|
||||
|
@ -4232,9 +4234,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "shardtree"
|
||||
version = "0.1.0"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c19f96dde3a8693874f7e7c53d95616569b4009379a903789efbd448f4ea9cc7"
|
||||
checksum = "3b3cdd24424ce0b381646737fedddc33c4dcf7dcd2d545056b53f7982097bef5"
|
||||
dependencies = [
|
||||
"bitflags 2.5.0",
|
||||
"either",
|
||||
|
@ -5743,24 +5745,27 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "zcash_client_backend"
|
||||
version = "0.10.0"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6a382af39be9ee5a3788157145c404b7cd19acc440903f6c34b09fb44f0e991"
|
||||
checksum = "0364e69c446fcf96a1f73f342c6c3fa697ea65ae7eeeae7d76ca847b9c442e40"
|
||||
dependencies = [
|
||||
"base64 0.21.7",
|
||||
"bech32",
|
||||
"bls12_381",
|
||||
"bs58",
|
||||
"crossbeam-channel",
|
||||
"document-features",
|
||||
"group",
|
||||
"hex",
|
||||
"incrementalmerkletree",
|
||||
"memuse",
|
||||
"nom",
|
||||
"orchard 0.6.0",
|
||||
"nonempty",
|
||||
"percent-encoding",
|
||||
"prost",
|
||||
"rand_core 0.6.4",
|
||||
"rayon",
|
||||
"sapling-crypto",
|
||||
"secrecy",
|
||||
"shardtree",
|
||||
"subtle",
|
||||
|
@ -5770,8 +5775,11 @@ dependencies = [
|
|||
"which",
|
||||
"zcash_address",
|
||||
"zcash_encoding",
|
||||
"zcash_keys",
|
||||
"zcash_note_encryption",
|
||||
"zcash_primitives 0.13.0",
|
||||
"zcash_primitives 0.15.0",
|
||||
"zcash_protocol",
|
||||
"zip32",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -5795,6 +5803,32 @@ dependencies = [
|
|||
"primitive-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zcash_keys"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "663489ffb4e51bc4436ff8796832612a9ff3c6516f1c620b5a840cb5dcd7b866"
|
||||
dependencies = [
|
||||
"bech32",
|
||||
"blake2b_simd",
|
||||
"bls12_381",
|
||||
"bs58",
|
||||
"document-features",
|
||||
"group",
|
||||
"memuse",
|
||||
"nonempty",
|
||||
"rand_core 0.6.4",
|
||||
"sapling-crypto",
|
||||
"secrecy",
|
||||
"subtle",
|
||||
"tracing",
|
||||
"zcash_address",
|
||||
"zcash_encoding",
|
||||
"zcash_primitives 0.15.0",
|
||||
"zcash_protocol",
|
||||
"zip32",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zcash_note_encryption"
|
||||
version = "0.4.0"
|
||||
|
@ -5808,42 +5842,6 @@ dependencies = [
|
|||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zcash_primitives"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d17e4c94ca8d69d2fcf2be97522da5732a580eb2125cda3b150761952f8df8e6"
|
||||
dependencies = [
|
||||
"aes",
|
||||
"bip0039",
|
||||
"bitvec",
|
||||
"blake2b_simd",
|
||||
"blake2s_simd",
|
||||
"bls12_381",
|
||||
"byteorder",
|
||||
"equihash",
|
||||
"ff",
|
||||
"fpe",
|
||||
"group",
|
||||
"hdwallet",
|
||||
"hex",
|
||||
"incrementalmerkletree",
|
||||
"jubjub",
|
||||
"lazy_static",
|
||||
"memuse",
|
||||
"nonempty",
|
||||
"orchard 0.6.0",
|
||||
"rand 0.8.5",
|
||||
"rand_core 0.6.4",
|
||||
"ripemd",
|
||||
"secp256k1",
|
||||
"sha2",
|
||||
"subtle",
|
||||
"zcash_address",
|
||||
"zcash_encoding",
|
||||
"zcash_note_encryption",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zcash_primitives"
|
||||
version = "0.14.0"
|
||||
|
@ -5882,6 +5880,42 @@ dependencies = [
|
|||
"zip32",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zcash_primitives"
|
||||
version = "0.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5a8d812efec385ecbcefc862c0005bb1336474ea7dd9b671d5bbddaadd04be2"
|
||||
dependencies = [
|
||||
"aes",
|
||||
"bip0039",
|
||||
"blake2b_simd",
|
||||
"byteorder",
|
||||
"document-features",
|
||||
"equihash",
|
||||
"ff",
|
||||
"fpe",
|
||||
"group",
|
||||
"hex",
|
||||
"incrementalmerkletree",
|
||||
"jubjub",
|
||||
"memuse",
|
||||
"nonempty",
|
||||
"orchard 0.8.0",
|
||||
"rand 0.8.5",
|
||||
"rand_core 0.6.4",
|
||||
"redjubjub",
|
||||
"sapling-crypto",
|
||||
"sha2",
|
||||
"subtle",
|
||||
"tracing",
|
||||
"zcash_address",
|
||||
"zcash_encoding",
|
||||
"zcash_note_encryption",
|
||||
"zcash_protocol",
|
||||
"zcash_spec",
|
||||
"zip32",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zcash_proofs"
|
||||
version = "0.14.0"
|
||||
|
@ -5991,7 +6025,7 @@ dependencies = [
|
|||
"jubjub",
|
||||
"lazy_static",
|
||||
"num-integer",
|
||||
"orchard 0.6.0",
|
||||
"orchard 0.7.1",
|
||||
"primitive-types",
|
||||
"proptest",
|
||||
"proptest-derive",
|
||||
|
@ -6002,6 +6036,7 @@ dependencies = [
|
|||
"reddsa",
|
||||
"redjubjub",
|
||||
"ripemd",
|
||||
"sapling-crypto",
|
||||
"secp256k1",
|
||||
"serde",
|
||||
"serde-big-array",
|
||||
|
@ -6021,7 +6056,7 @@ dependencies = [
|
|||
"zcash_encoding",
|
||||
"zcash_history",
|
||||
"zcash_note_encryption",
|
||||
"zcash_primitives 0.13.0",
|
||||
"zcash_primitives 0.14.0",
|
||||
"zcash_protocol",
|
||||
"zebra-test",
|
||||
]
|
||||
|
@ -6088,7 +6123,7 @@ dependencies = [
|
|||
"tonic-build 0.11.0",
|
||||
"tonic-reflection",
|
||||
"tower",
|
||||
"zcash_primitives 0.13.0",
|
||||
"zcash_primitives 0.14.0",
|
||||
"zebra-chain",
|
||||
"zebra-node-services",
|
||||
"zebra-state",
|
||||
|
@ -6171,7 +6206,7 @@ dependencies = [
|
|||
"tower",
|
||||
"tracing",
|
||||
"zcash_address",
|
||||
"zcash_primitives 0.13.0",
|
||||
"zcash_primitives 0.14.0",
|
||||
"zebra-chain",
|
||||
"zebra-consensus",
|
||||
"zebra-network",
|
||||
|
@ -6198,14 +6233,17 @@ dependencies = [
|
|||
"proptest",
|
||||
"proptest-derive",
|
||||
"rand 0.8.5",
|
||||
"sapling-crypto",
|
||||
"semver 1.0.23",
|
||||
"serde",
|
||||
"tokio",
|
||||
"tower",
|
||||
"tracing",
|
||||
"zcash_address",
|
||||
"zcash_client_backend",
|
||||
"zcash_keys",
|
||||
"zcash_note_encryption",
|
||||
"zcash_primitives 0.13.0",
|
||||
"zcash_primitives 0.14.0",
|
||||
"zebra-chain",
|
||||
"zebra-grpc",
|
||||
"zebra-node-services",
|
||||
|
@ -6321,7 +6359,8 @@ dependencies = [
|
|||
"tracing-error",
|
||||
"tracing-subscriber",
|
||||
"zcash_client_backend",
|
||||
"zcash_primitives 0.13.0",
|
||||
"zcash_primitives 0.15.0",
|
||||
"zcash_protocol",
|
||||
"zebra-chain",
|
||||
"zebra-node-services",
|
||||
"zebra-rpc",
|
||||
|
|
|
@ -84,9 +84,8 @@ skip-tree = [
|
|||
# ECC crates
|
||||
|
||||
# wait for zcash_client_backend
|
||||
{ name = "orchard", version = "=0.6.0" },
|
||||
{ name = "zcash_primitives", version = "=0.13.0" },
|
||||
{ name = "zcash_proofs", version = "=0.13.0" },
|
||||
{ name = "orchard", version = "=0.7.0" },
|
||||
{ name = "zcash_primitives", version = "=0.14.0" },
|
||||
|
||||
# wait for hdwallet to upgrade
|
||||
{ name = "ring", version = "=0.16.20" },
|
||||
|
|
|
@ -93,11 +93,12 @@ x25519-dalek = { version = "2.0.1", features = ["serde"] }
|
|||
|
||||
# ECC deps
|
||||
halo2 = { package = "halo2_proofs", version = "0.3.0" }
|
||||
orchard = "0.6.0"
|
||||
orchard = "0.7.0"
|
||||
zcash_encoding = "0.2.0"
|
||||
zcash_history = "0.4.0"
|
||||
zcash_note_encryption = "0.4.0"
|
||||
zcash_primitives = { version = "0.13.0", features = ["transparent-inputs"] }
|
||||
zcash_primitives = { version = "0.14.0", features = ["transparent-inputs"] }
|
||||
sapling = { package = "sapling-crypto", version = "0.1" }
|
||||
zcash_protocol = { version = "0.1.1" }
|
||||
zcash_address = { version = "0.3.2" }
|
||||
|
||||
|
@ -134,7 +135,7 @@ serde_json = { version = "1.0.117", optional = true }
|
|||
tokio = { version = "1.37.0", optional = true }
|
||||
|
||||
# Experimental feature shielded-scan
|
||||
zcash_client_backend = { version = "0.10.0-rc.1", optional = true }
|
||||
zcash_client_backend = { version = "0.12.1", optional = true }
|
||||
|
||||
# Optional testing dependencies
|
||||
proptest = { version = "1.4.0", optional = true }
|
||||
|
|
|
@ -30,7 +30,7 @@ pub const NETWORK_UPGRADES_IN_ORDER: [NetworkUpgrade; 8] = [
|
|||
///
|
||||
/// Network upgrades can change the Zcash network protocol or consensus rules in
|
||||
/// incompatible ways.
|
||||
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize, Ord, PartialOrd)]
|
||||
#[cfg_attr(any(test, feature = "proptest-impl"), derive(Arbitrary))]
|
||||
pub enum NetworkUpgrade {
|
||||
/// The Zcash protocol for a Genesis block.
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
//! Usage: <https://docs.rs/zcash_address/0.2.0/zcash_address/trait.TryFromAddress.html#examples>
|
||||
|
||||
use zcash_address::unified::{self, Container};
|
||||
use zcash_primitives::sapling;
|
||||
|
||||
use crate::{parameters::NetworkKind, transparent, BoxError};
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
//! Defines types and implements methods for parsing Sapling viewing keys and converting them to `zebra-chain` types
|
||||
|
||||
use zcash_client_backend::encoding::decode_extended_full_viewing_key;
|
||||
use zcash_primitives::{
|
||||
constants::*,
|
||||
sapling::keys::{FullViewingKey as SaplingFvk, SaplingIvk},
|
||||
zip32::DiversifiableFullViewingKey as SaplingDfvk,
|
||||
use sapling::keys::{FullViewingKey as SaplingFvk, SaplingIvk};
|
||||
use zcash_client_backend::{
|
||||
encoding::decode_extended_full_viewing_key,
|
||||
keys::sapling::DiversifiableFullViewingKey as SaplingDfvk,
|
||||
};
|
||||
use zcash_primitives::constants::*;
|
||||
|
||||
use crate::parameters::Network;
|
||||
|
||||
|
|
|
@ -20,16 +20,22 @@ pub fn decrypts_successfully(transaction: &Transaction, network: &Network, heigh
|
|||
let alt_tx = convert_tx_to_librustzcash(transaction, network_upgrade)
|
||||
.expect("zcash_primitives and Zebra transaction formats must be compatible");
|
||||
|
||||
let alt_height = height.0.into();
|
||||
let null_sapling_ovk = zcash_primitives::keys::OutgoingViewingKey([0u8; 32]);
|
||||
let null_sapling_ovk = sapling::keys::OutgoingViewingKey([0u8; 32]);
|
||||
|
||||
// Note that, since this function is used to validate coinbase transactions, we can ignore
|
||||
// the "grace period" mentioned in ZIP-212.
|
||||
let zip_212_enforcement = if network_upgrade >= NetworkUpgrade::Canopy {
|
||||
sapling::note_encryption::Zip212Enforcement::On
|
||||
} else {
|
||||
sapling::note_encryption::Zip212Enforcement::Off
|
||||
};
|
||||
|
||||
if let Some(bundle) = alt_tx.sapling_bundle() {
|
||||
for output in bundle.shielded_outputs().iter() {
|
||||
let recovery = zcash_primitives::sapling::note_encryption::try_sapling_output_recovery(
|
||||
network,
|
||||
alt_height,
|
||||
let recovery = sapling::note_encryption::try_sapling_output_recovery(
|
||||
&null_sapling_ovk,
|
||||
output,
|
||||
zip_212_enforcement,
|
||||
);
|
||||
if recovery.is_none() {
|
||||
return false;
|
||||
|
|
|
@ -29,13 +29,13 @@ impl zp_tx::components::transparent::Authorization for TransparentAuth<'_> {
|
|||
// In this block we convert our Output to a librustzcash to TxOut.
|
||||
// (We could do the serialize/deserialize route but it's simple enough to convert manually)
|
||||
impl zp_tx::sighash::TransparentAuthorizingContext for TransparentAuth<'_> {
|
||||
fn input_amounts(&self) -> Vec<zp_tx::components::amount::Amount> {
|
||||
fn input_amounts(&self) -> Vec<zp_tx::components::amount::NonNegativeAmount> {
|
||||
self.all_prev_outputs
|
||||
.iter()
|
||||
.map(|prevout| {
|
||||
zp_tx::components::amount::Amount::from_nonnegative_i64_le_bytes(
|
||||
prevout.value.to_bytes(),
|
||||
)
|
||||
prevout
|
||||
.value
|
||||
.try_into()
|
||||
.expect("will not fail since it was previously validated")
|
||||
})
|
||||
.collect()
|
||||
|
@ -83,39 +83,31 @@ impl<'a>
|
|||
|
||||
struct IdentityMap;
|
||||
|
||||
impl
|
||||
zp_tx::components::sapling::MapAuth<
|
||||
zp_tx::components::sapling::Authorized,
|
||||
zp_tx::components::sapling::Authorized,
|
||||
> for IdentityMap
|
||||
impl zp_tx::components::sapling::MapAuth<sapling::bundle::Authorized, sapling::bundle::Authorized>
|
||||
for IdentityMap
|
||||
{
|
||||
fn map_spend_proof(
|
||||
&self,
|
||||
p: <zp_tx::components::sapling::Authorized as zp_tx::components::sapling::Authorization>::SpendProof,
|
||||
) -> <zp_tx::components::sapling::Authorized as zp_tx::components::sapling::Authorization>::SpendProof
|
||||
{
|
||||
&mut self,
|
||||
p: <sapling::bundle::Authorized as sapling::bundle::Authorization>::SpendProof,
|
||||
) -> <sapling::bundle::Authorized as sapling::bundle::Authorization>::SpendProof {
|
||||
p
|
||||
}
|
||||
|
||||
fn map_output_proof(
|
||||
&self,
|
||||
p: <zp_tx::components::sapling::Authorized as zp_tx::components::sapling::Authorization>::OutputProof,
|
||||
) -> <zp_tx::components::sapling::Authorized as zp_tx::components::sapling::Authorization>::OutputProof
|
||||
{
|
||||
&mut self,
|
||||
p: <sapling::bundle::Authorized as sapling::bundle::Authorization>::OutputProof,
|
||||
) -> <sapling::bundle::Authorized as sapling::bundle::Authorization>::OutputProof {
|
||||
p
|
||||
}
|
||||
|
||||
fn map_auth_sig(
|
||||
&self,
|
||||
s: <zp_tx::components::sapling::Authorized as zp_tx::components::sapling::Authorization>::AuthSig,
|
||||
) -> <zp_tx::components::sapling::Authorized as zp_tx::components::sapling::Authorization>::AuthSig{
|
||||
&mut self,
|
||||
s: <sapling::bundle::Authorized as sapling::bundle::Authorization>::AuthSig,
|
||||
) -> <sapling::bundle::Authorized as sapling::bundle::Authorization>::AuthSig {
|
||||
s
|
||||
}
|
||||
|
||||
fn map_authorization(
|
||||
&self,
|
||||
a: zp_tx::components::sapling::Authorized,
|
||||
) -> zp_tx::components::sapling::Authorized {
|
||||
fn map_authorization(&mut self, a: sapling::bundle::Authorized) -> sapling::bundle::Authorized {
|
||||
a
|
||||
}
|
||||
}
|
||||
|
@ -141,7 +133,7 @@ struct PrecomputedAuth<'a> {
|
|||
|
||||
impl<'a> zp_tx::Authorization for PrecomputedAuth<'a> {
|
||||
type TransparentAuth = TransparentAuth<'a>;
|
||||
type SaplingAuth = zp_tx::components::sapling::Authorized;
|
||||
type SaplingAuth = sapling::bundle::Authorized;
|
||||
type OrchardAuth = orchard::bundle::Authorized;
|
||||
}
|
||||
|
||||
|
@ -213,12 +205,12 @@ impl TryFrom<transparent::Output> for zp_tx::components::TxOut {
|
|||
}
|
||||
}
|
||||
|
||||
/// Convert a Zebra Amount into a librustzcash one.
|
||||
impl TryFrom<Amount<NonNegative>> for zp_tx::components::Amount {
|
||||
/// Convert a Zebra non-negative Amount into a librustzcash one.
|
||||
impl TryFrom<Amount<NonNegative>> for zp_tx::components::amount::NonNegativeAmount {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(amount: Amount<NonNegative>) -> Result<Self, Self::Error> {
|
||||
zp_tx::components::Amount::from_u64(amount.into())
|
||||
zp_tx::components::amount::NonNegativeAmount::from_nonnegative_i64(amount.into())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -327,10 +319,10 @@ pub(crate) fn transparent_output_address(
|
|||
let alt_addr = tx_out.recipient_address();
|
||||
|
||||
match alt_addr {
|
||||
Some(zcash_primitives::legacy::TransparentAddress::PublicKey(pub_key_hash)) => Some(
|
||||
Some(zcash_primitives::legacy::TransparentAddress::PublicKeyHash(pub_key_hash)) => Some(
|
||||
transparent::Address::from_pub_key_hash(network.kind(), pub_key_hash),
|
||||
),
|
||||
Some(zcash_primitives::legacy::TransparentAddress::Script(script_hash)) => Some(
|
||||
Some(zcash_primitives::legacy::TransparentAddress::ScriptHash(script_hash)) => Some(
|
||||
transparent::Address::from_script_hash(network.kind(), script_hash),
|
||||
),
|
||||
None => None,
|
||||
|
|
|
@ -21,7 +21,7 @@ use crate::{
|
|||
};
|
||||
|
||||
use super::*;
|
||||
use sapling::{Output, SharedAnchor, Spend};
|
||||
use crate::sapling;
|
||||
|
||||
impl ZcashDeserialize for jubjub::Fq {
|
||||
fn zcash_deserialize<R: io::Read>(mut reader: R) -> Result<Self, SerializationError> {
|
||||
|
@ -110,7 +110,7 @@ where
|
|||
// range, so we can implement its serialization and deserialization separately.
|
||||
// (Unlike V4, where it must be serialized as part of the transaction.)
|
||||
|
||||
impl ZcashSerialize for Option<sapling::ShieldedData<SharedAnchor>> {
|
||||
impl ZcashSerialize for Option<sapling::ShieldedData<sapling::SharedAnchor>> {
|
||||
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
||||
match self {
|
||||
None => {
|
||||
|
@ -127,21 +127,24 @@ impl ZcashSerialize for Option<sapling::ShieldedData<SharedAnchor>> {
|
|||
}
|
||||
}
|
||||
|
||||
impl ZcashSerialize for sapling::ShieldedData<SharedAnchor> {
|
||||
impl ZcashSerialize for sapling::ShieldedData<sapling::SharedAnchor> {
|
||||
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
||||
// Collect arrays for Spends
|
||||
// There's no unzip3, so we have to unzip twice.
|
||||
let (spend_prefixes, spend_proofs_sigs): (Vec<_>, Vec<_>) = self
|
||||
.spends()
|
||||
.cloned()
|
||||
.map(sapling::Spend::<SharedAnchor>::into_v5_parts)
|
||||
.map(sapling::Spend::<sapling::SharedAnchor>::into_v5_parts)
|
||||
.map(|(prefix, proof, sig)| (prefix, (proof, sig)))
|
||||
.unzip();
|
||||
let (spend_proofs, spend_sigs) = spend_proofs_sigs.into_iter().unzip();
|
||||
|
||||
// Collect arrays for Outputs
|
||||
let (output_prefixes, output_proofs): (Vec<_>, _) =
|
||||
self.outputs().cloned().map(Output::into_v5_parts).unzip();
|
||||
let (output_prefixes, output_proofs): (Vec<_>, _) = self
|
||||
.outputs()
|
||||
.cloned()
|
||||
.map(sapling::Output::into_v5_parts)
|
||||
.unzip();
|
||||
|
||||
// Denoted as `nSpendsSapling` and `vSpendsSapling` in the spec.
|
||||
spend_prefixes.zcash_serialize(&mut writer)?;
|
||||
|
@ -175,7 +178,7 @@ impl ZcashSerialize for sapling::ShieldedData<SharedAnchor> {
|
|||
|
||||
// we can't split ShieldedData out of Option<ShieldedData> deserialization,
|
||||
// because the counts are read along with the arrays.
|
||||
impl ZcashDeserialize for Option<sapling::ShieldedData<SharedAnchor>> {
|
||||
impl ZcashDeserialize for Option<sapling::ShieldedData<sapling::SharedAnchor>> {
|
||||
#[allow(clippy::unwrap_in_result)]
|
||||
fn zcash_deserialize<R: io::Read>(mut reader: R) -> Result<Self, SerializationError> {
|
||||
// Denoted as `nSpendsSapling` and `vSpendsSapling` in the spec.
|
||||
|
@ -269,14 +272,16 @@ impl ZcashDeserialize for Option<sapling::ShieldedData<SharedAnchor>> {
|
|||
.into_iter()
|
||||
.zip(spend_proofs)
|
||||
.zip(spend_sigs)
|
||||
.map(|((prefix, proof), sig)| Spend::<SharedAnchor>::from_v5_parts(prefix, proof, sig))
|
||||
.map(|((prefix, proof), sig)| {
|
||||
sapling::Spend::<sapling::SharedAnchor>::from_v5_parts(prefix, proof, sig)
|
||||
})
|
||||
.collect();
|
||||
|
||||
// Create shielded outputs from deserialized parts
|
||||
let outputs = output_prefixes
|
||||
.into_iter()
|
||||
.zip(output_proofs)
|
||||
.map(|(prefix, proof)| Output::from_v5_parts(prefix, proof))
|
||||
.map(|(prefix, proof)| sapling::Output::from_v5_parts(prefix, proof))
|
||||
.collect();
|
||||
|
||||
// Create transfers
|
||||
|
@ -823,7 +828,7 @@ impl ZcashDeserialize for Transaction {
|
|||
let shielded_outputs =
|
||||
Vec::<sapling::OutputInTransactionV4>::zcash_deserialize(&mut limited_reader)?
|
||||
.into_iter()
|
||||
.map(Output::from_v4)
|
||||
.map(sapling::Output::from_v4)
|
||||
.collect();
|
||||
|
||||
// A bundle of fields denoted in the spec as `nJoinSplit`, `vJoinSplit`,
|
||||
|
|
|
@ -26,7 +26,7 @@ tokio-stream = "0.1.15"
|
|||
tower = { version = "0.4.13", features = ["util", "buffer"] }
|
||||
color-eyre = "0.6.3"
|
||||
|
||||
zcash_primitives = { version = "0.13.0" }
|
||||
zcash_primitives = { version = "0.14.0" }
|
||||
|
||||
zebra-node-services = { path = "../zebra-node-services", version = "1.0.0-beta.37", features = ["shielded-scan"] }
|
||||
zebra-chain = { path = "../zebra-chain" , version = "1.0.0-beta.37" }
|
||||
|
|
|
@ -64,7 +64,7 @@ tracing = "0.1.39"
|
|||
hex = { version = "0.4.3", features = ["serde"] }
|
||||
serde = { version = "1.0.203", features = ["serde_derive"] }
|
||||
|
||||
zcash_primitives = { version = "0.13.0" }
|
||||
zcash_primitives = { version = "0.14.0" }
|
||||
|
||||
# Experimental feature getblocktemplate-rpcs
|
||||
rand = { version = "0.8.5", optional = true }
|
||||
|
|
|
@ -51,8 +51,11 @@ tower = "0.4.13"
|
|||
tracing = "0.1.39"
|
||||
futures = "0.3.30"
|
||||
|
||||
zcash_client_backend = "0.10.0-rc.1"
|
||||
zcash_primitives = "0.13.0"
|
||||
zcash_client_backend = { version = "0.12.1" }
|
||||
zcash_keys = { version = "0.2.0", features = ["sapling"] }
|
||||
zcash_primitives = "0.14.0"
|
||||
zcash_address = "0.3.2"
|
||||
sapling = { package = "sapling-crypto", version = "0.1" }
|
||||
|
||||
zebra-chain = { path = "../zebra-chain", version = "1.0.0-beta.37", features = ["shielded-scan"] }
|
||||
zebra-state = { path = "../zebra-state", version = "1.0.0-beta.37", features = ["shielded-scan"] }
|
||||
|
|
|
@ -23,4 +23,4 @@ pub mod tests;
|
|||
pub use config::Config;
|
||||
pub use init::{init_with_server, spawn_init};
|
||||
|
||||
pub use zcash_primitives::{sapling::SaplingIvk, zip32::DiversifiableFullViewingKey};
|
||||
pub use sapling::{zip32::DiversifiableFullViewingKey, SaplingIvk};
|
||||
|
|
|
@ -8,12 +8,12 @@ use tokio::sync::{
|
|||
oneshot,
|
||||
};
|
||||
|
||||
use zcash_primitives::{sapling::SaplingIvk, zip32::DiversifiableFullViewingKey};
|
||||
use sapling::zip32::DiversifiableFullViewingKey;
|
||||
use zebra_chain::{block::Height, parameters::Network};
|
||||
use zebra_node_services::scan_service::response::ScanResult;
|
||||
use zebra_state::SaplingScanningKey;
|
||||
|
||||
use crate::scan::sapling_key_to_scan_block_keys;
|
||||
use crate::scan::sapling_key_to_dfvk;
|
||||
|
||||
use super::ScanTask;
|
||||
|
||||
|
@ -57,17 +57,11 @@ impl ScanTask {
|
|||
/// Returns newly registered keys for scanning.
|
||||
pub fn process_messages(
|
||||
cmd_receiver: &mut tokio::sync::mpsc::Receiver<ScanTaskCommand>,
|
||||
registered_keys: &mut HashMap<
|
||||
SaplingScanningKey,
|
||||
(Vec<DiversifiableFullViewingKey>, Vec<SaplingIvk>),
|
||||
>,
|
||||
registered_keys: &mut HashMap<SaplingScanningKey, DiversifiableFullViewingKey>,
|
||||
network: &Network,
|
||||
) -> Result<
|
||||
(
|
||||
HashMap<
|
||||
SaplingScanningKey,
|
||||
(Vec<DiversifiableFullViewingKey>, Vec<SaplingIvk>, Height),
|
||||
>,
|
||||
HashMap<SaplingScanningKey, (DiversifiableFullViewingKey, Height)>,
|
||||
HashMap<SaplingScanningKey, Sender<ScanResult>>,
|
||||
Vec<(Receiver<ScanResult>, oneshot::Sender<Receiver<ScanResult>>)>,
|
||||
),
|
||||
|
@ -117,9 +111,9 @@ impl ScanTask {
|
|||
sapling_activation_height
|
||||
};
|
||||
|
||||
sapling_key_to_scan_block_keys(&key.0, network)
|
||||
sapling_key_to_dfvk(&key.0, network)
|
||||
.ok()
|
||||
.map(|parsed| (key.0, (parsed.0, parsed.1, birth_height)))
|
||||
.map(|parsed| (key.0, (parsed, birth_height)))
|
||||
})
|
||||
.collect();
|
||||
|
||||
|
@ -128,10 +122,7 @@ impl ScanTask {
|
|||
|
||||
new_keys.extend(keys.clone());
|
||||
|
||||
registered_keys.extend(
|
||||
keys.into_iter()
|
||||
.map(|(key, (dfvks, ivks, _))| (key, (dfvks, ivks))),
|
||||
);
|
||||
registered_keys.extend(keys.into_iter().map(|(key, (dfvk, _))| (key, dfvk)));
|
||||
}
|
||||
|
||||
ScanTaskCommand::RemoveKeys { done_tx, keys } => {
|
||||
|
|
|
@ -15,18 +15,19 @@ use tokio::{
|
|||
use tower::{buffer::Buffer, util::BoxService, Service, ServiceExt};
|
||||
|
||||
use tracing::Instrument;
|
||||
use zcash_address::unified::{Encoding, Fvk, Ufvk};
|
||||
use zcash_client_backend::{
|
||||
data_api::ScannedBlock,
|
||||
encoding::decode_extended_full_viewing_key,
|
||||
keys::UnifiedFullViewingKey,
|
||||
proto::compact_formats::{
|
||||
ChainMetadata, CompactBlock, CompactSaplingOutput, CompactSaplingSpend, CompactTx,
|
||||
},
|
||||
scanning::{ScanError, ScanningKey},
|
||||
};
|
||||
use zcash_primitives::{
|
||||
sapling::SaplingIvk,
|
||||
zip32::{AccountId, DiversifiableFullViewingKey, Scope},
|
||||
scanning::{Nullifiers, ScanError, ScanningKeys},
|
||||
};
|
||||
use zcash_primitives::zip32::{AccountId, Scope};
|
||||
|
||||
use sapling::zip32::DiversifiableFullViewingKey;
|
||||
|
||||
use zebra_chain::{
|
||||
block::{Block, Height},
|
||||
|
@ -105,15 +106,9 @@ pub async fn start(
|
|||
|
||||
// Parse and convert keys once, then use them to scan all blocks.
|
||||
// There is some cryptography here, but it should be fast even with thousands of keys.
|
||||
let mut parsed_keys: HashMap<
|
||||
SaplingScanningKey,
|
||||
(Vec<DiversifiableFullViewingKey>, Vec<SaplingIvk>),
|
||||
> = key_heights
|
||||
let mut parsed_keys: HashMap<SaplingScanningKey, DiversifiableFullViewingKey> = key_heights
|
||||
.keys()
|
||||
.map(|key| {
|
||||
let parsed_keys = sapling_key_to_scan_block_keys(key, &network)?;
|
||||
Ok::<_, Report>((key.clone(), parsed_keys))
|
||||
})
|
||||
.map(|key| Ok::<_, Report>((key.clone(), sapling_key_to_dfvk(key, &network)?)))
|
||||
.try_collect()?;
|
||||
|
||||
let mut subscribed_keys: HashMap<SaplingScanningKey, Sender<ScanResult>> = HashMap::new();
|
||||
|
@ -165,7 +160,7 @@ pub async fn start(
|
|||
|
||||
let start_height = new_keys
|
||||
.iter()
|
||||
.map(|(_, (_, _, height))| *height)
|
||||
.map(|(_, (_, height))| *height)
|
||||
.min()
|
||||
.unwrap_or(sapling_activation_height);
|
||||
|
||||
|
@ -251,7 +246,7 @@ pub async fn scan_height_and_store_results(
|
|||
chain_tip_change: Option<ChainTipChange>,
|
||||
storage: Storage,
|
||||
key_last_scanned_heights: Arc<HashMap<SaplingScanningKey, Height>>,
|
||||
parsed_keys: HashMap<SaplingScanningKey, (Vec<DiversifiableFullViewingKey>, Vec<SaplingIvk>)>,
|
||||
parsed_keys: HashMap<String, DiversifiableFullViewingKey>,
|
||||
subscribed_keys_receiver: watch::Receiver<Arc<HashMap<String, Sender<ScanResult>>>>,
|
||||
) -> Result<Option<Height>, Report> {
|
||||
let network = storage.network();
|
||||
|
@ -277,8 +272,8 @@ pub async fn scan_height_and_store_results(
|
|||
_ => unreachable!("unmatched response to a state::Block request"),
|
||||
};
|
||||
|
||||
for (key_index_in_task, (sapling_key, (dfvks, ivks))) in parsed_keys.into_iter().enumerate() {
|
||||
match key_last_scanned_heights.get(&sapling_key) {
|
||||
for (key_index_in_task, (sapling_key, _)) in parsed_keys.iter().enumerate() {
|
||||
match key_last_scanned_heights.get(sapling_key) {
|
||||
// Only scan what was not scanned for each key
|
||||
Some(last_scanned_height) if height <= *last_scanned_height => continue,
|
||||
|
||||
|
@ -312,6 +307,7 @@ pub async fn scan_height_and_store_results(
|
|||
let block = block.clone();
|
||||
let mut storage = storage.clone();
|
||||
let network = network.clone();
|
||||
let parsed_keys = parsed_keys.clone();
|
||||
|
||||
// We use a dummy size of the Sapling note commitment tree.
|
||||
//
|
||||
|
@ -326,19 +322,19 @@ pub async fn scan_height_and_store_results(
|
|||
let sapling_tree_size = 1 << 16;
|
||||
|
||||
tokio::task::spawn_blocking(move || {
|
||||
let dfvk_res =
|
||||
scan_block(&network, &block, sapling_tree_size, &dfvks).map_err(|e| eyre!(e))?;
|
||||
let ivk_res =
|
||||
scan_block(&network, &block, sapling_tree_size, &ivks).map_err(|e| eyre!(e))?;
|
||||
// TODO:
|
||||
// - Wait until https://github.com/zcash/librustzcash/pull/1400 makes it to a release.
|
||||
// - Create the scanning keys outside of this thread and move them here instead.
|
||||
let scanning_keys = scanning_keys(parsed_keys.values()).expect("scanning keys");
|
||||
|
||||
let dfvk_res = scanned_block_to_db_result(dfvk_res);
|
||||
let ivk_res = scanned_block_to_db_result(ivk_res);
|
||||
let scanned_block = scan_block(&network, &block, sapling_tree_size, &scanning_keys)
|
||||
.map_err(|e| eyre!(e))?;
|
||||
|
||||
let scanning_result = scanned_block_to_db_result(scanned_block);
|
||||
|
||||
let latest_subscribed_keys = subscribed_keys_receiver.borrow().clone();
|
||||
if let Some(results_sender) = latest_subscribed_keys.get(&sapling_key).cloned() {
|
||||
let results = dfvk_res.iter().chain(ivk_res.iter());
|
||||
|
||||
for (_tx_index, &tx_id) in results {
|
||||
for (_tx_index, tx_id) in scanning_result.clone() {
|
||||
// TODO: Handle `SendErrors` by dropping sender from `subscribed_keys`
|
||||
let _ = results_sender.try_send(ScanResult {
|
||||
key: sapling_key.clone(),
|
||||
|
@ -348,9 +344,7 @@ pub async fn scan_height_and_store_results(
|
|||
}
|
||||
}
|
||||
|
||||
storage.add_sapling_results(&sapling_key, height, dfvk_res);
|
||||
storage.add_sapling_results(&sapling_key, height, ivk_res);
|
||||
|
||||
storage.add_sapling_results(&sapling_key, height, scanning_result);
|
||||
Ok::<_, Report>(())
|
||||
})
|
||||
.wait_for_panics()
|
||||
|
@ -361,11 +355,6 @@ pub async fn scan_height_and_store_results(
|
|||
}
|
||||
|
||||
/// Returns the transactions from `block` belonging to the given `scanning_keys`.
|
||||
/// This list of keys should come from a single configured `SaplingScanningKey`.
|
||||
///
|
||||
/// For example, there are two individual viewing keys for most shielded transfers:
|
||||
/// - the payment (external) key, and
|
||||
/// - the change (internal) key.
|
||||
///
|
||||
/// # Performance / Hangs
|
||||
///
|
||||
|
@ -375,12 +364,12 @@ pub async fn scan_height_and_store_results(
|
|||
/// TODO:
|
||||
/// - Pass the real `sapling_tree_size` parameter from the state.
|
||||
/// - Add other prior block metadata.
|
||||
pub fn scan_block<K: ScanningKey>(
|
||||
pub fn scan_block(
|
||||
network: &Network,
|
||||
block: &Block,
|
||||
sapling_tree_size: u32,
|
||||
scanning_keys: &[K],
|
||||
) -> Result<ScannedBlock<K::Nf>, ScanError> {
|
||||
scanning_key: &ScanningKeys<AccountId, (AccountId, Scope)>,
|
||||
) -> Result<ScannedBlock<AccountId>, ScanError> {
|
||||
// TODO: Implement a check that returns early when the block height is below the Sapling
|
||||
// activation height.
|
||||
|
||||
|
@ -390,45 +379,28 @@ pub fn scan_block<K: ScanningKey>(
|
|||
orchard_commitment_tree_size: 0,
|
||||
};
|
||||
|
||||
// Use a dummy `AccountId` as we don't use accounts yet.
|
||||
let dummy_account = AccountId::from(0);
|
||||
let scanning_keys: Vec<_> = scanning_keys
|
||||
.iter()
|
||||
.map(|key| (&dummy_account, key))
|
||||
.collect();
|
||||
|
||||
zcash_client_backend::scanning::scan_block(
|
||||
network,
|
||||
block_to_compact(block, chain_metadata),
|
||||
scanning_keys.as_slice(),
|
||||
scanning_key,
|
||||
// Ignore whether notes are change from a viewer's own spends for now.
|
||||
&[],
|
||||
&Nullifiers::empty(),
|
||||
// Ignore previous blocks for now.
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
/// Converts a Zebra-format scanning key into some `scan_block()` keys.
|
||||
///
|
||||
/// Currently only accepts extended full viewing keys, and returns both their diversifiable full
|
||||
/// viewing key and their individual viewing key, for testing purposes.
|
||||
///
|
||||
// TODO: work out what string format is used for SaplingIvk, if any, and support it here
|
||||
// performance: stop returning both the dfvk and ivk for the same key
|
||||
/// Converts a Zebra-format scanning key into diversifiable full viewing key.
|
||||
// TODO: use `ViewingKey::parse` from zebra-chain instead
|
||||
pub fn sapling_key_to_scan_block_keys(
|
||||
pub fn sapling_key_to_dfvk(
|
||||
key: &SaplingScanningKey,
|
||||
network: &Network,
|
||||
) -> Result<(Vec<DiversifiableFullViewingKey>, Vec<SaplingIvk>), Report> {
|
||||
let efvk =
|
||||
decode_extended_full_viewing_key(network.sapling_efvk_hrp(), key).map_err(|e| eyre!(e))?;
|
||||
|
||||
// Just return all the keys for now, so we can be sure our code supports them.
|
||||
let dfvk = efvk.to_diversifiable_full_viewing_key();
|
||||
let eivk = dfvk.to_ivk(Scope::External);
|
||||
let iivk = dfvk.to_ivk(Scope::Internal);
|
||||
|
||||
Ok((vec![dfvk], vec![eivk, iivk]))
|
||||
) -> Result<DiversifiableFullViewingKey, Report> {
|
||||
Ok(
|
||||
decode_extended_full_viewing_key(network.sapling_efvk_hrp(), key)
|
||||
.map_err(|e| eyre!(e))?
|
||||
.to_diversifiable_full_viewing_key(),
|
||||
)
|
||||
}
|
||||
|
||||
/// Converts a zebra block and meta data into a compact block.
|
||||
|
@ -525,8 +497,8 @@ fn scanned_block_to_db_result<Nf>(
|
|||
.iter()
|
||||
.map(|tx| {
|
||||
(
|
||||
TransactionIndex::from_usize(tx.index),
|
||||
SaplingScannedResult::from_bytes_in_display_order(*tx.txid.as_ref()),
|
||||
TransactionIndex::from_usize(tx.block_index()),
|
||||
SaplingScannedResult::from_bytes_in_display_order(*tx.txid().as_ref()),
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
|
@ -565,3 +537,24 @@ pub fn spawn_init(
|
|||
) -> JoinHandle<Result<(), Report>> {
|
||||
tokio::spawn(start(state, chain_tip_change, storage, cmd_receiver).in_current_span())
|
||||
}
|
||||
|
||||
/// Turns an iterator of [`DiversifiableFullViewingKey`]s to [`ScanningKeys`].
|
||||
pub fn scanning_keys<'a>(
|
||||
dfvks: impl IntoIterator<Item = &'a DiversifiableFullViewingKey>,
|
||||
) -> Result<ScanningKeys<AccountId, (AccountId, Scope)>, Report> {
|
||||
dfvks
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(i, dfvk)| Ok((AccountId::try_from(u32::try_from(i)?)?, dfvk_to_ufvk(dfvk)?)))
|
||||
.try_collect::<(_, _), Vec<(_, _)>, _>()
|
||||
.map(ScanningKeys::from_account_ufvks)
|
||||
}
|
||||
|
||||
/// Turns a [`DiversifiableFullViewingKey`] to [`UnifiedFullViewingKey`].
|
||||
pub fn dfvk_to_ufvk(dfvk: &DiversifiableFullViewingKey) -> Result<UnifiedFullViewingKey, Report> {
|
||||
UnifiedFullViewingKey::parse(&Ufvk::try_from_items(vec![Fvk::try_from((
|
||||
2,
|
||||
&dfvk.to_bytes()[..],
|
||||
))?])?)
|
||||
.map_err(|e| eyre!(e))
|
||||
}
|
||||
|
|
|
@ -7,12 +7,12 @@ use crate::{
|
|||
storage::Storage,
|
||||
};
|
||||
use color_eyre::eyre::Report;
|
||||
use sapling::zip32::DiversifiableFullViewingKey;
|
||||
use tokio::{
|
||||
sync::{mpsc::Sender, watch},
|
||||
task::JoinHandle,
|
||||
};
|
||||
use tracing::Instrument;
|
||||
use zcash_primitives::{sapling::SaplingIvk, zip32::DiversifiableFullViewingKey};
|
||||
use zebra_chain::block::Height;
|
||||
use zebra_node_services::scan_service::response::ScanResult;
|
||||
use zebra_state::SaplingScanningKey;
|
||||
|
@ -24,7 +24,7 @@ pub struct ScanRangeTaskBuilder {
|
|||
height_range: std::ops::Range<Height>,
|
||||
|
||||
/// The keys to be used for scanning blocks in this task
|
||||
keys: HashMap<SaplingScanningKey, (Vec<DiversifiableFullViewingKey>, Vec<SaplingIvk>, Height)>,
|
||||
keys: HashMap<SaplingScanningKey, (DiversifiableFullViewingKey, Height)>,
|
||||
|
||||
/// A handle to the state service for reading the blocks and the chain tip height
|
||||
state: State,
|
||||
|
@ -37,10 +37,7 @@ impl ScanRangeTaskBuilder {
|
|||
/// Creates a new [`ScanRangeTaskBuilder`]
|
||||
pub fn new(
|
||||
stop_height: Height,
|
||||
keys: HashMap<
|
||||
SaplingScanningKey,
|
||||
(Vec<DiversifiableFullViewingKey>, Vec<SaplingIvk>, Height),
|
||||
>,
|
||||
keys: HashMap<SaplingScanningKey, (DiversifiableFullViewingKey, Height)>,
|
||||
state: State,
|
||||
storage: Storage,
|
||||
) -> Self {
|
||||
|
@ -83,7 +80,7 @@ impl ScanRangeTaskBuilder {
|
|||
// TODO: update the first parameter to `std::ops::Range<Height>`
|
||||
pub async fn scan_range(
|
||||
stop_before_height: Height,
|
||||
keys: HashMap<SaplingScanningKey, (Vec<DiversifiableFullViewingKey>, Vec<SaplingIvk>, Height)>,
|
||||
keys: HashMap<SaplingScanningKey, (DiversifiableFullViewingKey, Height)>,
|
||||
state: State,
|
||||
storage: Storage,
|
||||
subscribed_keys_receiver: watch::Receiver<Arc<HashMap<String, Sender<ScanResult>>>>,
|
||||
|
@ -99,7 +96,7 @@ pub async fn scan_range(
|
|||
|
||||
let key_heights: HashMap<String, Height> = keys
|
||||
.iter()
|
||||
.map(|(key, (_, _, height))| (key.clone(), *height))
|
||||
.map(|(key, (_, height))| (key.clone(), *height))
|
||||
.collect();
|
||||
|
||||
let mut height = get_min_height(&key_heights).unwrap_or(sapling_activation_height);
|
||||
|
@ -107,12 +104,9 @@ pub async fn scan_range(
|
|||
let key_heights = Arc::new(key_heights);
|
||||
|
||||
// Parse and convert keys once, then use them to scan all blocks.
|
||||
let parsed_keys: HashMap<
|
||||
SaplingScanningKey,
|
||||
(Vec<DiversifiableFullViewingKey>, Vec<SaplingIvk>),
|
||||
> = keys
|
||||
let parsed_keys: HashMap<SaplingScanningKey, DiversifiableFullViewingKey> = keys
|
||||
.into_iter()
|
||||
.map(|(key, (decoded_dfvks, decoded_ivks, _h))| (key, (decoded_dfvks, decoded_ivks)))
|
||||
.map(|(key, (dfvk, _))| (key, dfvk))
|
||||
.collect();
|
||||
|
||||
while height < stop_before_height {
|
||||
|
|
|
@ -19,18 +19,14 @@ use zcash_client_backend::{
|
|||
},
|
||||
};
|
||||
use zcash_note_encryption::Domain;
|
||||
use zcash_primitives::{
|
||||
block::BlockHash,
|
||||
consensus::BlockHeight,
|
||||
use zcash_primitives::{block::BlockHash, consensus::BlockHeight, memo::MemoBytes};
|
||||
|
||||
use ::sapling::{
|
||||
constants::SPENDING_KEY_GENERATOR,
|
||||
memo::MemoBytes,
|
||||
sapling::{
|
||||
note_encryption::{sapling_note_encryption, SaplingDomain},
|
||||
util::generate_random_rseed,
|
||||
value::NoteValue,
|
||||
Note, Nullifier,
|
||||
},
|
||||
zip32,
|
||||
zip32, Note, Nullifier,
|
||||
};
|
||||
|
||||
use zebra_chain::{
|
||||
|
@ -73,12 +69,12 @@ pub fn mock_sapling_scanning_keys(num_keys: u8, network: &Network) -> Vec<Saplin
|
|||
keys
|
||||
}
|
||||
|
||||
/// Generates an [`zip32::sapling::ExtendedFullViewingKey`] from `seed` for tests.
|
||||
/// Generates an [`zip32::ExtendedFullViewingKey`] from `seed` for tests.
|
||||
#[allow(deprecated)]
|
||||
pub fn mock_sapling_efvk(seed: &[u8]) -> zip32::sapling::ExtendedFullViewingKey {
|
||||
pub fn mock_sapling_efvk(seed: &[u8]) -> zip32::ExtendedFullViewingKey {
|
||||
// TODO: Use `to_diversifiable_full_viewing_key` since `to_extended_full_viewing_key` is
|
||||
// deprecated.
|
||||
zip32::sapling::ExtendedSpendingKey::master(seed).to_extended_full_viewing_key()
|
||||
zip32::ExtendedSpendingKey::master(seed).to_extended_full_viewing_key()
|
||||
}
|
||||
|
||||
/// Generates a fake block containing a Sapling output decryptable by `dfvk`.
|
||||
|
@ -91,7 +87,7 @@ pub fn mock_sapling_efvk(seed: &[u8]) -> zip32::sapling::ExtendedFullViewingKey
|
|||
pub fn fake_block(
|
||||
height: BlockHeight,
|
||||
nf: Nullifier,
|
||||
dfvk: &zip32::sapling::DiversifiableFullViewingKey,
|
||||
dfvk: &zip32::DiversifiableFullViewingKey,
|
||||
value: u64,
|
||||
tx_after: bool,
|
||||
initial_sapling_tree_size: Option<u32>,
|
||||
|
@ -165,7 +161,7 @@ pub fn fake_compact_block(
|
|||
height: BlockHeight,
|
||||
prev_hash: BlockHash,
|
||||
nf: Nullifier,
|
||||
dfvk: &zip32::sapling::DiversifiableFullViewingKey,
|
||||
dfvk: &zip32::DiversifiableFullViewingKey,
|
||||
value: u64,
|
||||
tx_after: bool,
|
||||
initial_sapling_tree_size: Option<u32>,
|
||||
|
@ -174,23 +170,17 @@ pub fn fake_compact_block(
|
|||
|
||||
// Create a fake Note for the account
|
||||
let mut rng = OsRng;
|
||||
let rseed = generate_random_rseed(
|
||||
&zcash_primitives::consensus::Network::TestNetwork,
|
||||
height,
|
||||
&mut rng,
|
||||
);
|
||||
let rseed = generate_random_rseed(::sapling::note_encryption::Zip212Enforcement::Off, &mut rng);
|
||||
|
||||
let note = Note::from_parts(to, NoteValue::from_raw(value), rseed);
|
||||
let encryptor = sapling_note_encryption::<_, zcash_primitives::consensus::Network>(
|
||||
let encryptor = sapling_note_encryption::<_>(
|
||||
Some(dfvk.fvk().ovk),
|
||||
note.clone(),
|
||||
MemoBytes::empty(),
|
||||
*MemoBytes::empty().as_array(),
|
||||
&mut rng,
|
||||
);
|
||||
let cmu = note.cmu().to_bytes().to_vec();
|
||||
let ephemeral_key =
|
||||
SaplingDomain::<zcash_primitives::consensus::Network>::epk_bytes(encryptor.epk())
|
||||
.0
|
||||
.to_vec();
|
||||
let ephemeral_key = SaplingDomain::epk_bytes(encryptor.epk()).0.to_vec();
|
||||
let enc_ciphertext = encryptor.encrypt_note_plaintext();
|
||||
|
||||
// Create a fake CompactBlock containing the note
|
||||
|
|
|
@ -4,15 +4,15 @@ use std::sync::Arc;
|
|||
|
||||
use color_eyre::Result;
|
||||
|
||||
use sapling::{
|
||||
zip32::{DiversifiableFullViewingKey, ExtendedSpendingKey},
|
||||
Nullifier,
|
||||
};
|
||||
use zcash_client_backend::{
|
||||
encoding::{decode_extended_full_viewing_key, encode_extended_full_viewing_key},
|
||||
proto::compact_formats::ChainMetadata,
|
||||
};
|
||||
use zcash_primitives::{
|
||||
constants::mainnet::HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY,
|
||||
sapling::Nullifier,
|
||||
zip32::{DiversifiableFullViewingKey, ExtendedSpendingKey},
|
||||
};
|
||||
use zcash_primitives::constants::mainnet::HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY;
|
||||
|
||||
use zebra_chain::{
|
||||
block::{Block, Height},
|
||||
|
@ -23,7 +23,7 @@ use zebra_chain::{
|
|||
use zebra_state::{SaplingScannedResult, TransactionIndex};
|
||||
|
||||
use crate::{
|
||||
scan::{block_to_compact, scan_block},
|
||||
scan::{block_to_compact, scan_block, scanning_keys},
|
||||
storage::db::tests::new_test_storage,
|
||||
tests::{fake_block, mock_sapling_efvk, ZECPAGES_SAPLING_VIEWING_KEY},
|
||||
};
|
||||
|
@ -42,7 +42,9 @@ async fn scanning_from_fake_generated_blocks() -> Result<()> {
|
|||
|
||||
assert_eq!(block.transactions.len(), 4);
|
||||
|
||||
let res = scan_block(&Network::Mainnet, &block, sapling_tree_size, &[&dfvk]).unwrap();
|
||||
let scanning_keys = scanning_keys(&vec![dfvk]).expect("scanning key");
|
||||
|
||||
let res = scan_block(&Network::Mainnet, &block, sapling_tree_size, &scanning_keys).unwrap();
|
||||
|
||||
// The response should have one transaction relevant to the key we provided.
|
||||
assert_eq!(res.transactions().len(), 1);
|
||||
|
@ -52,11 +54,11 @@ async fn scanning_from_fake_generated_blocks() -> Result<()> {
|
|||
.transactions
|
||||
.iter()
|
||||
.map(|tx| tx.hash().bytes_in_display_order())
|
||||
.any(|txid| &txid == res.transactions()[0].txid.as_ref()));
|
||||
.any(|txid| &txid == res.transactions()[0].txid().as_ref()));
|
||||
|
||||
// Check that the txid in the scanning result matches the third tx in the original block.
|
||||
assert_eq!(
|
||||
res.transactions()[0].txid.as_ref(),
|
||||
res.transactions()[0].txid().as_ref(),
|
||||
&block.transactions[2].hash().bytes_in_display_order()
|
||||
);
|
||||
|
||||
|
@ -78,10 +80,7 @@ async fn scanning_zecpages_from_populated_zebra_state() -> Result<()> {
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
// Build a vector of viewing keys `vks` to scan for.
|
||||
let fvk = efvk.fvk;
|
||||
let ivk = fvk.vk.ivk();
|
||||
let ivks = vec![ivk];
|
||||
let dfvk = efvk.to_diversifiable_full_viewing_key();
|
||||
|
||||
let network = Network::Mainnet;
|
||||
|
||||
|
@ -103,6 +102,9 @@ async fn scanning_zecpages_from_populated_zebra_state() -> Result<()> {
|
|||
let mut transactions_found = 0;
|
||||
let mut transactions_scanned = 0;
|
||||
let mut blocks_scanned = 0;
|
||||
|
||||
let scanning_keys = scanning_keys(&vec![dfvk]).expect("scanning key");
|
||||
|
||||
while let Some(block) = db.block(height.into()) {
|
||||
// We use a dummy size of the Sapling note commitment tree. We can't set the size to zero
|
||||
// because the underlying scanning function would return
|
||||
|
@ -118,7 +120,12 @@ async fn scanning_zecpages_from_populated_zebra_state() -> Result<()> {
|
|||
|
||||
let compact_block = block_to_compact(&block, chain_metadata);
|
||||
|
||||
let res = scan_block(&network, &block, sapling_commitment_tree_size, &ivks)
|
||||
let res = scan_block(
|
||||
&network,
|
||||
&block,
|
||||
sapling_commitment_tree_size,
|
||||
&scanning_keys,
|
||||
)
|
||||
.expect("scanning block for the ZECpages viewing key should work");
|
||||
|
||||
transactions_found += res.transactions().len();
|
||||
|
@ -177,13 +184,16 @@ fn scanning_fake_blocks_store_key_and_results() -> Result<()> {
|
|||
|
||||
let (block, sapling_tree_size) = fake_block(1u32.into(), nf, &dfvk, 1, true, Some(0));
|
||||
|
||||
let result = scan_block(&Network::Mainnet, &block, sapling_tree_size, &[&dfvk]).unwrap();
|
||||
let scanning_keys = scanning_keys(&vec![dfvk]).expect("scanning key");
|
||||
|
||||
let result = scan_block(&Network::Mainnet, &block, sapling_tree_size, &scanning_keys).unwrap();
|
||||
|
||||
// The response should have one transaction relevant to the key we provided.
|
||||
assert_eq!(result.transactions().len(), 1);
|
||||
|
||||
let result =
|
||||
SaplingScannedResult::from_bytes_in_display_order(*result.transactions()[0].txid.as_ref());
|
||||
let result = SaplingScannedResult::from_bytes_in_display_order(
|
||||
*result.transactions()[0].txid().as_ref(),
|
||||
);
|
||||
|
||||
// Add result to database
|
||||
storage.add_sapling_results(
|
||||
|
|
|
@ -120,8 +120,9 @@ tokio = { version = "1.37.0", features = ["full"], optional = true }
|
|||
|
||||
jsonrpc = { version = "0.18.0", optional = true }
|
||||
|
||||
zcash_primitives = { version = "0.13.0", optional = true }
|
||||
zcash_client_backend = {version = "0.10.0-rc.1", optional = true}
|
||||
zcash_primitives = { version = "0.15.0", optional = true }
|
||||
zcash_client_backend = { version = "0.12.1", optional = true }
|
||||
zcash_protocol = { version = "0.1.1" }
|
||||
|
||||
# For the openapi generator
|
||||
syn = { version = "2.0.66", features = ["full"], optional = true }
|
||||
|
|
|
@ -8,17 +8,15 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use hex::ToHex;
|
||||
use itertools::Itertools;
|
||||
use jsonrpc::simple_http::SimpleHttpTransport;
|
||||
use jsonrpc::Client;
|
||||
|
||||
use zcash_client_backend::decrypt_transaction;
|
||||
use zcash_client_backend::keys::UnifiedFullViewingKey;
|
||||
use zcash_primitives::consensus::{BlockHeight, BranchId};
|
||||
use zcash_primitives::transaction::Transaction;
|
||||
use zcash_primitives::zip32::AccountId;
|
||||
|
||||
use zebra_scan::scan::sapling_key_to_scan_block_keys;
|
||||
use zebra_scan::scan::{dfvk_to_ufvk, sapling_key_to_dfvk};
|
||||
use zebra_scan::{storage::Storage, Config};
|
||||
|
||||
/// Prints the memos of transactions from Zebra's scanning results storage.
|
||||
|
@ -47,20 +45,13 @@ pub fn main() {
|
|||
let mut prev_memo = "".to_owned();
|
||||
|
||||
for (key, _) in storage.sapling_keys_last_heights().iter() {
|
||||
let dfvk = sapling_key_to_scan_block_keys(key, &network)
|
||||
.expect("Scanning key from the storage should be valid")
|
||||
.0
|
||||
.into_iter()
|
||||
.exactly_one()
|
||||
.expect("There should be exactly one dfvk");
|
||||
|
||||
let ufvk_with_acc_id = HashMap::from([(
|
||||
AccountId::from(1),
|
||||
UnifiedFullViewingKey::new(Some(dfvk), None).expect("`dfvk` should be `Some`"),
|
||||
let ufvks = HashMap::from([(
|
||||
AccountId::ZERO,
|
||||
dfvk_to_ufvk(&sapling_key_to_dfvk(key, &network).expect("dfvk")).expect("ufvk"),
|
||||
)]);
|
||||
|
||||
for (height, txids) in storage.sapling_results(key) {
|
||||
let height = BlockHeight::from(height);
|
||||
let height = BlockHeight::from(height.0);
|
||||
|
||||
for txid in txids.iter() {
|
||||
let tx = Transaction::read(
|
||||
|
@ -70,8 +61,8 @@ pub fn main() {
|
|||
)
|
||||
.expect("TX fetched via RPC should be deserializable from raw bytes");
|
||||
|
||||
for output in decrypt_transaction(&network, height, &tx, &ufvk_with_acc_id) {
|
||||
let memo = memo_bytes_to_string(output.memo.as_array());
|
||||
for output in decrypt_transaction(&network, height, &tx, &ufvks).sapling_outputs() {
|
||||
let memo = memo_bytes_to_string(output.memo().as_array());
|
||||
|
||||
if !memo.is_empty()
|
||||
// Filter out some uninteresting and repeating memos from ZECPages.
|
||||
|
|
Loading…
Reference in New Issue