add(chain): Adds `ViewingKey` type in zebra-chain (#8198)
* adds/impls types in zebra-chain to be used by the zebra-scan RPC server * Adds methods for parsing and a test * adds test for key hash encoding * Apply suggestions from code review Co-authored-by: Marek <mail@marek.onl> * refactors viewing key type * refactors/renames for viewing keys * fixes doc links * Apply suggestions from code review * Apply suggestions from code review * removes ViewingKeyHash and ViewingKeyWithHash types * removes `to_bytes` methods * remove outdated method and call --------- Co-authored-by: Marek <mail@marek.onl>
This commit is contained in:
parent
18477ecbbe
commit
768eb90722
|
@ -5709,6 +5709,7 @@ dependencies = [
|
||||||
"uint",
|
"uint",
|
||||||
"x25519-dalek",
|
"x25519-dalek",
|
||||||
"zcash_address",
|
"zcash_address",
|
||||||
|
"zcash_client_backend",
|
||||||
"zcash_encoding",
|
"zcash_encoding",
|
||||||
"zcash_history",
|
"zcash_history",
|
||||||
"zcash_note_encryption",
|
"zcash_note_encryption",
|
||||||
|
|
|
@ -34,6 +34,11 @@ getblocktemplate-rpcs = [
|
||||||
"zcash_address",
|
"zcash_address",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# Experimental shielded scanning support
|
||||||
|
shielded-scan = [
|
||||||
|
"zcash_client_backend"
|
||||||
|
]
|
||||||
|
|
||||||
# Experimental internal miner support
|
# Experimental internal miner support
|
||||||
# TODO: Internal miner feature functionality was removed at https://github.com/ZcashFoundation/zebra/issues/8180
|
# TODO: Internal miner feature functionality was removed at https://github.com/ZcashFoundation/zebra/issues/8180
|
||||||
# See what was removed at https://github.com/ZcashFoundation/zebra/blob/v1.5.1/zebra-chain/Cargo.toml#L38-L43
|
# See what was removed at https://github.com/ZcashFoundation/zebra/blob/v1.5.1/zebra-chain/Cargo.toml#L38-L43
|
||||||
|
@ -127,9 +132,12 @@ serde_json = { version = "1.0.113", optional = true }
|
||||||
# Production feature async-error and testing feature proptest-impl
|
# Production feature async-error and testing feature proptest-impl
|
||||||
tokio = { version = "1.35.1", optional = true }
|
tokio = { version = "1.35.1", optional = true }
|
||||||
|
|
||||||
# Experimental feature getblocktemplate-rpcs
|
# Production feature getblocktemplate-rpcs
|
||||||
zcash_address = { version = "0.3.1", optional = true }
|
zcash_address = { version = "0.3.1", optional = true }
|
||||||
|
|
||||||
|
# Experimental feature shielded-scan
|
||||||
|
zcash_client_backend = { version = "0.10.0-rc.1", optional = true }
|
||||||
|
|
||||||
# Optional testing dependencies
|
# Optional testing dependencies
|
||||||
proptest = { version = "1.4.0", optional = true }
|
proptest = { version = "1.4.0", optional = true }
|
||||||
proptest-derive = { version = "0.4.0", optional = true }
|
proptest-derive = { version = "0.4.0", optional = true }
|
||||||
|
|
|
@ -12,6 +12,9 @@ mod address;
|
||||||
#[cfg(feature = "getblocktemplate-rpcs")]
|
#[cfg(feature = "getblocktemplate-rpcs")]
|
||||||
pub use address::Address;
|
pub use address::Address;
|
||||||
|
|
||||||
|
#[cfg(feature = "shielded-scan")]
|
||||||
|
pub mod viewing_key;
|
||||||
|
|
||||||
pub mod byte_array;
|
pub mod byte_array;
|
||||||
|
|
||||||
pub use ed25519_zebra as ed25519;
|
pub use ed25519_zebra as ed25519;
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
//! Type definitions for viewing keys and their hashes.
|
||||||
|
|
||||||
|
use crate::parameters::Network;
|
||||||
|
|
||||||
|
mod orchard;
|
||||||
|
mod sapling;
|
||||||
|
|
||||||
|
use orchard::OrchardViewingKey;
|
||||||
|
use sapling::SaplingViewingKey;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests;
|
||||||
|
|
||||||
|
/// A Zcash Sapling or Orchard viewing key
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum ViewingKey {
|
||||||
|
/// A viewing key for Sapling
|
||||||
|
Sapling(SaplingViewingKey),
|
||||||
|
|
||||||
|
/// A viewing key for Orchard
|
||||||
|
Orchard(OrchardViewingKey),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ViewingKey {
|
||||||
|
/// Accepts an encoded Sapling viewing key to decode
|
||||||
|
///
|
||||||
|
/// Returns a [`ViewingKey`] if successful, or None otherwise
|
||||||
|
fn parse_sapling(sapling_key: &str, network: Network) -> Option<Self> {
|
||||||
|
SaplingViewingKey::parse(sapling_key, network).map(Self::Sapling)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Accepts an encoded Orchard viewing key to decode
|
||||||
|
///
|
||||||
|
/// Returns a [`ViewingKey`] if successful, or None otherwise
|
||||||
|
fn parse_orchard(sapling_key: &str, network: Network) -> Option<Self> {
|
||||||
|
OrchardViewingKey::parse(sapling_key, network).map(Self::Orchard)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parses an encoded viewing key and returns it as a [`ViewingKey`] type.
|
||||||
|
pub fn parse(key: &str, network: Network) -> Option<Self> {
|
||||||
|
Self::parse_sapling(key, network).or_else(|| Self::parse_orchard(key, network))
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
//! Defines types and implements methods for parsing Orchard viewing keys and converting them to `zebra-chain` types
|
||||||
|
|
||||||
|
use crate::parameters::Network;
|
||||||
|
|
||||||
|
/// A Zcash Orchard viewing key
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum OrchardViewingKey {}
|
||||||
|
|
||||||
|
impl OrchardViewingKey {
|
||||||
|
/// Accepts an encoded Orchard viewing key to decode
|
||||||
|
///
|
||||||
|
/// Returns a [`OrchardViewingKey`] if successful, or None otherwise
|
||||||
|
pub fn parse(_key: &str, _network: Network) -> Option<Self> {
|
||||||
|
// TODO: parse Orchard viewing keys
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,87 @@
|
||||||
|
//! 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 crate::parameters::Network;
|
||||||
|
|
||||||
|
/// A Zcash Sapling viewing key
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum SaplingViewingKey {
|
||||||
|
/// An incoming viewing key for Sapling
|
||||||
|
Ivk(Box<SaplingIvk>),
|
||||||
|
|
||||||
|
/// A full viewing key for Sapling
|
||||||
|
Fvk(Box<SaplingFvk>),
|
||||||
|
|
||||||
|
/// A diversifiable full viewing key for Sapling
|
||||||
|
Dfvk(Box<SaplingDfvk>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SaplingViewingKey {
|
||||||
|
/// Accepts an encoded Sapling extended full viewing key to decode
|
||||||
|
///
|
||||||
|
/// Returns a [`SaplingViewingKey::Dfvk`] if successful, or None otherwise
|
||||||
|
fn parse_extended_full_viewing_key(sapling_key: &str, network: Network) -> Option<Self> {
|
||||||
|
decode_extended_full_viewing_key(network.sapling_efvk_hrp(), sapling_key)
|
||||||
|
// this should fail often, so a debug-level log is okay
|
||||||
|
.map_err(|err| debug!(?err, "could not decode Sapling extended full viewing key"))
|
||||||
|
.ok()
|
||||||
|
.map(|efvk| Box::new(efvk.to_diversifiable_full_viewing_key()))
|
||||||
|
.map(Self::Dfvk)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Accepts an encoded Sapling diversifiable full viewing key to decode
|
||||||
|
///
|
||||||
|
/// Returns a [`SaplingViewingKey::Dfvk`] if successful, or None otherwise
|
||||||
|
fn parse_diversifiable_full_viewing_key(_sapling_key: &str, _network: Network) -> Option<Self> {
|
||||||
|
// TODO: Parse Sapling diversifiable full viewing key
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Accepts an encoded Sapling full viewing key to decode
|
||||||
|
///
|
||||||
|
/// Returns a [`SaplingViewingKey::Fvk`] if successful, or None otherwise
|
||||||
|
fn parse_full_viewing_key(_sapling_key: &str, _network: Network) -> Option<Self> {
|
||||||
|
// TODO: Parse Sapling full viewing key
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Accepts an encoded Sapling incoming viewing key to decode
|
||||||
|
///
|
||||||
|
/// Returns a [`SaplingViewingKey::Ivk`] if successful, or None otherwise
|
||||||
|
fn parse_incoming_viewing_key(_sapling_key: &str, _network: Network) -> Option<Self> {
|
||||||
|
// TODO: Parse Sapling incoming viewing key
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Accepts an encoded Sapling viewing key to decode
|
||||||
|
///
|
||||||
|
/// Returns a [`SaplingViewingKey`] if successful, or None otherwise
|
||||||
|
pub(super) fn parse(key: &str, network: Network) -> Option<Self> {
|
||||||
|
// TODO: Try types with prefixes first if some don't have prefixes?
|
||||||
|
Self::parse_extended_full_viewing_key(key, network)
|
||||||
|
.or_else(|| Self::parse_diversifiable_full_viewing_key(key, network))
|
||||||
|
.or_else(|| Self::parse_full_viewing_key(key, network))
|
||||||
|
.or_else(|| Self::parse_incoming_viewing_key(key, network))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Network {
|
||||||
|
/// Returns the human-readable prefix for an Zcash Sapling extended full viewing key
|
||||||
|
/// for this network.
|
||||||
|
fn sapling_efvk_hrp(&self) -> &'static str {
|
||||||
|
if self.is_a_test_network() {
|
||||||
|
// Assume custom testnets have the same HRP
|
||||||
|
//
|
||||||
|
// TODO: add the regtest HRP here
|
||||||
|
testnet::HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY
|
||||||
|
} else {
|
||||||
|
mainnet::HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
//! Tests for zebra-chain viewing key hashes
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
/// The extended Sapling viewing key of [ZECpages](https://zecpages.com/boardinfo)
|
||||||
|
pub const ZECPAGES_SAPLING_VIEWING_KEY: &str = "zxviews1q0duytgcqqqqpqre26wkl45gvwwwd706xw608hucmvfalr759ejwf7qshjf5r9aa7323zulvz6plhttp5mltqcgs9t039cx2d09mgq05ts63n8u35hyv6h9nc9ctqqtue2u7cer2mqegunuulq2luhq3ywjcz35yyljewa4mgkgjzyfwh6fr6jd0dzd44ghk0nxdv2hnv4j5nxfwv24rwdmgllhe0p8568sgqt9ckt02v2kxf5ahtql6s0ltjpkckw8gtymxtxuu9gcr0swvz";
|
||||||
|
|
||||||
|
/// Tests that `ViewingKey::parse` successfully decodes the zecpages sapling extended full viewing key
|
||||||
|
#[test]
|
||||||
|
fn parses_sapling_efvk_correctly() {
|
||||||
|
let _init_guard = zebra_test::init();
|
||||||
|
|
||||||
|
ViewingKey::parse(ZECPAGES_SAPLING_VIEWING_KEY, Network::Mainnet)
|
||||||
|
.expect("should parse hard-coded viewing key successfully");
|
||||||
|
}
|
|
@ -288,8 +288,9 @@ pub fn scan_block<K: ScanningKey>(
|
||||||
/// Currently only accepts extended full viewing keys, and returns both their diversifiable full
|
/// Currently only accepts extended full viewing keys, and returns both their diversifiable full
|
||||||
/// viewing key and their individual viewing key, for testing purposes.
|
/// 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
|
// 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
|
// performance: stop returning both the dfvk and ivk for the same key
|
||||||
|
// TODO: use `ViewingKey::parse` from zebra-chain instead
|
||||||
pub fn sapling_key_to_scan_block_keys(
|
pub fn sapling_key_to_scan_block_keys(
|
||||||
sapling_key: &SaplingScanningKey,
|
sapling_key: &SaplingScanningKey,
|
||||||
network: Network,
|
network: Network,
|
||||||
|
|
Loading…
Reference in New Issue