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",
|
||||
"x25519-dalek",
|
||||
"zcash_address",
|
||||
"zcash_client_backend",
|
||||
"zcash_encoding",
|
||||
"zcash_history",
|
||||
"zcash_note_encryption",
|
||||
|
|
|
@ -34,6 +34,11 @@ getblocktemplate-rpcs = [
|
|||
"zcash_address",
|
||||
]
|
||||
|
||||
# Experimental shielded scanning support
|
||||
shielded-scan = [
|
||||
"zcash_client_backend"
|
||||
]
|
||||
|
||||
# Experimental internal miner support
|
||||
# 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
|
||||
|
@ -127,9 +132,12 @@ serde_json = { version = "1.0.113", optional = true }
|
|||
# Production feature async-error and testing feature proptest-impl
|
||||
tokio = { version = "1.35.1", optional = true }
|
||||
|
||||
# Experimental feature getblocktemplate-rpcs
|
||||
# Production feature getblocktemplate-rpcs
|
||||
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
|
||||
proptest = { version = "1.4.0", optional = true }
|
||||
proptest-derive = { version = "0.4.0", optional = true }
|
||||
|
|
|
@ -12,6 +12,9 @@ mod address;
|
|||
#[cfg(feature = "getblocktemplate-rpcs")]
|
||||
pub use address::Address;
|
||||
|
||||
#[cfg(feature = "shielded-scan")]
|
||||
pub mod viewing_key;
|
||||
|
||||
pub mod byte_array;
|
||||
|
||||
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
|
||||
/// 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
|
||||
// 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
|
||||
// TODO: use `ViewingKey::parse` from zebra-chain instead
|
||||
pub fn sapling_key_to_scan_block_keys(
|
||||
sapling_key: &SaplingScanningKey,
|
||||
network: Network,
|
||||
|
|
Loading…
Reference in New Issue