Merge pull request #1113 from zcash/zcash_address-remove-type-aliases
zcash_address: Remove private type aliases for raw data sizes
This commit is contained in:
commit
75184acfdb
|
@ -2990,7 +2990,7 @@ checksum = "213b7324336b53d2414b2db8537e56544d981803139155afa84f76eeebb7a546"
|
|||
|
||||
[[package]]
|
||||
name = "zcash_address"
|
||||
version = "0.3.0"
|
||||
version = "0.3.1"
|
||||
dependencies = [
|
||||
"assert_matches",
|
||||
"bech32",
|
||||
|
|
|
@ -7,6 +7,11 @@ and this library adheres to Rust's notion of
|
|||
|
||||
## [Unreleased]
|
||||
|
||||
## [0.3.1] - 2024-01-12
|
||||
### Fixed
|
||||
- Stubs for `zcash_address::convert` traits that are created by `rust-analyzer`
|
||||
and similar LSPs no longer reference crate-private type aliases.
|
||||
|
||||
## [0.3.0] - 2023-06-06
|
||||
### Changed
|
||||
- Bumped bs58 dependency to `0.5`.
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
[package]
|
||||
name = "zcash_address"
|
||||
description = "Zcash address parsing and serialization"
|
||||
version = "0.3.0"
|
||||
version = "0.3.1"
|
||||
authors = [
|
||||
"Jack Grigg <jack@electriccoin.co>",
|
||||
]
|
||||
|
@ -14,6 +14,10 @@ rust-version = "1.52"
|
|||
categories = ["cryptography::cryptocurrencies", "encoding"]
|
||||
keywords = ["zcash", "address", "sapling", "unified"]
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
rustdoc-args = ["--cfg", "docsrs"]
|
||||
|
||||
[dependencies]
|
||||
bech32 = "0.9"
|
||||
bs58 = { version = "0.5", features = ["check"] }
|
||||
|
|
|
@ -2,7 +2,7 @@ use std::{error::Error, fmt};
|
|||
|
||||
use crate::{kind::*, AddressKind, Network, ZcashAddress};
|
||||
|
||||
/// An address type is not supported for conversion.
|
||||
/// An error indicating that an address type is not supported for conversion.
|
||||
#[derive(Debug)]
|
||||
pub struct UnsupportedAddress(&'static str);
|
||||
|
||||
|
@ -107,12 +107,12 @@ pub trait TryFromRawAddress: Sized {
|
|||
/// [`Self::try_from_raw_sapling`] as a valid Sapling address).
|
||||
type Error;
|
||||
|
||||
fn try_from_raw_sprout(data: sprout::Data) -> Result<Self, ConversionError<Self::Error>> {
|
||||
fn try_from_raw_sprout(data: [u8; 64]) -> Result<Self, ConversionError<Self::Error>> {
|
||||
let _ = data;
|
||||
Err(ConversionError::Unsupported(UnsupportedAddress("Sprout")))
|
||||
}
|
||||
|
||||
fn try_from_raw_sapling(data: sapling::Data) -> Result<Self, ConversionError<Self::Error>> {
|
||||
fn try_from_raw_sapling(data: [u8; 43]) -> Result<Self, ConversionError<Self::Error>> {
|
||||
let _ = data;
|
||||
Err(ConversionError::Unsupported(UnsupportedAddress("Sapling")))
|
||||
}
|
||||
|
@ -123,7 +123,7 @@ pub trait TryFromRawAddress: Sized {
|
|||
}
|
||||
|
||||
fn try_from_raw_transparent_p2pkh(
|
||||
data: p2pkh::Data,
|
||||
data: [u8; 20],
|
||||
) -> Result<Self, ConversionError<Self::Error>> {
|
||||
let _ = data;
|
||||
Err(ConversionError::Unsupported(UnsupportedAddress(
|
||||
|
@ -131,9 +131,7 @@ pub trait TryFromRawAddress: Sized {
|
|||
)))
|
||||
}
|
||||
|
||||
fn try_from_raw_transparent_p2sh(
|
||||
data: p2sh::Data,
|
||||
) -> Result<Self, ConversionError<Self::Error>> {
|
||||
fn try_from_raw_transparent_p2sh(data: [u8; 20]) -> Result<Self, ConversionError<Self::Error>> {
|
||||
let _ = data;
|
||||
Err(ConversionError::Unsupported(UnsupportedAddress(
|
||||
"transparent P2SH",
|
||||
|
@ -187,17 +185,14 @@ pub trait TryFromAddress: Sized {
|
|||
/// [`Self::try_from_sapling`] as a valid Sapling address).
|
||||
type Error;
|
||||
|
||||
fn try_from_sprout(
|
||||
net: Network,
|
||||
data: sprout::Data,
|
||||
) -> Result<Self, ConversionError<Self::Error>> {
|
||||
fn try_from_sprout(net: Network, data: [u8; 64]) -> Result<Self, ConversionError<Self::Error>> {
|
||||
let _ = (net, data);
|
||||
Err(ConversionError::Unsupported(UnsupportedAddress("Sprout")))
|
||||
}
|
||||
|
||||
fn try_from_sapling(
|
||||
net: Network,
|
||||
data: sapling::Data,
|
||||
data: [u8; 43],
|
||||
) -> Result<Self, ConversionError<Self::Error>> {
|
||||
let _ = (net, data);
|
||||
Err(ConversionError::Unsupported(UnsupportedAddress("Sapling")))
|
||||
|
@ -213,7 +208,7 @@ pub trait TryFromAddress: Sized {
|
|||
|
||||
fn try_from_transparent_p2pkh(
|
||||
net: Network,
|
||||
data: p2pkh::Data,
|
||||
data: [u8; 20],
|
||||
) -> Result<Self, ConversionError<Self::Error>> {
|
||||
let _ = (net, data);
|
||||
Err(ConversionError::Unsupported(UnsupportedAddress(
|
||||
|
@ -223,7 +218,7 @@ pub trait TryFromAddress: Sized {
|
|||
|
||||
fn try_from_transparent_p2sh(
|
||||
net: Network,
|
||||
data: p2sh::Data,
|
||||
data: [u8; 20],
|
||||
) -> Result<Self, ConversionError<Self::Error>> {
|
||||
let _ = (net, data);
|
||||
Err(ConversionError::Unsupported(UnsupportedAddress(
|
||||
|
@ -235,16 +230,13 @@ pub trait TryFromAddress: Sized {
|
|||
impl<T: TryFromRawAddress> TryFromAddress for (Network, T) {
|
||||
type Error = T::Error;
|
||||
|
||||
fn try_from_sprout(
|
||||
net: Network,
|
||||
data: sprout::Data,
|
||||
) -> Result<Self, ConversionError<Self::Error>> {
|
||||
fn try_from_sprout(net: Network, data: [u8; 64]) -> Result<Self, ConversionError<Self::Error>> {
|
||||
T::try_from_raw_sprout(data).map(|addr| (net, addr))
|
||||
}
|
||||
|
||||
fn try_from_sapling(
|
||||
net: Network,
|
||||
data: sapling::Data,
|
||||
data: [u8; 43],
|
||||
) -> Result<Self, ConversionError<Self::Error>> {
|
||||
T::try_from_raw_sapling(data).map(|addr| (net, addr))
|
||||
}
|
||||
|
@ -258,14 +250,14 @@ impl<T: TryFromRawAddress> TryFromAddress for (Network, T) {
|
|||
|
||||
fn try_from_transparent_p2pkh(
|
||||
net: Network,
|
||||
data: p2pkh::Data,
|
||||
data: [u8; 20],
|
||||
) -> Result<Self, ConversionError<Self::Error>> {
|
||||
T::try_from_raw_transparent_p2pkh(data).map(|addr| (net, addr))
|
||||
}
|
||||
|
||||
fn try_from_transparent_p2sh(
|
||||
net: Network,
|
||||
data: p2sh::Data,
|
||||
data: [u8; 20],
|
||||
) -> Result<Self, ConversionError<Self::Error>> {
|
||||
T::try_from_raw_transparent_p2sh(data).map(|addr| (net, addr))
|
||||
}
|
||||
|
@ -303,19 +295,19 @@ impl<T: TryFromRawAddress> TryFromAddress for (Network, T) {
|
|||
/// );
|
||||
/// ```
|
||||
pub trait ToAddress: private::Sealed {
|
||||
fn from_sprout(net: Network, data: sprout::Data) -> Self;
|
||||
fn from_sprout(net: Network, data: [u8; 64]) -> Self;
|
||||
|
||||
fn from_sapling(net: Network, data: sapling::Data) -> Self;
|
||||
fn from_sapling(net: Network, data: [u8; 43]) -> Self;
|
||||
|
||||
fn from_unified(net: Network, data: unified::Address) -> Self;
|
||||
|
||||
fn from_transparent_p2pkh(net: Network, data: p2pkh::Data) -> Self;
|
||||
fn from_transparent_p2pkh(net: Network, data: [u8; 20]) -> Self;
|
||||
|
||||
fn from_transparent_p2sh(net: Network, data: p2sh::Data) -> Self;
|
||||
fn from_transparent_p2sh(net: Network, data: [u8; 20]) -> Self;
|
||||
}
|
||||
|
||||
impl ToAddress for ZcashAddress {
|
||||
fn from_sprout(net: Network, data: sprout::Data) -> Self {
|
||||
fn from_sprout(net: Network, data: [u8; 64]) -> Self {
|
||||
ZcashAddress {
|
||||
net: if let Network::Regtest = net {
|
||||
Network::Test
|
||||
|
@ -326,7 +318,7 @@ impl ToAddress for ZcashAddress {
|
|||
}
|
||||
}
|
||||
|
||||
fn from_sapling(net: Network, data: sapling::Data) -> Self {
|
||||
fn from_sapling(net: Network, data: [u8; 43]) -> Self {
|
||||
ZcashAddress {
|
||||
net,
|
||||
kind: AddressKind::Sapling(data),
|
||||
|
@ -340,7 +332,7 @@ impl ToAddress for ZcashAddress {
|
|||
}
|
||||
}
|
||||
|
||||
fn from_transparent_p2pkh(net: Network, data: p2pkh::Data) -> Self {
|
||||
fn from_transparent_p2pkh(net: Network, data: [u8; 20]) -> Self {
|
||||
ZcashAddress {
|
||||
net: if let Network::Regtest = net {
|
||||
Network::Test
|
||||
|
@ -351,7 +343,7 @@ impl ToAddress for ZcashAddress {
|
|||
}
|
||||
}
|
||||
|
||||
fn from_transparent_p2sh(net: Network, data: p2sh::Data) -> Self {
|
||||
fn from_transparent_p2sh(net: Network, data: [u8; 20]) -> Self {
|
||||
ZcashAddress {
|
||||
net: if let Network::Regtest = net {
|
||||
Network::Test
|
||||
|
|
|
@ -3,5 +3,3 @@ pub(crate) const MAINNET: [u8; 2] = [0x1c, 0xb8];
|
|||
|
||||
/// The prefix for a Base58Check-encoded testnet transparent P2PKH address.
|
||||
pub(crate) const TESTNET: [u8; 2] = [0x1d, 0x25];
|
||||
|
||||
pub(crate) type Data = [u8; 20];
|
||||
|
|
|
@ -3,5 +3,3 @@ pub(crate) const MAINNET: [u8; 2] = [0x1c, 0xbd];
|
|||
|
||||
/// The prefix for a Base58Check-encoded testnet transparent P2SH address.
|
||||
pub(crate) const TESTNET: [u8; 2] = [0x1c, 0xba];
|
||||
|
||||
pub(crate) type Data = [u8; 20];
|
||||
|
|
|
@ -18,5 +18,3 @@ pub(crate) const TESTNET: &str = "ztestsapling";
|
|||
///
|
||||
/// [the `zcashd` codebase]: https://github.com/zcash/zcash/blob/128d863fb8be39ee294fda397c1ce3ba3b889cb2/src/chainparams.cpp#L493
|
||||
pub(crate) const REGTEST: &str = "zregtestsapling";
|
||||
|
||||
pub(crate) type Data = [u8; 43];
|
||||
|
|
|
@ -11,5 +11,3 @@ pub(crate) const MAINNET: [u8; 2] = [0x16, 0x9a];
|
|||
///
|
||||
/// [sproutpaymentaddrencoding]: https://zips.z.cash/protocol/protocol.pdf#sproutpaymentaddrencoding
|
||||
pub(crate) const TESTNET: [u8; 2] = [0x16, 0xb6];
|
||||
|
||||
pub(crate) type Data = [u8; 64];
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//! Implementation of [ZIP 316](https://zips.z.cash/zip-0316) Unified Addresses and Viewing Keys.
|
||||
|
||||
use bech32::{self, FromBase32, ToBase32, Variant};
|
||||
use std::cmp;
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
|
@ -17,12 +19,23 @@ pub use ivk::{Ivk, Uivk};
|
|||
|
||||
const PADDING_LEN: usize = 16;
|
||||
|
||||
/// The known Receiver and Viewing Key types.
|
||||
///
|
||||
/// The typecodes `0xFFFA..=0xFFFF` reserved for experiments are currently not
|
||||
/// distinguished from unknown values, and will be parsed as [`Typecode::Unknown`].
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum Typecode {
|
||||
/// A transparent P2PKH address, FVK, or IVK encoding as specified in [ZIP 316](https://zips.z.cash/zip-0316).
|
||||
P2pkh,
|
||||
/// A transparent P2SH address.
|
||||
///
|
||||
/// This typecode cannot occur in a [`Ufvk`] or [`Uivk`].
|
||||
P2sh,
|
||||
/// A Sapling raw address, FVK, or IVK encoding as specified in [ZIP 316](https://zips.z.cash/zip-0316).
|
||||
Sapling,
|
||||
/// An Orchard raw address, FVK, or IVK encoding as specified in [ZIP 316](https://zips.z.cash/zip-0316).
|
||||
Orchard,
|
||||
/// An unknown or experimental typecode.
|
||||
Unknown(u32),
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use super::{private::SealedItem, ParseError, Typecode};
|
||||
use crate::kind;
|
||||
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
|
||||
|
@ -7,9 +6,9 @@ use std::convert::{TryFrom, TryInto};
|
|||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum Receiver {
|
||||
Orchard([u8; 43]),
|
||||
Sapling(kind::sapling::Data),
|
||||
P2pkh(kind::p2pkh::Data),
|
||||
P2sh(kind::p2sh::Data),
|
||||
Sapling([u8; 43]),
|
||||
P2pkh([u8; 20]),
|
||||
P2sh([u8; 20]),
|
||||
Unknown { typecode: u32, data: Vec<u8> },
|
||||
}
|
||||
|
||||
|
@ -56,6 +55,49 @@ impl SealedItem for Receiver {
|
|||
}
|
||||
|
||||
/// A Unified Address.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use std::convert::Infallible;
|
||||
/// # use std::error::Error;
|
||||
/// use zcash_address::{
|
||||
/// unified::{self, Container, Encoding},
|
||||
/// ConversionError, TryFromRawAddress, ZcashAddress,
|
||||
/// };
|
||||
///
|
||||
/// # fn main() -> Result<(), Box<dyn Error>> {
|
||||
/// # let address_from_user = || "u1pg2aaph7jp8rpf6yhsza25722sg5fcn3vaca6ze27hqjw7jvvhhuxkpcg0ge9xh6drsgdkda8qjq5chpehkcpxf87rnjryjqwymdheptpvnljqqrjqzjwkc2ma6hcq666kgwfytxwac8eyex6ndgr6ezte66706e3vaqrd25dzvzkc69kw0jgywtd0cmq52q5lkw6uh7hyvzjse8ksx";
|
||||
/// let example_ua: &str = address_from_user();
|
||||
///
|
||||
/// // We can parse this directly as a `unified::Address`:
|
||||
/// let (network, ua) = unified::Address::decode(example_ua)?;
|
||||
///
|
||||
/// // Or we can parse via `ZcashAddress` (which you should do):
|
||||
/// struct MyUnifiedAddress(unified::Address);
|
||||
/// impl TryFromRawAddress for MyUnifiedAddress {
|
||||
/// // In this example we aren't checking the validity of the
|
||||
/// // inner Unified Address, but your code should do so!
|
||||
/// type Error = Infallible;
|
||||
///
|
||||
/// fn try_from_raw_unified(ua: unified::Address) -> Result<Self, ConversionError<Self::Error>> {
|
||||
/// Ok(MyUnifiedAddress(ua))
|
||||
/// }
|
||||
/// }
|
||||
/// let addr: ZcashAddress = example_ua.parse()?;
|
||||
/// let parsed = addr.convert_if_network::<MyUnifiedAddress>(network)?;
|
||||
/// assert_eq!(parsed.0, ua);
|
||||
///
|
||||
/// // We can obtain the receivers for the UA in preference order
|
||||
/// // (the order in which wallets should prefer to use them):
|
||||
/// let receivers: Vec<unified::Receiver> = ua.items();
|
||||
///
|
||||
/// // And we can create the UA from a list of receivers:
|
||||
/// let new_ua = unified::Address::try_from_items(receivers)?;
|
||||
/// assert_eq!(new_ua, ua);
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct Address(pub(crate) Vec<Receiver>);
|
||||
|
||||
|
|
|
@ -78,6 +78,30 @@ impl SealedItem for Fvk {
|
|||
}
|
||||
|
||||
/// A Unified Full Viewing Key.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use std::error::Error;
|
||||
/// use zcash_address::unified::{self, Container, Encoding};
|
||||
///
|
||||
/// # fn main() -> Result<(), Box<dyn Error>> {
|
||||
/// # let ufvk_from_user = || "uview1cgrqnry478ckvpr0f580t6fsahp0a5mj2e9xl7hv2d2jd4ldzy449mwwk2l9yeuts85wjls6hjtghdsy5vhhvmjdw3jxl3cxhrg3vs296a3czazrycrr5cywjhwc5c3ztfyjdhmz0exvzzeyejamyp0cr9z8f9wj0953fzht0m4lenk94t70ruwgjxag2tvp63wn9ftzhtkh20gyre3w5s24f6wlgqxnjh40gd2lxe75sf3z8h5y2x0atpxcyf9t3em4h0evvsftluruqne6w4sm066sw0qe5y8qg423grple5fftxrqyy7xmqmatv7nzd7tcjadu8f7mqz4l83jsyxy4t8pkayytyk7nrp467ds85knekdkvnd7hqkfer8mnqd7pv";
|
||||
/// let example_ufvk: &str = ufvk_from_user();
|
||||
///
|
||||
/// let (network, ufvk) = unified::Ufvk::decode(example_ufvk)?;
|
||||
///
|
||||
/// // We can obtain the pool-specific Full Viewing Keys for the UFVK in preference
|
||||
/// // order (the order in which wallets should prefer to use their corresponding
|
||||
/// // address receivers):
|
||||
/// let fvks: Vec<unified::Fvk> = ufvk.items();
|
||||
///
|
||||
/// // And we can create the UFVK from a list of FVKs:
|
||||
/// let new_ufvk = unified::Ufvk::try_from_items(fvks)?;
|
||||
/// assert_eq!(new_ufvk, ufvk);
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct Ufvk(pub(crate) Vec<Fvk>);
|
||||
|
||||
|
|
|
@ -83,6 +83,30 @@ impl SealedItem for Ivk {
|
|||
}
|
||||
|
||||
/// A Unified Incoming Viewing Key.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use std::error::Error;
|
||||
/// use zcash_address::unified::{self, Container, Encoding};
|
||||
///
|
||||
/// # fn main() -> Result<(), Box<dyn Error>> {
|
||||
/// # let uivk_from_user = || "uivk1djetqg3fws7y7qu5tekynvcdhz69gsyq07ewvppmzxdqhpfzdgmx8urnkqzv7ylz78ez43ux266pqjhecd59fzhn7wpe6zarnzh804hjtkyad25ryqla5pnc8p5wdl3phj9fczhz64zprun3ux7y9jc08567xryumuz59rjmg4uuflpjqwnq0j0tzce0x74t4tv3gfjq7nczkawxy6y7hse733ae3vw7qfjd0ss0pytvezxp42p6rrpzeh6t2zrz7zpjk0xhngcm6gwdppxs58jkx56gsfflugehf5vjlmu7vj3393gj6u37wenavtqyhdvcdeaj86s6jczl4zq";
|
||||
/// let example_uivk: &str = uivk_from_user();
|
||||
///
|
||||
/// let (network, uivk) = unified::Uivk::decode(example_uivk)?;
|
||||
///
|
||||
/// // We can obtain the pool-specific Incoming Viewing Keys for the UIVK in
|
||||
/// // preference order (the order in which wallets should prefer to use their
|
||||
/// // corresponding address receivers):
|
||||
/// let ivks: Vec<unified::Ivk> = uivk.items();
|
||||
///
|
||||
/// // And we can create the UIVK from a list of IVKs:
|
||||
/// let new_uivk = unified::Uivk::try_from_items(ivks)?;
|
||||
/// assert_eq!(new_uivk, uivk);
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct Uivk(pub(crate) Vec<Ivk>);
|
||||
|
||||
|
|
|
@ -1,3 +1,134 @@
|
|||
//! *Parser for all defined Zcash address types.*
|
||||
//!
|
||||
//! This crate implements address parsing as a two-phase process, built around the opaque
|
||||
//! [`ZcashAddress`] type.
|
||||
//!
|
||||
//! - [`ZcashAddress`] can be parsed from, and encoded to, strings.
|
||||
//! - [`ZcashAddress::convert`] or [`ZcashAddress::convert_if_network`] can be used to
|
||||
//! convert a parsed address into custom types that implement the [`TryFromAddress`] or
|
||||
//! [`TryFromRawAddress`] traits.
|
||||
//! - Custom types can be converted into a [`ZcashAddress`] via its implementation of the
|
||||
//! [`ToAddress`] trait.
|
||||
//!
|
||||
//! ```text
|
||||
//! s.parse() .convert()
|
||||
//! --------> --------->
|
||||
//! Strings ZcashAddress Custom types
|
||||
//! <-------- <---------
|
||||
//! .encode() ToAddress
|
||||
//! ```
|
||||
//!
|
||||
//! It is important to note that this crate does not depend on any of the Zcash protocol
|
||||
//! crates (e.g. `sapling-crypto` or `orchard`). This crate has minimal dependencies by
|
||||
//! design; it focuses solely on parsing, handling those concerns for you, while exposing
|
||||
//! APIs that enable you to convert the parsed data into the Rust types you want to use.
|
||||
//!
|
||||
//! # Using this crate
|
||||
//!
|
||||
//! ## I just need to validate Zcash addresses
|
||||
//!
|
||||
//! ```
|
||||
//! # use zcash_address::ZcashAddress;
|
||||
//! fn is_valid_zcash_address(addr_string: &str) -> bool {
|
||||
//! addr_string.parse::<ZcashAddress>().is_ok()
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! ## I want to parse Zcash addresses in a Rust wallet app that uses the `zcash_primitives` transaction builder
|
||||
//!
|
||||
//! Use `zcash_client_backend::address::RecipientAddress`, which implements the traits in
|
||||
//! this crate to parse address strings into protocol types that work with the transaction
|
||||
//! builder in the `zcash_primitives` crate (as well as the wallet functionality in the
|
||||
//! `zcash_client_backend` crate itself).
|
||||
//!
|
||||
//! > We intend to refactor the key and address types from the `zcash_client_backend` and
|
||||
//! > `zcash_primitives` crates into a separate crate focused on dealing with Zcash key
|
||||
//! > material. That crate will then be what you should use.
|
||||
//!
|
||||
//! ## I want to parse Unified Addresses
|
||||
//!
|
||||
//! See the [`unified::Address`] documentation for examples.
|
||||
//!
|
||||
//! While the [`unified::Address`] type does have parsing methods, you should still parse
|
||||
//! your address strings with [`ZcashAddress`] and then convert; this will ensure that for
|
||||
//! other Zcash address types you get a [`ConversionError::Unsupported`], which is a
|
||||
//! better error for your users.
|
||||
//!
|
||||
//! ## I want to parse mainnet Zcash addresses in a language that supports C FFI
|
||||
//!
|
||||
//! As an example, you could use static functions to create the address types in the
|
||||
//! target language from the parsed data.
|
||||
//!
|
||||
//! ```
|
||||
//! use std::ffi::{CStr, c_char, c_void};
|
||||
//! use std::ptr;
|
||||
//!
|
||||
//! use zcash_address::{ConversionError, Network, TryFromRawAddress, ZcashAddress};
|
||||
//!
|
||||
//! // Functions that return a pointer to a heap-allocated address of the given kind in
|
||||
//! // the target language. These should be augmented to return any relevant errors.
|
||||
//! extern {
|
||||
//! fn addr_from_sapling(data: *const u8) -> *mut c_void;
|
||||
//! fn addr_from_transparent_p2pkh(data: *const u8) -> *mut c_void;
|
||||
//! }
|
||||
//!
|
||||
//! struct ParsedAddress(*mut c_void);
|
||||
//!
|
||||
//! impl TryFromRawAddress for ParsedAddress {
|
||||
//! type Error = &'static str;
|
||||
//!
|
||||
//! fn try_from_raw_sapling(
|
||||
//! data: [u8; 43],
|
||||
//! ) -> Result<Self, ConversionError<Self::Error>> {
|
||||
//! let parsed = unsafe { addr_from_sapling(data[..].as_ptr()) };
|
||||
//! if parsed.is_null() {
|
||||
//! Err("Reason for the failure".into())
|
||||
//! } else {
|
||||
//! Ok(Self(parsed))
|
||||
//! }
|
||||
//! }
|
||||
//!
|
||||
//! fn try_from_raw_transparent_p2pkh(
|
||||
//! data: [u8; 20],
|
||||
//! ) -> Result<Self, ConversionError<Self::Error>> {
|
||||
//! let parsed = unsafe { addr_from_transparent_p2pkh(data[..].as_ptr()) };
|
||||
//! if parsed.is_null() {
|
||||
//! Err("Reason for the failure".into())
|
||||
//! } else {
|
||||
//! Ok(Self(parsed))
|
||||
//! }
|
||||
//! }
|
||||
//! }
|
||||
//!
|
||||
//! pub extern "C" fn parse_zcash_address(encoded: *const c_char) -> *mut c_void {
|
||||
//! let encoded = unsafe { CStr::from_ptr(encoded) }.to_str().expect("valid");
|
||||
//!
|
||||
//! let addr = match ZcashAddress::try_from_encoded(encoded) {
|
||||
//! Ok(addr) => addr,
|
||||
//! Err(e) => {
|
||||
//! // This was either an invalid address encoding, or not a Zcash address.
|
||||
//! // You should pass this error back across the FFI.
|
||||
//! return ptr::null_mut();
|
||||
//! }
|
||||
//! };
|
||||
//!
|
||||
//! match addr.convert_if_network::<ParsedAddress>(Network::Main) {
|
||||
//! Ok(parsed) => parsed.0,
|
||||
//! Err(e) => {
|
||||
//! // We didn't implement all of the methods of `TryFromRawAddress`, so if an
|
||||
//! // address with one of those kinds is parsed, it will result in an error
|
||||
//! // here that should be passed back across the FFI.
|
||||
//! ptr::null_mut()
|
||||
//! }
|
||||
//! }
|
||||
//! }
|
||||
//! ```
|
||||
|
||||
#![cfg_attr(docsrs, feature(doc_cfg))]
|
||||
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||
// Catch documentation errors caused by code changes.
|
||||
#![deny(rustdoc::broken_intra_doc_links)]
|
||||
|
||||
mod convert;
|
||||
mod encoding;
|
||||
mod kind;
|
||||
|
@ -35,11 +166,11 @@ pub enum Network {
|
|||
/// Known kinds of Zcash addresses.
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
enum AddressKind {
|
||||
Sprout(kind::sprout::Data),
|
||||
Sapling(kind::sapling::Data),
|
||||
Sprout([u8; 64]),
|
||||
Sapling([u8; 43]),
|
||||
Unified(unified::Address),
|
||||
P2pkh(kind::p2pkh::Data),
|
||||
P2sh(kind::p2sh::Data),
|
||||
P2pkh([u8; 20]),
|
||||
P2sh([u8; 20]),
|
||||
}
|
||||
|
||||
impl ZcashAddress {
|
||||
|
|
Loading…
Reference in New Issue