Implement OVK selection for z_sendmany.
This commit is contained in:
parent
bdcb12e445
commit
3ddbe1fa06
|
@ -103,6 +103,22 @@ UnifiedFullViewingKeyPtr* unified_full_viewing_key_from_components(
|
|||
const unsigned char* t_key,
|
||||
const unsigned char* sapling_key);
|
||||
|
||||
/**
|
||||
* Derive the internal and external OVKs for the binary encoding
|
||||
* of a transparent FVK (the concatenated bytes of the serialized
|
||||
* `(ChainCode, CPubKey)` pair.)
|
||||
*
|
||||
* Returns `true` if `t_key` was successfully deserialized,
|
||||
* in which case `internal_ovk_ret` and `external_ovk_ret` (which
|
||||
* should both point to 32-byte arrays) will have been updated
|
||||
* with the appropriate key bytes; otherwise, this procedure
|
||||
* returns `false` and the return values are unmodified.
|
||||
*/
|
||||
bool transparent_key_ovks(
|
||||
const unsigned char* t_key,
|
||||
unsigned char* internal_ovk_ret,
|
||||
unsigned char* external_ovk_ret);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -261,8 +261,8 @@ uint256 AsyncRPCOperation_sendmany::main_impl() {
|
|||
LogPrint("zrpcunsafe", "%s: private output: %s\n", getId(), FormatMoney(txOutputAmounts_.z_outputs_total));
|
||||
LogPrint("zrpc", "%s: fee: %s\n", getId(), FormatMoney(fee_));
|
||||
|
||||
auto ovks = this->SelectOVKs();
|
||||
auto selectorAccountId = pwalletMain->FindAccountForSelector(ztxoSelector_);
|
||||
auto ovks = this->SelectOVKs(spendable, selectorAccountId);
|
||||
std::visit(match {
|
||||
[&](const CKeyID& keyId) {
|
||||
auto accountId = selectorAccountId.value_or(ZCASH_LEGACY_ACCOUNT);
|
||||
|
@ -415,10 +415,64 @@ uint256 AsyncRPCOperation_sendmany::main_impl() {
|
|||
return tx.GetHash();
|
||||
}
|
||||
|
||||
std::pair<uint256, uint256> AsyncRPCOperation_sendmany::SelectOVKs() const {
|
||||
//TODO
|
||||
std::pair<uint256, uint256> AsyncRPCOperation_sendmany::SelectOVKs(
|
||||
const SpendableInputs& spendable, std::optional<AccountId> accountId) const {
|
||||
uint256 internalOVK;
|
||||
uint256 externalOVK;
|
||||
if (!spendable.saplingNoteEntries.empty()) {
|
||||
std::visit(match {
|
||||
[&](const libzcash::SaplingPaymentAddress& addr) {
|
||||
libzcash::SaplingExtendedSpendingKey extsk;
|
||||
assert(pwalletMain->GetSaplingExtendedSpendingKey(addr, extsk));
|
||||
auto extfvk = extsk.ToXFVK();
|
||||
externalOVK = extfvk.fvk.ovk;
|
||||
internalOVK = extfvk.GetInternalDFVK().fvk.ovk;
|
||||
},
|
||||
[&](const AccountZTXOPattern& acct) {
|
||||
auto ufvk = pwalletMain->GetUnifiedFullViewingKeyByAccount(acct.GetAccountId()).value();
|
||||
auto dfvk = ufvk.GetSaplingKey().value();
|
||||
externalOVK = dfvk.fvk.ovk;
|
||||
internalOVK = dfvk.GetInternalDFVK().fvk.ovk;
|
||||
},
|
||||
[&](const auto& other) {
|
||||
throw std::runtime_error("unreachable");
|
||||
}
|
||||
}, this->ztxoSelector_.GetPattern());
|
||||
} else if (!spendable.utxos.empty()) {
|
||||
std::optional<transparent::AccountPubKey> tfvk;
|
||||
std::visit(match {
|
||||
[&](const CKeyID& keyId) {
|
||||
tfvk = pwalletMain->GetLegacyAccountKey().ToAccountPubKey();
|
||||
},
|
||||
[&](const CScriptID& keyId) {
|
||||
tfvk = pwalletMain->GetLegacyAccountKey().ToAccountPubKey();
|
||||
},
|
||||
[&](const AccountZTXOPattern& acct) {
|
||||
// by the time we're here, we know that the UFVK exists for this account
|
||||
auto ufvk = pwalletMain->GetUnifiedFullViewingKeyByAccount(acct.GetAccountId()).value();
|
||||
tfvk = ufvk.GetTransparentKey().value();
|
||||
},
|
||||
[&](const auto& other) {
|
||||
//unreachable
|
||||
}
|
||||
}, this->ztxoSelector_.GetPattern());
|
||||
assert(tfvk.has_value());
|
||||
|
||||
auto ovks = tfvk.value().GetOVKsForShielding();
|
||||
internalOVK = ovks.first;
|
||||
externalOVK = ovks.second;
|
||||
} else if (!spendable.sproutNoteEntries.empty()) {
|
||||
// use the legacy transparent account OVKs when sending from Sprout
|
||||
auto tfvk = pwalletMain->GetLegacyAccountKey().ToAccountPubKey();
|
||||
auto ovks = tfvk.GetOVKsForShielding();
|
||||
internalOVK = ovks.first;
|
||||
externalOVK = ovks.second;
|
||||
} else {
|
||||
// This should be unreachable; it is left in place as a guard to ensure
|
||||
// that when new input types are added to SpendableInputs in the future
|
||||
// that we do not accidentally return the all-zeros OVK.
|
||||
throw std::runtime_error("No spendable inputs.");
|
||||
}
|
||||
|
||||
return std::make_pair(internalOVK, externalOVK);
|
||||
}
|
||||
|
|
|
@ -83,10 +83,9 @@ private:
|
|||
|
||||
/**
|
||||
* Compute the internal and external OVKs to use in transaction construction, given
|
||||
* the payment source and the set of types that correspond to outputs selected for
|
||||
* being spent in the transaction.
|
||||
* the spendable inputs.
|
||||
*/
|
||||
std::pair<uint256, uint256> SelectOVKs() const;
|
||||
std::pair<uint256, uint256> SelectOVKs(const SpendableInputs& spendable, std::optional<AccountId> accountId) const;
|
||||
|
||||
static CAmount DefaultDustThreshold();
|
||||
|
||||
|
|
|
@ -260,27 +260,13 @@ CPubKey CWallet::GenerateNewKey()
|
|||
{
|
||||
AssertLockHeld(cs_wallet); // mapKeyMetadata
|
||||
|
||||
auto seedOpt = GetMnemonicSeed();
|
||||
if (!seedOpt.has_value()) {
|
||||
throw std::runtime_error(
|
||||
"CWallet::GenerateNewKey(): Wallet does not have a mnemonic seed.");
|
||||
}
|
||||
auto seed = seedOpt.value();
|
||||
|
||||
if (!mnemonicHDChain.has_value()) {
|
||||
throw std::runtime_error(
|
||||
"CWallet::GenerateNewKey(): Wallet is missing mnemonic seed metadata.");
|
||||
}
|
||||
CHDChain& hdChain = mnemonicHDChain.value();
|
||||
|
||||
// All mnemonic seeds are checked at construction to ensure that we can obtain
|
||||
// a valid spending key for the account ZCASH_LEGACY_ACCOUNT;
|
||||
// therefore, the `value()` call here is safe.
|
||||
transparent::AccountKey accountKey = transparent::AccountKey::ForAccount(
|
||||
seed,
|
||||
BIP44CoinType(),
|
||||
ZCASH_LEGACY_ACCOUNT).value();
|
||||
|
||||
transparent::AccountKey accountKey = this->GetLegacyAccountKey();
|
||||
std::optional<CPubKey> pubkey = std::nullopt;
|
||||
do {
|
||||
auto index = hdChain.GetLegacyTKeyCounter();
|
||||
|
@ -288,7 +274,10 @@ CPubKey CWallet::GenerateNewKey()
|
|||
hdChain.IncrementLegacyTKeyCounter();
|
||||
if (key.has_value()) {
|
||||
auto keyPath = transparent::AccountKey::KeyPath(BIP44CoinType(), ZCASH_LEGACY_ACCOUNT, true, index);
|
||||
pubkey = AddTransparentSecretKey(seed.Fingerprint(), std::make_pair(key.value(), keyPath));
|
||||
pubkey = AddTransparentSecretKey(
|
||||
hdChain.GetSeedFingerprint(),
|
||||
std::make_pair(key.value(), keyPath)
|
||||
);
|
||||
}
|
||||
// if we did not successfully generate a key, try again.
|
||||
} while (!pubkey.has_value());
|
||||
|
@ -423,6 +412,24 @@ bool CWallet::AddCryptedSaplingSpendingKey(const libzcash::SaplingExtendedFullVi
|
|||
return false;
|
||||
}
|
||||
|
||||
libzcash::transparent::AccountKey CWallet::GetLegacyAccountKey() const {
|
||||
auto seedOpt = GetMnemonicSeed();
|
||||
if (!seedOpt.has_value()) {
|
||||
throw std::runtime_error(
|
||||
"CWallet::GenerateNewKey(): Wallet does not have a mnemonic seed.");
|
||||
}
|
||||
auto seed = seedOpt.value();
|
||||
|
||||
// All mnemonic seeds are checked at construction to ensure that we can obtain
|
||||
// a valid spending key for the account ZCASH_LEGACY_ACCOUNT;
|
||||
// therefore, the `value()` call here is safe.
|
||||
return transparent::AccountKey::ForAccount(
|
||||
seed,
|
||||
BIP44CoinType(),
|
||||
ZCASH_LEGACY_ACCOUNT).value();
|
||||
}
|
||||
|
||||
|
||||
std::pair<ZcashdUnifiedSpendingKey, libzcash::AccountId> CWallet::GenerateNewUnifiedSpendingKey() {
|
||||
AssertLockHeld(cs_wallet);
|
||||
|
||||
|
@ -6142,81 +6149,6 @@ std::optional<libzcash::ViewingKey> GetViewingKeyForPaymentAddress::operator()(
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
// GetSproutKeyForPaymentAddress
|
||||
|
||||
std::optional<libzcash::SproutSpendingKey> GetSproutKeyForPaymentAddress::operator()(
|
||||
const CKeyID &zaddr) const
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
std::optional<libzcash::SproutSpendingKey> GetSproutKeyForPaymentAddress::operator()(
|
||||
const CScriptID &zaddr) const
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
std::optional<libzcash::SproutSpendingKey> GetSproutKeyForPaymentAddress::operator()(
|
||||
const libzcash::SproutPaymentAddress &zaddr) const
|
||||
{
|
||||
libzcash::SproutSpendingKey k;
|
||||
if (m_wallet->GetSproutSpendingKey(zaddr, k)) {
|
||||
return k;
|
||||
} else {
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
std::optional<libzcash::SproutSpendingKey> GetSproutKeyForPaymentAddress::operator()(
|
||||
const libzcash::SaplingPaymentAddress &zaddr) const
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
std::optional<libzcash::SproutSpendingKey> GetSproutKeyForPaymentAddress::operator()(
|
||||
const libzcash::UnifiedAddress &uaddr) const
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// GetSaplingKeyForPaymentAddress
|
||||
|
||||
std::optional<libzcash::SaplingExtendedSpendingKey> GetSaplingKeyForPaymentAddress::operator()(
|
||||
const CKeyID &zaddr) const
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
std::optional<libzcash::SaplingExtendedSpendingKey> GetSaplingKeyForPaymentAddress::operator()(
|
||||
const CScriptID &zaddr) const
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
std::optional<libzcash::SaplingExtendedSpendingKey> GetSaplingKeyForPaymentAddress::operator()(
|
||||
const libzcash::SproutPaymentAddress &zaddr) const
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
std::optional<libzcash::SaplingExtendedSpendingKey> GetSaplingKeyForPaymentAddress::operator()(
|
||||
const libzcash::SaplingPaymentAddress &zaddr) const
|
||||
{
|
||||
libzcash::SaplingExtendedSpendingKey extsk;
|
||||
if (m_wallet->GetSaplingExtendedSpendingKey(zaddr, extsk)) {
|
||||
return extsk;
|
||||
} else {
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
std::optional<libzcash::SaplingExtendedSpendingKey> GetSaplingKeyForPaymentAddress::operator()(
|
||||
const libzcash::UnifiedAddress &uaddr) const
|
||||
{
|
||||
for (const libzcash::Receiver& receiver: uaddr) {
|
||||
auto saplingAddr = std::get_if<SaplingPaymentAddress>(&receiver);
|
||||
if (saplingAddr != nullptr) {
|
||||
libzcash::SaplingExtendedSpendingKey extsk;
|
||||
if (m_wallet->GetSaplingExtendedSpendingKey(*saplingAddr, extsk)) {
|
||||
return extsk;
|
||||
}
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// AddViewingKeyToWallet
|
||||
|
||||
KeyAddResult AddViewingKeyToWallet::operator()(const libzcash::SproutViewingKey &vkey) const {
|
||||
|
|
|
@ -1399,9 +1399,13 @@ public:
|
|||
const std::vector<unsigned char> &vchCryptedSecret);
|
||||
|
||||
//
|
||||
// Unified keys & addresses
|
||||
// Unified keys, addresses, and accounts
|
||||
//
|
||||
|
||||
//! Obtain the account key for the legacy account by deriving it from
|
||||
//! the wallet's mnemonic seed.
|
||||
libzcash::transparent::AccountKey GetLegacyAccountKey() const;
|
||||
|
||||
//! Generate the unified spending key from the wallet's mnemonic seed
|
||||
//! for the next unused account identifier.
|
||||
std::pair<libzcash::ZcashdUnifiedSpendingKey, libzcash::AccountId>
|
||||
|
@ -1766,34 +1770,6 @@ public:
|
|||
std::optional<libzcash::ViewingKey> operator()(const libzcash::UnifiedAddress &uaddr) const;
|
||||
};
|
||||
|
||||
class GetSproutKeyForPaymentAddress
|
||||
{
|
||||
private:
|
||||
CWallet *m_wallet;
|
||||
public:
|
||||
GetSproutKeyForPaymentAddress(CWallet *wallet) : m_wallet(wallet) {}
|
||||
|
||||
std::optional<libzcash::SproutSpendingKey> operator()(const CKeyID &zaddr) const;
|
||||
std::optional<libzcash::SproutSpendingKey> operator()(const CScriptID &zaddr) const;
|
||||
std::optional<libzcash::SproutSpendingKey> operator()(const libzcash::SproutPaymentAddress &zaddr) const;
|
||||
std::optional<libzcash::SproutSpendingKey> operator()(const libzcash::SaplingPaymentAddress &zaddr) const;
|
||||
std::optional<libzcash::SproutSpendingKey> operator()(const libzcash::UnifiedAddress &uaddr) const;
|
||||
};
|
||||
|
||||
class GetSaplingKeyForPaymentAddress
|
||||
{
|
||||
private:
|
||||
CWallet *m_wallet;
|
||||
public:
|
||||
GetSaplingKeyForPaymentAddress(CWallet *wallet) : m_wallet(wallet) {}
|
||||
|
||||
std::optional<libzcash::SaplingExtendedSpendingKey> operator()(const CKeyID &zaddr) const;
|
||||
std::optional<libzcash::SaplingExtendedSpendingKey> operator()(const CScriptID &zaddr) const;
|
||||
std::optional<libzcash::SaplingExtendedSpendingKey> operator()(const libzcash::SproutPaymentAddress &zaddr) const;
|
||||
std::optional<libzcash::SaplingExtendedSpendingKey> operator()(const libzcash::SaplingPaymentAddress &zaddr) const;
|
||||
std::optional<libzcash::SaplingExtendedSpendingKey> operator()(const libzcash::UnifiedAddress &uaddr) const;
|
||||
};
|
||||
|
||||
enum PaymentAddressSource {
|
||||
Random,
|
||||
LegacyHDSeed,
|
||||
|
|
|
@ -2,6 +2,9 @@
|
|||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or https://www.opensource.org/licenses/mit-license.php .
|
||||
|
||||
#include <rust/unified_keys.h>
|
||||
|
||||
#include "streams.h"
|
||||
#include "transparent.h"
|
||||
|
||||
namespace libzcash {
|
||||
|
@ -33,6 +36,23 @@ std::optional<CKeyID> AccountPubKey::GetChangeAddress(const diversifier_index_t&
|
|||
return changeKey.value().GetID();
|
||||
}
|
||||
|
||||
std::pair<uint256, uint256> AccountPubKey::GetOVKsForShielding() const {
|
||||
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss << pubkey;
|
||||
assert(ss.size() == 65);
|
||||
CSerializeData ss_bytes(ss.begin(), ss.end());
|
||||
|
||||
uint256 internalOVK;
|
||||
uint256 externalOVK;
|
||||
|
||||
assert(transparent_key_ovks(
|
||||
reinterpret_cast<unsigned char*>(ss_bytes.data()),
|
||||
internalOVK.begin(),
|
||||
externalOVK.begin()));
|
||||
|
||||
return std::make_pair(internalOVK, externalOVK);
|
||||
}
|
||||
|
||||
std::optional<std::pair<CKeyID, diversifier_index_t>> AccountPubKey::FindChangeAddress(diversifier_index_t j) const {
|
||||
while (true) {
|
||||
auto childIndex = j.ToTransparentChildIndex();
|
||||
|
|
|
@ -41,6 +41,12 @@ public:
|
|||
*/
|
||||
std::optional<std::pair<CKeyID, diversifier_index_t>> FindChangeAddress(diversifier_index_t j) const;
|
||||
|
||||
/**
|
||||
* Return the internal and external OVKs for shielding from transparent
|
||||
* addresses derived from this key.
|
||||
*/
|
||||
std::pair<uint256, uint256> GetOVKsForShielding() const;
|
||||
|
||||
friend bool operator==(const AccountPubKey& a, const AccountPubKey& b)
|
||||
{
|
||||
return a.pubkey == b.pubkey;
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
#include "zcash/Address.hpp"
|
||||
#include "unified.h"
|
||||
|
||||
#include <rust/unified_keys.h>
|
||||
|
||||
using namespace libzcash;
|
||||
|
||||
//
|
||||
|
@ -126,9 +128,11 @@ std::optional<RecipientAddress> ZcashdUnifiedFullViewingKey::GetChangeAddress(co
|
|||
std::optional<RecipientAddress> addr;
|
||||
std::visit(match {
|
||||
[&](const TransparentChangeRequest& req) {
|
||||
auto changeKey = this->GetTransparentChangeAddress(req.GetIndex());
|
||||
if (changeKey.has_value()) {
|
||||
addr = changeKey.value();
|
||||
if (transparentKey.has_value()) {
|
||||
auto changeAddr = transparentKey.value().GetChangeAddress(req.GetIndex());
|
||||
if (changeAddr.has_value()) {
|
||||
addr = changeAddr.value();
|
||||
}
|
||||
}
|
||||
},
|
||||
[&](const SaplingChangeRequest& req) {
|
||||
|
@ -141,38 +145,3 @@ std::optional<RecipientAddress> ZcashdUnifiedFullViewingKey::GetChangeAddress(co
|
|||
}, req);
|
||||
return addr;
|
||||
}
|
||||
|
||||
std::optional<CKeyID> ZcashdUnifiedFullViewingKey::GetTransparentChangeAddress(const diversifier_index_t& j) const {
|
||||
if (transparentKey.has_value()) {
|
||||
auto childIndex = j.ToTransparentChildIndex();
|
||||
if (!childIndex.has_value()) return std::nullopt;
|
||||
|
||||
auto changeKey = transparentKey.value().DeriveInternal(childIndex.value());
|
||||
if (!changeKey.has_value()) return std::nullopt;
|
||||
|
||||
return changeKey.value().GetID();
|
||||
} else {
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
//std::optional<std::pair<uint256, uint256>> ZcashdUnifiedFullViewingKey::GetTransparentOVKsForShielding() const {
|
||||
// if (transparentKey.has_value()) {
|
||||
// CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
||||
// ss << transparentKey.value().GetPubKey();
|
||||
// assert(ss.size() == 65);
|
||||
// CSerializeData ss_bytes(ss.begin(), ss.end());
|
||||
//
|
||||
// uint256 internalOVK;
|
||||
// uint256 externalOVK;
|
||||
//
|
||||
// assert(transparent_key_ovks(
|
||||
// reinterpret_cast<unsigned char*>(ss_bytes.data()),
|
||||
// internalOVK.begin(),
|
||||
// externalOVK.begin()));
|
||||
//
|
||||
// return std::make_pair(internalOVK, externalOVK);
|
||||
// } else {
|
||||
// return std::nullopt;
|
||||
// }
|
||||
//}
|
||||
|
|
|
@ -195,13 +195,6 @@ public:
|
|||
*/
|
||||
std::optional<RecipientAddress> GetChangeAddress(const ChangeRequest& req) const;
|
||||
|
||||
/**
|
||||
* Return the transparent change address for this UFVK a the given diversifier
|
||||
* index, if the UFVK has a transparent component and it is possible to derive
|
||||
* an address at this index.
|
||||
*/
|
||||
std::optional<CKeyID> GetTransparentChangeAddress(const diversifier_index_t& j) const;
|
||||
|
||||
friend bool operator==(const ZcashdUnifiedFullViewingKey& a, const ZcashdUnifiedFullViewingKey& b)
|
||||
{
|
||||
return a.transparentKey == b.transparentKey && a.saplingKey == b.saplingKey;
|
||||
|
|
|
@ -126,7 +126,7 @@ libzcash::SaplingPaymentAddress SaplingDiversifiableFullViewingKey::DefaultAddre
|
|||
}
|
||||
}
|
||||
|
||||
libzcash::SaplingPaymentAddress SaplingDiversifiableFullViewingKey::GetChangeAddress() const {
|
||||
libzcash::SaplingDiversifiableFullViewingKey SaplingDiversifiableFullViewingKey::GetInternalDFVK() const {
|
||||
CDataStream ss_fvk(SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss_fvk << fvk;
|
||||
CSerializeData fvk_bytes(ss_fvk.begin(), ss_fvk.end());
|
||||
|
@ -141,7 +141,11 @@ libzcash::SaplingPaymentAddress SaplingDiversifiableFullViewingKey::GetChangeAdd
|
|||
|
||||
CDataStream ss_fvk_ret(fvk_bytes_ret, SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss_fvk_ret >> internalDFVK.fvk;
|
||||
return internalDFVK;
|
||||
}
|
||||
|
||||
libzcash::SaplingPaymentAddress SaplingDiversifiableFullViewingKey::GetChangeAddress() const {
|
||||
auto internalDFVK = this->GetInternalDFVK();
|
||||
return internalDFVK.DefaultAddress();
|
||||
}
|
||||
|
||||
|
|
|
@ -153,6 +153,8 @@ public:
|
|||
return std::make_pair(addr.value(), j);
|
||||
}
|
||||
|
||||
SaplingDiversifiableFullViewingKey GetInternalDFVK() const;
|
||||
|
||||
libzcash::SaplingPaymentAddress DefaultAddress() const;
|
||||
|
||||
libzcash::SaplingPaymentAddress GetChangeAddress() const;
|
||||
|
|
Loading…
Reference in New Issue