Merge pull request #5522 from nuttycom/feature/wallet_unified_addresses-balance_for_vk
Replace z_getbalanceforaddress with z_getbalanceforviewingkey
This commit is contained in:
commit
09593559f8
|
@ -47,6 +47,11 @@ New RPC Methods
|
||||||
being confirmed might be leaked via the user's shell history or the system
|
being confirmed might be leaked via the user's shell history or the system
|
||||||
process table; `zcashd-wallet-tool` is specifically provided to avoid this
|
process table; `zcashd-wallet-tool` is specifically provided to avoid this
|
||||||
problem.
|
problem.
|
||||||
|
- 'z_getbalanceforviewingkey' This newly created API allows a user to obtain
|
||||||
|
balance information for funds visible to a Sapling or Unified full
|
||||||
|
viewing key; if a Sprout viewing key is provided, this method allows
|
||||||
|
retrieval of the balance only in the case that the wallet controls the
|
||||||
|
corresponding spending key.
|
||||||
|
|
||||||
RPC Changes
|
RPC Changes
|
||||||
-----------
|
-----------
|
||||||
|
|
|
@ -43,10 +43,11 @@ class WalletAccountsTest(BitcoinTestFramework):
|
||||||
# Check we only have balances in the expected pools.
|
# Check we only have balances in the expected pools.
|
||||||
# Remember that empty pools are omitted from the output.
|
# Remember that empty pools are omitted from the output.
|
||||||
def check_address_balance(self, address, expected, minconf=None):
|
def check_address_balance(self, address, expected, minconf=None):
|
||||||
|
fvk = self.nodes[0].z_exportviewingkey(address)
|
||||||
if minconf is None:
|
if minconf is None:
|
||||||
actual = self.nodes[0].z_getbalanceforaddress(address)
|
actual = self.nodes[0].z_getbalanceforviewingkey(fvk)
|
||||||
else:
|
else:
|
||||||
actual = self.nodes[0].z_getbalanceforaddress(address, minconf)
|
actual = self.nodes[0].z_getbalanceforviewingkey(fvk, minconf)
|
||||||
assert_equal(set(expected), set(actual['pools']))
|
assert_equal(set(expected), set(actual['pools']))
|
||||||
for pool in expected:
|
for pool in expected:
|
||||||
assert_equal(expected[pool] * COIN, actual['pools'][pool]['valueZat'])
|
assert_equal(expected[pool] * COIN, actual['pools'][pool]['valueZat'])
|
||||||
|
|
|
@ -35,7 +35,8 @@ class WalletZSendmanyTest(BitcoinTestFramework):
|
||||||
|
|
||||||
def check_balance(self, node, account, address, expected, minconf=None):
|
def check_balance(self, node, account, address, expected, minconf=None):
|
||||||
self._check_balance_for_rpc('z_getbalanceforaccount', node, account, expected, minconf)
|
self._check_balance_for_rpc('z_getbalanceforaccount', node, account, expected, minconf)
|
||||||
self._check_balance_for_rpc('z_getbalanceforaddress', node, address, expected, minconf)
|
fvk = self.nodes[node].z_exportviewingkey(address)
|
||||||
|
self._check_balance_for_rpc('z_getbalanceforviewingkey', node, fvk, expected, minconf)
|
||||||
|
|
||||||
def run_test(self):
|
def run_test(self):
|
||||||
# z_sendmany is expected to fail if tx size breaks limit
|
# z_sendmany is expected to fail if tx size breaks limit
|
||||||
|
|
|
@ -1683,7 +1683,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||||
if (!zaddr.has_value()) {
|
if (!zaddr.has_value()) {
|
||||||
return InitError(_("-mineraddress is not a valid " PACKAGE_NAME " address."));
|
return InitError(_("-mineraddress is not a valid " PACKAGE_NAME " address."));
|
||||||
}
|
}
|
||||||
auto ztxoSelector = pwalletMain->ToZTXOSelector(zaddr.value(), true);
|
auto ztxoSelector = pwalletMain->ZTXOSelectorForAddress(zaddr.value(), true);
|
||||||
minerAddressInLocalWallet = ztxoSelector.has_value();
|
minerAddressInLocalWallet = ztxoSelector.has_value();
|
||||||
}
|
}
|
||||||
if (GetBoolArg("-minetolocalwallet", true) && !minerAddressInLocalWallet) {
|
if (GetBoolArg("-minetolocalwallet", true) && !minerAddressInLocalWallet) {
|
||||||
|
|
|
@ -373,6 +373,32 @@ CBasicKeyStore::GetUFVKMetadataForReceiver(const libzcash::Receiver& receiver) c
|
||||||
return std::visit(FindUFVKId(*this), receiver);
|
return std::visit(FindUFVKId(*this), receiver);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<libzcash::UFVKId> CBasicKeyStore::GetUFVKIdForViewingKey(const libzcash::ViewingKey& vk) const
|
||||||
|
{
|
||||||
|
std::optional<libzcash::UFVKId> result;
|
||||||
|
std::visit(match {
|
||||||
|
[&](const libzcash::SproutViewingKey& vk) {},
|
||||||
|
[&](const libzcash::SaplingExtendedFullViewingKey& extfvk) {
|
||||||
|
const auto saplingIvk = extfvk.ToIncomingViewingKey();
|
||||||
|
const auto ufvkId = mapSaplingKeyUnified.find(saplingIvk);
|
||||||
|
if (ufvkId != mapSaplingKeyUnified.end()) {
|
||||||
|
result = ufvkId->second;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[&](const libzcash::UnifiedFullViewingKey& ufvk) {
|
||||||
|
const auto saplingDfvk = ufvk.GetSaplingKey();
|
||||||
|
if (saplingDfvk.has_value()) {
|
||||||
|
const auto saplingIvk = saplingDfvk.value().ToIncomingViewingKey();
|
||||||
|
const auto ufvkId = mapSaplingKeyUnified.find(saplingIvk);
|
||||||
|
if (ufvkId != mapSaplingKeyUnified.end()) {
|
||||||
|
result = ufvkId->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, vk);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
std::optional<std::pair<libzcash::UFVKId, std::optional<libzcash::diversifier_index_t>>>
|
std::optional<std::pair<libzcash::UFVKId, std::optional<libzcash::diversifier_index_t>>>
|
||||||
FindUFVKId::operator()(const libzcash::SaplingPaymentAddress& saplingAddr) const {
|
FindUFVKId::operator()(const libzcash::SaplingPaymentAddress& saplingAddr) const {
|
||||||
const auto saplingIvk = keystore.mapSaplingIncomingViewingKeys.find(saplingAddr);
|
const auto saplingIvk = keystore.mapSaplingIncomingViewingKeys.find(saplingAddr);
|
||||||
|
|
|
@ -132,6 +132,11 @@ public:
|
||||||
GetUFVKMetadataForReceiver(
|
GetUFVKMetadataForReceiver(
|
||||||
const libzcash::Receiver& receiver
|
const libzcash::Receiver& receiver
|
||||||
) const = 0;
|
) const = 0;
|
||||||
|
|
||||||
|
virtual std::optional<libzcash::UFVKId>
|
||||||
|
GetUFVKIdForViewingKey(
|
||||||
|
const libzcash::ViewingKey& vk
|
||||||
|
) const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::map<CKeyID, CKey> KeyMap;
|
typedef std::map<CKeyID, CKey> KeyMap;
|
||||||
|
@ -372,6 +377,11 @@ public:
|
||||||
GetUFVKMetadataForReceiver(
|
GetUFVKMetadataForReceiver(
|
||||||
const libzcash::Receiver& receiver
|
const libzcash::Receiver& receiver
|
||||||
) const;
|
) const;
|
||||||
|
|
||||||
|
virtual std::optional<libzcash::UFVKId>
|
||||||
|
GetUFVKIdForViewingKey(
|
||||||
|
const libzcash::ViewingKey& vk
|
||||||
|
) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::vector<unsigned char, secure_allocator<unsigned char> > CKeyingMaterial;
|
typedef std::vector<unsigned char, secure_allocator<unsigned char> > CKeyingMaterial;
|
||||||
|
|
|
@ -290,6 +290,10 @@ uint256 AsyncRPCOperation_sendmany::main_impl() {
|
||||||
// for Sprout, we return change to the originating address.
|
// for Sprout, we return change to the originating address.
|
||||||
builder_.SendChangeToSprout(addr);
|
builder_.SendChangeToSprout(addr);
|
||||||
},
|
},
|
||||||
|
[&](const libzcash::SproutViewingKey& vk) {
|
||||||
|
// for Sprout, we return change to the originating address.
|
||||||
|
builder_.SendChangeToSprout(vk.address());
|
||||||
|
},
|
||||||
[&](const libzcash::SaplingPaymentAddress& addr) {
|
[&](const libzcash::SaplingPaymentAddress& addr) {
|
||||||
// for Sapling, if using a legacy address, return change to the
|
// for Sapling, if using a legacy address, return change to the
|
||||||
// originating address; otherwise return it to the Sapling internal
|
// originating address; otherwise return it to the Sapling internal
|
||||||
|
@ -303,6 +307,29 @@ uint256 AsyncRPCOperation_sendmany::main_impl() {
|
||||||
builder_.SendChangeTo(changeAddr.value(), ovks.first);
|
builder_.SendChangeTo(changeAddr.value(), ovks.first);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
[&](const libzcash::SaplingExtendedFullViewingKey& fvk) {
|
||||||
|
// for Sapling, if using a legacy address, return change to the
|
||||||
|
// originating address; otherwise return it to the Sapling internal
|
||||||
|
// address corresponding to the UFVK.
|
||||||
|
if (sendFromAccount_ == ZCASH_LEGACY_ACCOUNT) {
|
||||||
|
builder_.SendChangeTo(fvk.DefaultAddress(), ovks.first);
|
||||||
|
} else {
|
||||||
|
auto changeAddr = pwalletMain->GenerateChangeAddressForAccount(
|
||||||
|
sendFromAccount_, allowedChangeTypes_);
|
||||||
|
assert(changeAddr.has_value());
|
||||||
|
builder_.SendChangeTo(changeAddr.value(), ovks.first);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[&](const libzcash::UnifiedFullViewingKey& fvk) {
|
||||||
|
auto zufvk = ZcashdUnifiedFullViewingKey::FromUnifiedFullViewingKey(Params(), fvk);
|
||||||
|
auto changeAddr = zufvk.GetChangeAddress();
|
||||||
|
if (!changeAddr.has_value()) {
|
||||||
|
throw JSONRPCError(
|
||||||
|
RPC_WALLET_ERROR,
|
||||||
|
"Could not generate a change address from the specified full viewing key ");
|
||||||
|
}
|
||||||
|
builder_.SendChangeTo(changeAddr.value(), ovks.first);
|
||||||
|
},
|
||||||
[&](const AccountZTXOPattern& acct) {
|
[&](const AccountZTXOPattern& acct) {
|
||||||
for (ReceiverType rtype : acct.GetReceiverTypes()) {
|
for (ReceiverType rtype : acct.GetReceiverTypes()) {
|
||||||
switch (rtype) {
|
switch (rtype) {
|
||||||
|
|
|
@ -3551,7 +3551,7 @@ UniValue z_getbalance(const UniValue& params, bool fHelp)
|
||||||
"\nReturns the balance of a taddr or zaddr belonging to the node's wallet.\n"
|
"\nReturns the balance of a taddr or zaddr belonging to the node's wallet.\n"
|
||||||
"\nCAUTION: If the wallet has only an incoming viewing key for this address, then spends cannot be"
|
"\nCAUTION: If the wallet has only an incoming viewing key for this address, then spends cannot be"
|
||||||
"\ndetected, and so the returned balance may be larger than the actual balance."
|
"\ndetected, and so the returned balance may be larger than the actual balance."
|
||||||
"\nThe argument address may not be a Unified Address; please use z_getbalanceforaddress instead.\n"
|
"\nThe argument address may not be a Unified Address; please use z_getbalanceforviewingkey instead.\n"
|
||||||
"\nArguments:\n"
|
"\nArguments:\n"
|
||||||
"1. \"address\" (string) The selected address. It may be a transparent or shielded address.\n"
|
"1. \"address\" (string) The selected address. It may be a transparent or shielded address.\n"
|
||||||
"2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
|
"2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
|
||||||
|
@ -3618,32 +3618,33 @@ UniValue z_getbalance(const UniValue& params, bool fHelp)
|
||||||
return ValueFromAmount(nBalance);
|
return ValueFromAmount(nBalance);
|
||||||
}
|
}
|
||||||
|
|
||||||
UniValue z_getbalanceforaddress(const UniValue& params, bool fHelp)
|
UniValue z_getbalanceforviewingkey(const UniValue& params, bool fHelp)
|
||||||
{
|
{
|
||||||
if (!EnsureWalletIsAvailable(fHelp))
|
if (!EnsureWalletIsAvailable(fHelp))
|
||||||
return NullUniValue;
|
return NullUniValue;
|
||||||
|
|
||||||
if (fHelp || params.size() < 1 || params.size() > 2)
|
if (fHelp || params.size() < 1 || params.size() > 2)
|
||||||
throw runtime_error(
|
throw runtime_error(
|
||||||
"z_getbalanceforaddress \"address\" ( minconf )\n"
|
"z_getbalanceforviewingkey \"fvk\" ( minconf )\n"
|
||||||
"\nReturns the per-pool balances of a Unified Address belonging to the node's wallet."
|
"\nReturns the per-pool balances viewable by a full viewing key known to the node's wallet."
|
||||||
|
"\nSprout viewing keys may be used only if the wallet controls the corresponding spending key."
|
||||||
"\nArguments:\n"
|
"\nArguments:\n"
|
||||||
"1. \"address\" (string) The selected address. It may be a transparent or shielded address.\n"
|
"1. \"fvk\" (string) The selected full viewing key.\n"
|
||||||
"2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
|
"2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
|
||||||
"\nResult:\n"
|
"\nResult:\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" \"pools\": {\n"
|
" \"pools\": {\n"
|
||||||
" \"transparent\": {\n"
|
" \"transparent\": {\n"
|
||||||
" \"valueZat\": amount (numeric) The amount held in the transparent pool by this account\n"
|
" \"valueZat\": amount (numeric) The amount held in the transparent pool viewable by this fvk\n"
|
||||||
" \"},\n"
|
" \"},\n"
|
||||||
" \"sprout\": {\n"
|
" \"sprout\": {\n"
|
||||||
" \"valueZat\": amount (numeric) The amount held in the sprout pool by this account\n"
|
" \"valueZat\": amount (numeric) The amount held in the sprout pool viewable by this fvk\n"
|
||||||
" \"},\n"
|
" \"},\n"
|
||||||
" \"sapling\": {\n"
|
" \"sapling\": {\n"
|
||||||
" \"valueZat\": amount (numeric) The amount held in the sapling pool by this account\n"
|
" \"valueZat\": amount (numeric) The amount held in the sapling pool viewable by this fvk\n"
|
||||||
" \"},\n"
|
" \"},\n"
|
||||||
" \"orchard\": {\n"
|
" \"orchard\": {\n"
|
||||||
" \"valueZat\": amount (numeric) The amount held in the orchard pool by this account\n"
|
" \"valueZat\": amount (numeric) The amount held in the orchard pool viewable by this fvk\n"
|
||||||
" \"}\n"
|
" \"}\n"
|
||||||
" \"},\n"
|
" \"},\n"
|
||||||
" \"minimum_confirmations\": n (numeric) The given minconf argument\n"
|
" \"minimum_confirmations\": n (numeric) The given minconf argument\n"
|
||||||
|
@ -3651,12 +3652,12 @@ UniValue z_getbalanceforaddress(const UniValue& params, bool fHelp)
|
||||||
"Result amounts are in units of " + MINOR_CURRENCY_UNIT + ".\n"
|
"Result amounts are in units of " + MINOR_CURRENCY_UNIT + ".\n"
|
||||||
"Pools for which the balance is zero are not shown.\n"
|
"Pools for which the balance is zero are not shown.\n"
|
||||||
"\nExamples:\n"
|
"\nExamples:\n"
|
||||||
"\nThe per-pool amount received by address \"myaddress\" with at least 1 block confirmed\n"
|
"\nThe per-pool amount viewable by key \"myfvk\" with at least 1 block confirmed\n"
|
||||||
+ HelpExampleCli("z_getbalanceforaddress", "\"myaddress\"") +
|
+ HelpExampleCli("z_getbalanceforviewingkey", "\"myfvk\"") +
|
||||||
"\nThe per-pool amount received by address \"myaddress\" with at least 5 blocks confirmed\n"
|
"\nThe per-pool amount viewable by key \"myfvk\" with at least 5 blocks confirmed\n"
|
||||||
+ HelpExampleCli("z_getbalanceforaddress", "\"myaddress\" 5") +
|
+ HelpExampleCli("z_getbalanceforviewingkey", "\"myfvk\" 5") +
|
||||||
"\nAs a JSON RPC call\n"
|
"\nAs a JSON RPC call\n"
|
||||||
+ HelpExampleRpc("z_getbalanceforaddress", "\"myaddress\", 5")
|
+ HelpExampleRpc("z_getbalanceforviewingkey", "\"myfvk\", 5")
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!fExperimentalOrchardWallet) {
|
if (!fExperimentalOrchardWallet) {
|
||||||
|
@ -3664,11 +3665,11 @@ UniValue z_getbalanceforaddress(const UniValue& params, bool fHelp)
|
||||||
}
|
}
|
||||||
|
|
||||||
KeyIO keyIO(Params());
|
KeyIO keyIO(Params());
|
||||||
auto decoded = keyIO.DecodePaymentAddress(params[0].get_str());
|
auto decoded = keyIO.DecodeViewingKey(params[0].get_str());
|
||||||
if (!decoded.has_value()) {
|
if (!decoded.has_value()) {
|
||||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid full viewing key");
|
||||||
}
|
}
|
||||||
auto address = decoded.value();
|
auto fvk = decoded.value();
|
||||||
|
|
||||||
int minconf = 1;
|
int minconf = 1;
|
||||||
if (params.size() > 1) {
|
if (params.size() > 1) {
|
||||||
|
@ -3680,14 +3681,17 @@ UniValue z_getbalanceforaddress(const UniValue& params, bool fHelp)
|
||||||
|
|
||||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||||
|
|
||||||
// Get the receivers for this address.
|
// Sprout viewing keys cannot provide accurate balance information because they
|
||||||
auto selector = pwalletMain->ToZTXOSelector(address, false);
|
// cannot detect spends, so we require that the wallet control the spending key
|
||||||
|
// in the case that a Sprout viewing key is provided. Sapling and unified
|
||||||
|
// FVKs make it possible to correctly determine balance without having the
|
||||||
|
// spending key, so we permit that here.
|
||||||
|
bool requireSpendingKey = std::holds_alternative<libzcash::SproutViewingKey>(fvk);
|
||||||
|
auto selector = pwalletMain->ZTXOSelectorForViewingKey(fvk, requireSpendingKey);
|
||||||
if (!selector.has_value()) {
|
if (!selector.has_value()) {
|
||||||
// The only way we'd reach this is if the address is a unified address for which
|
|
||||||
// we do not know its UFVK.
|
|
||||||
throw JSONRPCError(
|
throw JSONRPCError(
|
||||||
RPC_INVALID_PARAMETER,
|
RPC_INVALID_PARAMETER,
|
||||||
"Error: wallet does not have the Unified Full Viewing Key for the given address");
|
"Error: the wallet does not recognize the specified viewing key.");
|
||||||
}
|
}
|
||||||
|
|
||||||
auto spendableInputs = pwalletMain->FindSpendableInputs(selector.value(), true, minconf);
|
auto spendableInputs = pwalletMain->FindSpendableInputs(selector.value(), true, minconf);
|
||||||
|
@ -4278,11 +4282,20 @@ size_t EstimateTxSize(
|
||||||
[&](const CScriptID& scriptId) {
|
[&](const CScriptID& scriptId) {
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
[&](const libzcash::UnifiedFullViewingKey& ufvk) {
|
||||||
|
return ufvk.GetTransparentKey().has_value();
|
||||||
|
},
|
||||||
[&](const libzcash::SproutPaymentAddress& addr) {
|
[&](const libzcash::SproutPaymentAddress& addr) {
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
[&](const libzcash::SproutViewingKey& addr) {
|
||||||
|
return false;
|
||||||
|
},
|
||||||
[&](const libzcash::SaplingPaymentAddress& addr) {
|
[&](const libzcash::SaplingPaymentAddress& addr) {
|
||||||
return false;
|
return false;
|
||||||
|
},
|
||||||
|
[&](const libzcash::SaplingExtendedFullViewingKey& addr) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}, ztxoSelector.GetPattern());
|
}, ztxoSelector.GetPattern());
|
||||||
|
|
||||||
|
@ -4380,7 +4393,7 @@ UniValue z_sendmany(const UniValue& params, bool fHelp)
|
||||||
auto fromaddress = params[0].get_str();
|
auto fromaddress = params[0].get_str();
|
||||||
ZTXOSelector ztxoSelector = [&]() {
|
ZTXOSelector ztxoSelector = [&]() {
|
||||||
if (fromaddress == "ANY_TADDR") {
|
if (fromaddress == "ANY_TADDR") {
|
||||||
return CWallet::LegacyTransparentZTXOSelector();
|
return CWallet::LegacyTransparentZTXOSelector(true);
|
||||||
} else {
|
} else {
|
||||||
auto decoded = keyIO.DecodePaymentAddress(fromaddress);
|
auto decoded = keyIO.DecodePaymentAddress(fromaddress);
|
||||||
if (!decoded.has_value()) {
|
if (!decoded.has_value()) {
|
||||||
|
@ -4389,7 +4402,7 @@ UniValue z_sendmany(const UniValue& params, bool fHelp)
|
||||||
"Invalid from address: should be a taddr, a zaddr, or the string 'ANY_TADDR'.");
|
"Invalid from address: should be a taddr, a zaddr, or the string 'ANY_TADDR'.");
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ztxoSelectorOpt = pwalletMain->ToZTXOSelector(decoded.value(), true);
|
auto ztxoSelectorOpt = pwalletMain->ZTXOSelectorForAddress(decoded.value(), true);
|
||||||
if (!ztxoSelectorOpt.has_value()) {
|
if (!ztxoSelectorOpt.has_value()) {
|
||||||
throw JSONRPCError(
|
throw JSONRPCError(
|
||||||
RPC_INVALID_ADDRESS_OR_KEY,
|
RPC_INVALID_ADDRESS_OR_KEY,
|
||||||
|
@ -5542,7 +5555,7 @@ static const CRPCCommand commands[] =
|
||||||
{ "wallet", "z_listunspent", &z_listunspent, false },
|
{ "wallet", "z_listunspent", &z_listunspent, false },
|
||||||
{ "wallet", "z_getbalance", &z_getbalance, false },
|
{ "wallet", "z_getbalance", &z_getbalance, false },
|
||||||
{ "wallet", "z_gettotalbalance", &z_gettotalbalance, false },
|
{ "wallet", "z_gettotalbalance", &z_gettotalbalance, false },
|
||||||
{ "wallet", "z_getbalanceforaddress", &z_getbalanceforaddress, false },
|
{ "wallet", "z_getbalanceforviewingkey",&z_getbalanceforviewingkey,false },
|
||||||
{ "wallet", "z_getbalanceforaccount", &z_getbalanceforaccount, false },
|
{ "wallet", "z_getbalanceforaccount", &z_getbalanceforaccount, false },
|
||||||
{ "wallet", "z_mergetoaddress", &z_mergetoaddress, false },
|
{ "wallet", "z_mergetoaddress", &z_mergetoaddress, false },
|
||||||
{ "wallet", "z_sendmany", &z_sendmany, false },
|
{ "wallet", "z_sendmany", &z_sendmany, false },
|
||||||
|
|
|
@ -801,7 +801,7 @@ void CheckHaveAddr(const std::optional<libzcash::PaymentAddress>& addr) {
|
||||||
auto addr_of_type = std::get_if<ADDR_TYPE>(&(addr.value()));
|
auto addr_of_type = std::get_if<ADDR_TYPE>(&(addr.value()));
|
||||||
BOOST_ASSERT(addr_of_type != nullptr);
|
BOOST_ASSERT(addr_of_type != nullptr);
|
||||||
|
|
||||||
BOOST_CHECK(pwalletMain->ToZTXOSelector(*addr_of_type, true).has_value());
|
BOOST_CHECK(pwalletMain->ZTXOSelectorForAddress(*addr_of_type, true).has_value());
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(rpc_wallet_z_getnewaddress) {
|
BOOST_AUTO_TEST_CASE(rpc_wallet_z_getnewaddress) {
|
||||||
|
@ -1235,7 +1235,7 @@ BOOST_AUTO_TEST_CASE(rpc_z_sendmany_internals)
|
||||||
|
|
||||||
// there are no utxos to spend
|
// there are no utxos to spend
|
||||||
{
|
{
|
||||||
auto selector = pwalletMain->ToZTXOSelector(taddr1, true).value();
|
auto selector = pwalletMain->ZTXOSelectorForAddress(taddr1, true).value();
|
||||||
TransactionBuilder builder(consensusParams, nHeight + 1, pwalletMain);
|
TransactionBuilder builder(consensusParams, nHeight + 1, pwalletMain);
|
||||||
std::vector<SendManyRecipient> recipients = { SendManyRecipient(zaddr1, 100*COIN, "DEADBEEF") };
|
std::vector<SendManyRecipient> recipients = { SendManyRecipient(zaddr1, 100*COIN, "DEADBEEF") };
|
||||||
std::shared_ptr<AsyncRPCOperation> operation(new AsyncRPCOperation_sendmany(builder, selector, recipients, 1));
|
std::shared_ptr<AsyncRPCOperation> operation(new AsyncRPCOperation_sendmany(builder, selector, recipients, 1));
|
||||||
|
@ -1247,7 +1247,7 @@ BOOST_AUTO_TEST_CASE(rpc_z_sendmany_internals)
|
||||||
|
|
||||||
// there are no unspent notes to spend
|
// there are no unspent notes to spend
|
||||||
{
|
{
|
||||||
auto selector = pwalletMain->ToZTXOSelector(zaddr1, true).value();
|
auto selector = pwalletMain->ZTXOSelectorForAddress(zaddr1, true).value();
|
||||||
TransactionBuilder builder(consensusParams, nHeight + 1, pwalletMain);
|
TransactionBuilder builder(consensusParams, nHeight + 1, pwalletMain);
|
||||||
std::vector<SendManyRecipient> recipients = { SendManyRecipient(taddr1, 100*COIN, "DEADBEEF") };
|
std::vector<SendManyRecipient> recipients = { SendManyRecipient(taddr1, 100*COIN, "DEADBEEF") };
|
||||||
std::shared_ptr<AsyncRPCOperation> operation(new AsyncRPCOperation_sendmany(builder, selector, recipients, 1));
|
std::shared_ptr<AsyncRPCOperation> operation(new AsyncRPCOperation_sendmany(builder, selector, recipients, 1));
|
||||||
|
@ -1259,7 +1259,7 @@ BOOST_AUTO_TEST_CASE(rpc_z_sendmany_internals)
|
||||||
|
|
||||||
// get_memo_from_hex_string())
|
// get_memo_from_hex_string())
|
||||||
{
|
{
|
||||||
auto selector = pwalletMain->ToZTXOSelector(zaddr1, true).value();
|
auto selector = pwalletMain->ZTXOSelectorForAddress(zaddr1, true).value();
|
||||||
TransactionBuilder builder(consensusParams, nHeight + 1, pwalletMain);
|
TransactionBuilder builder(consensusParams, nHeight + 1, pwalletMain);
|
||||||
std::vector<SendManyRecipient> recipients = { SendManyRecipient(zaddr1, 100*COIN, "DEADBEEF") };
|
std::vector<SendManyRecipient> recipients = { SendManyRecipient(zaddr1, 100*COIN, "DEADBEEF") };
|
||||||
std::shared_ptr<AsyncRPCOperation> operation(new AsyncRPCOperation_sendmany(builder, selector, recipients, 1));
|
std::shared_ptr<AsyncRPCOperation> operation(new AsyncRPCOperation_sendmany(builder, selector, recipients, 1));
|
||||||
|
@ -1360,7 +1360,7 @@ BOOST_AUTO_TEST_CASE(rpc_z_sendmany_taddr_to_sapling)
|
||||||
auto builder = TransactionBuilder(consensusParams, nextBlockHeight, pwalletMain);
|
auto builder = TransactionBuilder(consensusParams, nextBlockHeight, pwalletMain);
|
||||||
mtx = CreateNewContextualCMutableTransaction(consensusParams, nextBlockHeight);
|
mtx = CreateNewContextualCMutableTransaction(consensusParams, nextBlockHeight);
|
||||||
|
|
||||||
auto selector = pwalletMain->ToZTXOSelector(taddr, true).value();
|
auto selector = pwalletMain->ZTXOSelectorForAddress(taddr, true).value();
|
||||||
std::vector<SendManyRecipient> recipients = { SendManyRecipient(pa, 1*COIN, "ABCD") };
|
std::vector<SendManyRecipient> recipients = { SendManyRecipient(pa, 1*COIN, "ABCD") };
|
||||||
std::shared_ptr<AsyncRPCOperation> operation(new AsyncRPCOperation_sendmany(builder, selector, recipients, 0));
|
std::shared_ptr<AsyncRPCOperation> operation(new AsyncRPCOperation_sendmany(builder, selector, recipients, 0));
|
||||||
std::shared_ptr<AsyncRPCOperation_sendmany> ptr = std::dynamic_pointer_cast<AsyncRPCOperation_sendmany> (operation);
|
std::shared_ptr<AsyncRPCOperation_sendmany> ptr = std::dynamic_pointer_cast<AsyncRPCOperation_sendmany> (operation);
|
||||||
|
|
|
@ -1466,7 +1466,7 @@ std::optional<ZTXOSelector> CWallet::ZTXOSelectorForAccount(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<ZTXOSelector> CWallet::ToZTXOSelector(const libzcash::PaymentAddress& addr, bool requireSpendingKey) const {
|
std::optional<ZTXOSelector> CWallet::ZTXOSelectorForAddress(const libzcash::PaymentAddress& addr, bool requireSpendingKey) const {
|
||||||
auto self = this;
|
auto self = this;
|
||||||
std::optional<ZTXOPattern> pattern = std::nullopt;
|
std::optional<ZTXOPattern> pattern = std::nullopt;
|
||||||
std::visit(match {
|
std::visit(match {
|
||||||
|
@ -1513,10 +1513,45 @@ std::optional<ZTXOSelector> CWallet::ToZTXOSelector(const libzcash::PaymentAddre
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ZTXOSelector CWallet::LegacyTransparentZTXOSelector() {
|
std::optional<ZTXOSelector> CWallet::ZTXOSelectorForViewingKey(
|
||||||
|
const libzcash::ViewingKey& vk,
|
||||||
|
bool requireSpendingKey) const
|
||||||
|
{
|
||||||
|
auto self = this;
|
||||||
|
std::optional<ZTXOPattern> pattern = std::nullopt;
|
||||||
|
std::visit(match {
|
||||||
|
[&](const libzcash::SaplingExtendedFullViewingKey& vk) {
|
||||||
|
if (!requireSpendingKey || self->HaveSaplingSpendingKey(vk)) {
|
||||||
|
pattern = vk;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[&](const libzcash::SproutViewingKey& vk) {
|
||||||
|
if (!requireSpendingKey || self->HaveSproutSpendingKey(vk.address())) {
|
||||||
|
pattern = vk;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[&](const libzcash::UnifiedFullViewingKey& ufvk) {
|
||||||
|
auto ufvkId = ufvk.GetKeyID(Params());
|
||||||
|
auto accountId = this->GetUnifiedAccountId(ufvkId);
|
||||||
|
if (accountId.has_value()) {
|
||||||
|
pattern = AccountZTXOPattern(accountId.value(), ufvk.GetKnownReceiverTypes());
|
||||||
|
} else {
|
||||||
|
pattern = ufvk;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, vk);
|
||||||
|
|
||||||
|
if (pattern.has_value()) {
|
||||||
|
return ZTXOSelector(pattern.value(), requireSpendingKey);
|
||||||
|
} else {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ZTXOSelector CWallet::LegacyTransparentZTXOSelector(bool requireSpendingKey) {
|
||||||
return ZTXOSelector(
|
return ZTXOSelector(
|
||||||
AccountZTXOPattern(ZCASH_LEGACY_ACCOUNT, {ReceiverType::P2PKH, ReceiverType::P2SH}),
|
AccountZTXOPattern(ZCASH_LEGACY_ACCOUNT, {ReceiverType::P2PKH, ReceiverType::P2SH}),
|
||||||
true);
|
requireSpendingKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<libzcash::AccountId> CWallet::FindAccountForSelector(const ZTXOSelector& selector) const {
|
std::optional<libzcash::AccountId> CWallet::FindAccountForSelector(const ZTXOSelector& selector) const {
|
||||||
|
@ -1536,12 +1571,22 @@ std::optional<libzcash::AccountId> CWallet::FindAccountForSelector(const ZTXOSel
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[&](const libzcash::SproutPaymentAddress& addr) { },
|
[&](const libzcash::SproutPaymentAddress& addr) { },
|
||||||
|
[&](const libzcash::SproutViewingKey& vk) { },
|
||||||
[&](const libzcash::SaplingPaymentAddress& addr) {
|
[&](const libzcash::SaplingPaymentAddress& addr) {
|
||||||
auto meta = GetUFVKMetadataForReceiver(addr);
|
auto meta = GetUFVKMetadataForReceiver(addr);
|
||||||
if (meta.has_value()) {
|
if (meta.has_value()) {
|
||||||
result = self->GetUnifiedAccountId(meta.value().first);
|
result = self->GetUnifiedAccountId(meta.value().first);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
[&](const libzcash::SaplingExtendedFullViewingKey& vk) {
|
||||||
|
auto ufvkid = GetUFVKIdForViewingKey(vk);
|
||||||
|
if (ufvkid.has_value()) {
|
||||||
|
result = self->GetUnifiedAccountId(ufvkid.value());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[&](const libzcash::UnifiedFullViewingKey& vk) {
|
||||||
|
result = self->GetUnifiedAccountId(vk.GetKeyID(Params()));
|
||||||
|
},
|
||||||
[&](const AccountZTXOPattern& acct) {
|
[&](const AccountZTXOPattern& acct) {
|
||||||
if (self->mnemonicHDChain.has_value() &&
|
if (self->mnemonicHDChain.has_value() &&
|
||||||
self->mapUnifiedAccountKeys.count(
|
self->mapUnifiedAccountKeys.count(
|
||||||
|
@ -1554,6 +1599,8 @@ std::optional<libzcash::AccountId> CWallet::FindAccountForSelector(const ZTXOSel
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SelectorMatchesAddress is overloaded for:
|
||||||
|
// Transparent
|
||||||
bool CWallet::SelectorMatchesAddress(
|
bool CWallet::SelectorMatchesAddress(
|
||||||
const ZTXOSelector& selector,
|
const ZTXOSelector& selector,
|
||||||
const CTxDestination& address) const {
|
const CTxDestination& address) const {
|
||||||
|
@ -1568,7 +1615,17 @@ bool CWallet::SelectorMatchesAddress(
|
||||||
return address == scriptIdDest;
|
return address == scriptIdDest;
|
||||||
},
|
},
|
||||||
[&](const libzcash::SproutPaymentAddress& addr) { return false; },
|
[&](const libzcash::SproutPaymentAddress& addr) { return false; },
|
||||||
|
[&](const libzcash::SproutViewingKey& vk) { return false; },
|
||||||
[&](const libzcash::SaplingPaymentAddress& addr) { return false; },
|
[&](const libzcash::SaplingPaymentAddress& addr) { return false; },
|
||||||
|
[&](const libzcash::SaplingExtendedFullViewingKey& extfvk) { return false; },
|
||||||
|
[&](const libzcash::UnifiedFullViewingKey& ufvk) {
|
||||||
|
std::optional<std::pair<libzcash::UFVKId, std::optional<libzcash::diversifier_index_t>>> meta;
|
||||||
|
std::visit(match {
|
||||||
|
[&](const CNoDestination& none) { meta = std::nullopt; },
|
||||||
|
[&](const auto& addr) { meta = self->GetUFVKMetadataForReceiver(addr); }
|
||||||
|
}, address);
|
||||||
|
return (meta.has_value() && meta.value().first == ufvk.GetKeyID(Params()));
|
||||||
|
},
|
||||||
[&](const AccountZTXOPattern& acct) {
|
[&](const AccountZTXOPattern& acct) {
|
||||||
if (acct.IncludesP2PKH() || acct.IncludesP2SH()) {
|
if (acct.IncludesP2PKH() || acct.IncludesP2SH()) {
|
||||||
std::optional<std::pair<libzcash::UFVKId, std::optional<libzcash::diversifier_index_t>>> meta;
|
std::optional<std::pair<libzcash::UFVKId, std::optional<libzcash::diversifier_index_t>>> meta;
|
||||||
|
@ -1591,16 +1648,17 @@ bool CWallet::SelectorMatchesAddress(
|
||||||
}
|
}
|
||||||
}, selector.GetPattern());
|
}, selector.GetPattern());
|
||||||
}
|
}
|
||||||
|
// Sprout
|
||||||
bool CWallet::SelectorMatchesAddress(
|
bool CWallet::SelectorMatchesAddress(
|
||||||
const ZTXOSelector& selector,
|
const ZTXOSelector& selector,
|
||||||
const libzcash::SproutPaymentAddress& a0) const {
|
const libzcash::SproutPaymentAddress& a0) const {
|
||||||
return std::visit(match {
|
return std::visit(match {
|
||||||
[&](const libzcash::SproutPaymentAddress& a1) { return a0 == a1; },
|
[&](const libzcash::SproutPaymentAddress& a1) { return a0 == a1; },
|
||||||
|
[&](const libzcash::SproutViewingKey& vk) { return a0 == vk.address(); },
|
||||||
[&](const auto& addr) { return false; },
|
[&](const auto& addr) { return false; },
|
||||||
}, selector.GetPattern());
|
}, selector.GetPattern());
|
||||||
}
|
}
|
||||||
|
// Sapling
|
||||||
bool CWallet::SelectorMatchesAddress(
|
bool CWallet::SelectorMatchesAddress(
|
||||||
const ZTXOSelector& selector,
|
const ZTXOSelector& selector,
|
||||||
const libzcash::SaplingPaymentAddress& a0) const {
|
const libzcash::SaplingPaymentAddress& a0) const {
|
||||||
|
@ -1609,7 +1667,25 @@ bool CWallet::SelectorMatchesAddress(
|
||||||
[&](const CKeyID& keyId) { return false; },
|
[&](const CKeyID& keyId) { return false; },
|
||||||
[&](const CScriptID& scriptId) { return false; },
|
[&](const CScriptID& scriptId) { return false; },
|
||||||
[&](const libzcash::SproutPaymentAddress& addr) { return false; },
|
[&](const libzcash::SproutPaymentAddress& addr) { return false; },
|
||||||
[&](const libzcash::SaplingPaymentAddress& a1) { return a0 == a1; },
|
[&](const libzcash::SproutViewingKey& vk) { return false; },
|
||||||
|
[&](const libzcash::SaplingPaymentAddress& a1) {
|
||||||
|
return a0 == a1;
|
||||||
|
},
|
||||||
|
[&](const libzcash::SaplingExtendedFullViewingKey& extfvk) {
|
||||||
|
auto j = extfvk.DecryptDiversifier(a0.d);
|
||||||
|
auto addr = extfvk.Address(j);
|
||||||
|
return addr.has_value() && addr.value() == a0;
|
||||||
|
},
|
||||||
|
[&](const libzcash::UnifiedFullViewingKey& ufvk) {
|
||||||
|
auto saplingKey = ufvk.GetSaplingKey();
|
||||||
|
if (saplingKey.has_value()) {
|
||||||
|
auto j = saplingKey.value().DecryptDiversifier(a0.d);
|
||||||
|
auto addr = saplingKey.value().Address(j);
|
||||||
|
return addr.has_value() && addr.value() == a0;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
[&](const AccountZTXOPattern& acct) {
|
[&](const AccountZTXOPattern& acct) {
|
||||||
if (acct.IncludesSapling()) {
|
if (acct.IncludesSapling()) {
|
||||||
const auto meta = self->GetUFVKMetadataForReceiver(a0);
|
const auto meta = self->GetUFVKMetadataForReceiver(a0);
|
||||||
|
@ -6218,8 +6294,11 @@ std::optional<libzcash::ViewingKey> GetViewingKeyForPaymentAddress::operator()(
|
||||||
std::optional<libzcash::ViewingKey> GetViewingKeyForPaymentAddress::operator()(
|
std::optional<libzcash::ViewingKey> GetViewingKeyForPaymentAddress::operator()(
|
||||||
const libzcash::UnifiedAddress &uaddr) const
|
const libzcash::UnifiedAddress &uaddr) const
|
||||||
{
|
{
|
||||||
// TODO
|
auto ufvkid = m_wallet->FindUnifiedFullViewingKey(uaddr);
|
||||||
return std::nullopt;
|
if (!ufvkid.has_value()) return std::nullopt;
|
||||||
|
auto zufvk = m_wallet->GetUnifiedFullViewingKey(ufvkid.value());
|
||||||
|
if (!zufvk.has_value()) return std::nullopt;
|
||||||
|
return zufvk.value().ToFullViewingKey();
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddViewingKeyToWallet
|
// AddViewingKeyToWallet
|
||||||
|
@ -6355,33 +6434,25 @@ std::optional<libzcash::UnifiedAddress> UnifiedAddressForReceiver::operator()(co
|
||||||
if (ufvkPair.has_value()) {
|
if (ufvkPair.has_value()) {
|
||||||
auto ufvkid = ufvkPair.value().first;
|
auto ufvkid = ufvkPair.value().first;
|
||||||
auto ufvk = wallet.GetUnifiedFullViewingKey(ufvkid);
|
auto ufvk = wallet.GetUnifiedFullViewingKey(ufvkid);
|
||||||
assert(ufvk.has_value() && ufvk.value().GetSaplingKey().has_value());
|
assert(ufvk.has_value());
|
||||||
|
|
||||||
diversifier_index_t j;
|
|
||||||
// If the wallet is missing metadata at this UFVK id, it is probably
|
// If the wallet is missing metadata at this UFVK id, it is probably
|
||||||
// corrupt and the node should shut down.
|
// corrupt and the node should shut down.
|
||||||
const auto& metadata = wallet.mapUfvkAddressMetadata.at(ufvkid);
|
const auto& metadata = wallet.mapUfvkAddressMetadata.at(ufvkid);
|
||||||
librustzcash_sapling_diversifier_index(
|
auto saplingKey = ufvk.value().GetSaplingKey();
|
||||||
ufvk.value().GetSaplingKey().value().dk.begin(),
|
if (saplingKey.has_value()) {
|
||||||
saplingAddr.d.begin(),
|
diversifier_index_t j = saplingKey.value().DecryptDiversifier(saplingAddr.d);
|
||||||
j.begin());
|
auto receivers = metadata.GetReceivers(j);
|
||||||
auto receivers = metadata.GetReceivers(j);
|
if (receivers.has_value()) {
|
||||||
if (receivers.has_value()) {
|
auto addr = ufvk.value().Address(j, receivers.value());
|
||||||
auto addr = ufvk.value().Address(j, receivers.value());
|
auto addrPtr = std::get_if<std::pair<UnifiedAddress, diversifier_index_t>>(&addr);
|
||||||
auto addrPtr = std::get_if<std::pair<UnifiedAddress, diversifier_index_t>>(&addr);
|
if (addrPtr != nullptr) {
|
||||||
if (addrPtr == nullptr) {
|
return addrPtr->first;
|
||||||
return std::nullopt;
|
}
|
||||||
} else {
|
|
||||||
return addrPtr->first;
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// If we don't know the receiver types at which the address was originally
|
|
||||||
// generated, we can't reconstruct the address.
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
}
|
||||||
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
std::optional<libzcash::UnifiedAddress> UnifiedAddressForReceiver::operator()(const CScriptID& scriptId) const {
|
std::optional<libzcash::UnifiedAddress> UnifiedAddressForReceiver::operator()(const CScriptID& scriptId) const {
|
||||||
// We do not currently generate unified addresses containing P2SH components,
|
// We do not currently generate unified addresses containing P2SH components,
|
||||||
|
@ -6429,16 +6500,25 @@ bool ZTXOSelector::SelectsTransparent() {
|
||||||
[](const CKeyID& keyId) { return true; },
|
[](const CKeyID& keyId) { return true; },
|
||||||
[](const CScriptID& scriptId) { return true; },
|
[](const CScriptID& scriptId) { return true; },
|
||||||
[](const libzcash::SproutPaymentAddress& addr) { return false; },
|
[](const libzcash::SproutPaymentAddress& addr) { return false; },
|
||||||
|
[](const libzcash::SproutViewingKey& vk) { return false; },
|
||||||
[](const libzcash::SaplingPaymentAddress& addr) { return false; },
|
[](const libzcash::SaplingPaymentAddress& addr) { return false; },
|
||||||
|
[](const libzcash::SaplingExtendedFullViewingKey& vk) { return false; },
|
||||||
|
[](const libzcash::UnifiedFullViewingKey& ufvk) { return ufvk.GetTransparentKey().has_value(); },
|
||||||
[](const AccountZTXOPattern& acct) { return acct.IncludesP2PKH() || acct.IncludesP2SH(); }
|
[](const AccountZTXOPattern& acct) { return acct.IncludesP2PKH() || acct.IncludesP2SH(); }
|
||||||
}, this->pattern);
|
}, this->pattern);
|
||||||
}
|
}
|
||||||
bool ZTXOSelector::SelectsSprout() {
|
bool ZTXOSelector::SelectsSprout() {
|
||||||
return std::holds_alternative<libzcash::SproutPaymentAddress>(this->pattern);
|
return std::visit(match {
|
||||||
|
[](const libzcash::SproutViewingKey& addr) { return true; },
|
||||||
|
[](const libzcash::SproutPaymentAddress& extfvk) { return true; },
|
||||||
|
[](const auto& addr) { return false; }
|
||||||
|
}, this->pattern);
|
||||||
}
|
}
|
||||||
bool ZTXOSelector::SelectsSapling() {
|
bool ZTXOSelector::SelectsSapling() {
|
||||||
return std::visit(match {
|
return std::visit(match {
|
||||||
[](const libzcash::SaplingPaymentAddress& addr) { return true; },
|
[](const libzcash::SaplingPaymentAddress& addr) { return true; },
|
||||||
|
[](const libzcash::SaplingExtendedSpendingKey& extfvk) { return true; },
|
||||||
|
[](const libzcash::UnifiedFullViewingKey& ufvk) { return ufvk.GetSaplingKey().has_value(); },
|
||||||
[](const AccountZTXOPattern& acct) { return acct.IncludesSapling(); },
|
[](const AccountZTXOPattern& acct) { return acct.IncludesSapling(); },
|
||||||
[](const auto& addr) { return false; }
|
[](const auto& addr) { return false; }
|
||||||
}, this->pattern);
|
}, this->pattern);
|
||||||
|
|
|
@ -738,7 +738,10 @@ typedef std::variant<
|
||||||
CKeyID,
|
CKeyID,
|
||||||
CScriptID,
|
CScriptID,
|
||||||
libzcash::SproutPaymentAddress,
|
libzcash::SproutPaymentAddress,
|
||||||
|
libzcash::SproutViewingKey,
|
||||||
libzcash::SaplingPaymentAddress,
|
libzcash::SaplingPaymentAddress,
|
||||||
|
libzcash::SaplingExtendedFullViewingKey,
|
||||||
|
libzcash::UnifiedFullViewingKey,
|
||||||
AccountZTXOPattern> ZTXOPattern;
|
AccountZTXOPattern> ZTXOPattern;
|
||||||
|
|
||||||
class ZTXOSelector {
|
class ZTXOSelector {
|
||||||
|
@ -1220,7 +1223,7 @@ public:
|
||||||
static bool SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int nConfTheirs, std::vector<COutput> vCoins, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet);
|
static bool SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int nConfTheirs, std::vector<COutput> vCoins, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtain the ZTXO selector for the specified account ID.
|
* Returns the ZTXO selector for the specified account ID.
|
||||||
*
|
*
|
||||||
* Returns `std::nullopt` if the account ID has not been generated yet by
|
* Returns `std::nullopt` if the account ID has not been generated yet by
|
||||||
* the wallet.
|
* the wallet.
|
||||||
|
@ -1234,15 +1237,30 @@ public:
|
||||||
std::set<libzcash::ReceiverType> receiverTypes={}) const;
|
std::set<libzcash::ReceiverType> receiverTypes={}) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtain the ZTXO selector for the specified payment address. If the
|
* Returns the ZTXO selector for the specified payment address, if the
|
||||||
* `requireSpendingKey` flag is set, this will only return a selector
|
* address is known to the wallet. If the `requireSpendingKey` flag is set,
|
||||||
* that will choose outputs for which this wallet holds the spending keys.
|
* this will only return a selector that will choose outputs for which this
|
||||||
|
* wallet holds the spending keys.
|
||||||
*/
|
*/
|
||||||
std::optional<ZTXOSelector> ToZTXOSelector(
|
std::optional<ZTXOSelector> ZTXOSelectorForAddress(
|
||||||
const libzcash::PaymentAddress& addr,
|
const libzcash::PaymentAddress& addr,
|
||||||
bool requireSpendingKey) const;
|
bool requireSpendingKey) const;
|
||||||
|
|
||||||
static ZTXOSelector LegacyTransparentZTXOSelector();
|
/**
|
||||||
|
* Returns the ZTXO selector for the specified viewing key, if that key
|
||||||
|
* is known to the wallet. If the `requireSpendingKey` flag is set, this
|
||||||
|
* will only return a selector that will choose outputs for which this
|
||||||
|
* wallet holds the spending keys.
|
||||||
|
*/
|
||||||
|
std::optional<ZTXOSelector> ZTXOSelectorForViewingKey(
|
||||||
|
const libzcash::ViewingKey& vk,
|
||||||
|
bool requireSpendingKey) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the ZTXO selector that will select UTXOs sent to legacy
|
||||||
|
* transparent addresses managed by this wallet.
|
||||||
|
*/
|
||||||
|
static ZTXOSelector LegacyTransparentZTXOSelector(bool requireSpendingKey);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Look up the account for a given selector. This resolves the account ID
|
* Look up the account for a given selector. This resolves the account ID
|
||||||
|
|
|
@ -177,6 +177,17 @@ public:
|
||||||
|
|
||||||
UFVKId GetKeyID(const KeyConstants& keyConstants) const;
|
UFVKId GetKeyID(const KeyConstants& keyConstants) const;
|
||||||
|
|
||||||
|
std::set<ReceiverType> GetKnownReceiverTypes() const {
|
||||||
|
std::set<ReceiverType> result;
|
||||||
|
if (GetTransparentKey().has_value()) {
|
||||||
|
result.insert(ReceiverType::P2PKH);
|
||||||
|
}
|
||||||
|
if (GetSaplingKey().has_value()) {
|
||||||
|
result.insert(ReceiverType::Sapling);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
UnifiedFullViewingKey& operator=(UnifiedFullViewingKey&& key)
|
UnifiedFullViewingKey& operator=(UnifiedFullViewingKey&& key)
|
||||||
{
|
{
|
||||||
if (this != &key) {
|
if (this != &key) {
|
||||||
|
|
|
@ -157,3 +157,31 @@ std::optional<RecipientAddress> ZcashdUnifiedFullViewingKey::GetChangeAddress(co
|
||||||
}, req);
|
}, req);
|
||||||
return addr;
|
return addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<RecipientAddress> ZcashdUnifiedFullViewingKey::GetChangeAddress() const {
|
||||||
|
if (saplingKey.has_value()) {
|
||||||
|
return saplingKey.value().GetChangeAddress();
|
||||||
|
}
|
||||||
|
if (transparentKey.has_value()) {
|
||||||
|
auto changeAddr = transparentKey.value().GetChangeAddress(diversifier_index_t(0));
|
||||||
|
if (changeAddr.has_value()) {
|
||||||
|
return changeAddr.value();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
UnifiedFullViewingKey ZcashdUnifiedFullViewingKey::ToFullViewingKey() const {
|
||||||
|
UnifiedFullViewingKeyBuilder builder;
|
||||||
|
|
||||||
|
if (transparentKey.has_value()) {
|
||||||
|
builder.AddTransparentKey(transparentKey.value());
|
||||||
|
}
|
||||||
|
if (saplingKey.has_value()) {
|
||||||
|
builder.AddSaplingKey(saplingKey.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
// This call to .value() is safe as ZcashdUnifiedFullViewingKey values are always
|
||||||
|
// constructed to contain all required components.
|
||||||
|
return builder.build().value();
|
||||||
|
}
|
||||||
|
|
|
@ -214,6 +214,18 @@ public:
|
||||||
*/
|
*/
|
||||||
std::optional<RecipientAddress> GetChangeAddress(const ChangeRequest& req) const;
|
std::optional<RecipientAddress> GetChangeAddress(const ChangeRequest& req) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the "best available" change address. This returns `std::nullopt`
|
||||||
|
* only in the case of derivation failure for all key types. This will only
|
||||||
|
* return a transparent change address under highly exceptional
|
||||||
|
* circumstances, (i.e. it was not possible to derive a change address for
|
||||||
|
* *any* shielded pool) in which case the change address returned will be
|
||||||
|
* associated with diversifier index 0.
|
||||||
|
*/
|
||||||
|
std::optional<RecipientAddress> GetChangeAddress() const;
|
||||||
|
|
||||||
|
UnifiedFullViewingKey ToFullViewingKey() const;
|
||||||
|
|
||||||
friend bool operator==(const ZcashdUnifiedFullViewingKey& a, const ZcashdUnifiedFullViewingKey& b)
|
friend bool operator==(const ZcashdUnifiedFullViewingKey& a, const ZcashdUnifiedFullViewingKey& b)
|
||||||
{
|
{
|
||||||
return a.transparentKey == b.transparentKey && a.saplingKey == b.saplingKey;
|
return a.transparentKey == b.transparentKey && a.saplingKey == b.saplingKey;
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include "uint256.h"
|
#include "uint256.h"
|
||||||
#include "utiltime.h"
|
#include "utiltime.h"
|
||||||
#include "zcash/address/sapling.hpp"
|
#include "zcash/address/sapling.hpp"
|
||||||
|
#include <librustzcash.h>
|
||||||
#include <rust/zip339.h>
|
#include <rust/zip339.h>
|
||||||
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
@ -171,6 +172,12 @@ public:
|
||||||
*/
|
*/
|
||||||
std::pair<uint256, uint256> GetOVKs() const;
|
std::pair<uint256, uint256> GetOVKs() const;
|
||||||
|
|
||||||
|
diversifier_index_t DecryptDiversifier(const diversifier_t& d) const {
|
||||||
|
diversifier_index_t j;
|
||||||
|
librustzcash_sapling_diversifier_index(dk.begin(), d.begin(), j.begin());
|
||||||
|
return j;
|
||||||
|
}
|
||||||
|
|
||||||
ADD_SERIALIZE_METHODS;
|
ADD_SERIALIZE_METHODS;
|
||||||
|
|
||||||
template <typename Stream, typename Operation>
|
template <typename Stream, typename Operation>
|
||||||
|
|
Loading…
Reference in New Issue