From 55d5fbda2759ac4a151e0786a4d67ec14cfc1876 Mon Sep 17 00:00:00 2001 From: Francisco Gindre Date: Thu, 14 Nov 2024 13:17:19 -0300 Subject: [PATCH 01/21] Add "ledger-support" feature to `zingolib` crate --- zingolib/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/zingolib/Cargo.toml b/zingolib/Cargo.toml index 18d305068..d037da435 100644 --- a/zingolib/Cargo.toml +++ b/zingolib/Cargo.toml @@ -16,6 +16,7 @@ tempfile = ["dep:tempfile"] test-elevation = ["portpicker", "testvectors", "tempfile", "tempdir"] sync = ['dep:zingo-sync'] zaino-test = ['test-elevation'] +ledger-support = [] [dependencies] zingo-memo = { path = "../zingo-memo" } From 768587e3cecfafb3b1c9245990de60f5d3c8be26 Mon Sep 17 00:00:00 2001 From: Francisco Gindre Date: Thu, 14 Nov 2024 15:35:32 -0300 Subject: [PATCH 02/21] Always build all features in the IDE --- .vscode/settings.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index b458b995e..f5738c794 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,6 @@ { "rust-analyzer.diagnostics.disabled": [ "unresolved-macro-call" - ] + ], + "rust-analyzer.cargo.features": "all" } \ No newline at end of file From e1d582b687d3f1fb6b6b26f0ab1bf2987683e5c6 Mon Sep 17 00:00:00 2001 From: Francisco Gindre Date: Thu, 14 Nov 2024 15:36:27 -0300 Subject: [PATCH 03/21] Add a feature-gated `ledger` field in `WalletCapability` --- zingolib/src/wallet/keys.rs | 2 + zingolib/src/wallet/keys/ledger.rs | 71 +++++++++++++++++++++++++++++ zingolib/src/wallet/keys/unified.rs | 17 ++++++- 3 files changed, 89 insertions(+), 1 deletion(-) create mode 100644 zingolib/src/wallet/keys/ledger.rs diff --git a/zingolib/src/wallet/keys.rs b/zingolib/src/wallet/keys.rs index 66667ec35..b114baa80 100644 --- a/zingolib/src/wallet/keys.rs +++ b/zingolib/src/wallet/keys.rs @@ -15,6 +15,8 @@ use zcash_primitives::{ pub mod legacy; pub mod unified; +#[cfg(feature = "ledger-support")] +pub mod ledger; /// Sha256(Sha256(value)) pub fn double_sha256(payload: &[u8]) -> Vec { diff --git a/zingolib/src/wallet/keys/ledger.rs b/zingolib/src/wallet/keys/ledger.rs new file mode 100644 index 000000000..ff7bd348f --- /dev/null +++ b/zingolib/src/wallet/keys/ledger.rs @@ -0,0 +1,71 @@ +/// +/// Holds information related to the ledger + + + +use std::io; +use secp256k1::PublicKey as SecpPublicKey; +use tracing_subscriber::field::debug; +use crate::wallet::traits::ReadableWriteable; + +/// Holds ledger things +#[derive(Debug)] +pub struct LedgerKeys { + ledger_id: SecpPublicKey, + _app: ZcashApp +} + +/// Placeholder for the real thing +#[derive(Debug)] +pub struct ZcashApp {} + +impl ZcashApp { + fn new() -> ZcashApp { ZcashApp { }} +} + +impl ReadableWriteable for LedgerKeys { + const VERSION: u8 = 0; //not applicable + + fn read(mut reader: R, _input: ()) -> std::io::Result { + // let version = Self::read_version(&mut reader)?; + + // if version > Self::VERSION { + // let e = format!( + // "Don't know how to read ledger wallet version {}. Do you have the latest version?", + // version + // ); + // return Err(io::Error::new(io::ErrorKind::InvalidData, e)); + // } + + //retrieve the ledger id and verify it matches with the aocnnected device + let ledger_id = { + let mut buf = [0; secp256k1::constants::PUBLIC_KEY_SIZE]; + reader.read_exact(&mut buf)?; + + SecpPublicKey::from_slice(&buf).map_err(|e| { + io::Error::new( + io::ErrorKind::InvalidData, + format!("Bad public key stored for ledger id: {:?}", e), + ) + })? + }; + + // let app = Self::connect_ledger()?; + // // lets used futures simpler executor + // if ledger_id != futures::executor::block_on(Self::get_id(&app))? { + // return Err(io::Error::new( + // io::ErrorKind::InvalidInput, + // "Detected different ledger than used previously".to_string(), + // )); + // } + Ok(LedgerKeys { ledger_id, _app: ZcashApp::new()}) + + } + + fn write(&self, mut writer: W, _input: ()) -> std::io::Result<()> { + let id = self.ledger_id.serialize(); + writer.write_all(&id)?; + + Ok(()) + } +} \ No newline at end of file diff --git a/zingolib/src/wallet/keys/unified.rs b/zingolib/src/wallet/keys/unified.rs index 8ac01d427..4420a838a 100644 --- a/zingolib/src/wallet/keys/unified.rs +++ b/zingolib/src/wallet/keys/unified.rs @@ -34,6 +34,7 @@ use crate::{ wallet::data::new_rejection_address, }; +use super::ledger::LedgerKeys; use super::legacy::{generate_transparent_address_from_legacy_key, legacy_sks_to_usk, Capability}; use super::ToBase58Check; @@ -218,6 +219,9 @@ impl TryFrom<&UnifiedKeyStore> for zcash_primitives::legacy::keys::AccountPubKey /// or a [`zcash_keys::keys::UnifiedFullViewingKey`].

/// In addition to fundamental spending and viewing keys, the type caches generated addresses. pub struct WalletCapability { + + #[cfg(feature = "ledger-support")] + ledger: Option, /// Unified key store pub unified_key_store: UnifiedKeyStore, /// Cache of transparent addresses that the user has created. @@ -235,6 +239,8 @@ pub struct WalletCapability { impl Default for WalletCapability { fn default() -> Self { Self { + #[cfg(feature = "ledger-support")] + ledger: None, unified_key_store: UnifiedKeyStore::Empty, transparent_child_addresses: Arc::new(AppendOnlyVec::new()), rejection_addresses: Arc::new(AppendOnlyVec::new()), @@ -621,7 +627,7 @@ impl WalletCapability { } impl ReadableWriteable for WalletCapability { - const VERSION: u8 = 4; + const VERSION: u8 = 5; fn read(mut reader: R, input: ChainType) -> io::Result { let version = Self::get_version(&mut reader)?; @@ -758,6 +764,15 @@ impl ReadableWriteable for WalletCapability { ..Default::default() } } + 5 => { + legacy_key = false; + length_of_rejection_addresses = reader.read_u32::()?; + + Self { + unified_key_store: UnifiedKeyStore::read(&mut reader, input)?, + ..Default::default() + } + } _ => { return Err(io::Error::new( io::ErrorKind::InvalidData, From f2665ba25270b5dc4980cf4bfccfbf6c95e16e19 Mon Sep 17 00:00:00 2001 From: Francisco Gindre Date: Thu, 14 Nov 2024 17:00:38 -0300 Subject: [PATCH 04/21] Ledger WalletBase, KeyError, WalletCapability::new_with_ledger --- zingolib/src/config.rs | 7 +++ zingolib/src/wallet.rs | 15 +++++ zingolib/src/wallet/disk/testing/tests.rs | 68 +++++++++++++++++++++-- zingolib/src/wallet/error.rs | 4 ++ zingolib/src/wallet/keys/ledger.rs | 24 ++++++-- zingolib/src/wallet/keys/unified.rs | 20 +++++++ 6 files changed, 127 insertions(+), 11 deletions(-) diff --git a/zingolib/src/config.rs b/zingolib/src/config.rs index e1ec4455b..b676248ef 100644 --- a/zingolib/src/config.rs +++ b/zingolib/src/config.rs @@ -103,6 +103,8 @@ pub fn load_clientconfig( wallet_dir: data_dir, wallet_name: DEFAULT_WALLET_NAME.into(), logfile_name: DEFAULT_LOGFILE_NAME.into(), + #[cfg(feature = "ledger-support")] + use_ledger: false, }; Ok(config) @@ -170,6 +172,9 @@ pub struct ZingoConfig { pub wallet_name: PathBuf, /// The filename of the logfile. This will be created in the `wallet_dir`. pub logfile_name: PathBuf, + #[cfg(feature = "ledger-support")] + /// if this option is enabled, the LightClient will look for a ledger device to initialize or resume the wallet + pub use_ledger: bool, } impl ZingoConfigBuilder { @@ -225,6 +230,8 @@ impl ZingoConfigBuilder { wallet_dir: self.wallet_dir.clone(), wallet_name: DEFAULT_WALLET_NAME.into(), logfile_name: DEFAULT_LOGFILE_NAME.into(), + #[cfg(feature = "ledger-support")] + use_ledger: false, } } } diff --git a/zingolib/src/wallet.rs b/zingolib/src/wallet.rs index 381fd7534..ef0e851a0 100644 --- a/zingolib/src/wallet.rs +++ b/zingolib/src/wallet.rs @@ -175,6 +175,9 @@ pub enum WalletBase { Ufvk(String), /// Unified spending key Usk(Vec), + #[cfg(feature = "ledger-support")] + /// A hardware wallet + Ledger } impl WalletBase { @@ -381,6 +384,18 @@ impl LightWallet { )?; (wc, None) } + #[cfg(feature = "ledger-support")] + WalletBase::Ledger => { + let wc = WalletCapability::new_with_ledger(&config).map_err( + |e| { + Error::new( + ErrorKind::Other, + format!("Error initilizing Ledger Device: {}", e), + ) + }, + )?; + (wc, None) + } }; if let Err(e) = wc.new_address(wc.can_view(), false) { diff --git a/zingolib/src/wallet/disk/testing/tests.rs b/zingolib/src/wallet/disk/testing/tests.rs index ed73b3f7d..4d1af3783 100644 --- a/zingolib/src/wallet/disk/testing/tests.rs +++ b/zingolib/src/wallet/disk/testing/tests.rs @@ -4,8 +4,7 @@ use zcash_client_backend::{PoolType, ShieldedProtocol}; use zcash_keys::keys::Era; use crate::{ - lightclient::LightClient, - wallet::{ + lightclient::LightClient, wallet::{ disk::testing::{ assert_wallet_capability_matches_seed, examples::{ @@ -13,10 +12,8 @@ use crate::{ HospitalMuseumVersion, HotelHumorVersion, MainnetSeedVersion, MobileShuffleVersion, NetworkSeedVersion, RegtestSeedVersion, TestnetSeedVersion, VillageTargetVersion, }, - }, - keys::unified::UnifiedKeyStore, - LightWallet, - }, + }, error::KeyError, keys::unified::UnifiedKeyStore, LightWallet + } }; // moving toward completeness: each of these tests should assert everything known about the LightWallet without network. @@ -299,3 +296,62 @@ async fn reload_wallet_from_buffer() { let balance = client.do_balance().await; assert_eq!(balance.orchard_balance, Some(10342837)); } + +#[tokio::test] +async fn test_ledger_initialization() { + use crate::wallet::WalletCapability; + + let mid_wallet = + NetworkSeedVersion::Testnet(TestnetSeedVersion::ChimneyBetter(ChimneyBetterVersion::V28)) + .load_example_wallet_with_verification() + .await; + + let mid_client = LightClient::create_from_wallet_async(mid_wallet) + .await + .unwrap(); + + let mut config = mid_client.wallet.transaction_context.config; + config.use_ledger = true; + + let expected_wc = WalletCapability::new_with_ledger(&config); + assert!(expected_wc.is_ok()); + + match expected_wc { + Ok(w) => { + assert!(w.is_ledger()) + }, + Err(_) => assert!(false), + } + +} + +#[cfg(feature = "ledger-support")] +#[tokio::test] +async fn test_ledger_initialization_fails_with_wrong_config() { + use crate::wallet::WalletCapability; + + let mid_wallet = + NetworkSeedVersion::Testnet(TestnetSeedVersion::ChimneyBetter(ChimneyBetterVersion::V28)) + .load_example_wallet_with_verification() + .await; + + let mid_client = LightClient::create_from_wallet_async(mid_wallet) + .await + .unwrap(); + + let mut config = mid_client.wallet.transaction_context.config; + config.use_ledger = false; // this should make things fail + + let expected_wc = WalletCapability::new_with_ledger(&config); + assert!(expected_wc.is_err()); + + match expected_wc { + Ok(_) => { + assert!(false) + }, + Err(e) => match e { + KeyError::LedgerNotSet => assert!(true), + _ => assert!(false) + } + } +} \ No newline at end of file diff --git a/zingolib/src/wallet/error.rs b/zingolib/src/wallet/error.rs index 151d16017..c53c98076 100644 --- a/zingolib/src/wallet/error.rs +++ b/zingolib/src/wallet/error.rs @@ -77,4 +77,8 @@ pub enum KeyError { /// Invalid format #[error("Viewing keys must be imported in the unified format")] InvalidFormat, + #[cfg(feature = "ledger-support")] + #[error("Ledger device not set.")] + /// Ledger flag was not set or device not found + LedgerNotSet } diff --git a/zingolib/src/wallet/keys/ledger.rs b/zingolib/src/wallet/keys/ledger.rs index ff7bd348f..c808c2593 100644 --- a/zingolib/src/wallet/keys/ledger.rs +++ b/zingolib/src/wallet/keys/ledger.rs @@ -1,20 +1,34 @@ -/// /// Holds information related to the ledger use std::io; -use secp256k1::PublicKey as SecpPublicKey; -use tracing_subscriber::field::debug; +use secp256k1::{PublicKey, Secp256k1, SecretKey}; use crate::wallet::traits::ReadableWriteable; /// Holds ledger things #[derive(Debug)] pub struct LedgerKeys { - ledger_id: SecpPublicKey, + ledger_id: PublicKey, _app: ZcashApp } +//TODO! this is all mocked code +impl LedgerKeys { + /// TODO! this is all mocked code + pub fn new() -> LedgerKeys{ + // Create a new secp256k1 context + let secp = Secp256k1::new(); + + // Generate a secret key for testing purposes (not secure) + let secret_key = SecretKey::from_slice(&[0x01; 32]).expect("32 bytes, within curve order"); + + // Derive the corresponding public key + let public_key = PublicKey::from_secret_key(&secp, &secret_key); + LedgerKeys { ledger_id: public_key, _app: ZcashApp::new() } + } +} + /// Placeholder for the real thing #[derive(Debug)] pub struct ZcashApp {} @@ -42,7 +56,7 @@ impl ReadableWriteable for LedgerKeys { let mut buf = [0; secp256k1::constants::PUBLIC_KEY_SIZE]; reader.read_exact(&mut buf)?; - SecpPublicKey::from_slice(&buf).map_err(|e| { + PublicKey::from_slice(&buf).map_err(|e| { io::Error::new( io::ErrorKind::InvalidData, format!("Bad public key stored for ledger id: {:?}", e), diff --git a/zingolib/src/wallet/keys/unified.rs b/zingolib/src/wallet/keys/unified.rs index 4420a838a..d0b1d8c72 100644 --- a/zingolib/src/wallet/keys/unified.rs +++ b/zingolib/src/wallet/keys/unified.rs @@ -312,6 +312,12 @@ fn read_write_receiver_selections() { } impl WalletCapability { + #[cfg(feature = "ledger-support")] + /// checks whether this WalletCapability is a Ledger device or not + pub fn is_ledger(&self) -> bool { + self.ledger.is_some() + } + pub(crate) fn get_ua_from_contained_transparent_receiver( &self, receiver: &TransparentAddress, @@ -557,6 +563,20 @@ impl WalletCapability { }) } + #[cfg(feature = "ledger-support")] + /// initializes a new wallet with a ledger + pub fn new_with_ledger(config: &ZingoConfig) -> Result { + if !config.use_ledger { + return Err(KeyError::LedgerNotSet) + } + + let mut wc = WalletCapability::default(); + + wc.ledger = Some(LedgerKeys::new()); + + Ok(wc) + } + /// external here refers to HD keys: /// /// where external and internal were inherited from the BIP44 conventions From 833a13e6009e3ea8680327177ba307ce5f0e19db Mon Sep 17 00:00:00 2001 From: Francisco Gindre Date: Thu, 14 Nov 2024 19:27:40 -0300 Subject: [PATCH 05/21] Create `InternalCapability` capability trait --- zingolib/src/wallet/keys/ledger.rs | 2 +- zingolib/src/wallet/keys/unified.rs | 45 +++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/zingolib/src/wallet/keys/ledger.rs b/zingolib/src/wallet/keys/ledger.rs index c808c2593..3569f07bf 100644 --- a/zingolib/src/wallet/keys/ledger.rs +++ b/zingolib/src/wallet/keys/ledger.rs @@ -1,4 +1,4 @@ -/// Holds information related to the ledger +//! Holds information related to the ledger diff --git a/zingolib/src/wallet/keys/unified.rs b/zingolib/src/wallet/keys/unified.rs index d0b1d8c72..291f10bb3 100644 --- a/zingolib/src/wallet/keys/unified.rs +++ b/zingolib/src/wallet/keys/unified.rs @@ -311,6 +311,50 @@ fn read_write_receiver_selections() { } } +pub (crate) trait InternalCapability { + fn get_ua_from_contained_transparent_receiver( + &self, + capability: WalletCapability, + receiver: &TransparentAddress, + ) -> Option; + + fn addresses(&self, capability: WalletCapability) -> &AppendOnlyVec; + + fn transparent_child_addresses( + &self, + capability: WalletCapability + ) -> &Arc>; + + fn new_address( + &self, + capability: WalletCapability, + desired_receivers: ReceiverSelection, + legacy_key: bool, + ) -> Result; + + fn generate_transparent_receiver( + &self, + capability: WalletCapability, + // this should only be `true` when generating transparent addresses while loading from legacy keys (pre wallet version 29) + // legacy transparent keys are already derived to the external scope so setting `legacy_key` to `true` will skip this scope derivation + legacy_key: bool, + ) -> Result, bip32::Error>; + + /// TODO: Add Doc Comment Here! + #[deprecated(note = "not used in zingolib codebase")] + fn get_taddr_to_secretkey_map( + &self, + capability: WalletCapability, + chain: &ChainType, + ) -> Result, KeyError>; + + fn first_sapling_address(&self, capability: WalletCapability) -> sapling_crypto::PaymentAddress; + + fn get_trees_witness_trees(&self, capability: WalletCapability) -> Option; + + fn can_view(&self, capability: WalletCapability) -> ReceiverSelection; +} + impl WalletCapability { #[cfg(feature = "ledger-support")] /// checks whether this WalletCapability is a Ledger device or not @@ -601,6 +645,7 @@ impl WalletCapability { .collect() } + /// TODO: This does not appear to be used pub(crate) fn get_taddrs(&self, chain: &crate::config::ChainType) -> HashSet { self.get_external_taddrs(chain) .union(&self.get_rejection_address_set(chain)) From ffcbf7dd50d5c357ee0e600318b19390636e5631 Mon Sep 17 00:00:00 2001 From: Francisco Gindre Date: Tue, 19 Nov 2024 17:42:19 -0300 Subject: [PATCH 06/21] Implement `InternalCapability` trait for `InMemory` keys. --- zingolib/src/wallet/keys.rs | 1 + zingolib/src/wallet/keys/capability.rs | 348 +++++++++++++++++++++++++ zingolib/src/wallet/keys/ledger.rs | 80 +++++- zingolib/src/wallet/keys/unified.rs | 58 +---- 4 files changed, 437 insertions(+), 50 deletions(-) create mode 100644 zingolib/src/wallet/keys/capability.rs diff --git a/zingolib/src/wallet/keys.rs b/zingolib/src/wallet/keys.rs index b114baa80..bbce0a3d1 100644 --- a/zingolib/src/wallet/keys.rs +++ b/zingolib/src/wallet/keys.rs @@ -18,6 +18,7 @@ pub mod unified; #[cfg(feature = "ledger-support")] pub mod ledger; +mod capability; /// Sha256(Sha256(value)) pub fn double_sha256(payload: &[u8]) -> Vec { let h1 = ::digest(payload); diff --git a/zingolib/src/wallet/keys/capability.rs b/zingolib/src/wallet/keys/capability.rs new file mode 100644 index 000000000..25c3d7e29 --- /dev/null +++ b/zingolib/src/wallet/keys/capability.rs @@ -0,0 +1,348 @@ +//! This implements the Internal Capability + +use std::{collections::{HashMap, HashSet}, sync::{atomic, Arc}}; + +use append_only_vec::AppendOnlyVec; +use zcash_keys::{address::UnifiedAddress, keys::DerivationError}; +use zcash_primitives::{consensus::NetworkConstants, legacy::{keys::{AccountPubKey, IncomingViewingKey, NonHardenedChildIndex}, TransparentAddress}}; +use zip32::DiversifierIndex; +use crate::{config::ChainType, wallet::error::KeyError}; +use super::{legacy::generate_transparent_address_from_legacy_key, unified::{ReceiverSelection, UnifiedKeyStore, WalletCapability}, ToBase58Check}; + +pub (crate) trait InternalCapability: std::fmt::Debug + Send + Sync { + fn get_ua_from_contained_transparent_receiver( + &self, + capability: &WalletCapability, + receiver: &TransparentAddress, + ) -> Option; + + fn addresses<'a>(&'a self, capability: &'a WalletCapability) -> &'a AppendOnlyVec; + + fn transparent_child_addresses<'a>( + &'a self, + capability: &'a WalletCapability + ) -> &'a Arc>; + + fn new_address( + &self, + capability: &WalletCapability, + desired_receivers: ReceiverSelection, + legacy_key: bool, + ) -> Result; + + fn generate_transparent_receiver( + &self, + capability: &WalletCapability, + // this should only be `true` when generating transparent addresses while loading from legacy keys (pre wallet version 29) + // legacy transparent keys are already derived to the external scope so setting `legacy_key` to `true` will skip this scope derivation + legacy_key: bool, + ) -> Result, bip32::Error>; + + /// TODO: Add Doc Comment Here! + #[deprecated(note = "not used in zingolib codebase")] + fn get_taddr_to_secretkey_map( + &self, + capability: &WalletCapability, + chain: &ChainType, + ) -> Result, KeyError>; + + fn get_external_taddrs( + &self, + capability: &WalletCapability, + chain: &crate::config::ChainType + ) -> HashSet; + + fn get_taddrs(&self, + capability: &WalletCapability, + chain: &crate::config::ChainType + ) -> HashSet; + + fn first_sapling_address(&self, capability: &WalletCapability) -> sapling_crypto::PaymentAddress; + + fn get_trees_witness_trees(&self, capability: &WalletCapability) -> Option; + + fn can_view(&self, capability: &WalletCapability) -> ReceiverSelection; +} + +#[derive(Debug)] +pub (crate) struct InMemoryWallet {} + +impl InMemoryWallet { + pub(crate) fn new() -> InMemoryWallet { + InMemoryWallet{} + } +} +impl InternalCapability for InMemoryWallet { + fn get_ua_from_contained_transparent_receiver( + &self, + capability: &WalletCapability, + receiver: &TransparentAddress, + ) -> Option { + capability.unified_addresses + .iter() + .find(|ua| ua.transparent() == Some(receiver)) + .cloned() + } + /// TODO: Add Doc Comment Here! + fn addresses<'a>(&'a self, capability: &'a WalletCapability) -> &'a AppendOnlyVec { + &capability.unified_addresses + } + + /// TODO: Add Doc Comment Here! + fn transparent_child_addresses<'a>( + &'a self, + capability: &'a WalletCapability + ) -> &'a Arc> { + &capability.transparent_child_addresses + } + /// Generates a unified address from the given desired receivers + /// + /// See [`crate::wallet::WalletCapability::generate_transparent_receiver`] for information on using `legacy_key` + fn new_address( + &self, + capability: &WalletCapability, + desired_receivers: ReceiverSelection, + legacy_key: bool, + ) -> Result { + if capability + .addresses_write_lock + .swap(true, atomic::Ordering::Acquire) + { + return Err("addresses_write_lock collision!".to_string()); + } + + let previous_num_addresses = capability.unified_addresses.len(); + let orchard_receiver = if desired_receivers.orchard { + let fvk: orchard::keys::FullViewingKey = match capability.unified_key_store().try_into() { + Ok(viewkey) => viewkey, + Err(e) => { + capability.addresses_write_lock + .swap(false, atomic::Ordering::Release); + return Err(e.to_string()); + } + }; + Some(fvk.address_at(capability.unified_addresses.len(), orchard::keys::Scope::External)) + } else { + None + }; + + // produce a Sapling address to increment Sapling diversifier index + let sapling_receiver = if desired_receivers.sapling { + let mut sapling_diversifier_index = DiversifierIndex::new(); + let mut address; + let mut count = 0; + let fvk: sapling_crypto::zip32::DiversifiableFullViewingKey = + match capability.unified_key_store().try_into() { + Ok(viewkey) => viewkey, + Err(e) => { + capability.addresses_write_lock + .swap(false, atomic::Ordering::Release); + return Err(e.to_string()); + } + }; + loop { + (sapling_diversifier_index, address) = fvk + .find_address(sapling_diversifier_index) + .expect("Diversifier index overflow"); + sapling_diversifier_index + .increment() + .expect("Diversifier index overflow"); + // Not all sapling_diversifier_indexes produce valid + // sapling addresses. + // Because of this self.unified_addresses.len() + // will be <= sapling_diversifier_index + if count == capability.unified_addresses.len() { + break; + } + count += 1; + } + Some(address) + } else { + None + }; + + let transparent_receiver = if desired_receivers.transparent { + capability.generate_transparent_receiver(legacy_key) + .map_err(|e| e.to_string())? + } else { + None + }; + + let ua = UnifiedAddress::from_receivers( + orchard_receiver, + sapling_receiver, + transparent_receiver, + ); + let ua = match ua { + Some(address) => address, + None => { + capability.addresses_write_lock + .swap(false, atomic::Ordering::Release); + return Err( + "Invalid receivers requested! At least one of sapling or orchard required" + .to_string(), + ); + } + }; + capability.unified_addresses.push(ua.clone()); + assert_eq!(capability.unified_addresses.len(), previous_num_addresses + 1); + capability.addresses_write_lock + .swap(false, atomic::Ordering::Release); + Ok(ua) + } + + /// Generates a transparent receiver for the specified scope. + fn generate_transparent_receiver( + &self, + capability: &WalletCapability, + // this should only be `true` when generating transparent addresses while loading from legacy keys (pre wallet version 29) + // legacy transparent keys are already derived to the external scope so setting `legacy_key` to `true` will skip this scope derivation + legacy_key: bool, + ) -> Result, bip32::Error> { + let derive_address = |transparent_fvk: &AccountPubKey, + child_index: NonHardenedChildIndex| + -> Result { + let t_addr = if legacy_key { + generate_transparent_address_from_legacy_key(transparent_fvk, child_index)? + } else { + transparent_fvk + .derive_external_ivk()? + .derive_address(child_index)? + }; + + capability.transparent_child_addresses + .push((capability.addresses().len(), t_addr)); + Ok(t_addr) + }; + let child_index = NonHardenedChildIndex::from_index(capability.addresses().len() as u32) + .expect("hardened bit should not be set for non-hardened child indexes"); + let transparent_receiver = match capability.unified_key_store() { + UnifiedKeyStore::Spend(usk) => { + derive_address(&usk.transparent().to_account_pubkey(), child_index) + .map(Option::Some) + } + UnifiedKeyStore::View(ufvk) => ufvk + .transparent() + .map(|pub_key| derive_address(pub_key, child_index)) + .transpose(), + UnifiedKeyStore::Empty => Ok(None), + }?; + + Ok(transparent_receiver) + } + + /// TODO: Add Doc Comment Here! + fn get_taddr_to_secretkey_map( + &self, + capability: &WalletCapability, + chain: &ChainType, + ) -> Result, KeyError> { + if let UnifiedKeyStore::Spend(usk) = capability.unified_key_store() { + capability.transparent_child_addresses() + .iter() + .map(|(i, taddr)| -> Result<_, KeyError> { + let hash = match taddr { + TransparentAddress::PublicKeyHash(hash) => hash, + TransparentAddress::ScriptHash(hash) => hash, + }; + Ok(( + hash.to_base58check(&chain.b58_script_address_prefix(), &[]), + usk.transparent() + .derive_external_secret_key( + NonHardenedChildIndex::from_index(*i as u32) + .ok_or(KeyError::InvalidNonHardenedChildIndex)?, + ) + .map_err(DerivationError::Transparent) + .map_err(KeyError::KeyDerivationError)?, + )) + }) + .collect::>() + } else { + Err(KeyError::NoSpendCapability) + } + } + + /// external here refers to HD keys: + /// + /// where external and internal were inherited from the BIP44 conventions + fn get_external_taddrs( + &self, + capability: &WalletCapability, + chain: &crate::config::ChainType) -> HashSet { + capability.unified_addresses + .iter() + .filter_map(|address| { + address.transparent().and_then(|transparent_receiver| { + if let zcash_primitives::legacy::TransparentAddress::PublicKeyHash(hash) = + transparent_receiver + { + Some(super::ToBase58Check::to_base58check( + hash.as_slice(), + &chain.b58_pubkey_address_prefix(), + &[], + )) + } else { + None + } + }) + }) + .collect() + } + + /// TODO: This does not appear to be used + fn get_taddrs(&self, + capability: &WalletCapability, + chain: &crate::config::ChainType + ) -> HashSet { + self.get_external_taddrs(capability, chain,) + .union(&capability.get_rejection_address_set(chain)) + .cloned() + .collect() + } + /// TODO: Add Doc Comment Here! + fn first_sapling_address( + &self, + capability: &WalletCapability + ) -> sapling_crypto::PaymentAddress { + // This index is dangerous, but all ways to instantiate a UnifiedSpendAuthority + // create it with a suitable first address + *capability.addresses()[0].sapling().unwrap() + } + + /// TODO: Add Doc Comment Here! + //TODO: NAME?????!! + fn get_trees_witness_trees( + &self, + capability: &WalletCapability, + ) -> Option { + if capability.unified_key_store().is_spending_key() { + Some(crate::data::witness_trees::WitnessTrees::default()) + } else { + None + } + } + + /// Returns a selection of pools where the wallet can view funds. + fn can_view( + &self, + capability: &WalletCapability, + ) -> ReceiverSelection { + match capability.unified_key_store() { + UnifiedKeyStore::Spend(_) => ReceiverSelection { + orchard: true, + sapling: true, + transparent: true, + }, + UnifiedKeyStore::View(ufvk) => ReceiverSelection { + orchard: ufvk.orchard().is_some(), + sapling: ufvk.sapling().is_some(), + transparent: ufvk.transparent().is_some(), + }, + UnifiedKeyStore::Empty => ReceiverSelection { + orchard: false, + sapling: false, + transparent: false, + }, + } + } +} \ No newline at end of file diff --git a/zingolib/src/wallet/keys/ledger.rs b/zingolib/src/wallet/keys/ledger.rs index 3569f07bf..117bc5824 100644 --- a/zingolib/src/wallet/keys/ledger.rs +++ b/zingolib/src/wallet/keys/ledger.rs @@ -4,7 +4,10 @@ use std::io; use secp256k1::{PublicKey, Secp256k1, SecretKey}; -use crate::wallet::traits::ReadableWriteable; +use crate::wallet::{ + traits::ReadableWriteable, + keys::capability::InternalCapability, +}; /// Holds ledger things #[derive(Debug)] @@ -82,4 +85,79 @@ impl ReadableWriteable for LedgerKeys { Ok(()) } +} + +impl InternalCapability for LedgerKeys { + fn get_ua_from_contained_transparent_receiver( + &self, + capability: &super::unified::WalletCapability, + receiver: &zcash_primitives::legacy::TransparentAddress, + ) -> Option { + todo!() + } + + fn addresses(&self, capability: &super::unified::WalletCapability) -> &append_only_vec::AppendOnlyVec { + todo!() + } + + fn transparent_child_addresses( + &self, + capability: &super::unified::WalletCapability + ) -> &std::sync::Arc> { + todo!() + } + + fn new_address( + &self, + capability: &super::unified::WalletCapability, + desired_receivers: super::unified::ReceiverSelection, + legacy_key: bool, + ) -> Result { + todo!() + } + + fn generate_transparent_receiver( + &self, + capability: &super::unified::WalletCapability, + // this should only be `true` when generating transparent addresses while loading from legacy keys (pre wallet version 29) + // legacy transparent keys are already derived to the external scope so setting `legacy_key` to `true` will skip this scope derivation + legacy_key: bool, + ) -> Result, bip32::Error> { + todo!() + } + + fn get_taddr_to_secretkey_map( + &self, + capability: &super::unified::WalletCapability, + chain: &crate::config::ChainType, + ) -> Result, crate::wallet::error::KeyError> { + todo!() + } + + fn first_sapling_address(&self, capability: &super::unified::WalletCapability) -> sapling_crypto::PaymentAddress { + todo!() + } + + fn get_trees_witness_trees(&self, capability: &super::unified::WalletCapability) -> Option { + todo!() + } + + fn can_view(&self, capability: &super::unified::WalletCapability) -> super::unified::ReceiverSelection { + todo!() + } + + fn get_external_taddrs( + &self, + capability: &super::unified::WalletCapability, + chain: &crate::config::ChainType + ) -> std::collections::HashSet { + todo!() + } + + fn get_taddrs(&self, + capability: &super::unified::WalletCapability, + chain: &crate::config::ChainType + ) -> std::collections::HashSet { + todo!() + } } \ No newline at end of file diff --git a/zingolib/src/wallet/keys/unified.rs b/zingolib/src/wallet/keys/unified.rs index 291f10bb3..6918c158e 100644 --- a/zingolib/src/wallet/keys/unified.rs +++ b/zingolib/src/wallet/keys/unified.rs @@ -38,6 +38,8 @@ use super::ledger::LedgerKeys; use super::legacy::{generate_transparent_address_from_legacy_key, legacy_sks_to_usk, Capability}; use super::ToBase58Check; +use crate::wallet::keys::capability::{InternalCapability, InMemoryWallet}; + pub(crate) const KEY_TYPE_EMPTY: u8 = 0; pub(crate) const KEY_TYPE_VIEW: u8 = 1; pub(crate) const KEY_TYPE_SPEND: u8 = 2; @@ -221,20 +223,21 @@ impl TryFrom<&UnifiedKeyStore> for zcash_primitives::legacy::keys::AccountPubKey pub struct WalletCapability { #[cfg(feature = "ledger-support")] - ledger: Option, + pub(crate) ledger: Option, /// Unified key store pub unified_key_store: UnifiedKeyStore, /// Cache of transparent addresses that the user has created. /// Receipts to a single address are correlated on chain. /// TODO: Is there any reason to have this field, apart from the /// unified_addresses field? - transparent_child_addresses: Arc>, + pub(crate) transparent_child_addresses: Arc>, // TODO: read/write for ephmereral addresses // TODO: Remove this field and exclusively use the TxMap field instead - rejection_addresses: Arc>, + pub(crate) rejection_addresses: Arc>, /// Cache of unified_addresses - unified_addresses: append_only_vec::AppendOnlyVec, - addresses_write_lock: AtomicBool, + pub(crate) unified_addresses: append_only_vec::AppendOnlyVec, + pub(crate) addresses_write_lock: AtomicBool, + pub(crate) capability: Box, } impl Default for WalletCapability { fn default() -> Self { @@ -246,6 +249,7 @@ impl Default for WalletCapability { rejection_addresses: Arc::new(AppendOnlyVec::new()), unified_addresses: AppendOnlyVec::new(), addresses_write_lock: AtomicBool::new(false), + capability: Box::new(InMemoryWallet::new()), } } } @@ -311,50 +315,6 @@ fn read_write_receiver_selections() { } } -pub (crate) trait InternalCapability { - fn get_ua_from_contained_transparent_receiver( - &self, - capability: WalletCapability, - receiver: &TransparentAddress, - ) -> Option; - - fn addresses(&self, capability: WalletCapability) -> &AppendOnlyVec; - - fn transparent_child_addresses( - &self, - capability: WalletCapability - ) -> &Arc>; - - fn new_address( - &self, - capability: WalletCapability, - desired_receivers: ReceiverSelection, - legacy_key: bool, - ) -> Result; - - fn generate_transparent_receiver( - &self, - capability: WalletCapability, - // this should only be `true` when generating transparent addresses while loading from legacy keys (pre wallet version 29) - // legacy transparent keys are already derived to the external scope so setting `legacy_key` to `true` will skip this scope derivation - legacy_key: bool, - ) -> Result, bip32::Error>; - - /// TODO: Add Doc Comment Here! - #[deprecated(note = "not used in zingolib codebase")] - fn get_taddr_to_secretkey_map( - &self, - capability: WalletCapability, - chain: &ChainType, - ) -> Result, KeyError>; - - fn first_sapling_address(&self, capability: WalletCapability) -> sapling_crypto::PaymentAddress; - - fn get_trees_witness_trees(&self, capability: WalletCapability) -> Option; - - fn can_view(&self, capability: WalletCapability) -> ReceiverSelection; -} - impl WalletCapability { #[cfg(feature = "ledger-support")] /// checks whether this WalletCapability is a Ledger device or not From dd2c8eefa606799fd3e1df658ff421777717b158 Mon Sep 17 00:00:00 2001 From: Francisco Gindre Date: Tue, 19 Nov 2024 17:48:49 -0300 Subject: [PATCH 07/21] Move to InternalCapability's `get_ua_from_contained_transparent_receiver` --- zingolib/src/wallet/keys/unified.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/zingolib/src/wallet/keys/unified.rs b/zingolib/src/wallet/keys/unified.rs index 6918c158e..dcb221d6a 100644 --- a/zingolib/src/wallet/keys/unified.rs +++ b/zingolib/src/wallet/keys/unified.rs @@ -326,10 +326,7 @@ impl WalletCapability { &self, receiver: &TransparentAddress, ) -> Option { - self.unified_addresses - .iter() - .find(|ua| ua.transparent() == Some(receiver)) - .cloned() + self.capability.get_ua_from_contained_transparent_receiver(self, receiver) } /// TODO: Add Doc Comment Here! pub fn addresses(&self) -> &AppendOnlyVec { From b259c42f7828892e3f01029558dd36ad6c64177a Mon Sep 17 00:00:00 2001 From: Francisco Gindre Date: Tue, 19 Nov 2024 17:52:10 -0300 Subject: [PATCH 08/21] move WalletCapability `addresses()` to delegate to InternalCapability --- zingolib/src/wallet/keys/unified.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zingolib/src/wallet/keys/unified.rs b/zingolib/src/wallet/keys/unified.rs index dcb221d6a..a302f14da 100644 --- a/zingolib/src/wallet/keys/unified.rs +++ b/zingolib/src/wallet/keys/unified.rs @@ -330,7 +330,7 @@ impl WalletCapability { } /// TODO: Add Doc Comment Here! pub fn addresses(&self) -> &AppendOnlyVec { - &self.unified_addresses + self.capability.addresses(&self) } /// TODO: Add Doc Comment Here! From af319c3637bcf0fbe43e3e3a5b3709502f88d1b2 Mon Sep 17 00:00:00 2001 From: Francisco Gindre Date: Tue, 19 Nov 2024 17:54:12 -0300 Subject: [PATCH 09/21] Move `transparent_child_addresses` to `InternalWalletCapability` --- zingolib/src/wallet/keys/unified.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zingolib/src/wallet/keys/unified.rs b/zingolib/src/wallet/keys/unified.rs index a302f14da..ca9d908d8 100644 --- a/zingolib/src/wallet/keys/unified.rs +++ b/zingolib/src/wallet/keys/unified.rs @@ -335,7 +335,7 @@ impl WalletCapability { /// TODO: Add Doc Comment Here! pub fn transparent_child_addresses(&self) -> &Arc> { - &self.transparent_child_addresses + self.capability.transparent_child_addresses(&self) } /// Generates a unified address from the given desired receivers /// From c5a307722a1b5405920bb42650e6abeea0419d39 Mon Sep 17 00:00:00 2001 From: Francisco Gindre Date: Tue, 19 Nov 2024 17:58:19 -0300 Subject: [PATCH 10/21] Move `new_address` to InternalCapability implementation --- zingolib/src/wallet/keys/unified.rs | 88 +---------------------------- 1 file changed, 2 insertions(+), 86 deletions(-) diff --git a/zingolib/src/wallet/keys/unified.rs b/zingolib/src/wallet/keys/unified.rs index ca9d908d8..f3dc9c29a 100644 --- a/zingolib/src/wallet/keys/unified.rs +++ b/zingolib/src/wallet/keys/unified.rs @@ -94,7 +94,7 @@ impl ReadableWriteable for UnifiedKeyStore { match self { UnifiedKeyStore::Spend(usk) => { writer.write_u8(KEY_TYPE_SPEND)?; - usk.write(&mut writer, ()) + usk.write(&mut writer) } UnifiedKeyStore::View(ufvk) => { writer.write_u8(KEY_TYPE_VIEW)?; @@ -345,91 +345,7 @@ impl WalletCapability { desired_receivers: ReceiverSelection, legacy_key: bool, ) -> Result { - if self - .addresses_write_lock - .swap(true, atomic::Ordering::Acquire) - { - return Err("addresses_write_lock collision!".to_string()); - } - - let previous_num_addresses = self.unified_addresses.len(); - let orchard_receiver = if desired_receivers.orchard { - let fvk: orchard::keys::FullViewingKey = match (&self.unified_key_store).try_into() { - Ok(viewkey) => viewkey, - Err(e) => { - self.addresses_write_lock - .swap(false, atomic::Ordering::Release); - return Err(e.to_string()); - } - }; - Some(fvk.address_at(self.unified_addresses.len(), orchard::keys::Scope::External)) - } else { - None - }; - - // produce a Sapling address to increment Sapling diversifier index - let sapling_receiver = if desired_receivers.sapling { - let mut sapling_diversifier_index = DiversifierIndex::new(); - let mut address; - let mut count = 0; - let fvk: sapling_crypto::zip32::DiversifiableFullViewingKey = - match (&self.unified_key_store).try_into() { - Ok(viewkey) => viewkey, - Err(e) => { - self.addresses_write_lock - .swap(false, atomic::Ordering::Release); - return Err(e.to_string()); - } - }; - loop { - (sapling_diversifier_index, address) = fvk - .find_address(sapling_diversifier_index) - .expect("Diversifier index overflow"); - sapling_diversifier_index - .increment() - .expect("Diversifier index overflow"); - // Not all sapling_diversifier_indexes produce valid - // sapling addresses. - // Because of this self.unified_addresses.len() - // will be <= sapling_diversifier_index - if count == self.unified_addresses.len() { - break; - } - count += 1; - } - Some(address) - } else { - None - }; - - let transparent_receiver = if desired_receivers.transparent { - self.generate_transparent_receiver(legacy_key) - .map_err(|e| e.to_string())? - } else { - None - }; - - let ua = UnifiedAddress::from_receivers( - orchard_receiver, - sapling_receiver, - transparent_receiver, - ); - let ua = match ua { - Some(address) => address, - None => { - self.addresses_write_lock - .swap(false, atomic::Ordering::Release); - return Err( - "Invalid receivers requested! At least one of sapling or orchard required" - .to_string(), - ); - } - }; - self.unified_addresses.push(ua.clone()); - assert_eq!(self.unified_addresses.len(), previous_num_addresses + 1); - self.addresses_write_lock - .swap(false, atomic::Ordering::Release); - Ok(ua) + self.capability.new_address(&self, desired_receivers, legacy_key) } /// Generates a transparent receiver for the specified scope. From 7377e12d34fe6bcff5ed1c9a29d13c4a5d5b89e0 Mon Sep 17 00:00:00 2001 From: Francisco Gindre Date: Tue, 19 Nov 2024 17:59:50 -0300 Subject: [PATCH 11/21] Move `generate_transparent_receiver` to `InternalCapability` impl --- zingolib/src/wallet/keys/unified.rs | 31 +---------------------------- 1 file changed, 1 insertion(+), 30 deletions(-) diff --git a/zingolib/src/wallet/keys/unified.rs b/zingolib/src/wallet/keys/unified.rs index f3dc9c29a..e60ec0b6a 100644 --- a/zingolib/src/wallet/keys/unified.rs +++ b/zingolib/src/wallet/keys/unified.rs @@ -355,36 +355,7 @@ impl WalletCapability { // legacy transparent keys are already derived to the external scope so setting `legacy_key` to `true` will skip this scope derivation legacy_key: bool, ) -> Result, bip32::Error> { - let derive_address = |transparent_fvk: &AccountPubKey, - child_index: NonHardenedChildIndex| - -> Result { - let t_addr = if legacy_key { - generate_transparent_address_from_legacy_key(transparent_fvk, child_index)? - } else { - transparent_fvk - .derive_external_ivk()? - .derive_address(child_index)? - }; - - self.transparent_child_addresses - .push((self.addresses().len(), t_addr)); - Ok(t_addr) - }; - let child_index = NonHardenedChildIndex::from_index(self.addresses().len() as u32) - .expect("hardened bit should not be set for non-hardened child indexes"); - let transparent_receiver = match &self.unified_key_store { - UnifiedKeyStore::Spend(usk) => { - derive_address(&usk.transparent().to_account_pubkey(), child_index) - .map(Option::Some) - } - UnifiedKeyStore::View(ufvk) => ufvk - .transparent() - .map(|pub_key| derive_address(pub_key, child_index)) - .transpose(), - UnifiedKeyStore::Empty => Ok(None), - }?; - - Ok(transparent_receiver) + self.capability.generate_transparent_receiver(&self, legacy_key) } /// TODO: Add Doc Comment Here! From 18b2388062b282ab6210e696bf9dd14d7d2c7577 Mon Sep 17 00:00:00 2001 From: Francisco Gindre Date: Tue, 19 Nov 2024 18:00:31 -0300 Subject: [PATCH 12/21] Move `get_taddr_to_secretkey_map` to `InternalCapability` impl --- zingolib/src/wallet/keys/unified.rs | 24 +----------------------- 1 file changed, 1 insertion(+), 23 deletions(-) diff --git a/zingolib/src/wallet/keys/unified.rs b/zingolib/src/wallet/keys/unified.rs index e60ec0b6a..0dd13a765 100644 --- a/zingolib/src/wallet/keys/unified.rs +++ b/zingolib/src/wallet/keys/unified.rs @@ -364,29 +364,7 @@ impl WalletCapability { &self, chain: &ChainType, ) -> Result, KeyError> { - if let UnifiedKeyStore::Spend(usk) = &self.unified_key_store { - self.transparent_child_addresses() - .iter() - .map(|(i, taddr)| -> Result<_, KeyError> { - let hash = match taddr { - TransparentAddress::PublicKeyHash(hash) => hash, - TransparentAddress::ScriptHash(hash) => hash, - }; - Ok(( - hash.to_base58check(&chain.b58_pubkey_address_prefix(), &[]), - usk.transparent() - .derive_external_secret_key( - NonHardenedChildIndex::from_index(*i as u32) - .ok_or(KeyError::InvalidNonHardenedChildIndex)?, - ) - .map_err(DerivationError::Transparent) - .map_err(KeyError::KeyDerivationError)?, - )) - }) - .collect::>() - } else { - Err(KeyError::NoSpendCapability) - } + self.capability.get_taddr_to_secretkey_map(&self, chain) } /// TODO: Add Doc Comment Here! From d97c22c8eb153f2c346a737f635fdec76ca7712c Mon Sep 17 00:00:00 2001 From: Francisco Gindre Date: Tue, 19 Nov 2024 18:07:55 -0300 Subject: [PATCH 13/21] Move `get_external_taddrs` to `InternalCapability` implementation --- zingolib/src/wallet/keys/unified.rs | 29 +---------------------------- 1 file changed, 1 insertion(+), 28 deletions(-) diff --git a/zingolib/src/wallet/keys/unified.rs b/zingolib/src/wallet/keys/unified.rs index 0dd13a765..a785baa43 100644 --- a/zingolib/src/wallet/keys/unified.rs +++ b/zingolib/src/wallet/keys/unified.rs @@ -443,36 +443,9 @@ impl WalletCapability { Ok(wc) } - /// external here refers to HD keys: - /// - /// where external and internal were inherited from the BIP44 conventions - fn get_external_taddrs(&self, chain: &crate::config::ChainType) -> HashSet { - self.unified_addresses - .iter() - .filter_map(|address| { - address.transparent().and_then(|transparent_receiver| { - if let zcash_primitives::legacy::TransparentAddress::PublicKeyHash(hash) = - transparent_receiver - { - Some(super::ToBase58Check::to_base58check( - hash.as_slice(), - &chain.b58_pubkey_address_prefix(), - &[], - )) - } else { - None - } - }) - }) - .collect() - } - /// TODO: This does not appear to be used pub(crate) fn get_taddrs(&self, chain: &crate::config::ChainType) -> HashSet { - self.get_external_taddrs(chain) - .union(&self.get_rejection_address_set(chain)) - .cloned() - .collect() + self.capability.get_taddrs(&self, chain) } /// TODO: Add Doc Comment Here! pub fn first_sapling_address(&self) -> sapling_crypto::PaymentAddress { From d8d961aa9bd998317677974de03e5587916a837e Mon Sep 17 00:00:00 2001 From: Francisco Gindre Date: Tue, 19 Nov 2024 18:12:50 -0300 Subject: [PATCH 14/21] remove `get_trees_witness_trees` function from `InternalCapability` --- zingolib/src/wallet/keys/capability.rs | 15 --------------- zingolib/src/wallet/keys/ledger.rs | 4 ---- zingolib/src/wallet/keys/unified.rs | 1 + 3 files changed, 1 insertion(+), 19 deletions(-) diff --git a/zingolib/src/wallet/keys/capability.rs b/zingolib/src/wallet/keys/capability.rs index 25c3d7e29..e7409a7ea 100644 --- a/zingolib/src/wallet/keys/capability.rs +++ b/zingolib/src/wallet/keys/capability.rs @@ -59,8 +59,6 @@ pub (crate) trait InternalCapability: std::fmt::Debug + Send + Sync { fn first_sapling_address(&self, capability: &WalletCapability) -> sapling_crypto::PaymentAddress; - fn get_trees_witness_trees(&self, capability: &WalletCapability) -> Option; - fn can_view(&self, capability: &WalletCapability) -> ReceiverSelection; } @@ -309,19 +307,6 @@ impl InternalCapability for InMemoryWallet { *capability.addresses()[0].sapling().unwrap() } - /// TODO: Add Doc Comment Here! - //TODO: NAME?????!! - fn get_trees_witness_trees( - &self, - capability: &WalletCapability, - ) -> Option { - if capability.unified_key_store().is_spending_key() { - Some(crate::data::witness_trees::WitnessTrees::default()) - } else { - None - } - } - /// Returns a selection of pools where the wallet can view funds. fn can_view( &self, diff --git a/zingolib/src/wallet/keys/ledger.rs b/zingolib/src/wallet/keys/ledger.rs index 117bc5824..33bf346c0 100644 --- a/zingolib/src/wallet/keys/ledger.rs +++ b/zingolib/src/wallet/keys/ledger.rs @@ -138,10 +138,6 @@ impl InternalCapability for LedgerKeys { todo!() } - fn get_trees_witness_trees(&self, capability: &super::unified::WalletCapability) -> Option { - todo!() - } - fn can_view(&self, capability: &super::unified::WalletCapability) -> super::unified::ReceiverSelection { todo!() } diff --git a/zingolib/src/wallet/keys/unified.rs b/zingolib/src/wallet/keys/unified.rs index a785baa43..b7455d551 100644 --- a/zingolib/src/wallet/keys/unified.rs +++ b/zingolib/src/wallet/keys/unified.rs @@ -447,6 +447,7 @@ impl WalletCapability { pub(crate) fn get_taddrs(&self, chain: &crate::config::ChainType) -> HashSet { self.capability.get_taddrs(&self, chain) } + /// TODO: Add Doc Comment Here! pub fn first_sapling_address(&self) -> sapling_crypto::PaymentAddress { // This index is dangerous, but all ways to instantiate a UnifiedSpendAuthority From 8667db8c0318735ab7bd473331b782a7431e87e3 Mon Sep 17 00:00:00 2001 From: Francisco Gindre Date: Tue, 19 Nov 2024 18:34:22 -0300 Subject: [PATCH 15/21] Scaffolding for introducing a LedgerCapability --- zingolib/src/wallet/keys/ledger.rs | 10 +++++++++- zingolib/src/wallet/keys/unified.rs | 22 +++++++++------------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/zingolib/src/wallet/keys/ledger.rs b/zingolib/src/wallet/keys/ledger.rs index 33bf346c0..54a313bc6 100644 --- a/zingolib/src/wallet/keys/ledger.rs +++ b/zingolib/src/wallet/keys/ledger.rs @@ -87,7 +87,15 @@ impl ReadableWriteable for LedgerKeys { } } -impl InternalCapability for LedgerKeys { +#[derive(Debug)] +pub (crate) struct LedgerCapability {} + +impl LedgerCapability { + pub(crate) fn new() -> LedgerCapability { + LedgerCapability {} + } +} +impl InternalCapability for LedgerCapability { fn get_ua_from_contained_transparent_receiver( &self, capability: &super::unified::WalletCapability, diff --git a/zingolib/src/wallet/keys/unified.rs b/zingolib/src/wallet/keys/unified.rs index b7455d551..a9ad57887 100644 --- a/zingolib/src/wallet/keys/unified.rs +++ b/zingolib/src/wallet/keys/unified.rs @@ -1,6 +1,5 @@ //! TODO: Add Mod Description Here! -use std::sync::atomic; use std::{ collections::{HashMap, HashSet}, io::{self, Read, Write}, @@ -19,13 +18,10 @@ use zcash_client_backend::address::UnifiedAddress; use zcash_client_backend::keys::{Era, UnifiedSpendingKey}; use zcash_client_backend::wallet::TransparentAddressMetadata; use zcash_encoding::{CompactSize, Vector}; -use zcash_keys::keys::{DerivationError, UnifiedFullViewingKey}; +use zcash_keys::keys::UnifiedFullViewingKey; use zcash_primitives::consensus::{NetworkConstants, Parameters}; -use zcash_primitives::legacy::{ - keys::{AccountPubKey, IncomingViewingKey, NonHardenedChildIndex}, - TransparentAddress, -}; -use zcash_primitives::zip32::{AccountId, DiversifierIndex}; +use zcash_primitives::legacy::TransparentAddress; +use zcash_primitives::zip32::AccountId; use crate::wallet::error::KeyError; use crate::wallet::traits::{DomainWalletExt, ReadableWriteable, Recipient}; @@ -35,8 +31,7 @@ use crate::{ }; use super::ledger::LedgerKeys; -use super::legacy::{generate_transparent_address_from_legacy_key, legacy_sks_to_usk, Capability}; -use super::ToBase58Check; +use super::legacy::{legacy_sks_to_usk, Capability}; use crate::wallet::keys::capability::{InternalCapability, InMemoryWallet}; @@ -432,6 +427,8 @@ impl WalletCapability { #[cfg(feature = "ledger-support")] /// initializes a new wallet with a ledger pub fn new_with_ledger(config: &ZingoConfig) -> Result { + use super::ledger::LedgerCapability; + if !config.use_ledger { return Err(KeyError::LedgerNotSet) } @@ -439,6 +436,7 @@ impl WalletCapability { let mut wc = WalletCapability::default(); wc.ledger = Some(LedgerKeys::new()); + wc.capability = Box::new(LedgerCapability::new()); Ok(wc) } @@ -447,12 +445,10 @@ impl WalletCapability { pub(crate) fn get_taddrs(&self, chain: &crate::config::ChainType) -> HashSet { self.capability.get_taddrs(&self, chain) } - + /// TODO: Add Doc Comment Here! pub fn first_sapling_address(&self) -> sapling_crypto::PaymentAddress { - // This index is dangerous, but all ways to instantiate a UnifiedSpendAuthority - // create it with a suitable first address - *self.addresses()[0].sapling().unwrap() + self.capability.first_sapling_address(&self) } /// TODO: Add Doc Comment Here! From 10c41b0a28a4edc5569f4ba92b424a5a5caa5603 Mon Sep 17 00:00:00 2001 From: Francisco Gindre Date: Tue, 19 Nov 2024 19:21:09 -0300 Subject: [PATCH 16/21] fix feature compile errors --- zingolib/src/wallet/disk/testing/tests.rs | 1 + zingolib/src/wallet/keys/unified.rs | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/zingolib/src/wallet/disk/testing/tests.rs b/zingolib/src/wallet/disk/testing/tests.rs index 4d1af3783..cc2ce54e3 100644 --- a/zingolib/src/wallet/disk/testing/tests.rs +++ b/zingolib/src/wallet/disk/testing/tests.rs @@ -297,6 +297,7 @@ async fn reload_wallet_from_buffer() { assert_eq!(balance.orchard_balance, Some(10342837)); } +#[cfg(feature = "ledger-support")] #[tokio::test] async fn test_ledger_initialization() { use crate::wallet::WalletCapability; diff --git a/zingolib/src/wallet/keys/unified.rs b/zingolib/src/wallet/keys/unified.rs index a9ad57887..ddabdb0bc 100644 --- a/zingolib/src/wallet/keys/unified.rs +++ b/zingolib/src/wallet/keys/unified.rs @@ -30,9 +30,10 @@ use crate::{ wallet::data::new_rejection_address, }; +#[cfg(feature = "ledger-support")] use super::ledger::LedgerKeys; -use super::legacy::{legacy_sks_to_usk, Capability}; +use super::legacy::{legacy_sks_to_usk, Capability}; use crate::wallet::keys::capability::{InternalCapability, InMemoryWallet}; pub(crate) const KEY_TYPE_EMPTY: u8 = 0; From f2a59b391aef15e08f4a000ff79934f46fb0be50 Mon Sep 17 00:00:00 2001 From: Francisco Gindre Date: Tue, 19 Nov 2024 20:01:00 -0300 Subject: [PATCH 17/21] move `can_view` to `InternalCapability` Implementation --- zingolib/src/wallet/keys/unified.rs | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/zingolib/src/wallet/keys/unified.rs b/zingolib/src/wallet/keys/unified.rs index ddabdb0bc..39368ac46 100644 --- a/zingolib/src/wallet/keys/unified.rs +++ b/zingolib/src/wallet/keys/unified.rs @@ -464,23 +464,7 @@ impl WalletCapability { /// Returns a selection of pools where the wallet can view funds. pub fn can_view(&self) -> ReceiverSelection { - match &self.unified_key_store { - UnifiedKeyStore::Spend(_) => ReceiverSelection { - orchard: true, - sapling: true, - transparent: true, - }, - UnifiedKeyStore::View(ufvk) => ReceiverSelection { - orchard: ufvk.orchard().is_some(), - sapling: ufvk.sapling().is_some(), - transparent: ufvk.transparent().is_some(), - }, - UnifiedKeyStore::Empty => ReceiverSelection { - orchard: false, - sapling: false, - transparent: false, - }, - } + self.capability.can_view(&self) } } From 1ed8389e65ca618c9b63d4542aa1ee3520e7df3c Mon Sep 17 00:00:00 2001 From: Francisco Gindre Date: Thu, 21 Nov 2024 16:41:21 -0300 Subject: [PATCH 18/21] Add ledger-support feature to ZingoCli interface --- zingocli/Cargo.toml | 3 + zingocli/src/lib.rs | 136 +++++++++++++++++----------- zingolib/src/config.rs | 16 +++- zingolib/src/wallet/disk/testing.rs | 2 + 4 files changed, 102 insertions(+), 55 deletions(-) diff --git a/zingocli/Cargo.toml b/zingocli/Cargo.toml index a3af13608..c7aba2286 100644 --- a/zingocli/Cargo.toml +++ b/zingocli/Cargo.toml @@ -15,3 +15,6 @@ rustyline = { workspace = true } shellwords = { workspace = true } rustls.workspace = true + +[features] +ledger-support = [] diff --git a/zingocli/src/lib.rs b/zingocli/src/lib.rs index d6d3b6c6f..3114f80d3 100644 --- a/zingocli/src/lib.rs +++ b/zingocli/src/lib.rs @@ -20,60 +20,63 @@ pub mod version; /// TODO: Add Doc Comment Here! pub fn build_clap_app() -> clap::ArgMatches { - clap::Command::new("Zingo CLI").version(version::VERSION) - .arg(Arg::new("nosync") - .help("By default, zingo-cli will sync the wallet at startup. Pass --nosync to prevent the automatic sync at startup.") - .long("nosync") - .short('n') - .action(clap::ArgAction::SetTrue)) - .arg(Arg::new("regtest") - .long("regtest") - .help("Regtest mode") - .action(clap::ArgAction::SetTrue) ) - .arg(Arg::new("no-clean") - .long("no-clean") - .help("Don't clean regtest state before running. Regtest mode only") - .action(clap::ArgAction::SetTrue)) - .arg(Arg::new("chain") - .long("chain").short('c') - .help(r#"What chain to expect, if it's not inferable from the server URI. One of "mainnet", "testnet", or "regtest""#)) - .arg(Arg::new("seed") - .short('s') - .long("seed") - .value_name("SEED PHRASE") - .value_parser(parse_seed) - .help("Create a new wallet with the given 24-word seed phrase. Will fail if wallet already exists")) - .arg(Arg::new("viewkey") - .long("viewkey") - .value_name("UFVK") - .value_parser(parse_ufvk) - .help("Create a new wallet with the given encoded unified full viewing key. Will fail if wallet already exists")) - .arg(Arg::new("birthday") - .long("birthday") - .value_name("birthday") - .value_parser(clap::value_parser!(u32)) - .help("Specify wallet birthday when restoring from seed. This is the earliest block height where the wallet has a transaction.")) - .arg(Arg::new("server") - .long("server") - .value_name("server") - .help("Lightwalletd server to connect to.") - .value_parser(parse_uri) - .default_value(zingolib::config::DEFAULT_LIGHTWALLETD_SERVER)) - .arg(Arg::new("data-dir") - .long("data-dir") - .value_name("data-dir") - .help("Absolute path to use as data directory")) - .arg(Arg::new("COMMAND") - .help("Command to execute. If a command is not specified, zingo-cli will start in interactive mode.") - .required(false) - .index(1)) - .arg(Arg::new("extra_args") - .help("Params to execute command with. Run the 'help' command to get usage help.") - .required(false) - .num_args(1..) - .index(2) - .action(clap::ArgAction::Append) - ).get_matches() + let cmd = clap::Command::new("Zingo CLI").version(version::VERSION) + .arg(Arg::new("nosync") + .help("By default, zingo-cli will sync the wallet at startup. Pass --nosync to prevent the automatic sync at startup.") + .long("nosync") + .short('n') + .action(clap::ArgAction::SetTrue)) + .arg(Arg::new("regtest") + .long("regtest") + .help("Regtest mode") + .action(clap::ArgAction::SetTrue) ) + .arg(Arg::new("no-clean") + .long("no-clean") + .help("Don't clean regtest state before running. Regtest mode only") + .action(clap::ArgAction::SetTrue)) + .arg(Arg::new("chain") + .long("chain").short('c') + .help(r#"What chain to expect, if it's not inferable from the server URI. One of "mainnet", "testnet", or "regtest""#)) + .arg(Arg::new("seed") + .short('s') + .long("seed") + .value_name("SEED PHRASE") + .value_parser(parse_seed) + .help("Create a new wallet with the given 24-word seed phrase. Will fail if wallet already exists")) + .arg(Arg::new("viewkey") + .long("viewkey") + .value_name("UFVK") + .value_parser(parse_ufvk) + .help("Create a new wallet with the given encoded unified full viewing key. Will fail if wallet already exists")) + .arg(Arg::new("birthday") + .long("birthday") + .value_name("birthday") + .value_parser(clap::value_parser!(u32)) + .help("Specify wallet birthday when restoring from seed. This is the earliest block height where the wallet has a transaction.")) + .arg(Arg::new("server") + .long("server") + .value_name("server") + .help("Lightwalletd server to connect to.") + .value_parser(parse_uri) + .default_value(zingolib::config::DEFAULT_LIGHTWALLETD_SERVER)) + .arg(Arg::new("data-dir") + .long("data-dir") + .value_name("data-dir") + .help("Absolute path to use as data directory")) + .arg(Arg::new("COMMAND") + .help("Command to execute. If a command is not specified, zingo-cli will start in interactive mode.") + .required(false) + .index(1)) + .arg(Arg::new("extra_args") + .help("Params to execute command with. Run the 'help' command to get usage help.") + .required(false) + .num_args(1..) + .index(2) + .action(clap::ArgAction::Append) + ); + + add_if_ledger(cmd) + .get_matches() } /// Custom function to parse a string into an http::Uri @@ -280,6 +283,8 @@ pub struct ConfigTemplate { #[allow(dead_code)] // This field is defined so that it can be used in Drop::drop child_process_handler: Option, chaintype: ChainType, + #[cfg(feature = "ledger-support")] + ledger: bool, } use commands::ShortCircuitedCommand; fn short_circuit_on_help(params: Vec) { @@ -354,6 +359,10 @@ If you don't remember the block height, you can pass '--birthday 0' to scan from }; let clean_regtest_data = !matches.get_flag("no-clean"); + + #[cfg(feature = "ledger-support")] + let ledger = matches.get_flag("ledger"); + let data_dir = if let Some(dir) = matches.get_one::("data-dir") { PathBuf::from(dir.clone()) } else if is_regtest { @@ -412,6 +421,8 @@ If you don't remember the block height, you can pass '--birthday 0' to scan from regtest_manager, child_process_handler, chaintype, + #[cfg(feature = "ledger-support")] + ledger, }) } } @@ -439,6 +450,8 @@ pub fn startup( Some(data_dir), filled_template.chaintype, true, + #[cfg(feature = "ledger-support")] + filled_template.ledger, ) .unwrap(); regtest_config_check(&filled_template.regtest_manager, &config.chain); @@ -551,3 +564,18 @@ pub fn run_cli() { Err(e) => eprintln!("Error filling config template: {:?}", e), } } + + +fn add_if_ledger(cmd: clap::Command) -> clap::Command { + + #[cfg(feature = "ledger-support")] + return cmd + .arg(Arg::new("ledger") + .long("ledger") + .value_name("ledger") + .help("Create a new wallet by connecting to a ledger") + .action(clap::ArgAction::SetTrue)); + + #[cfg(not(feature = "ledger-support"))] + return cmd; +} \ No newline at end of file diff --git a/zingolib/src/config.rs b/zingolib/src/config.rs index b676248ef..59385c8d2 100644 --- a/zingolib/src/config.rs +++ b/zingolib/src/config.rs @@ -69,6 +69,8 @@ pub fn load_clientconfig( data_dir: Option, chain: ChainType, monitor_mempool: bool, + #[cfg(feature = "ledger-support")] + ledger: bool, ) -> std::io::Result { use std::net::ToSocketAddrs; @@ -104,7 +106,7 @@ pub fn load_clientconfig( wallet_name: DEFAULT_WALLET_NAME.into(), logfile_name: DEFAULT_LOGFILE_NAME.into(), #[cfg(feature = "ledger-support")] - use_ledger: false, + use_ledger: ledger, }; Ok(config) @@ -153,6 +155,9 @@ pub struct ZingoConfigBuilder { pub wallet_name: Option, /// The filename of the logfile. This will be created in the `wallet_dir`. pub logfile_name: Option, + /// set to true if you will use a ledger hw wallet + #[cfg(feature = "ledger-support")] + pub use_ledger: bool, } /// Configuration data that is necessary? and sufficient? for the creation of a LightClient. @@ -219,6 +224,13 @@ impl ZingoConfigBuilder { self } + #[cfg(feature = "ledger-support")] + /// set to true to use a ledger hardware wallet + pub fn set_use_ledger(&mut self, ledger: bool) -> &mut Self { + self.use_ledger = ledger; + self + } + /// TODO: Add Doc Comment Here! pub fn create(&self) -> ZingoConfig { let lightwalletd_uri = self.lightwalletd_uri.clone().unwrap_or_default(); @@ -246,6 +258,8 @@ impl Default for ZingoConfigBuilder { wallet_name: None, logfile_name: None, chain: ChainType::Mainnet, + #[cfg(feature = "ledger-support")] + use_ledger: false, } } } diff --git a/zingolib/src/wallet/disk/testing.rs b/zingolib/src/wallet/disk/testing.rs index 282da5642..e86c8b52e 100644 --- a/zingolib/src/wallet/disk/testing.rs +++ b/zingolib/src/wallet/disk/testing.rs @@ -20,6 +20,8 @@ impl LightWallet { None, crate::config::ChainType::Regtest(crate::config::RegtestNetwork::all_upgrades_active()), true, + #[cfg(feature = "ledger-support")] + false, ) .unwrap(); Self::read_internal(data, &config) From eae49fb846b0054d1a8a28ab6db2f4b00604acfd Mon Sep 17 00:00:00 2001 From: Francisco Gindre Date: Thu, 21 Nov 2024 19:44:29 -0300 Subject: [PATCH 19/21] add "ledger-support" feature to libtonode-tests --- libtonode-tests/Cargo.toml | 1 + libtonode-tests/tests/concrete.rs | 2 ++ libtonode-tests/tests/sync.rs | 2 ++ 3 files changed, 5 insertions(+) diff --git a/libtonode-tests/Cargo.toml b/libtonode-tests/Cargo.toml index 314855c7d..5a72be807 100644 --- a/libtonode-tests/Cargo.toml +++ b/libtonode-tests/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" [features] chain_generic_tests = [] ci = ["zingolib/ci"] +ledger-support = [] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] diff --git a/libtonode-tests/tests/concrete.rs b/libtonode-tests/tests/concrete.rs index 1c2afcbaf..0fa51bbb8 100644 --- a/libtonode-tests/tests/concrete.rs +++ b/libtonode-tests/tests/concrete.rs @@ -1601,6 +1601,8 @@ mod slow { Some(client_builder.zingo_datadir), ChainType::Regtest(regtest_network), true, + #[cfg(feature = "ledger-support")] + false, ) .unwrap(); diff --git a/libtonode-tests/tests/sync.rs b/libtonode-tests/tests/sync.rs index a0a8e196d..9a0d2f40b 100644 --- a/libtonode-tests/tests/sync.rs +++ b/libtonode-tests/tests/sync.rs @@ -26,6 +26,8 @@ async fn sync_mainnet_test() { Some(temp_path), zingolib::config::ChainType::Mainnet, true, + #[cfg(feature = "ledger-support")] + false, ) .unwrap(); let mut lightclient = LightClient::create_from_wallet_base_async( From 0a8c4123b8d78a75fc95dd264333c949249cc610 Mon Sep 17 00:00:00 2001 From: Francisco Gindre Date: Thu, 12 Dec 2024 08:09:44 -0300 Subject: [PATCH 20/21] add ledger repos --- Cargo.lock | 139 +++++++++++++++++++++++++++++++++++++------- Cargo.toml | 2 +- zingolib/Cargo.toml | 5 ++ 3 files changed, 124 insertions(+), 22 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0317df288..b68dab05a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -33,7 +33,7 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "cipher", "cpufeatures", ] @@ -265,7 +265,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ "addr2line", - "cfg-if", + "cfg-if 1.0.0", "libc", "miniz_oxide", "object", @@ -527,6 +527,12 @@ dependencies = [ "nom", ] +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + [[package]] name = "cfg-if" version = "1.0.0" @@ -539,7 +545,7 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "cipher", "cpufeatures", ] @@ -831,7 +837,7 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "dirs-sys-next", ] @@ -869,6 +875,12 @@ dependencies = [ "syn 2.0.90", ] +[[package]] +name = "doc-comment" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" + [[package]] name = "document-features" version = "0.2.10" @@ -896,7 +908,7 @@ version = "0.8.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", ] [[package]] @@ -972,7 +984,7 @@ version = "3.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef033ed5e9bad94e55838ca0ca906db0e043f517adda0c8b79c7a8c66c93c1b5" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "rustix", "windows-sys 0.48.0", ] @@ -1161,7 +1173,7 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "libc", "wasi", ] @@ -1273,6 +1285,12 @@ version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + [[package]] name = "heck" version = "0.5.0" @@ -1291,6 +1309,18 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hidapi" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "798154e4b6570af74899d71155fb0072d5b17e6aa12f39c8ef22c60fb8ec99e7" +dependencies = [ + "cc", + "libc", + "pkg-config", + "winapi", +] + [[package]] name = "hmac" version = "0.12.1" @@ -1757,6 +1787,43 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" +[[package]] +name = "ledger-apdu" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bb49f088676533baec18c9b4846c8af3c8ca9dbab80de9b90391851a1185319" +dependencies = [ + "arrayref", + "no-std-compat", + "snafu", +] + +[[package]] +name = "ledger-transport" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f2dc35b802e5df613fd337a7d8010213f6b454022d12c003d6a8cc58eaec5f9" +dependencies = [ + "async-trait", + "ledger-apdu", +] + +[[package]] +name = "ledger-transport-hid" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fd04436e96d73d8b7848017ccfaed6624acfeaf5f86a238f1a38d64cc97d3ee" +dependencies = [ + "byteorder", + "cfg-if 0.1.10", + "hex", + "hidapi", + "ledger-transport", + "libc", + "log", + "thiserror", +] + [[package]] name = "libc" version = "0.2.167" @@ -1769,7 +1836,7 @@ version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "windows-targets 0.52.6", ] @@ -1902,7 +1969,7 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "rayon", ] @@ -1992,10 +2059,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" dependencies = [ "bitflags 1.3.2", - "cfg-if", + "cfg-if 1.0.0", "libc", ] +[[package]] +name = "no-std-compat" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b93853da6d84c2e3c7d730d6473e8817692dd89be387eb01b94d7f108ecb5b8c" + [[package]] name = "nom" version = "7.1.3" @@ -2095,7 +2168,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5" dependencies = [ "bitflags 2.6.0", - "cfg-if", + "cfg-if 1.0.0", "foreign-types", "libc", "once_cell", @@ -2209,7 +2282,7 @@ version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "libc", "redox_syscall", "smallvec", @@ -2425,7 +2498,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c1318b19085f08681016926435853bbf7858f9c082d0999b80550ff5d9abe15" dependencies = [ "bytes", - "heck", + "heck 0.5.0", "itertools 0.13.0", "log", "multimap", @@ -2727,7 +2800,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" dependencies = [ "cc", - "cfg-if", + "cfg-if 1.0.0", "getrandom", "libc", "spin", @@ -2883,7 +2956,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5dfc8644681285d1fb67a467fb3021bfea306b99b4146b166a1fe3ada965eece" dependencies = [ "bitflags 1.3.2", - "cfg-if", + "cfg-if 1.0.0", "clipboard-win", "dirs-next", "fd-lock", @@ -3097,7 +3170,7 @@ version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "cpufeatures", "digest", ] @@ -3163,6 +3236,28 @@ version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +[[package]] +name = "snafu" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4de37ad025c587a29e8f3f5605c00f70b98715ef90b9061a815b9e59e9042d6" +dependencies = [ + "doc-comment", + "snafu-derive", +] + +[[package]] +name = "snafu-derive" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990079665f075b699031e9c08fd3ab99be5029b96f3b78dc0709e8f77e4efebf" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "socket2" version = "0.5.8" @@ -3300,7 +3395,7 @@ version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "fastrand", "once_cell", "rustix", @@ -3322,7 +3417,7 @@ version = "3.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adcb7fd841cd518e279be3d5a3eb0636409487998a4aff22f3de87b81e88384f" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "proc-macro2", "quote", "syn 2.0.90", @@ -3384,7 +3479,7 @@ version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "once_cell", ] @@ -3852,7 +3947,7 @@ version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d15e63b4482863c109d70a7b8706c1e364eb6ea449b201a76c5b89cedcec2d5c" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "once_cell", "wasm-bindgen-macro", ] @@ -3878,7 +3973,7 @@ version = "0.4.47" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9dfaf8f50e5f293737ee323940c7d8b08a66a95a419223d9f41610ca08b0833d" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "js-sys", "once_cell", "wasm-bindgen", @@ -4602,6 +4697,8 @@ dependencies = [ "json", "jubjub", "lazy_static", + "ledger-transport", + "ledger-transport-hid", "log", "log4rs", "nonempty", diff --git a/Cargo.toml b/Cargo.toml index 19b8c1cb6..bebaf8a30 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,7 @@ members = [ resolver = "2" [workspace.dependencies] -bip0039 = "0.11" +bip0039 = "0.9" incrementalmerkletree = "0.7" orchard = "0.10" sapling-crypto = "0.3" diff --git a/zingolib/Cargo.toml b/zingolib/Cargo.toml index d037da435..2013b8a1f 100644 --- a/zingolib/Cargo.toml +++ b/zingolib/Cargo.toml @@ -86,6 +86,11 @@ tonic = { workspace = true } tracing-subscriber = { workspace = true } bech32 = { workspace = true } +ledger-transport-hid = { version = "0.9", optional = true } +ledger-transport = { version = "0.9.0", optional = true } +zcash-hsmbuilder = { git = "https://github.com/Zondax/ledger-zcash-rs", package = "ledger-zcash-builder",branch = "feat/nu6-dev", default-features = false, optional = true } +ledger-zcash = { git = "https://github.com/Zondax/ledger-zcash-rs", package = "ledger-zcash", branch = "feat/nu6-dev", default-features = false, optional = true } + [dev-dependencies] portpicker = { workspace = true } tempfile = { workspace = true } From b8291f82a71ac820eba31d5e6750780d70f23332 Mon Sep 17 00:00:00 2001 From: Francisco Gindre Date: Mon, 23 Dec 2024 16:07:37 -0300 Subject: [PATCH 21/21] Fix compile errors and dependency issues --- Cargo.lock | 195 +++++++++++++++++-------- Cargo.toml | 2 +- zingolib/Cargo.toml | 22 ++- zingolib/src/testutils/scenarios.rs | 2 + zingolib/src/wallet/keys/capability.rs | 2 +- zingolib/src/wallet/keys/unified.rs | 28 +++- 6 files changed, 176 insertions(+), 75 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b68dab05a..de9341c49 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -33,7 +33,7 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "cipher", "cpufeatures", ] @@ -265,7 +265,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ "addr2line", - "cfg-if 1.0.0", + "cfg-if", "libc", "miniz_oxide", "object", @@ -355,9 +355,9 @@ dependencies = [ [[package]] name = "bip0039" -version = "0.11.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e68a5a99c65851e7be249f5cf510c0a136f18c9bca32139576d59bd3f577b043" +checksum = "568b6890865156d9043af490d4c4081c385dd68ea10acd6ca15733d511e6b51c" dependencies = [ "hmac", "pbkdf2", @@ -486,6 +486,12 @@ version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +[[package]] +name = "bytemuck" +version = "1.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef657dfab802224e671f5818e9a4935f9b1957ed18e58292690cc39e7a4092a3" + [[package]] name = "byteorder" version = "1.5.0" @@ -527,12 +533,6 @@ dependencies = [ "nom", ] -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - [[package]] name = "cfg-if" version = "1.0.0" @@ -545,7 +545,7 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "cipher", "cpufeatures", ] @@ -837,7 +837,7 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "dirs-sys-next", ] @@ -875,12 +875,6 @@ dependencies = [ "syn 2.0.90", ] -[[package]] -name = "doc-comment" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" - [[package]] name = "document-features" version = "0.2.10" @@ -896,6 +890,18 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" +[[package]] +name = "educe" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4bd92664bf78c4d3dba9b7cdafce6fa15b13ed3ed16175218196942e99168a8" +dependencies = [ + "enum-ordinalize", + "proc-macro2", + "quote", + "syn 2.0.90", +] + [[package]] name = "either" version = "1.13.0" @@ -908,7 +914,7 @@ version = "0.8.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] @@ -917,6 +923,26 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" +[[package]] +name = "enum-ordinalize" +version = "4.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea0dcfa4e54eeb516fe454635a95753ddd39acda650ce703031c6973e315dd5" +dependencies = [ + "enum-ordinalize-derive", +] + +[[package]] +name = "enum-ordinalize-derive" +version = "4.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d28318a75d4aead5c4db25382e8ef717932d0346600cacae6357eb5941bc5ff" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + [[package]] name = "enum_dispatch" version = "0.3.13" @@ -984,7 +1010,7 @@ version = "3.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef033ed5e9bad94e55838ca0ca906db0e043f517adda0c8b79c7a8c66c93c1b5" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "rustix", "windows-sys 0.48.0", ] @@ -1173,7 +1199,7 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "wasi", ] @@ -1285,12 +1311,6 @@ version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - [[package]] name = "heck" version = "0.5.0" @@ -1311,14 +1331,15 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "hidapi" -version = "1.5.0" +version = "2.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "798154e4b6570af74899d71155fb0072d5b17e6aa12f39c8ef22c60fb8ec99e7" +checksum = "03b876ecf37e86b359573c16c8366bc3eba52b689884a0fc42ba3f67203d2a8b" dependencies = [ "cc", + "cfg-if", "libc", "pkg-config", - "winapi", + "windows-sys 0.48.0", ] [[package]] @@ -1789,9 +1810,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "ledger-apdu" -version = "0.9.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bb49f088676533baec18c9b4846c8af3c8ca9dbab80de9b90391851a1185319" +checksum = "c21ffd28d97c9252671ab2ebe7078c9fa860ff3c5a125039e174d25ec6872169" dependencies = [ "arrayref", "no-std-compat", @@ -1800,9 +1821,9 @@ dependencies = [ [[package]] name = "ledger-transport" -version = "0.9.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f2dc35b802e5df613fd337a7d8010213f6b454022d12c003d6a8cc58eaec5f9" +checksum = "c2f18de77d956a030dbc5869ced47d404bbd641216ef2f9dce7ca90833ca64ff" dependencies = [ "async-trait", "ledger-apdu", @@ -1810,12 +1831,12 @@ dependencies = [ [[package]] name = "ledger-transport-hid" -version = "0.9.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fd04436e96d73d8b7848017ccfaed6624acfeaf5f86a238f1a38d64cc97d3ee" +checksum = "a4e34341e2708fbf805a9ada44ef6182170c6464c4fc068ab801abb7562fd5e8" dependencies = [ "byteorder", - "cfg-if 0.1.10", + "cfg-if", "hex", "hidapi", "ledger-transport", @@ -1824,6 +1845,38 @@ dependencies = [ "thiserror", ] +[[package]] +name = "ledger-zcash" +version = "2.0.0" +source = "git+https://github.com/zecdev/ledger-zcash-rs.git?rev=e441e4c0e1c21a77ed7bfaf768eabd6074df5124#e441e4c0e1c21a77ed7bfaf768eabd6074df5124" +dependencies = [ + "byteorder", + "cfg-if", + "educe", + "hex", + "lazy_static", + "ledger-transport", + "ledger-zondax-generic", + "log", + "serde", + "sha2", + "thiserror", + "tokio", + "zx-bip44", +] + +[[package]] +name = "ledger-zondax-generic" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7b7e1b78719fff5e70a67bab7224b1ed917aebb2b38521ffa047a9d93cc0501" +dependencies = [ + "async-trait", + "ledger-transport", + "serde", + "thiserror", +] + [[package]] name = "libc" version = "0.2.167" @@ -1836,7 +1889,7 @@ version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "windows-targets 0.52.6", ] @@ -1969,7 +2022,7 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "rayon", ] @@ -1981,9 +2034,9 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memuse" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2145869435ace5ea6ea3d35f59be559317ec9a0d04e1812d5f185a87b6d36f1a" +checksum = "3d97bbf43eb4f088f8ca469930cde17fa036207c9a5e02ccc5107c4e8b17c964" dependencies = [ "nonempty", ] @@ -2059,7 +2112,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" dependencies = [ "bitflags 1.3.2", - "cfg-if 1.0.0", + "cfg-if", "libc", ] @@ -2168,7 +2221,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5" dependencies = [ "bitflags 2.6.0", - "cfg-if 1.0.0", + "cfg-if", "foreign-types", "libc", "once_cell", @@ -2282,7 +2335,7 @@ version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "redox_syscall", "smallvec", @@ -2291,9 +2344,9 @@ dependencies = [ [[package]] name = "password-hash" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" +checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" dependencies = [ "base64ct", "rand_core 0.6.4", @@ -2323,9 +2376,9 @@ checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "pbkdf2" -version = "0.11.0" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" dependencies = [ "digest", "password-hash", @@ -2498,7 +2551,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c1318b19085f08681016926435853bbf7858f9c082d0999b80550ff5d9abe15" dependencies = [ "bytes", - "heck 0.5.0", + "heck", "itertools 0.13.0", "log", "multimap", @@ -2800,7 +2853,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" dependencies = [ "cc", - "cfg-if 1.0.0", + "cfg-if", "getrandom", "libc", "spin", @@ -2956,7 +3009,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5dfc8644681285d1fb67a467fb3021bfea306b99b4146b166a1fe3ada965eece" dependencies = [ "bitflags 1.3.2", - "cfg-if 1.0.0", + "cfg-if", "clipboard-win", "dirs-next", "fd-lock", @@ -3170,7 +3223,7 @@ version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "cpufeatures", "digest", ] @@ -3238,24 +3291,23 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "snafu" -version = "0.7.5" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4de37ad025c587a29e8f3f5605c00f70b98715ef90b9061a815b9e59e9042d6" +checksum = "223891c85e2a29c3fe8fb900c1fae5e69c2e42415e3177752e8718475efa5019" dependencies = [ - "doc-comment", "snafu-derive", ] [[package]] name = "snafu-derive" -version = "0.7.5" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "990079665f075b699031e9c08fd3ab99be5029b96f3b78dc0709e8f77e4efebf" +checksum = "03c3c6b7927ffe7ecaa769ee0e3994da3b8cafc8f444578982c83ecb161af917" dependencies = [ - "heck 0.4.1", + "heck", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.90", ] [[package]] @@ -3395,7 +3447,7 @@ version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "fastrand", "once_cell", "rustix", @@ -3417,7 +3469,7 @@ version = "3.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adcb7fd841cd518e279be3d5a3eb0636409487998a4aff22f3de87b81e88384f" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "proc-macro2", "quote", "syn 2.0.90", @@ -3479,7 +3531,7 @@ version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "once_cell", ] @@ -3947,7 +3999,7 @@ version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d15e63b4482863c109d70a7b8706c1e364eb6ea449b201a76c5b89cedcec2d5c" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "once_cell", "wasm-bindgen-macro", ] @@ -3973,7 +4025,7 @@ version = "0.4.47" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9dfaf8f50e5f293737ee323940c7d8b08a66a95a419223d9f41610ca08b0833d" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "js-sys", "once_cell", "wasm-bindgen", @@ -4681,6 +4733,7 @@ dependencies = [ "bls12_381", "bs58", "build_utils", + "bytemuck", "byteorder", "bytes", "chrono", @@ -4699,6 +4752,8 @@ dependencies = [ "lazy_static", "ledger-transport", "ledger-transport-hid", + "ledger-zcash", + "ledger-zondax-generic", "log", "log4rs", "nonempty", @@ -4707,6 +4762,7 @@ dependencies = [ "proptest", "prost", "rand 0.8.5", + "redjubjub", "reqwest", "ring", "rust-embed", @@ -4739,6 +4795,7 @@ dependencies = [ "zingo-status", "zingo-sync", "zip32", + "zx-bip44", ] [[package]] @@ -4764,3 +4821,13 @@ dependencies = [ "zcash_address", "zcash_protocol", ] + +[[package]] +name = "zx-bip44" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ed17b569d1ea6903d5dc061602c6dc45f816cd0171d67d3b40fc1f6caf1ade0" +dependencies = [ + "byteorder", + "thiserror", +] diff --git a/Cargo.toml b/Cargo.toml index bebaf8a30..f8f7b0cda 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,7 @@ members = [ resolver = "2" [workspace.dependencies] -bip0039 = "0.9" +bip0039 = "0.12" incrementalmerkletree = "0.7" orchard = "0.10" sapling-crypto = "0.3" diff --git a/zingolib/Cargo.toml b/zingolib/Cargo.toml index 2013b8a1f..e5a7218de 100644 --- a/zingolib/Cargo.toml +++ b/zingolib/Cargo.toml @@ -16,7 +16,13 @@ tempfile = ["dep:tempfile"] test-elevation = ["portpicker", "testvectors", "tempfile", "tempdir"] sync = ['dep:zingo-sync'] zaino-test = ['test-elevation'] -ledger-support = [] +ledger-support = [ + "dep:ledger-zcash", + "dep:zx-bip44", + "dep:ledger-transport", + "dep:ledger-zondax-generic", + "dep:bytemuck", +] [dependencies] zingo-memo = { path = "../zingo-memo" } @@ -86,10 +92,16 @@ tonic = { workspace = true } tracing-subscriber = { workspace = true } bech32 = { workspace = true } -ledger-transport-hid = { version = "0.9", optional = true } -ledger-transport = { version = "0.9.0", optional = true } -zcash-hsmbuilder = { git = "https://github.com/Zondax/ledger-zcash-rs", package = "ledger-zcash-builder",branch = "feat/nu6-dev", default-features = false, optional = true } -ledger-zcash = { git = "https://github.com/Zondax/ledger-zcash-rs", package = "ledger-zcash", branch = "feat/nu6-dev", default-features = false, optional = true } +# Ledger Support +ledger-zcash = { git = "https://github.com/zecdev/ledger-zcash-rs.git", rev = "e441e4c0e1c21a77ed7bfaf768eabd6074df5124", optional = true } +zx-bip44 = { version = "0.1.0", optional = true } +redjubjub = { version = "0.7", optional = true } +ledger-transport = { version = "0.11", optional = true } +ledger-zondax-generic = { version = "0.11", optional = true } +ledger-transport-hid = { version = "0.11", optional = true } + +# Manage HidApi instance. +bytemuck = { version = "1.20.0", optional = true } [dev-dependencies] portpicker = { workspace = true } diff --git a/zingolib/src/testutils/scenarios.rs b/zingolib/src/testutils/scenarios.rs index 16282bf52..272897979 100644 --- a/zingolib/src/testutils/scenarios.rs +++ b/zingolib/src/testutils/scenarios.rs @@ -208,6 +208,8 @@ pub mod setup { Some(conf_path), crate::config::ChainType::Regtest(regtest_network), true, + #[cfg(feature = "ledger-support")] + false, ) .unwrap() } diff --git a/zingolib/src/wallet/keys/capability.rs b/zingolib/src/wallet/keys/capability.rs index e7409a7ea..81fdac4bf 100644 --- a/zingolib/src/wallet/keys/capability.rs +++ b/zingolib/src/wallet/keys/capability.rs @@ -312,7 +312,7 @@ impl InternalCapability for InMemoryWallet { &self, capability: &WalletCapability, ) -> ReceiverSelection { - match capability.unified_key_store() { + match &capability.unified_key_store { UnifiedKeyStore::Spend(_) => ReceiverSelection { orchard: true, sapling: true, diff --git a/zingolib/src/wallet/keys/unified.rs b/zingolib/src/wallet/keys/unified.rs index 39368ac46..7fb3e5db3 100644 --- a/zingolib/src/wallet/keys/unified.rs +++ b/zingolib/src/wallet/keys/unified.rs @@ -41,7 +41,7 @@ pub(crate) const KEY_TYPE_VIEW: u8 = 1; pub(crate) const KEY_TYPE_SPEND: u8 = 2; /// In-memory store for wallet spending or viewing keys -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum UnifiedKeyStore { /// Wallet with spend capability Spend(Box), @@ -90,7 +90,7 @@ impl ReadableWriteable for UnifiedKeyStore { match self { UnifiedKeyStore::Spend(usk) => { writer.write_u8(KEY_TYPE_SPEND)?; - usk.write(&mut writer) + usk.write(&mut writer, ()) } UnifiedKeyStore::View(ufvk) => { writer.write_u8(KEY_TYPE_VIEW)?; @@ -221,7 +221,7 @@ pub struct WalletCapability { #[cfg(feature = "ledger-support")] pub(crate) ledger: Option, /// Unified key store - pub unified_key_store: UnifiedKeyStore, + pub (crate) unified_key_store: UnifiedKeyStore, /// Cache of transparent addresses that the user has created. /// Receipts to a single address are correlated on chain. /// TODO: Is there any reason to have this field, apart from the @@ -312,6 +312,10 @@ fn read_write_receiver_selections() { } impl WalletCapability { + /// returns reference of Unified Key Store + pub fn unified_key_store(&self) -> &UnifiedKeyStore { + &self.unified_key_store + } #[cfg(feature = "ledger-support")] /// checks whether this WalletCapability is a Ledger device or not pub fn is_ledger(&self) -> bool { @@ -464,7 +468,23 @@ impl WalletCapability { /// Returns a selection of pools where the wallet can view funds. pub fn can_view(&self) -> ReceiverSelection { - self.capability.can_view(&self) + match &self.unified_key_store { + UnifiedKeyStore::Spend(_) => ReceiverSelection { + orchard: true, + sapling: true, + transparent: true, + }, + UnifiedKeyStore::View(ufvk) => ReceiverSelection { + orchard: ufvk.orchard().is_some(), + sapling: ufvk.sapling().is_some(), + transparent: ufvk.transparent().is_some(), + }, + UnifiedKeyStore::Empty => ReceiverSelection { + orchard: false, + sapling: false, + transparent: false, + }, + } } }