From f320a6cc24632df377308c0ce572368844a68680 Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Wed, 9 Feb 2022 18:59:13 -0700 Subject: [PATCH] Add unified address support to GetSourceForPaymentAddress --- src/wallet/rpcwallet.cpp | 12 ++-- src/wallet/wallet.cpp | 116 ++++++++++++++++++++++++++++++--------- src/wallet/wallet.h | 4 +- 3 files changed, 100 insertions(+), 32 deletions(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index b9dcf38d2..5ef5f4c6a 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -500,7 +500,7 @@ UniValue listaddresses(const UniValue& params, bool fHelp) UniValue sapling_obj(UniValue::VOBJ); - if (source == LegacyHDSeed || source == MnemonicHDSeed) { + if (source == PaymentAddressSource::LegacyHDSeed || source == PaymentAddressSource::MnemonicHDSeed) { std::string hdKeyPath = pwalletMain->mapSaplingZKeyMetadata[ivk].hdKeypath; if (hdKeyPath != "") { sapling_obj.pushKV("zip32KeyPath", hdKeyPath); @@ -531,7 +531,7 @@ UniValue listaddresses(const UniValue& params, bool fHelp) { UniValue imported_sprout_addrs(UniValue::VARR); for (const SproutPaymentAddress& addr : sproutAddresses) { - if (GetSourceForPaymentAddress(pwalletMain)(addr) == Imported) { + if (GetSourceForPaymentAddress(pwalletMain)(addr) == PaymentAddressSource::Imported) { imported_sprout_addrs.push_back(keyIO.EncodePaymentAddress(addr)); } } @@ -544,7 +544,7 @@ UniValue listaddresses(const UniValue& params, bool fHelp) } } - hasData |= add_sapling(saplingAddresses, Imported, entry); + hasData |= add_sapling(saplingAddresses, PaymentAddressSource::Imported, entry); if (hasData) { ret.push_back(entry); @@ -573,7 +573,7 @@ UniValue listaddresses(const UniValue& params, bool fHelp) { UniValue watchonly_sprout_addrs(UniValue::VARR); for (const SproutPaymentAddress& addr : sproutAddresses) { - if (GetSourceForPaymentAddress(pwalletMain)(addr) == ImportedWatchOnly) { + if (GetSourceForPaymentAddress(pwalletMain)(addr) == PaymentAddressSource::ImportedWatchOnly) { watchonly_sprout_addrs.push_back(keyIO.EncodePaymentAddress(addr)); } } @@ -586,7 +586,7 @@ UniValue listaddresses(const UniValue& params, bool fHelp) } } - hasData |= add_sapling(saplingAddresses, ImportedWatchOnly, entry); + hasData |= add_sapling(saplingAddresses, PaymentAddressSource::ImportedWatchOnly, entry); if (hasData) { ret.push_back(entry); @@ -598,7 +598,7 @@ UniValue listaddresses(const UniValue& params, bool fHelp) UniValue entry(UniValue::VOBJ); entry.pushKV("source", "legacy_hdseed"); - bool hasData = add_sapling(saplingAddresses, LegacyHDSeed, entry); + bool hasData = add_sapling(saplingAddresses, PaymentAddressSource::LegacyHDSeed, entry); if (hasData) { ret.push_back(entry); diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index dd5105f45..a64790a28 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -6146,48 +6146,114 @@ bool PaymentAddressBelongsToWallet::operator()(const libzcash::UnifiedAddress &u // GetSourceForPaymentAddress -PaymentAddressSource GetSourceForPaymentAddress::operator()(const CKeyID &zaddr) const +PaymentAddressSource GetSourceForPaymentAddress::GetUnifiedSource(const libzcash::Receiver& receiver) const { - // TODO - return AddressNotFound; + auto hdChain = m_wallet->GetMnemonicHDChain(); + assert(hdChain.has_value()); + + auto ufvkMeta = m_wallet->GetUFVKMetadataForReceiver(receiver); + if (ufvkMeta.has_value()) { + auto ufvkid = ufvkMeta.value().first; + // Look through the UFVKs that we have generated, and confirm that the + // seed fingerprint for the key we find for the ufvkid corresponds to + // the wallet's mnemonic seed. + for (const auto& [k, v] : m_wallet->mapUnifiedAccountKeys) { + if (v == ufvkid && k.first == hdChain.value().GetSeedFingerprint()) { + return PaymentAddressSource::MnemonicHDSeed; + } + } + return PaymentAddressSource::ImportedWatchOnly; + } else { + return PaymentAddressSource::AddressNotFound; + } } -PaymentAddressSource GetSourceForPaymentAddress::operator()(const CScriptID &zaddr) const + +PaymentAddressSource GetSourceForPaymentAddress::operator()(const CKeyID &addr) const { - // TODO - return AddressNotFound; + auto ufvkSource = this->GetUnifiedSource(addr); + if (ufvkSource == PaymentAddressSource::AddressNotFound) { + if (m_wallet->HaveKey(addr)) { + return PaymentAddressSource::Random; + } else { + if (m_wallet->HaveWatchOnly(GetScriptForDestination(addr))) { + return PaymentAddressSource::ImportedWatchOnly; + } + } + } + + return ufvkSource; +} +PaymentAddressSource GetSourceForPaymentAddress::operator()(const CScriptID &addr) const +{ + auto ufvkSource = this->GetUnifiedSource(addr); + if (ufvkSource == PaymentAddressSource::AddressNotFound) { + if (m_wallet->HaveCScript(addr)) { + return PaymentAddressSource::Imported; + } else { + if (m_wallet->HaveWatchOnly(GetScriptForDestination(addr))) { + return PaymentAddressSource::ImportedWatchOnly; + } + } + } + + return ufvkSource; } PaymentAddressSource GetSourceForPaymentAddress::operator()(const libzcash::SproutPaymentAddress &zaddr) const { - return Random; + if (m_wallet->HaveSproutSpendingKey(zaddr)) { + return PaymentAddressSource::Random; + } else if (m_wallet->HaveSproutViewingKey(zaddr)) { + return PaymentAddressSource::ImportedWatchOnly; + } else { + return PaymentAddressSource::AddressNotFound; + } } PaymentAddressSource GetSourceForPaymentAddress::operator()(const libzcash::SaplingPaymentAddress &zaddr) const { - libzcash::SaplingIncomingViewingKey ivk; + auto ufvkSource = this->GetUnifiedSource(zaddr); + if (ufvkSource == PaymentAddressSource::AddressNotFound) { + libzcash::SaplingIncomingViewingKey ivk; - // If we have a SaplingExtendedSpendingKey in the wallet, then we will - // also have the corresponding SaplingExtendedFullViewingKey. - if (m_wallet->GetSaplingIncomingViewingKey(zaddr, ivk)) { - if (m_wallet->HaveSaplingFullViewingKey(ivk)) { - // If we have the HD keypath, it's related to the legacy seed - if (m_wallet->mapSaplingZKeyMetadata.count(ivk) > 0 && - m_wallet->mapSaplingZKeyMetadata[ivk].hdKeypath != "") { - return LegacyHDSeed; - } else if (m_wallet->HaveSaplingSpendingKeyForAddress(zaddr)) { - return Imported; + // If we have a SaplingExtendedSpendingKey in the wallet, then we will + // also have the corresponding SaplingExtendedFullViewingKey. + if (m_wallet->GetSaplingIncomingViewingKey(zaddr, ivk)) { + if (m_wallet->HaveSaplingFullViewingKey(ivk)) { + // If we have the HD keypath, it's related to the legacy seed + if (m_wallet->mapSaplingZKeyMetadata.count(ivk) > 0 && + m_wallet->mapSaplingZKeyMetadata[ivk].hdKeypath != "") { + return PaymentAddressSource::LegacyHDSeed; + } else if (m_wallet->HaveSaplingSpendingKeyForAddress(zaddr)) { + return PaymentAddressSource::Imported; + } else { + return PaymentAddressSource::ImportedWatchOnly; + } } else { - return ImportedWatchOnly; + return PaymentAddressSource::ImportedWatchOnly; } - } else { - return ImportedWatchOnly; } - } else { - return AddressNotFound; } + + return ufvkSource; } PaymentAddressSource GetSourceForPaymentAddress::operator()(const libzcash::UnifiedAddress &uaddr) const { - // TODO - return AddressNotFound; + auto hdChain = m_wallet->GetMnemonicHDChain(); + assert(hdChain.has_value()); + + auto ufvkid = m_wallet->FindUnifiedFullViewingKey(uaddr); + if (ufvkid.has_value()) { + // Look through the UFVKs that we have generated, and confirm that the + // seed fingerprint for the key we find for the ufvkid corresponds to + // the wallet's mnemonic seed. + for (const auto& [k, v] : m_wallet->mapUnifiedAccountKeys) { + if (v == ufvkid.value() && k.first == hdChain.value().GetSeedFingerprint()) { + return PaymentAddressSource::MnemonicHDSeed; + } + } + return PaymentAddressSource::ImportedWatchOnly; + } else { + return PaymentAddressSource::AddressNotFound; + } } // GetViewingKeyForPaymentAddress diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 50377c331..1589a7560 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -1781,7 +1781,7 @@ public: std::optional operator()(const libzcash::UnifiedAddress &uaddr) const; }; -enum PaymentAddressSource { +enum class PaymentAddressSource { Random, LegacyHDSeed, MnemonicHDSeed, @@ -1797,6 +1797,8 @@ private: public: GetSourceForPaymentAddress(CWallet *wallet) : m_wallet(wallet) {} + PaymentAddressSource GetUnifiedSource(const libzcash::Receiver& receiver) const; + PaymentAddressSource operator()(const CKeyID &zaddr) const; PaymentAddressSource operator()(const CScriptID &zaddr) const; PaymentAddressSource operator()(const libzcash::SproutPaymentAddress &zaddr) const;