Merge pull request #5440 from nuttycom/cleanup/sendmany_txbuilder-prereq
Prerequisites for replacing manual transaction construction in asyncrpcoperation_sendmany with the transaction builder.
This commit is contained in:
commit
005a8624bf
|
@ -82,9 +82,11 @@ class WalletShieldingCoinbaseTest (BitcoinTestFramework):
|
|||
# Node 3 will test that watch only address utxos are not selected
|
||||
self.nodes[3].importaddress(mytaddr)
|
||||
recipients= [{"address":myzaddr, "amount": Decimal('1')}]
|
||||
myopid = self.nodes[3].z_sendmany(mytaddr, recipients)
|
||||
|
||||
wait_and_assert_operationid_status(self.nodes[3], myopid, "failed", "Insufficient transparent funds, no UTXOs found for taddr from address.", 10)
|
||||
try:
|
||||
myopid = self.nodes[3].z_sendmany(mytaddr, recipients)
|
||||
except JSONRPCException as e:
|
||||
errorString = e.error['message']
|
||||
assert_equal("Invalid from address: does not belong to this node, spending key not found.", errorString);
|
||||
|
||||
# This send will fail because our wallet does not allow any change when shielding a coinbase utxo,
|
||||
# as it's currently not possible to specify a change address in z_sendmany.
|
||||
|
@ -151,7 +153,7 @@ class WalletShieldingCoinbaseTest (BitcoinTestFramework):
|
|||
results = self.nodes[1].z_listunspent(1, 999, False, [myzaddr])
|
||||
except JSONRPCException as e:
|
||||
errorString = e.error['message']
|
||||
assert_equal("Invalid parameter, spending key for address does not belong to wallet" in errorString, True)
|
||||
assert_equal("Invalid parameter, spending key for an address does not belong to the wallet.", errorString)
|
||||
|
||||
# Verify that debug=zrpcunsafe logs params, and that full txid is associated with opid
|
||||
initialized_line = check_node_log(self, 0, myopid + ": z_sendmany initialized", False)
|
||||
|
|
|
@ -822,10 +822,10 @@ CScript CChainParams::GetFoundersRewardScriptAtHeight(int nHeight) const {
|
|||
assert(nHeight > 0 && nHeight <= consensus.GetLastFoundersRewardBlockHeight(nHeight));
|
||||
|
||||
KeyIO keyIO(*this);
|
||||
CTxDestination address = keyIO.DecodeDestination(GetFoundersRewardAddressAtHeight(nHeight).c_str());
|
||||
assert(IsValidDestination(address));
|
||||
assert(IsScriptDestination(address));
|
||||
CScriptID scriptID = std::get<CScriptID>(address); // address is a variant
|
||||
auto address = keyIO.DecodePaymentAddress(GetFoundersRewardAddressAtHeight(nHeight).c_str());
|
||||
assert(address.has_value());
|
||||
assert(std::holds_alternative<CScriptID>(address.value()));
|
||||
CScriptID scriptID = std::get<CScriptID>(address.value());
|
||||
CScript script = CScript() << OP_HASH160 << ToByteVector(scriptID) << OP_EQUAL;
|
||||
return script;
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <script/standard.h>
|
||||
#include "upgrades.h"
|
||||
#include "util.h"
|
||||
#include "util/match.h"
|
||||
|
||||
namespace Consensus {
|
||||
bool Params::NetworkUpgradeActive(int nHeight, Consensus::UpgradeIndex idx) const {
|
||||
|
@ -163,17 +164,26 @@ namespace Consensus {
|
|||
|
||||
// Parse the address strings into concrete types.
|
||||
std::vector<FundingStreamAddress> addresses;
|
||||
for (auto addr : strAddresses) {
|
||||
auto taddr = keyIO.DecodeDestination(addr);
|
||||
if (IsValidDestination(taddr)) {
|
||||
addresses.push_back(GetScriptForDestination(taddr));
|
||||
} else {
|
||||
auto zaddr = keyIO.DecodePaymentAddress(addr);
|
||||
// If the string is not a valid transparent or Sapling address, we will
|
||||
// throw here.
|
||||
|
||||
addresses.push_back(std::get<libzcash::SaplingPaymentAddress>(zaddr));
|
||||
for (const auto& strAddr : strAddresses) {
|
||||
auto addr = keyIO.DecodePaymentAddress(strAddr);
|
||||
if (!addr.has_value()) {
|
||||
throw std::runtime_error("Funding stream address was not a valid " PACKAGE_NAME " address.");
|
||||
}
|
||||
|
||||
std::visit(match {
|
||||
[&](const CKeyID& keyId) {
|
||||
addresses.push_back(GetScriptForDestination(keyId));
|
||||
},
|
||||
[&](const CScriptID& scriptId) {
|
||||
addresses.push_back(GetScriptForDestination(scriptId));
|
||||
},
|
||||
[&](const libzcash::SaplingPaymentAddress& zaddr) {
|
||||
addresses.push_back(zaddr);
|
||||
},
|
||||
[&](const auto& zaddr) {
|
||||
throw std::runtime_error("Funding stream address was not a valid transparent P2SH or Sapling address.");
|
||||
}
|
||||
}, addr.value());
|
||||
}
|
||||
|
||||
auto validationResult = FundingStream::ValidateFundingStream(params, startHeight, endHeight, addresses);
|
||||
|
|
|
@ -27,11 +27,11 @@ TEST(Keys, EncodeAndDecodeSapling)
|
|||
Params().Bech32HRP(CChainParams::SAPLING_EXTENDED_SPEND_KEY));
|
||||
|
||||
auto spendingkey2 = keyIO.DecodeSpendingKey(sk_string);
|
||||
EXPECT_TRUE(IsValidSpendingKey(spendingkey2));
|
||||
EXPECT_TRUE(spendingkey2.has_value());
|
||||
|
||||
ASSERT_TRUE(std::get_if<libzcash::SaplingExtendedSpendingKey>(&spendingkey2) != nullptr);
|
||||
auto sk2 = std::get<libzcash::SaplingExtendedSpendingKey>(spendingkey2);
|
||||
EXPECT_EQ(sk, sk2);
|
||||
auto sk2 = std::get_if<libzcash::SaplingExtendedSpendingKey>(&spendingkey2.value());
|
||||
EXPECT_NE(sk2, nullptr);
|
||||
EXPECT_EQ(sk, *sk2);
|
||||
}
|
||||
{
|
||||
auto extfvk = sk.ToXFVK();
|
||||
|
@ -41,11 +41,11 @@ TEST(Keys, EncodeAndDecodeSapling)
|
|||
Params().Bech32HRP(CChainParams::SAPLING_EXTENDED_FVK));
|
||||
|
||||
auto viewingkey2 = keyIO.DecodeViewingKey(vk_string);
|
||||
EXPECT_TRUE(IsValidViewingKey(viewingkey2));
|
||||
EXPECT_TRUE(viewingkey2.has_value());
|
||||
|
||||
ASSERT_TRUE(std::get_if<libzcash::SaplingExtendedFullViewingKey>(&viewingkey2) != nullptr);
|
||||
auto extfvk2 = std::get<libzcash::SaplingExtendedFullViewingKey>(viewingkey2);
|
||||
EXPECT_EQ(extfvk, extfvk2);
|
||||
auto extfvk2 = std::get_if<libzcash::SaplingExtendedFullViewingKey>(&viewingkey2.value());
|
||||
EXPECT_NE(extfvk2, nullptr);
|
||||
EXPECT_EQ(extfvk, *extfvk2);
|
||||
}
|
||||
{
|
||||
auto addr = sk.DefaultAddress();
|
||||
|
@ -56,11 +56,11 @@ TEST(Keys, EncodeAndDecodeSapling)
|
|||
Params().Bech32HRP(CChainParams::SAPLING_PAYMENT_ADDRESS));
|
||||
|
||||
auto paymentaddr2 = keyIO.DecodePaymentAddress(addr_string);
|
||||
EXPECT_TRUE(IsValidPaymentAddress(paymentaddr2));
|
||||
EXPECT_TRUE(paymentaddr2.has_value());
|
||||
|
||||
ASSERT_TRUE(std::get_if<libzcash::SaplingPaymentAddress>(&paymentaddr2) != nullptr);
|
||||
auto addr2 = std::get<libzcash::SaplingPaymentAddress>(paymentaddr2);
|
||||
EXPECT_EQ(addr, addr2);
|
||||
auto addr2 = std::get_if<libzcash::SaplingPaymentAddress>(&paymentaddr2.value());
|
||||
EXPECT_NE(addr2, nullptr);
|
||||
EXPECT_EQ(addr, *addr2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -78,11 +78,11 @@ namespace libzcash {
|
|||
return tfm::format("Sapling(%s)", HexStr(ss.begin(), ss.end()));
|
||||
}
|
||||
|
||||
std::string operator()(const P2SHAddress &p2sh) const {
|
||||
std::string operator()(const CScriptID &p2sh) const {
|
||||
return tfm::format("P2SH(%s)", p2sh.GetHex());
|
||||
}
|
||||
|
||||
std::string operator()(const P2PKHAddress &p2pkh) const {
|
||||
std::string operator()(const CKeyID &p2pkh) const {
|
||||
return tfm::format("P2PKH(%s)", p2pkh.GetHex());
|
||||
}
|
||||
|
||||
|
@ -140,11 +140,11 @@ TEST(Keys, EncodeAndDecodeUnified)
|
|||
ua.AddReceiver(r);
|
||||
}
|
||||
if (!test[1].isNull()) {
|
||||
libzcash::P2SHAddress r(ParseHex(test[1].get_str()));
|
||||
CScriptID r(ParseHex(test[1].get_str()));
|
||||
ua.AddReceiver(r);
|
||||
}
|
||||
if (!test[0].isNull()) {
|
||||
libzcash::P2PKHAddress r(ParseHex(test[0].get_str()));
|
||||
CKeyID r(ParseHex(test[0].get_str()));
|
||||
ua.AddReceiver(r);
|
||||
}
|
||||
|
||||
|
@ -152,8 +152,10 @@ TEST(Keys, EncodeAndDecodeUnified)
|
|||
std::string expected(expectedBytes.begin(), expectedBytes.end());
|
||||
|
||||
auto decoded = keyIO.DecodePaymentAddress(expected);
|
||||
ASSERT_TRUE(std::holds_alternative<libzcash::UnifiedAddress>(decoded));
|
||||
EXPECT_EQ(std::get<libzcash::UnifiedAddress>(decoded), ua);
|
||||
EXPECT_TRUE(decoded.has_value());
|
||||
auto ua_ptr = std::get_if<libzcash::UnifiedAddress>(&decoded.value());
|
||||
EXPECT_NE(ua_ptr, nullptr);
|
||||
EXPECT_EQ(*ua_ptr, ua);
|
||||
|
||||
auto encoded = keyIO.EncodePaymentAddress(ua);
|
||||
EXPECT_EQ(encoded, expected);
|
||||
|
|
28
src/init.cpp
28
src/init.cpp
|
@ -1098,16 +1098,11 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
|||
KeyIO keyIO(chainparams);
|
||||
#ifdef ENABLE_MINING
|
||||
if (mapArgs.count("-mineraddress")) {
|
||||
CTxDestination addr = keyIO.DecodeDestination(mapArgs["-mineraddress"]);
|
||||
if (!IsValidDestination(addr)) {
|
||||
// Try a payment address
|
||||
auto zaddr = keyIO.DecodePaymentAddress(mapArgs["-mineraddress"]);
|
||||
if (!std::visit(IsValidMinerAddress(), std::visit(ExtractMinerAddress(), zaddr)))
|
||||
{
|
||||
return InitError(strprintf(
|
||||
_("Invalid address for -mineraddress=<addr>: '%s' (must be a Sapling or transparent address)"),
|
||||
mapArgs["-mineraddress"]));
|
||||
}
|
||||
auto addr = keyIO.DecodePaymentAddress(mapArgs["-mineraddress"]);
|
||||
if (!(addr.has_value() && std::visit(ExtractMinerAddress(), addr.value()).has_value())) {
|
||||
return InitError(strprintf(
|
||||
_("Invalid address for -mineraddress=<addr>: '%s' (must be a Sapling or transparent P2PKH address)"),
|
||||
mapArgs["-mineraddress"]));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -1678,15 +1673,12 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
|||
#ifdef ENABLE_WALLET
|
||||
bool minerAddressInLocalWallet = false;
|
||||
if (pwalletMain) {
|
||||
CTxDestination addr = keyIO.DecodeDestination(mapArgs["-mineraddress"]);
|
||||
if (IsValidDestination(addr)) {
|
||||
CKeyID keyID = std::get<CKeyID>(addr);
|
||||
minerAddressInLocalWallet = pwalletMain->HaveKey(keyID);
|
||||
} else {
|
||||
auto zaddr = keyIO.DecodePaymentAddress(mapArgs["-mineraddress"]);
|
||||
minerAddressInLocalWallet = std::visit(
|
||||
HaveSpendingKeyForPaymentAddress(pwalletMain), zaddr);
|
||||
auto zaddr = keyIO.DecodePaymentAddress(mapArgs["-mineraddress"]);
|
||||
if (!zaddr.has_value()) {
|
||||
return InitError(_("-mineraddress is not a valid " PACKAGE_NAME " address."));
|
||||
}
|
||||
minerAddressInLocalWallet = std::visit(
|
||||
HaveSpendingKeyForPaymentAddress(pwalletMain), zaddr.value());
|
||||
}
|
||||
if (GetBoolArg("-minetolocalwallet", true) && !minerAddressInLocalWallet) {
|
||||
return InitError(_("-mineraddress is not in the local wallet. Either use a local address, or set -minetolocalwallet=0"));
|
||||
|
|
129
src/key_io.cpp
129
src/key_io.cpp
|
@ -16,6 +16,7 @@
|
|||
#include <string.h>
|
||||
#include <algorithm>
|
||||
#include <variant>
|
||||
#include "util/match.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
@ -56,8 +57,8 @@ public:
|
|||
DataLenForReceiver() {}
|
||||
|
||||
size_t operator()(const libzcash::SaplingPaymentAddress &zaddr) const { return 43; }
|
||||
size_t operator()(const libzcash::P2SHAddress &p2sh) const { return 20; }
|
||||
size_t operator()(const libzcash::P2PKHAddress &p2pkh) const { return 20; }
|
||||
size_t operator()(const CScriptID &p2sh) const { return 20; }
|
||||
size_t operator()(const CKeyID &p2pkh) const { return 20; }
|
||||
size_t operator()(const libzcash::UnknownReceiver &unknown) const { return unknown.data.size(); }
|
||||
};
|
||||
|
||||
|
@ -82,11 +83,11 @@ public:
|
|||
memcpy(data, ss.data(), ss.size());
|
||||
}
|
||||
|
||||
void operator()(const libzcash::P2SHAddress &p2sh) const {
|
||||
void operator()(const CScriptID &p2sh) const {
|
||||
memcpy(data, p2sh.begin(), p2sh.size());
|
||||
}
|
||||
|
||||
void operator()(const libzcash::P2PKHAddress &p2pkh) const {
|
||||
void operator()(const CKeyID &p2pkh) const {
|
||||
memcpy(data, p2pkh.begin(), p2pkh.size());
|
||||
}
|
||||
|
||||
|
@ -113,6 +114,14 @@ private:
|
|||
public:
|
||||
PaymentAddressEncoder(const KeyConstants& keyConstants) : keyConstants(keyConstants) {}
|
||||
|
||||
std::string operator()(const CKeyID& id) const
|
||||
{
|
||||
return DestinationEncoder(keyConstants)(id);
|
||||
}
|
||||
std::string operator()(const CScriptID& id) const
|
||||
{
|
||||
return DestinationEncoder(keyConstants)(id);
|
||||
}
|
||||
std::string operator()(const libzcash::SproutPaymentAddress& zaddr) const
|
||||
{
|
||||
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
||||
|
@ -151,8 +160,6 @@ public:
|
|||
zcash_address_string_free(encoded);
|
||||
return res;
|
||||
}
|
||||
|
||||
std::string operator()(const libzcash::InvalidEncoding& no) const { return {}; }
|
||||
};
|
||||
|
||||
class ViewingKeyEncoder
|
||||
|
@ -189,8 +196,6 @@ public:
|
|||
memory_cleanse(data.data(), data.size());
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string operator()(const libzcash::InvalidEncoding& no) const { return {}; }
|
||||
};
|
||||
|
||||
class SpendingKeyEncoder
|
||||
|
@ -227,8 +232,6 @@ public:
|
|||
memory_cleanse(data.data(), data.size());
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string operator()(const libzcash::InvalidEncoding& no) const { return {}; }
|
||||
};
|
||||
|
||||
// Sizes of SaplingPaymentAddress, SaplingExtendedFullViewingKey, and
|
||||
|
@ -355,17 +358,16 @@ std::string KeyIO::EncodePaymentAddress(const libzcash::PaymentAddress& zaddr)
|
|||
return std::visit(PaymentAddressEncoder(keyConstants), zaddr);
|
||||
}
|
||||
|
||||
template<typename T1, typename T2, typename T3>
|
||||
T1 DecodeAny(
|
||||
const KeyConstants& keyConstants,
|
||||
const std::string& str,
|
||||
std::pair<KeyConstants::Base58Type, size_t> sprout,
|
||||
std::pair<KeyConstants::Bech32Type, size_t> sapling)
|
||||
template<typename T1, typename T2>
|
||||
std::optional<T1> DecodeSprout(
|
||||
const KeyConstants& keyConstants,
|
||||
const std::string& str,
|
||||
const std::pair<KeyConstants::Base58Type, size_t>& keyMeta)
|
||||
{
|
||||
std::vector<unsigned char> data;
|
||||
if (DecodeBase58Check(str, data)) {
|
||||
const std::vector<unsigned char>& prefix = keyConstants.Base58Prefix(sprout.first);
|
||||
if ((data.size() == sprout.second + prefix.size()) &&
|
||||
const std::vector<unsigned char>& prefix = keyConstants.Base58Prefix(keyMeta.first);
|
||||
if ((data.size() == keyMeta.second + prefix.size()) &&
|
||||
std::equal(prefix.begin(), prefix.end(), data.begin())) {
|
||||
CSerializeData serialized(data.begin() + prefix.size(), data.end());
|
||||
CDataStream ss(serialized, SER_NETWORK, PROTOCOL_VERSION);
|
||||
|
@ -377,15 +379,26 @@ T1 DecodeAny(
|
|||
}
|
||||
}
|
||||
|
||||
data.clear();
|
||||
memory_cleanse(data.data(), data.size());
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
template<typename T1, typename T2>
|
||||
std::optional<T1> DecodeSapling(
|
||||
const KeyConstants& keyConstants,
|
||||
const std::string& str,
|
||||
const std::pair<KeyConstants::Bech32Type, size_t>& keyMeta)
|
||||
{
|
||||
std::vector<unsigned char> data;
|
||||
|
||||
auto bech = bech32::Decode(str);
|
||||
if (bech.first == keyConstants.Bech32HRP(sapling.first) &&
|
||||
bech.second.size() == sapling.second) {
|
||||
if (bech.first == keyConstants.Bech32HRP(keyMeta.first) &&
|
||||
bech.second.size() == keyMeta.second) {
|
||||
// Bech32 decoding
|
||||
data.reserve((bech.second.size() * 5) / 8);
|
||||
if (ConvertBits<5, 8, false>([&](unsigned char c) { data.push_back(c); }, bech.second.begin(), bech.second.end())) {
|
||||
CDataStream ss(data, SER_NETWORK, PROTOCOL_VERSION);
|
||||
T3 ret;
|
||||
T2 ret;
|
||||
ss >> ret;
|
||||
memory_cleanse(data.data(), data.size());
|
||||
return ret;
|
||||
|
@ -393,7 +406,27 @@ T1 DecodeAny(
|
|||
}
|
||||
|
||||
memory_cleanse(data.data(), data.size());
|
||||
return libzcash::InvalidEncoding();
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
template<typename T1, typename T2, typename T3>
|
||||
std::optional<T1> DecodeAny(
|
||||
const KeyConstants& keyConstants,
|
||||
const std::string& str,
|
||||
const std::pair<KeyConstants::Base58Type, size_t>& sproutKeyMeta,
|
||||
const std::pair<KeyConstants::Bech32Type, size_t>& saplingKeyMeta)
|
||||
{
|
||||
auto sprout = DecodeSprout<T1, T2>(keyConstants, str, sproutKeyMeta);
|
||||
if (sprout.has_value()) {
|
||||
return sprout.value();
|
||||
}
|
||||
|
||||
auto sapling = DecodeSapling<T1, T3>(keyConstants, str, saplingKeyMeta);
|
||||
if (sapling.has_value()) {
|
||||
return sapling.value();
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -421,7 +454,7 @@ static bool AddP2SHReceiver(void* ua, const unsigned char* raw)
|
|||
reinterpret_cast<const char*>(raw + 20),
|
||||
SER_NETWORK,
|
||||
PROTOCOL_VERSION);
|
||||
libzcash::P2SHAddress receiver;
|
||||
CScriptID receiver;
|
||||
ss >> receiver;
|
||||
return reinterpret_cast<libzcash::UnifiedAddress*>(ua)->AddReceiver(receiver);
|
||||
}
|
||||
|
@ -436,7 +469,7 @@ static bool AddP2PKHReceiver(void* ua, const unsigned char* raw)
|
|||
reinterpret_cast<const char*>(raw + 20),
|
||||
SER_NETWORK,
|
||||
PROTOCOL_VERSION);
|
||||
libzcash::P2PKHAddress receiver;
|
||||
CKeyID receiver;
|
||||
ss >> receiver;
|
||||
return reinterpret_cast<libzcash::UnifiedAddress*>(ua)->AddReceiver(receiver);
|
||||
}
|
||||
|
@ -447,7 +480,7 @@ static bool AddUnknownReceiver(void* ua, uint32_t typecode, const unsigned char*
|
|||
return reinterpret_cast<libzcash::UnifiedAddress*>(ua)->AddReceiver(receiver);
|
||||
}
|
||||
|
||||
libzcash::PaymentAddress KeyIO::DecodePaymentAddress(const std::string& str)
|
||||
std::optional<libzcash::PaymentAddress> KeyIO::DecodePaymentAddress(const std::string& str)
|
||||
{
|
||||
// Try parsing as a Unified Address.
|
||||
libzcash::UnifiedAddress ua;
|
||||
|
@ -463,19 +496,43 @@ libzcash::PaymentAddress KeyIO::DecodePaymentAddress(const std::string& str)
|
|||
return ua;
|
||||
}
|
||||
|
||||
// Fall back on trying Sprout or Sapling.
|
||||
return DecodeAny<libzcash::PaymentAddress,
|
||||
libzcash::SproutPaymentAddress,
|
||||
libzcash::SaplingPaymentAddress>(
|
||||
// Try parsing as a Sapling address
|
||||
auto sapling = DecodeSapling<libzcash::SaplingPaymentAddress, libzcash::SaplingPaymentAddress>(
|
||||
keyConstants,
|
||||
str,
|
||||
std::make_pair(KeyConstants::ZCPAYMENT_ADDRESS, libzcash::SerializedSproutPaymentAddressSize),
|
||||
std::make_pair(KeyConstants::SAPLING_PAYMENT_ADDRESS, ConvertedSaplingPaymentAddressSize)
|
||||
);
|
||||
std::make_pair(KeyConstants::SAPLING_PAYMENT_ADDRESS, ConvertedSaplingPaymentAddressSize));
|
||||
if (sapling.has_value()) {
|
||||
return sapling.value();
|
||||
}
|
||||
|
||||
// Try parsing as a Sprout address
|
||||
auto sprout = DecodeSprout<libzcash::SproutPaymentAddress, libzcash::SproutPaymentAddress>(
|
||||
keyConstants,
|
||||
str,
|
||||
std::make_pair(KeyConstants::ZCPAYMENT_ADDRESS, libzcash::SerializedSproutPaymentAddressSize));
|
||||
if (sprout.has_value()) {
|
||||
return sprout.value();
|
||||
}
|
||||
|
||||
// Finally, try parsing as transparent
|
||||
return std::visit(match {
|
||||
[](const CKeyID& keyIdIn) {
|
||||
std::optional<libzcash::PaymentAddress> keyId = keyIdIn;
|
||||
return keyId;
|
||||
},
|
||||
[](const CScriptID& scriptIdIn) {
|
||||
std::optional<libzcash::PaymentAddress> scriptId = scriptIdIn;
|
||||
return scriptId;
|
||||
},
|
||||
[](const CNoDestination& d) {
|
||||
std::optional<libzcash::PaymentAddress> result = std::nullopt;
|
||||
return result;
|
||||
}
|
||||
}, DecodeDestination(str));
|
||||
}
|
||||
|
||||
bool KeyIO::IsValidPaymentAddressString(const std::string& str) {
|
||||
return IsValidPaymentAddress(DecodePaymentAddress(str));
|
||||
return DecodePaymentAddress(str).has_value();
|
||||
}
|
||||
|
||||
std::string KeyIO::EncodeViewingKey(const libzcash::ViewingKey& vk)
|
||||
|
@ -483,7 +540,7 @@ std::string KeyIO::EncodeViewingKey(const libzcash::ViewingKey& vk)
|
|||
return std::visit(ViewingKeyEncoder(keyConstants), vk);
|
||||
}
|
||||
|
||||
libzcash::ViewingKey KeyIO::DecodeViewingKey(const std::string& str)
|
||||
std::optional<libzcash::ViewingKey> KeyIO::DecodeViewingKey(const std::string& str)
|
||||
{
|
||||
return DecodeAny<libzcash::ViewingKey,
|
||||
libzcash::SproutViewingKey,
|
||||
|
@ -500,7 +557,7 @@ std::string KeyIO::EncodeSpendingKey(const libzcash::SpendingKey& zkey)
|
|||
return std::visit(SpendingKeyEncoder(keyConstants), zkey);
|
||||
}
|
||||
|
||||
libzcash::SpendingKey KeyIO::DecodeSpendingKey(const std::string& str)
|
||||
std::optional<libzcash::SpendingKey> KeyIO::DecodeSpendingKey(const std::string& str)
|
||||
{
|
||||
|
||||
return DecodeAny<libzcash::SpendingKey,
|
||||
|
|
|
@ -37,14 +37,14 @@ public:
|
|||
bool IsValidDestinationString(const std::string& str);
|
||||
|
||||
std::string EncodePaymentAddress(const libzcash::PaymentAddress& zaddr);
|
||||
libzcash::PaymentAddress DecodePaymentAddress(const std::string& str);
|
||||
std::optional<libzcash::PaymentAddress> DecodePaymentAddress(const std::string& str);
|
||||
bool IsValidPaymentAddressString(const std::string& str);
|
||||
|
||||
std::string EncodeViewingKey(const libzcash::ViewingKey& vk);
|
||||
libzcash::ViewingKey DecodeViewingKey(const std::string& str);
|
||||
std::optional<libzcash::ViewingKey> DecodeViewingKey(const std::string& str);
|
||||
|
||||
std::string EncodeSpendingKey(const libzcash::SpendingKey& zkey);
|
||||
libzcash::SpendingKey DecodeSpendingKey(const std::string& str);
|
||||
std::optional<libzcash::SpendingKey> DecodeSpendingKey(const std::string& str);
|
||||
};
|
||||
|
||||
#endif // BITCOIN_KEY_IO_H
|
||||
|
|
|
@ -151,7 +151,7 @@ bool CBasicKeyStore::AddSproutSpendingKey(const libzcash::SproutSpendingKey &sk)
|
|||
return true;
|
||||
}
|
||||
|
||||
//! Sapling
|
||||
//! Sapling
|
||||
bool CBasicKeyStore::AddSaplingSpendingKey(
|
||||
const libzcash::SaplingExtendedSpendingKey &sk)
|
||||
{
|
||||
|
@ -187,7 +187,7 @@ bool CBasicKeyStore::AddSaplingFullViewingKey(
|
|||
return CBasicKeyStore::AddSaplingIncomingViewingKey(ivk, extfvk.DefaultAddress());
|
||||
}
|
||||
|
||||
// This function updates the wallet's internal address->ivk map.
|
||||
// This function updates the wallet's internal address->ivk map.
|
||||
// If we add an address that is already in the map, the map will
|
||||
// remain unchanged as each address only has one ivk.
|
||||
bool CBasicKeyStore::AddSaplingIncomingViewingKey(
|
||||
|
@ -265,8 +265,9 @@ bool CBasicKeyStore::GetSaplingIncomingViewingKey(const libzcash::SaplingPayment
|
|||
return false;
|
||||
}
|
||||
|
||||
bool CBasicKeyStore::GetSaplingExtendedSpendingKey(const libzcash::SaplingPaymentAddress &addr,
|
||||
libzcash::SaplingExtendedSpendingKey &extskOut) const {
|
||||
bool CBasicKeyStore::GetSaplingExtendedSpendingKey(
|
||||
const libzcash::SaplingPaymentAddress &addr,
|
||||
libzcash::SaplingExtendedSpendingKey &extskOut) const {
|
||||
libzcash::SaplingIncomingViewingKey ivk;
|
||||
libzcash::SaplingExtendedFullViewingKey extfvk;
|
||||
|
||||
|
@ -275,3 +276,13 @@ bool CBasicKeyStore::GetSaplingExtendedSpendingKey(const libzcash::SaplingPaymen
|
|||
GetSaplingFullViewingKey(ivk, extfvk) &&
|
||||
GetSaplingSpendingKey(extfvk, extskOut);
|
||||
}
|
||||
|
||||
bool CBasicKeyStore::HaveSaplingSpendingKeyForAddress(
|
||||
const libzcash::SaplingPaymentAddress &addr) const {
|
||||
libzcash::SaplingIncomingViewingKey ivk;
|
||||
libzcash::SaplingExtendedFullViewingKey extfvk;
|
||||
|
||||
return GetSaplingIncomingViewingKey(addr, ivk) &&
|
||||
GetSaplingFullViewingKey(ivk, extfvk) &&
|
||||
HaveSaplingSpendingKey(extfvk);
|
||||
}
|
||||
|
|
|
@ -66,6 +66,8 @@ public:
|
|||
//! Check whether a Sapling spending key corresponding to a given Sapling viewing key is present in the store.
|
||||
virtual bool HaveSaplingSpendingKey(
|
||||
const libzcash::SaplingExtendedFullViewingKey &extfvk) const =0;
|
||||
virtual bool HaveSaplingSpendingKeyForAddress(
|
||||
const libzcash::SaplingPaymentAddress &addr) const =0;
|
||||
virtual bool GetSaplingSpendingKey(
|
||||
const libzcash::SaplingExtendedFullViewingKey &extfvk,
|
||||
libzcash::SaplingExtendedSpendingKey& skOut) const =0;
|
||||
|
@ -246,6 +248,7 @@ public:
|
|||
}
|
||||
return result;
|
||||
}
|
||||
bool HaveSaplingSpendingKeyForAddress(const libzcash::SaplingPaymentAddress &addr) const;
|
||||
bool GetSaplingSpendingKey(
|
||||
const libzcash::SaplingExtendedFullViewingKey &extfvk,
|
||||
libzcash::SaplingExtendedSpendingKey &skOut) const
|
||||
|
|
|
@ -117,9 +117,7 @@ void UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams,
|
|||
}
|
||||
|
||||
bool IsShieldedMinerAddress(const MinerAddress& minerAddr) {
|
||||
return !(
|
||||
std::holds_alternative<InvalidMinerAddress>(minerAddr) ||
|
||||
std::holds_alternative<boost::shared_ptr<CReserveScript>>(minerAddr));
|
||||
return !std::holds_alternative<boost::shared_ptr<CReserveScript>>(minerAddr);
|
||||
}
|
||||
|
||||
class AddFundingStreamValueToTx
|
||||
|
@ -241,8 +239,6 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
void operator()(const InvalidMinerAddress &invalid) const {}
|
||||
|
||||
// Create shielded output
|
||||
void operator()(const libzcash::SaplingPaymentAddress &pa) const {
|
||||
auto ctx = librustzcash_sapling_proving_ctx_init();
|
||||
|
@ -706,24 +702,40 @@ class MinerAddressScript : public CReserveScript
|
|||
void KeepScript() {}
|
||||
};
|
||||
|
||||
std::optional<MinerAddress> ExtractMinerAddress::operator()(const CKeyID &keyID) const {
|
||||
boost::shared_ptr<MinerAddressScript> mAddr(new MinerAddressScript());
|
||||
mAddr->reserveScript = CScript() << OP_DUP << OP_HASH160 << ToByteVector(keyID) << OP_EQUALVERIFY << OP_CHECKSIG;
|
||||
return mAddr;
|
||||
}
|
||||
std::optional<MinerAddress> ExtractMinerAddress::operator()(const CScriptID &addr) const {
|
||||
return std::nullopt;
|
||||
}
|
||||
std::optional<MinerAddress> ExtractMinerAddress::operator()(const libzcash::SproutPaymentAddress &addr) const {
|
||||
return std::nullopt;
|
||||
}
|
||||
std::optional<MinerAddress> ExtractMinerAddress::operator()(const libzcash::SaplingPaymentAddress &addr) const {
|
||||
return addr;
|
||||
}
|
||||
std::optional<MinerAddress> ExtractMinerAddress::operator()(const libzcash::UnifiedAddress &addr) const {
|
||||
for (const auto& receiver: addr) {
|
||||
if (std::holds_alternative<libzcash::SaplingPaymentAddress>(receiver)) {
|
||||
return std::get<libzcash::SaplingPaymentAddress>(receiver);
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
|
||||
void GetMinerAddress(MinerAddress &minerAddress)
|
||||
{
|
||||
KeyIO keyIO(Params());
|
||||
|
||||
// Try a transparent address first
|
||||
auto mAddrArg = GetArg("-mineraddress", "");
|
||||
CTxDestination addr = keyIO.DecodeDestination(mAddrArg);
|
||||
if (IsValidDestination(addr)) {
|
||||
boost::shared_ptr<MinerAddressScript> mAddr(new MinerAddressScript());
|
||||
CKeyID keyID = std::get<CKeyID>(addr);
|
||||
|
||||
mAddr->reserveScript = CScript() << OP_DUP << OP_HASH160 << ToByteVector(keyID) << OP_EQUALVERIFY << OP_CHECKSIG;
|
||||
minerAddress = mAddr;
|
||||
} else {
|
||||
// Try a payment address
|
||||
auto zaddr = std::visit(ExtractMinerAddress(), keyIO.DecodePaymentAddress(mAddrArg));
|
||||
if (std::visit(IsValidMinerAddress(), zaddr)) {
|
||||
minerAddress = zaddr;
|
||||
auto zaddr0 = keyIO.DecodePaymentAddress(mAddrArg);
|
||||
if (zaddr0.has_value()) {
|
||||
auto zaddr = std::visit(ExtractMinerAddress(), zaddr0.value());
|
||||
if (zaddr.has_value()) {
|
||||
minerAddress = zaddr.value();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
46
src/miner.h
46
src/miner.h
|
@ -23,14 +23,7 @@ static const int DEFAULT_GENERATE_THREADS = 1;
|
|||
|
||||
static const bool DEFAULT_PRINTPRIORITY = false;
|
||||
|
||||
class InvalidMinerAddress {
|
||||
public:
|
||||
friend bool operator==(const InvalidMinerAddress &a, const InvalidMinerAddress &b) { return true; }
|
||||
friend bool operator<(const InvalidMinerAddress &a, const InvalidMinerAddress &b) { return true; }
|
||||
};
|
||||
|
||||
typedef std::variant<
|
||||
InvalidMinerAddress,
|
||||
libzcash::SaplingPaymentAddress,
|
||||
boost::shared_ptr<CReserveScript>> MinerAddress;
|
||||
|
||||
|
@ -39,36 +32,11 @@ class ExtractMinerAddress
|
|||
public:
|
||||
ExtractMinerAddress() {}
|
||||
|
||||
MinerAddress operator()(const libzcash::InvalidEncoding &invalid) const {
|
||||
return InvalidMinerAddress();
|
||||
}
|
||||
MinerAddress operator()(const libzcash::SproutPaymentAddress &addr) const {
|
||||
return InvalidMinerAddress();
|
||||
}
|
||||
MinerAddress operator()(const libzcash::SaplingPaymentAddress &addr) const {
|
||||
return addr;
|
||||
}
|
||||
MinerAddress operator()(const libzcash::UnifiedAddress &addr) const {
|
||||
auto recipient = RecipientForPaymentAddress()(addr);
|
||||
if (recipient) {
|
||||
// This looks like a recursive call, but we are actually calling
|
||||
// ExtractMinerAddress with a different type:
|
||||
// - libzcash::PaymentAddress has a libzcash::UnifiedAddress
|
||||
// alternative, which invokes this method.
|
||||
// - RecipientForPaymentAddress() returns libzcash::RawAddress,
|
||||
// which does not have a libzcash::UnifiedAddress alternative.
|
||||
//
|
||||
// This works because std::visit does not require the visitor to
|
||||
// solely match the std::variant, only that it can handle all of
|
||||
// the variant's alternatives.
|
||||
return std::visit(ExtractMinerAddress(), *recipient);
|
||||
} else {
|
||||
// Either the UA only contains unknown shielded receivers (unlikely that we
|
||||
// wouldn't know about them), or it only contains transparent receivers
|
||||
// (which are invalid).
|
||||
return InvalidMinerAddress();
|
||||
}
|
||||
}
|
||||
std::optional<MinerAddress> operator()(const CKeyID &keyID) const;
|
||||
std::optional<MinerAddress> operator()(const CScriptID &addr) const;
|
||||
std::optional<MinerAddress> operator()(const libzcash::SproutPaymentAddress &addr) const;
|
||||
std::optional<MinerAddress> operator()(const libzcash::SaplingPaymentAddress &addr) const;
|
||||
std::optional<MinerAddress> operator()(const libzcash::UnifiedAddress &addr) const;
|
||||
};
|
||||
|
||||
class KeepMinerAddress
|
||||
|
@ -76,7 +44,6 @@ class KeepMinerAddress
|
|||
public:
|
||||
KeepMinerAddress() {}
|
||||
|
||||
void operator()(const InvalidMinerAddress &invalid) const {}
|
||||
void operator()(const libzcash::SaplingPaymentAddress &pa) const {}
|
||||
void operator()(const boost::shared_ptr<CReserveScript> &coinbaseScript) const {
|
||||
coinbaseScript->KeepScript();
|
||||
|
@ -90,9 +57,6 @@ class IsValidMinerAddress
|
|||
public:
|
||||
IsValidMinerAddress() {}
|
||||
|
||||
bool operator()(const InvalidMinerAddress &invalid) const {
|
||||
return false;
|
||||
}
|
||||
bool operator()(const libzcash::SaplingPaymentAddress &pa) const {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ class CKeyID : public uint160
|
|||
public:
|
||||
CKeyID() : uint160() {}
|
||||
CKeyID(const uint160& in) : uint160(in) {}
|
||||
explicit CKeyID(const std::vector<unsigned char>& vch) : uint160(vch) {}
|
||||
};
|
||||
|
||||
typedef uint256 ChainCode;
|
||||
|
|
|
@ -217,7 +217,27 @@ UniValue validateaddress(const UniValue& params, bool fHelp)
|
|||
class DescribePaymentAddressVisitor
|
||||
{
|
||||
public:
|
||||
UniValue operator()(const libzcash::InvalidEncoding &zaddr) const { return UniValue(UniValue::VOBJ); }
|
||||
UniValue operator()(const CKeyID &addr) const {
|
||||
UniValue obj(UniValue::VOBJ);
|
||||
obj.pushKV("type", "p2pkh");
|
||||
#ifdef ENABLE_WALLET
|
||||
if (pwalletMain) {
|
||||
obj.pushKV("ismine", pwalletMain->HaveKey(addr));
|
||||
}
|
||||
#endif
|
||||
return obj;
|
||||
}
|
||||
|
||||
UniValue operator()(const CScriptID &addr) const {
|
||||
UniValue obj(UniValue::VOBJ);
|
||||
obj.pushKV("type", "p2sh");
|
||||
#ifdef ENABLE_WALLET
|
||||
if (pwalletMain) {
|
||||
obj.pushKV("ismine", pwalletMain->HaveCScript(addr));
|
||||
}
|
||||
#endif
|
||||
return obj;
|
||||
}
|
||||
|
||||
UniValue operator()(const libzcash::SproutPaymentAddress &zaddr) const {
|
||||
UniValue obj(UniValue::VOBJ);
|
||||
|
@ -226,7 +246,7 @@ public:
|
|||
obj.pushKV("transmissionkey", zaddr.pk_enc.GetHex());
|
||||
#ifdef ENABLE_WALLET
|
||||
if (pwalletMain) {
|
||||
obj.pushKV("ismine", HaveSpendingKeyForPaymentAddress(pwalletMain)(zaddr));
|
||||
obj.pushKV("ismine", pwalletMain->HaveSproutSpendingKey(zaddr));
|
||||
}
|
||||
#endif
|
||||
return obj;
|
||||
|
@ -239,7 +259,7 @@ public:
|
|||
obj.pushKV("diversifiedtransmissionkey", zaddr.pk_d.GetHex());
|
||||
#ifdef ENABLE_WALLET
|
||||
if (pwalletMain) {
|
||||
obj.pushKV("ismine", HaveSpendingKeyForPaymentAddress(pwalletMain)(zaddr));
|
||||
obj.pushKV("ismine", pwalletMain->HaveSaplingSpendingKeyForAddress(zaddr));
|
||||
}
|
||||
#endif
|
||||
return obj;
|
||||
|
@ -257,16 +277,16 @@ UniValue z_validateaddress(const UniValue& params, bool fHelp)
|
|||
{
|
||||
if (fHelp || params.size() != 1)
|
||||
throw runtime_error(
|
||||
"z_validateaddress \"zaddr\"\n"
|
||||
"\nReturn information about the given z address.\n"
|
||||
"z_validateaddress \"address\"\n"
|
||||
"\nReturn information about the given address.\n"
|
||||
"\nArguments:\n"
|
||||
"1. \"zaddr\" (string, required) The z address to validate\n"
|
||||
"1. \"address\" (string, required) The address to validate\n"
|
||||
"\nResult:\n"
|
||||
"{\n"
|
||||
" \"isvalid\" : true|false, (boolean) If the address is valid or not. If not, this is the only property returned.\n"
|
||||
" \"address\" : \"zaddr\", (string) The z address validated\n"
|
||||
" \"type\" : \"xxxx\", (string) \"sprout\" or \"sapling\"\n"
|
||||
" \"ismine\" : true|false, (boolean) If the address is yours or not\n"
|
||||
" \"isvalid\" : true|false, (boolean) If the address is valid or not. If not, this is the only property returned.\n"
|
||||
" \"address\" : \"addr\", (string) The address validated\n"
|
||||
" \"type\" : \"xxxx\", (string) \"p2pkh\", \"p2sh\", \"sprout\" or \"sapling\"\n"
|
||||
" \"ismine\" : true|false, (boolean) If the address is yours or not\n"
|
||||
" \"payingkey\" : \"hex\", (string) [sprout] The hex value of the paying key, a_pk\n"
|
||||
" \"transmissionkey\" : \"hex\", (string) [sprout] The hex value of the transmission key, pk_enc\n"
|
||||
" \"diversifier\" : \"hex\", (string) [sapling] The hex value of the diversifier, d\n"
|
||||
|
@ -288,14 +308,14 @@ UniValue z_validateaddress(const UniValue& params, bool fHelp)
|
|||
KeyIO keyIO(Params());
|
||||
string strAddress = params[0].get_str();
|
||||
auto address = keyIO.DecodePaymentAddress(strAddress);
|
||||
bool isValid = IsValidPaymentAddress(address);
|
||||
bool isValid = address.has_value();
|
||||
|
||||
UniValue ret(UniValue::VOBJ);
|
||||
ret.pushKV("isvalid", isValid);
|
||||
if (isValid)
|
||||
{
|
||||
ret.pushKV("address", strAddress);
|
||||
UniValue detail = std::visit(DescribePaymentAddressVisitor(), address);
|
||||
UniValue detail = std::visit(DescribePaymentAddressVisitor(), address.value());
|
||||
ret.pushKVs(detail);
|
||||
}
|
||||
return ret;
|
||||
|
|
|
@ -625,6 +625,16 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
/** A reference to a CScript: the Hash160 of its serialization */
|
||||
class CScriptID : public uint160
|
||||
{
|
||||
public:
|
||||
CScriptID() : uint160() {}
|
||||
explicit CScriptID(const CScript& in);
|
||||
CScriptID(const uint160& in) : uint160(in) {}
|
||||
explicit CScriptID(const std::vector<unsigned char>& vch) : uint160(vch) {}
|
||||
};
|
||||
|
||||
class CReserveScript
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -18,15 +18,6 @@ static const bool DEFAULT_ACCEPT_DATACARRIER = true;
|
|||
class CKeyID;
|
||||
class CScript;
|
||||
|
||||
/** A reference to a CScript: the Hash160 of its serialization (see script.h) */
|
||||
class CScriptID : public uint160
|
||||
{
|
||||
public:
|
||||
CScriptID() : uint160() {}
|
||||
explicit CScriptID(const CScript& in);
|
||||
CScriptID(const uint160& in) : uint160(in) {}
|
||||
};
|
||||
|
||||
/**
|
||||
* Default setting for nMaxDatacarrierBytes. 80 bytes of data, +1 for OP_RETURN,
|
||||
* +2 for the pushdata opcodes.
|
||||
|
|
|
@ -202,9 +202,9 @@ BOOST_AUTO_TEST_CASE(zc_address_test)
|
|||
BOOST_CHECK(sk_string[1] == 'K');
|
||||
|
||||
auto spendingkey2 = keyIO.DecodeSpendingKey(sk_string);
|
||||
BOOST_CHECK(IsValidSpendingKey(spendingkey2));
|
||||
BOOST_ASSERT(std::get_if<SproutSpendingKey>(&spendingkey2) != nullptr);
|
||||
auto sk2 = std::get<SproutSpendingKey>(spendingkey2);
|
||||
BOOST_CHECK(spendingkey2.has_value());
|
||||
BOOST_ASSERT(std::get_if<SproutSpendingKey>(&spendingkey2.value()) != nullptr);
|
||||
auto sk2 = std::get<SproutSpendingKey>(spendingkey2.value());
|
||||
BOOST_CHECK(sk.inner() == sk2.inner());
|
||||
}
|
||||
{
|
||||
|
@ -216,10 +216,10 @@ BOOST_AUTO_TEST_CASE(zc_address_test)
|
|||
BOOST_CHECK(addr_string[1] == 'c');
|
||||
|
||||
auto paymentaddr2 = keyIO.DecodePaymentAddress(addr_string);
|
||||
BOOST_ASSERT(IsValidPaymentAddress(paymentaddr2));
|
||||
BOOST_ASSERT(paymentaddr2.has_value());
|
||||
|
||||
BOOST_ASSERT(std::get_if<SproutPaymentAddress>(&paymentaddr2) != nullptr);
|
||||
auto addr2 = std::get<SproutPaymentAddress>(paymentaddr2);
|
||||
BOOST_ASSERT(std::get_if<SproutPaymentAddress>(&paymentaddr2.value()) != nullptr);
|
||||
auto addr2 = std::get<SproutPaymentAddress>(paymentaddr2.value());
|
||||
BOOST_CHECK(addr.a_pk == addr2.a_pk);
|
||||
BOOST_CHECK(addr.pk_enc == addr2.pk_enc);
|
||||
}
|
||||
|
@ -240,10 +240,10 @@ BOOST_AUTO_TEST_CASE(zs_address_test)
|
|||
BOOST_CHECK(sk_string.compare(0, 27, Params().Bech32HRP(CChainParams::SAPLING_EXTENDED_SPEND_KEY)) == 0);
|
||||
|
||||
auto spendingkey2 = keyIO.DecodeSpendingKey(sk_string);
|
||||
BOOST_CHECK(IsValidSpendingKey(spendingkey2));
|
||||
BOOST_CHECK(spendingkey2.has_value());
|
||||
|
||||
BOOST_ASSERT(std::get_if<SaplingExtendedSpendingKey>(&spendingkey2) != nullptr);
|
||||
auto sk2 = std::get<SaplingExtendedSpendingKey>(spendingkey2);
|
||||
BOOST_ASSERT(std::get_if<SaplingExtendedSpendingKey>(&spendingkey2.value()) != nullptr);
|
||||
auto sk2 = std::get<SaplingExtendedSpendingKey>(spendingkey2.value());
|
||||
BOOST_CHECK(sk == sk2);
|
||||
}
|
||||
{
|
||||
|
@ -253,10 +253,10 @@ BOOST_AUTO_TEST_CASE(zs_address_test)
|
|||
BOOST_CHECK(addr_string.compare(0, 15, Params().Bech32HRP(CChainParams::SAPLING_PAYMENT_ADDRESS)) == 0);
|
||||
|
||||
auto paymentaddr2 = keyIO.DecodePaymentAddress(addr_string);
|
||||
BOOST_CHECK(IsValidPaymentAddress(paymentaddr2));
|
||||
BOOST_CHECK(paymentaddr2.has_value());
|
||||
|
||||
BOOST_ASSERT(std::get_if<SaplingPaymentAddress>(&paymentaddr2) != nullptr);
|
||||
auto addr2 = std::get<SaplingPaymentAddress>(paymentaddr2);
|
||||
BOOST_ASSERT(std::get_if<SaplingPaymentAddress>(&paymentaddr2.value()) != nullptr);
|
||||
auto addr2 = std::get<SaplingPaymentAddress>(paymentaddr2.value());
|
||||
BOOST_CHECK(addr == addr2);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
// Copyright (c) 2021 The Zcash developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or https://www.opensource.org/licenses/mit-license.php .
|
||||
|
||||
#ifndef ZCASH_UTIL_MATCH_H
|
||||
#define ZCASH_UTIL_MATCH_H
|
||||
|
||||
// Helper for using `std::visit` with Rust-style match syntax.
|
||||
//
|
||||
// This can be used in place of defining an explicit visitor. `std::visit` requires an
|
||||
// exhaustive match; to emulate Rust's catch-all binding, use an `(auto arg)` template
|
||||
// operator().
|
||||
//
|
||||
// Care must be taken that implicit conversions are handled correctly. For instance, a
|
||||
// `(double arg)` operator() *will also* bind to `int` and `long`, if there isn't an
|
||||
// earlier satisfying match.
|
||||
//
|
||||
// This corresponds to visitor example #4 in the `std::visit` documentation:
|
||||
// https://en.cppreference.com/w/cpp/utility/variant/visit
|
||||
template<class... Ts> struct match : Ts... { using Ts::operator()...; };
|
||||
// explicit deduction guide (not needed as of C++20)
|
||||
template<class... Ts> match(Ts...) -> match<Ts...>;
|
||||
|
||||
#endif // ZCASH_UTIL_MATCH_H
|
|
@ -22,6 +22,7 @@
|
|||
#include "timedata.h"
|
||||
#include "transaction_builder.h"
|
||||
#include "util.h"
|
||||
#include "util/match.h"
|
||||
#include "utilmoneystr.h"
|
||||
#include "utiltime.h"
|
||||
#include "wallet.h"
|
||||
|
@ -67,7 +68,7 @@ AsyncRPCOperation_mergetoaddress::AsyncRPCOperation_mergetoaddress(
|
|||
CAmount fee,
|
||||
UniValue contextInfo) :
|
||||
tx_(contextualTx), utxoInputs_(utxoInputs), sproutNoteInputs_(sproutNoteInputs),
|
||||
saplingNoteInputs_(saplingNoteInputs), recipient_(recipient), fee_(fee), contextinfo_(contextInfo)
|
||||
saplingNoteInputs_(saplingNoteInputs), memo_(recipient.second), fee_(fee), contextinfo_(contextInfo)
|
||||
{
|
||||
if (fee < 0 || fee > MAX_MONEY) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Fee is out of range");
|
||||
|
@ -77,10 +78,6 @@ AsyncRPCOperation_mergetoaddress::AsyncRPCOperation_mergetoaddress(
|
|||
throw JSONRPCError(RPC_INVALID_PARAMETER, "No inputs");
|
||||
}
|
||||
|
||||
if (std::get<0>(recipient).size() == 0) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Recipient parameter missing");
|
||||
}
|
||||
|
||||
if (sproutNoteInputs.size() > 0 && saplingNoteInputs.size() > 0) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot send from both Sprout and Sapling addresses using z_mergetoaddress");
|
||||
}
|
||||
|
@ -96,19 +93,32 @@ AsyncRPCOperation_mergetoaddress::AsyncRPCOperation_mergetoaddress(
|
|||
}
|
||||
|
||||
KeyIO keyIO(Params());
|
||||
toTaddr_ = keyIO.DecodeDestination(std::get<0>(recipient));
|
||||
isToTaddr_ = IsValidDestination(toTaddr_);
|
||||
isToTaddr_ = false;
|
||||
isToZaddr_ = false;
|
||||
|
||||
if (!isToTaddr_) {
|
||||
auto address = keyIO.DecodePaymentAddress(std::get<0>(recipient));
|
||||
if (IsValidPaymentAddress(address)) {
|
||||
std::visit(match {
|
||||
[&](const CKeyID& keyId) {
|
||||
toTaddr_ = keyId;
|
||||
isToTaddr_ = true;
|
||||
},
|
||||
[&](const CScriptID& scriptId) {
|
||||
toTaddr_ = scriptId;
|
||||
isToTaddr_ = true;
|
||||
},
|
||||
[&](const libzcash::SproutPaymentAddress& addr) {
|
||||
toPaymentAddress_ = addr;
|
||||
isToZaddr_ = true;
|
||||
toPaymentAddress_ = address;
|
||||
} else {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid recipient address");
|
||||
}
|
||||
}
|
||||
},
|
||||
[&](const libzcash::SaplingPaymentAddress& addr) {
|
||||
toPaymentAddress_ = addr;
|
||||
isToZaddr_ = true;
|
||||
},
|
||||
[&](const libzcash::UnifiedAddress& addr) {
|
||||
throw JSONRPCError(
|
||||
RPC_INVALID_ADDRESS_OR_KEY,
|
||||
"z_mergetoaddress does not yet support sending to unified addresses");
|
||||
},
|
||||
}, recipient.first);
|
||||
|
||||
// Log the context info i.e. the call parameters to z_mergetoaddress
|
||||
if (LogAcceptCategory("zrpcunsafe")) {
|
||||
|
@ -331,9 +341,7 @@ bool AsyncRPCOperation_mergetoaddress::main_impl()
|
|||
if (isToTaddr_) {
|
||||
builder_.AddTransparentOutput(toTaddr_, sendAmount);
|
||||
} else {
|
||||
std::string zaddr = std::get<0>(recipient_);
|
||||
std::string memo = std::get<1>(recipient_);
|
||||
std::array<unsigned char, ZC_MEMO_SIZE> hexMemo = get_memo_from_hex_string(memo);
|
||||
std::array<unsigned char, ZC_MEMO_SIZE> hexMemo = get_memo_from_hex_string(memo_);
|
||||
auto saplingPaymentAddress = std::get_if<libzcash::SaplingPaymentAddress>(&toPaymentAddress_);
|
||||
if (saplingPaymentAddress == nullptr) {
|
||||
// This should never happen as we have already determined that the payment is to sapling
|
||||
|
@ -385,14 +393,11 @@ bool AsyncRPCOperation_mergetoaddress::main_impl()
|
|||
* END SCENARIO #1
|
||||
*/
|
||||
|
||||
|
||||
// Prepare raw transaction to handle JoinSplits
|
||||
CMutableTransaction mtx(tx_);
|
||||
ed25519_generate_keypair(&joinSplitPrivKey_, &joinSplitPubKey_);
|
||||
mtx.joinSplitPubKey = joinSplitPubKey_;
|
||||
tx_ = CTransaction(mtx);
|
||||
std::string hexMemo = std::get<1>(recipient_);
|
||||
|
||||
|
||||
/**
|
||||
* SCENARIO #2
|
||||
|
@ -408,8 +413,8 @@ bool AsyncRPCOperation_mergetoaddress::main_impl()
|
|||
info.vpub_new = 0;
|
||||
|
||||
JSOutput jso = JSOutput(std::get<libzcash::SproutPaymentAddress>(toPaymentAddress_), sendAmount);
|
||||
if (hexMemo.size() > 0) {
|
||||
jso.memo = get_memo_from_hex_string(hexMemo);
|
||||
if (memo_.size() > 0) {
|
||||
jso.memo = get_memo_from_hex_string(memo_);
|
||||
}
|
||||
info.vjsout.push_back(jso);
|
||||
|
||||
|
@ -697,8 +702,8 @@ bool AsyncRPCOperation_mergetoaddress::main_impl()
|
|||
if (isToZaddr_ && vpubNewProcessed) {
|
||||
outputType = "target";
|
||||
jso.addr = std::get<libzcash::SproutPaymentAddress>(toPaymentAddress_);
|
||||
if (!hexMemo.empty()) {
|
||||
jso.memo = get_memo_from_hex_string(hexMemo);
|
||||
if (!memo_.empty()) {
|
||||
jso.memo = get_memo_from_hex_string(memo_);
|
||||
}
|
||||
}
|
||||
info.vjsout.push_back(jso);
|
||||
|
|
|
@ -34,7 +34,7 @@ typedef std::tuple<JSOutPoint, SproutNote, CAmount, SproutSpendingKey> MergeToAd
|
|||
typedef std::tuple<SaplingOutPoint, SaplingNote, CAmount, SaplingExpandedSpendingKey> MergeToAddressInputSaplingNote;
|
||||
|
||||
// A recipient is a tuple of address, memo (optional if zaddr)
|
||||
typedef std::tuple<std::string, std::string> MergeToAddressRecipient;
|
||||
typedef std::pair<libzcash::PaymentAddress, std::string> MergeToAddressRecipient;
|
||||
|
||||
// Package of info which is passed to perform_joinsplit methods.
|
||||
struct MergeToAddressJSInfo {
|
||||
|
@ -89,11 +89,11 @@ private:
|
|||
uint32_t consensusBranchId_;
|
||||
CAmount fee_;
|
||||
int mindepth_;
|
||||
MergeToAddressRecipient recipient_;
|
||||
bool isToTaddr_;
|
||||
bool isToZaddr_;
|
||||
CTxDestination toTaddr_;
|
||||
PaymentAddress toPaymentAddress_;
|
||||
std::string memo_;
|
||||
|
||||
Ed25519VerificationKey joinSplitPubKey_;
|
||||
Ed25519SigningKey joinSplitPrivKey_;
|
||||
|
|
|
@ -85,7 +85,7 @@ bool AsyncRPCOperation_saplingmigration::main_impl() {
|
|||
// We set minDepth to 11 to avoid unconfirmed notes and in anticipation of specifying
|
||||
// an anchor at height N-10 for each Sprout JoinSplit description
|
||||
// Consider, should notes be sorted?
|
||||
pwalletMain->GetFilteredNotes(sproutEntries, saplingEntries, "", 11);
|
||||
pwalletMain->GetFilteredNotes(sproutEntries, saplingEntries, std::nullopt, 11);
|
||||
}
|
||||
CAmount availableFunds = 0;
|
||||
for (const SproutNoteEntry& sproutEntry : sproutEntries) {
|
||||
|
@ -197,8 +197,9 @@ libzcash::SaplingPaymentAddress AsyncRPCOperation_saplingmigration::getMigration
|
|||
if (mapArgs.count("-migrationdestaddress")) {
|
||||
std::string migrationDestAddress = mapArgs["-migrationdestaddress"];
|
||||
auto address = keyIO.DecodePaymentAddress(migrationDestAddress);
|
||||
auto saplingAddress = std::get_if<libzcash::SaplingPaymentAddress>(&address);
|
||||
assert(saplingAddress != nullptr); // This is checked in init.cpp
|
||||
assert(address.has_value()); // This is checked in init.cpp
|
||||
auto saplingAddress = std::get_if<libzcash::SaplingPaymentAddress>(&address.value());
|
||||
assert(saplingAddress != nullptr); // This is also checked in init.cpp
|
||||
return *saplingAddress;
|
||||
}
|
||||
// Derive the address for Sapling account 0
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "transaction_builder.h"
|
||||
#include "timedata.h"
|
||||
#include "util.h"
|
||||
#include "util/match.h"
|
||||
#include "utilmoneystr.h"
|
||||
#include "wallet.h"
|
||||
#include "walletdb.h"
|
||||
|
@ -92,21 +93,41 @@ AsyncRPCOperation_sendmany::AsyncRPCOperation_sendmany(
|
|||
KeyIO keyIO(Params());
|
||||
|
||||
useanyutxo_ = fromAddress == "ANY_TADDR";
|
||||
fromtaddr_ = keyIO.DecodeDestination(fromAddress);
|
||||
isfromtaddr_ = useanyutxo_ || IsValidDestination(fromtaddr_);
|
||||
isfromzaddr_ = false;
|
||||
|
||||
if (!isfromtaddr_) {
|
||||
if (useanyutxo_) {
|
||||
isfromtaddr_ = true;
|
||||
} else {
|
||||
auto address = keyIO.DecodePaymentAddress(fromAddress);
|
||||
if (IsValidPaymentAddress(address)) {
|
||||
if (address.has_value()) {
|
||||
// We don't need to lock on the wallet as spending key related methods are thread-safe
|
||||
if (!std::visit(HaveSpendingKeyForPaymentAddress(pwalletMain), address)) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, no spending key found for zaddr");
|
||||
if (!std::visit(HaveSpendingKeyForPaymentAddress(pwalletMain), address.value())) {
|
||||
throw JSONRPCError(
|
||||
RPC_INVALID_ADDRESS_OR_KEY,
|
||||
"Invalid from address, no spending key found for address");
|
||||
}
|
||||
|
||||
isfromzaddr_ = true;
|
||||
frompaymentaddress_ = address;
|
||||
spendingkey_ = std::visit(GetSpendingKeyForPaymentAddress(pwalletMain), address).value();
|
||||
std::visit(match {
|
||||
[&](const CKeyID& keyId) {
|
||||
fromtaddr_ = keyId;
|
||||
isfromtaddr_ = true;
|
||||
},
|
||||
[&](const CScriptID& scriptId) {
|
||||
fromtaddr_ = scriptId;
|
||||
isfromtaddr_ = true;
|
||||
},
|
||||
[&](const libzcash::SproutPaymentAddress& addr) {
|
||||
frompaymentaddress_ = addr;
|
||||
isfromzaddr_ = true;
|
||||
},
|
||||
[&](const libzcash::SaplingPaymentAddress& addr) {
|
||||
frompaymentaddress_ = addr;
|
||||
isfromzaddr_ = true;
|
||||
},
|
||||
[&](const libzcash::UnifiedAddress& addr) {
|
||||
throw JSONRPCError(
|
||||
RPC_INVALID_ADDRESS_OR_KEY,
|
||||
"Unified addresses are not yet supported by z_sendmany");
|
||||
}
|
||||
}, address.value());
|
||||
} else {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address");
|
||||
}
|
||||
|
@ -306,9 +327,9 @@ bool AsyncRPCOperation_sendmany::main_impl() {
|
|||
// Get various necessary keys
|
||||
SaplingExpandedSpendingKey expsk;
|
||||
uint256 ovk;
|
||||
if (isfromzaddr_) {
|
||||
auto sk = std::get<libzcash::SaplingExtendedSpendingKey>(spendingkey_);
|
||||
expsk = sk.expsk;
|
||||
auto saplingKey = std::visit(GetSaplingKeyForPaymentAddress(pwalletMain), frompaymentaddress_);
|
||||
if (saplingKey.has_value()) {
|
||||
expsk = saplingKey.value().expsk;
|
||||
ovk = expsk.full_viewing_key().ovk;
|
||||
} else {
|
||||
// Sending from a t-address, which we don't have an ovk for. Instead,
|
||||
|
@ -375,8 +396,8 @@ bool AsyncRPCOperation_sendmany::main_impl() {
|
|||
auto hexMemo = r.memo;
|
||||
|
||||
auto addr = keyIO.DecodePaymentAddress(address);
|
||||
assert(std::get_if<libzcash::SaplingPaymentAddress>(&addr) != nullptr);
|
||||
auto to = std::get<libzcash::SaplingPaymentAddress>(addr);
|
||||
assert(addr.has_value() && std::get_if<libzcash::SaplingPaymentAddress>(&addr.value()) != nullptr);
|
||||
auto to = std::get<libzcash::SaplingPaymentAddress>(addr.value());
|
||||
|
||||
auto memo = get_memo_from_hex_string(hexMemo);
|
||||
|
||||
|
@ -533,12 +554,14 @@ bool AsyncRPCOperation_sendmany::main_impl() {
|
|||
std::string hexMemo = smr.memo;
|
||||
zOutputsDeque.pop_front();
|
||||
|
||||
PaymentAddress pa = keyIO.DecodePaymentAddress(address);
|
||||
JSOutput jso = JSOutput(std::get<libzcash::SproutPaymentAddress>(pa), value);
|
||||
if (hexMemo.size() > 0) {
|
||||
jso.memo = get_memo_from_hex_string(hexMemo);
|
||||
std::optional<PaymentAddress> pa = keyIO.DecodePaymentAddress(address);
|
||||
if (pa.has_value()) {
|
||||
JSOutput jso = JSOutput(std::get<libzcash::SproutPaymentAddress>(pa.value()), value);
|
||||
if (hexMemo.size() > 0) {
|
||||
jso.memo = get_memo_from_hex_string(hexMemo);
|
||||
}
|
||||
info.vjsout.push_back(jso);
|
||||
}
|
||||
info.vjsout.push_back(jso);
|
||||
|
||||
// Funds are removed from the value pool and enter the private pool
|
||||
info.vpub_old += value;
|
||||
|
@ -639,7 +662,9 @@ bool AsyncRPCOperation_sendmany::main_impl() {
|
|||
intermediates.insert(std::make_pair(tree.root(), tree)); // chained js are interstitial (found in between block boundaries)
|
||||
|
||||
// Decrypt the change note's ciphertext to retrieve some data we need
|
||||
ZCNoteDecryption decryptor(std::get<libzcash::SproutSpendingKey>(spendingkey_).receiving_key());
|
||||
// FIXME: make sure this .value() call is safe
|
||||
auto sk = std::visit(GetSproutKeyForPaymentAddress(pwalletMain), frompaymentaddress_).value();
|
||||
ZCNoteDecryption decryptor(sk.receiving_key());
|
||||
auto hSig = ZCJoinSplit::h_sig(
|
||||
prevJoinSplit.randomSeed,
|
||||
prevJoinSplit.nullifiers,
|
||||
|
@ -800,13 +825,15 @@ bool AsyncRPCOperation_sendmany::main_impl() {
|
|||
assert(value==0);
|
||||
info.vjsout.push_back(JSOutput()); // dummy output while we accumulate funds into a change note for vpub_new
|
||||
} else {
|
||||
PaymentAddress pa = keyIO.DecodePaymentAddress(address);
|
||||
// If we are here, we know we have no Sapling outputs.
|
||||
JSOutput jso = JSOutput(std::get<libzcash::SproutPaymentAddress>(pa), value);
|
||||
if (hexMemo.size() > 0) {
|
||||
jso.memo = get_memo_from_hex_string(hexMemo);
|
||||
std::optional<PaymentAddress> pa = keyIO.DecodePaymentAddress(address);
|
||||
if (pa.has_value()) {
|
||||
// If we are here, we know we have no Sapling outputs.
|
||||
JSOutput jso = JSOutput(std::get<libzcash::SproutPaymentAddress>(pa.value()), value);
|
||||
if (hexMemo.size() > 0) {
|
||||
jso.memo = get_memo_from_hex_string(hexMemo);
|
||||
}
|
||||
info.vjsout.push_back(jso);
|
||||
}
|
||||
info.vjsout.push_back(jso);
|
||||
}
|
||||
|
||||
// create output for any change
|
||||
|
@ -927,7 +954,13 @@ bool AsyncRPCOperation_sendmany::load_inputs(TxValues& txValues) {
|
|||
bool AsyncRPCOperation_sendmany::find_unspent_notes() {
|
||||
std::vector<SproutNoteEntry> sproutEntries;
|
||||
std::vector<SaplingNoteEntry> saplingEntries;
|
||||
pwalletMain->GetFilteredNotes(sproutEntries, saplingEntries, fromaddress_, mindepth_);
|
||||
// TODO: move this to the caller
|
||||
auto zaddr = KeyIO(Params()).DecodePaymentAddress(fromaddress_);
|
||||
std::optional<AddrSet> noteFilter = std::nullopt;
|
||||
if (zaddr.has_value()) {
|
||||
noteFilter = AddrSet::ForPaymentAddresses(std::vector({zaddr.value()}));
|
||||
}
|
||||
pwalletMain->GetFilteredNotes(sproutEntries, saplingEntries, noteFilter, mindepth_);
|
||||
|
||||
// If using the TransactionBuilder, we only want Sapling notes.
|
||||
// If not using it, we only want Sprout notes.
|
||||
|
@ -1017,7 +1050,8 @@ UniValue AsyncRPCOperation_sendmany::perform_joinsplit(
|
|||
if (!witnesses[i]) {
|
||||
throw runtime_error("joinsplit input could not be found in tree");
|
||||
}
|
||||
info.vjsin.push_back(JSInput(*witnesses[i], info.notes[i], std::get<libzcash::SproutSpendingKey>(spendingkey_)));
|
||||
auto sk = std::visit(GetSproutKeyForPaymentAddress(pwalletMain), frompaymentaddress_).value();
|
||||
info.vjsin.push_back(JSInput(*witnesses[i], info.notes[i], sk));
|
||||
}
|
||||
|
||||
// Make sure there are two inputs and two outputs
|
||||
|
|
|
@ -94,17 +94,16 @@ private:
|
|||
|
||||
UniValue contextinfo_; // optional data to include in return value from getStatus()
|
||||
|
||||
bool isUsingBuilder_; // Indicates that no Sprout addresses are involved
|
||||
bool isUsingBuilder_{false}; // Indicates that no Sprout addresses are involved
|
||||
uint32_t consensusBranchId_;
|
||||
CAmount fee_;
|
||||
int mindepth_;
|
||||
int mindepth_{1};
|
||||
std::string fromaddress_;
|
||||
bool useanyutxo_;
|
||||
bool isfromtaddr_;
|
||||
bool isfromzaddr_;
|
||||
bool useanyutxo_{false};
|
||||
bool isfromtaddr_{false};
|
||||
bool isfromzaddr_{false};
|
||||
CTxDestination fromtaddr_;
|
||||
PaymentAddress frompaymentaddress_;
|
||||
SpendingKey spendingkey_;
|
||||
|
||||
Ed25519VerificationKey joinSplitPubKey_;
|
||||
Ed25519SigningKey joinSplitPrivKey_;
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "walletdb.h"
|
||||
#include "script/interpreter.h"
|
||||
#include "utiltime.h"
|
||||
#include "util/match.h"
|
||||
#include "zcash/IncrementalMerkleTree.hpp"
|
||||
#include "miner.h"
|
||||
#include "wallet/paymentdisclosuredb.h"
|
||||
|
@ -63,7 +64,7 @@ AsyncRPCOperation_shieldcoinbase::AsyncRPCOperation_shieldcoinbase(
|
|||
TransactionBuilder builder,
|
||||
CMutableTransaction contextualTx,
|
||||
std::vector<ShieldCoinbaseUTXO> inputs,
|
||||
std::string toAddress,
|
||||
PaymentAddress toAddress,
|
||||
CAmount fee,
|
||||
UniValue contextInfo) :
|
||||
builder_(builder), tx_(contextualTx), inputs_(inputs), fee_(fee), contextinfo_(contextInfo)
|
||||
|
@ -79,13 +80,23 @@ AsyncRPCOperation_shieldcoinbase::AsyncRPCOperation_shieldcoinbase(
|
|||
}
|
||||
|
||||
// Check the destination address is valid for this network i.e. not testnet being used on mainnet
|
||||
KeyIO keyIO(Params());
|
||||
auto address = keyIO.DecodePaymentAddress(toAddress);
|
||||
if (IsValidPaymentAddress(address)) {
|
||||
tozaddr_ = address;
|
||||
} else {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid to address");
|
||||
}
|
||||
std::visit(match {
|
||||
[&](CKeyID addr) {
|
||||
throw JSONRPCError(RPC_VERIFY_REJECTED, "Cannot shield coinbase output to a p2pkh address.");
|
||||
},
|
||||
[&](CScriptID addr) {
|
||||
throw JSONRPCError(RPC_VERIFY_REJECTED, "Cannot shield coinbase output to a p2sh address.");
|
||||
},
|
||||
[&](libzcash::SaplingPaymentAddress addr) {
|
||||
tozaddr_ = addr;
|
||||
},
|
||||
[&](libzcash::SproutPaymentAddress addr) {
|
||||
tozaddr_ = addr;
|
||||
},
|
||||
[&](libzcash::UnifiedAddress) {
|
||||
throw JSONRPCError(RPC_VERIFY_REJECTED, "Cannot shield coinbase output to a unified address.");
|
||||
}
|
||||
}, toAddress);
|
||||
|
||||
// Log the context info
|
||||
if (LogAcceptCategory("zrpcunsafe")) {
|
||||
|
@ -202,6 +213,14 @@ bool AsyncRPCOperation_shieldcoinbase::main_impl() {
|
|||
return std::visit(ShieldToAddress(this, sendAmount), tozaddr_);
|
||||
}
|
||||
|
||||
bool ShieldToAddress::operator()(const CKeyID &addr) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ShieldToAddress::operator()(const CScriptID &addr) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ShieldToAddress::operator()(const libzcash::SproutPaymentAddress &zaddr) const {
|
||||
// update the transaction with these inputs
|
||||
CMutableTransaction rawTx(m_op->tx_);
|
||||
|
@ -264,11 +283,6 @@ bool ShieldToAddress::operator()(const libzcash::UnifiedAddress &uaddr) const {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool ShieldToAddress::operator()(const libzcash::InvalidEncoding& no) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
UniValue AsyncRPCOperation_shieldcoinbase::perform_joinsplit(ShieldCoinbaseJSInfo & info) {
|
||||
uint32_t consensusBranchId;
|
||||
uint256 anchor;
|
||||
|
|
|
@ -45,7 +45,7 @@ public:
|
|||
TransactionBuilder builder,
|
||||
CMutableTransaction contextualTx,
|
||||
std::vector<ShieldCoinbaseUTXO> inputs,
|
||||
std::string toAddress,
|
||||
PaymentAddress toAddress,
|
||||
CAmount fee = DEFAULT_FEE,
|
||||
UniValue contextInfo = NullUniValue);
|
||||
virtual ~AsyncRPCOperation_shieldcoinbase();
|
||||
|
@ -103,10 +103,11 @@ public:
|
|||
ShieldToAddress(AsyncRPCOperation_shieldcoinbase *op, CAmount sendAmount) :
|
||||
m_op(op), sendAmount(sendAmount) {}
|
||||
|
||||
bool operator()(const CKeyID &zaddr) const;
|
||||
bool operator()(const CScriptID &zaddr) const;
|
||||
bool operator()(const libzcash::SproutPaymentAddress &zaddr) const;
|
||||
bool operator()(const libzcash::SaplingPaymentAddress &zaddr) const;
|
||||
bool operator()(const libzcash::UnifiedAddress &uaddr) const;
|
||||
bool operator()(const libzcash::InvalidEncoding& no) const;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -206,11 +206,11 @@ TEST(WalletTests, FindUnspentSproutNotes) {
|
|||
// We currently have an unspent and unconfirmed note in the wallet (depth of -1)
|
||||
std::vector<SproutNoteEntry> sproutEntries;
|
||||
std::vector<SaplingNoteEntry> saplingEntries;
|
||||
wallet.GetFilteredNotes(sproutEntries, saplingEntries, "", 0);
|
||||
wallet.GetFilteredNotes(sproutEntries, saplingEntries, std::nullopt, 0);
|
||||
EXPECT_EQ(0, sproutEntries.size());
|
||||
sproutEntries.clear();
|
||||
saplingEntries.clear();
|
||||
wallet.GetFilteredNotes(sproutEntries, saplingEntries, "", -1);
|
||||
wallet.GetFilteredNotes(sproutEntries, saplingEntries, std::nullopt, -1);
|
||||
EXPECT_EQ(1, sproutEntries.size());
|
||||
sproutEntries.clear();
|
||||
saplingEntries.clear();
|
||||
|
@ -233,15 +233,15 @@ TEST(WalletTests, FindUnspentSproutNotes) {
|
|||
|
||||
|
||||
// We now have an unspent and confirmed note in the wallet (depth of 1)
|
||||
wallet.GetFilteredNotes(sproutEntries, saplingEntries, "", 0);
|
||||
wallet.GetFilteredNotes(sproutEntries, saplingEntries, std::nullopt, 0);
|
||||
EXPECT_EQ(1, sproutEntries.size());
|
||||
sproutEntries.clear();
|
||||
saplingEntries.clear();
|
||||
wallet.GetFilteredNotes(sproutEntries, saplingEntries, "", 1);
|
||||
wallet.GetFilteredNotes(sproutEntries, saplingEntries, std::nullopt, 1);
|
||||
EXPECT_EQ(1, sproutEntries.size());
|
||||
sproutEntries.clear();
|
||||
saplingEntries.clear();
|
||||
wallet.GetFilteredNotes(sproutEntries, saplingEntries, "", 2);
|
||||
wallet.GetFilteredNotes(sproutEntries, saplingEntries, std::nullopt, 2);
|
||||
EXPECT_EQ(0, sproutEntries.size());
|
||||
sproutEntries.clear();
|
||||
saplingEntries.clear();
|
||||
|
@ -271,22 +271,22 @@ TEST(WalletTests, FindUnspentSproutNotes) {
|
|||
EXPECT_TRUE(wallet.IsSproutSpent(nullifier));
|
||||
|
||||
// The note has been spent. By default, GetFilteredNotes() ignores spent notes.
|
||||
wallet.GetFilteredNotes(sproutEntries, saplingEntries, "", 0);
|
||||
wallet.GetFilteredNotes(sproutEntries, saplingEntries, std::nullopt, 0);
|
||||
EXPECT_EQ(0, sproutEntries.size());
|
||||
sproutEntries.clear();
|
||||
saplingEntries.clear();
|
||||
// Let's include spent notes to retrieve it.
|
||||
wallet.GetFilteredNotes(sproutEntries, saplingEntries, "", 0, false);
|
||||
wallet.GetFilteredNotes(sproutEntries, saplingEntries, std::nullopt, 0, INT_MAX, false);
|
||||
EXPECT_EQ(1, sproutEntries.size());
|
||||
sproutEntries.clear();
|
||||
saplingEntries.clear();
|
||||
// The spent note has two confirmations.
|
||||
wallet.GetFilteredNotes(sproutEntries, saplingEntries, "", 2, false);
|
||||
wallet.GetFilteredNotes(sproutEntries, saplingEntries, std::nullopt, 2, INT_MAX, false);
|
||||
EXPECT_EQ(1, sproutEntries.size());
|
||||
sproutEntries.clear();
|
||||
saplingEntries.clear();
|
||||
// It does not have 3 confirmations.
|
||||
wallet.GetFilteredNotes(sproutEntries, saplingEntries, "", 3, false);
|
||||
wallet.GetFilteredNotes(sproutEntries, saplingEntries, std::nullopt, 3, INT_MAX, false);
|
||||
EXPECT_EQ(0, sproutEntries.size());
|
||||
sproutEntries.clear();
|
||||
saplingEntries.clear();
|
||||
|
@ -329,22 +329,22 @@ TEST(WalletTests, FindUnspentSproutNotes) {
|
|||
wallet.AddToWallet(wtx3, true, NULL);
|
||||
|
||||
// We now have an unspent note which has one confirmation, in addition to our spent note.
|
||||
wallet.GetFilteredNotes(sproutEntries, saplingEntries, "", 1);
|
||||
wallet.GetFilteredNotes(sproutEntries, saplingEntries, std::nullopt, 1);
|
||||
EXPECT_EQ(1, sproutEntries.size());
|
||||
sproutEntries.clear();
|
||||
saplingEntries.clear();
|
||||
// Let's return the spent note too.
|
||||
wallet.GetFilteredNotes(sproutEntries, saplingEntries, "", 1, false);
|
||||
wallet.GetFilteredNotes(sproutEntries, saplingEntries, std::nullopt, 1, INT_MAX, false);
|
||||
EXPECT_EQ(2, sproutEntries.size());
|
||||
sproutEntries.clear();
|
||||
saplingEntries.clear();
|
||||
// Increasing number of confirmations will exclude our new unspent note.
|
||||
wallet.GetFilteredNotes(sproutEntries, saplingEntries, "", 2, false);
|
||||
wallet.GetFilteredNotes(sproutEntries, saplingEntries, std::nullopt, 2, INT_MAX, false);
|
||||
EXPECT_EQ(1, sproutEntries.size());
|
||||
sproutEntries.clear();
|
||||
saplingEntries.clear();
|
||||
// If we also ignore spent notes at this depth, we won't find any notes.
|
||||
wallet.GetFilteredNotes(sproutEntries, saplingEntries, "", 2, true);
|
||||
wallet.GetFilteredNotes(sproutEntries, saplingEntries, std::nullopt, 2, INT_MAX, true);
|
||||
EXPECT_EQ(0, sproutEntries.size());
|
||||
sproutEntries.clear();
|
||||
saplingEntries.clear();
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
// file COPYING or https://www.opensource.org/licenses/mit-license.php .
|
||||
|
||||
#include "chain.h"
|
||||
#include "core_io.h"
|
||||
#include "key_io.h"
|
||||
#include "rpc/server.h"
|
||||
#include "init.h"
|
||||
|
@ -11,6 +12,7 @@
|
|||
#include "script/standard.h"
|
||||
#include "sync.h"
|
||||
#include "util.h"
|
||||
#include "util/match.h"
|
||||
#include "utiltime.h"
|
||||
#include "wallet.h"
|
||||
|
||||
|
@ -67,7 +69,7 @@ std::string DecodeDumpString(const std::string &str) {
|
|||
for (unsigned int pos = 0; pos < str.length(); pos++) {
|
||||
unsigned char c = str[pos];
|
||||
if (c == '%' && pos+2 < str.length()) {
|
||||
c = (((str[pos+1]>>6)*9+((str[pos+1]-'0')&15)) << 4) |
|
||||
c = (((str[pos+1]>>6)*9+((str[pos+1]-'0')&15)) << 4) |
|
||||
((str[pos+2]>>6)*9+((str[pos+2]-'0')&15));
|
||||
pos += 2;
|
||||
}
|
||||
|
@ -80,7 +82,7 @@ UniValue importprivkey(const UniValue& params, bool fHelp)
|
|||
{
|
||||
if (!EnsureWalletIsAvailable(fHelp))
|
||||
return NullUniValue;
|
||||
|
||||
|
||||
if (fHelp || params.size() < 1 || params.size() > 3)
|
||||
throw runtime_error(
|
||||
"importprivkey \"zcashprivkey\" ( \"label\" rescan )\n"
|
||||
|
@ -189,7 +191,7 @@ UniValue importaddress(const UniValue& params, bool fHelp)
|
|||
{
|
||||
if (!EnsureWalletIsAvailable(fHelp))
|
||||
return NullUniValue;
|
||||
|
||||
|
||||
if (fHelp || params.size() < 1 || params.size() > 4)
|
||||
throw runtime_error(
|
||||
"importaddress \"address\" ( \"label\" rescan p2sh )\n"
|
||||
|
@ -338,7 +340,7 @@ UniValue importwallet(const UniValue& params, bool fHelp)
|
|||
{
|
||||
if (!EnsureWalletIsAvailable(fHelp))
|
||||
return NullUniValue;
|
||||
|
||||
|
||||
if (fHelp || params.size() != 1)
|
||||
throw runtime_error(
|
||||
"importwallet \"filename\"\n"
|
||||
|
@ -400,9 +402,9 @@ UniValue importwallet_impl(const UniValue& params, bool fImportZKeys)
|
|||
// Only include hdKeypath and seedFpStr if we have both
|
||||
std::optional<std::string> hdKeypath = (vstr.size() > 3) ? std::optional<std::string>(vstr[2]) : std::nullopt;
|
||||
std::optional<std::string> seedFpStr = (vstr.size() > 3) ? std::optional<std::string>(vstr[3]) : std::nullopt;
|
||||
if (IsValidSpendingKey(spendingkey)) {
|
||||
if (spendingkey.has_value()) {
|
||||
auto addResult = std::visit(
|
||||
AddSpendingKeyToWallet(pwalletMain, Params().GetConsensus(), nTime, hdKeypath, seedFpStr, true), spendingkey);
|
||||
AddSpendingKeyToWallet(pwalletMain, Params().GetConsensus(), nTime, hdKeypath, seedFpStr, true), spendingkey.value());
|
||||
if (addResult == KeyAlreadyExists){
|
||||
LogPrint("zrpc", "Skipping import of zaddr (key already present)\n");
|
||||
} else if (addResult == KeyNotAdded) {
|
||||
|
@ -476,7 +478,7 @@ UniValue dumpprivkey(const UniValue& params, bool fHelp)
|
|||
{
|
||||
if (!EnsureWalletIsAvailable(fHelp))
|
||||
return NullUniValue;
|
||||
|
||||
|
||||
if (fHelp || params.size() != 1)
|
||||
throw runtime_error(
|
||||
"dumpprivkey \"t-addr\"\n"
|
||||
|
@ -520,7 +522,7 @@ UniValue z_exportwallet(const UniValue& params, bool fHelp)
|
|||
{
|
||||
if (!EnsureWalletIsAvailable(fHelp))
|
||||
return NullUniValue;
|
||||
|
||||
|
||||
if (fHelp || params.size() != 1)
|
||||
throw runtime_error(
|
||||
"z_exportwallet \"filename\"\n"
|
||||
|
@ -751,17 +753,17 @@ UniValue z_importkey(const UniValue& params, bool fHelp)
|
|||
KeyIO keyIO(Params());
|
||||
string strSecret = params[0].get_str();
|
||||
auto spendingkey = keyIO.DecodeSpendingKey(strSecret);
|
||||
if (!IsValidSpendingKey(spendingkey)) {
|
||||
if (!spendingkey.has_value()) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid spending key");
|
||||
}
|
||||
|
||||
auto addrInfo = std::visit(libzcash::AddressInfoFromSpendingKey{}, spendingkey);
|
||||
auto addrInfo = std::visit(libzcash::AddressInfoFromSpendingKey{}, spendingkey.value());
|
||||
UniValue result(UniValue::VOBJ);
|
||||
result.pushKV("type", addrInfo.first);
|
||||
result.pushKV("address", keyIO.EncodePaymentAddress(addrInfo.second));
|
||||
|
||||
// Sapling support
|
||||
auto addResult = std::visit(AddSpendingKeyToWallet(pwalletMain, Params().GetConsensus()), spendingkey);
|
||||
auto addResult = std::visit(AddSpendingKeyToWallet(pwalletMain, Params().GetConsensus()), spendingkey.value());
|
||||
if (addResult == KeyAlreadyExists && fIgnoreExistingKey) {
|
||||
return result;
|
||||
}
|
||||
|
@ -769,10 +771,10 @@ UniValue z_importkey(const UniValue& params, bool fHelp)
|
|||
if (addResult == KeyNotAdded) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding spending key to wallet");
|
||||
}
|
||||
|
||||
|
||||
// whenever a key is imported, we need to scan the whole chain
|
||||
pwalletMain->nTimeFirstKey = 1; // 0 would be considered 'no value'
|
||||
|
||||
|
||||
// We want to scan for transactions and notes
|
||||
if (fRescan) {
|
||||
pwalletMain->ScanForWalletTransactions(chainActive[nRescanHeight], true);
|
||||
|
@ -846,17 +848,17 @@ UniValue z_importviewingkey(const UniValue& params, bool fHelp)
|
|||
KeyIO keyIO(Params());
|
||||
string strVKey = params[0].get_str();
|
||||
auto viewingkey = keyIO.DecodeViewingKey(strVKey);
|
||||
if (!IsValidViewingKey(viewingkey)) {
|
||||
if (!viewingkey.has_value()) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid viewing key");
|
||||
}
|
||||
|
||||
auto addrInfo = std::visit(libzcash::AddressInfoFromViewingKey{}, viewingkey);
|
||||
auto addrInfo = std::visit(libzcash::AddressInfoFromViewingKey{}, viewingkey.value());
|
||||
UniValue result(UniValue::VOBJ);
|
||||
const string strAddress = keyIO.EncodePaymentAddress(addrInfo.second);
|
||||
result.pushKV("type", addrInfo.first);
|
||||
result.pushKV("address", strAddress);
|
||||
|
||||
auto addResult = std::visit(AddViewingKeyToWallet(pwalletMain), viewingkey);
|
||||
auto addResult = std::visit(AddViewingKeyToWallet(pwalletMain), viewingkey.value());
|
||||
if (addResult == SpendingKeyExists) {
|
||||
throw JSONRPCError(
|
||||
RPC_WALLET_ERROR,
|
||||
|
@ -905,16 +907,52 @@ UniValue z_exportkey(const UniValue& params, bool fHelp)
|
|||
|
||||
KeyIO keyIO(Params());
|
||||
auto address = keyIO.DecodePaymentAddress(strAddress);
|
||||
if (!IsValidPaymentAddress(address)) {
|
||||
if (!address.has_value()) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid zaddr");
|
||||
}
|
||||
|
||||
// Sapling support
|
||||
auto sk = std::visit(GetSpendingKeyForPaymentAddress(pwalletMain), address);
|
||||
if (!sk) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Wallet does not hold private zkey for this zaddr");
|
||||
}
|
||||
return keyIO.EncodeSpendingKey(sk.value());
|
||||
std::string result = std::visit(match {
|
||||
[&](const CKeyID& addr) {
|
||||
CKey key;
|
||||
if (pwalletMain->GetKey(addr, key)) {
|
||||
return keyIO.EncodeSecret(key);
|
||||
} else {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Wallet does not hold the private key for this address.");
|
||||
}
|
||||
},
|
||||
[&](const CScriptID& addr) {
|
||||
CScript redeemScript;
|
||||
if (pwalletMain->GetCScript(addr, redeemScript)) {
|
||||
return FormatScript(redeemScript);
|
||||
} else {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Wallet does not hold the redeem script for this P2SH address.");
|
||||
}
|
||||
},
|
||||
[&](const libzcash::SproutPaymentAddress& addr) {
|
||||
libzcash::SproutSpendingKey key;
|
||||
if (pwalletMain->GetSproutSpendingKey(addr, key)) {
|
||||
return keyIO.EncodeSpendingKey(key);
|
||||
} else {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Wallet does not hold the private spending key for this Sprout address");
|
||||
}
|
||||
},
|
||||
[&](const libzcash::SaplingPaymentAddress& addr) {
|
||||
libzcash::SaplingExtendedSpendingKey extsk;
|
||||
if (pwalletMain->GetSaplingExtendedSpendingKey(addr, extsk)) {
|
||||
return keyIO.EncodeSpendingKey(extsk);
|
||||
} else {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Wallet does not hold the private spending key for this Sapling address");
|
||||
}
|
||||
},
|
||||
[&](const libzcash::UnifiedAddress& ua) {
|
||||
throw JSONRPCError(
|
||||
RPC_WALLET_ERROR,
|
||||
"No serialized form is defined for unified spending keys. "
|
||||
"Use the emergency recovery phrase for this wallet for backup purposes instead.");
|
||||
return std::string(); //unreachable, here to make the compiler happy
|
||||
}
|
||||
}, address.value());
|
||||
return result;
|
||||
}
|
||||
|
||||
UniValue z_exportviewingkey(const UniValue& params, bool fHelp)
|
||||
|
@ -944,11 +982,11 @@ UniValue z_exportviewingkey(const UniValue& params, bool fHelp)
|
|||
|
||||
KeyIO keyIO(Params());
|
||||
auto address = keyIO.DecodePaymentAddress(strAddress);
|
||||
if (!IsValidPaymentAddress(address)) {
|
||||
if (!address.has_value()) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid zaddr");
|
||||
}
|
||||
|
||||
auto vk = std::visit(GetViewingKeyForPaymentAddress(pwalletMain), address);
|
||||
auto vk = std::visit(GetViewingKeyForPaymentAddress(pwalletMain), address.value());
|
||||
if (vk) {
|
||||
return keyIO.EncodeViewingKey(vk.value());
|
||||
} else {
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -362,20 +362,25 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_getbalance)
|
|||
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
UniValue retValue;
|
||||
BOOST_CHECK_NO_THROW(retValue = CallRPC("getnewaddress"));
|
||||
std::string taddr1 = retValue.get_str();
|
||||
|
||||
BOOST_CHECK_THROW(CallRPC("z_getbalance too many args"), runtime_error);
|
||||
BOOST_CHECK_THROW(CallRPC("z_getbalance invalidaddress"), runtime_error);
|
||||
BOOST_CHECK_NO_THROW(CallRPC("z_getbalance tmC6YZnCUhm19dEXxh3Jb7srdBJxDawaCab"));
|
||||
BOOST_CHECK_THROW(CallRPC("z_getbalance tmC6YZnCUhm19dEXxh3Jb7srdBJxDawaCab -1"), runtime_error);
|
||||
BOOST_CHECK_NO_THROW(CallRPC("z_getbalance tmC6YZnCUhm19dEXxh3Jb7srdBJxDawaCab 0"));
|
||||
// address does not belong to wallet
|
||||
BOOST_CHECK_THROW(CallRPC("z_getbalance tmC6YZnCUhm19dEXxh3Jb7srdBJxDawaCab"), runtime_error);
|
||||
BOOST_CHECK_NO_THROW(CallRPC(std::string("z_getbalance ") + taddr1));
|
||||
// negative minconf not allowed
|
||||
BOOST_CHECK_THROW(CallRPC(std::string("z_getbalance ") + taddr1 + " -1"), runtime_error);
|
||||
BOOST_CHECK_NO_THROW(CallRPC(std::string("z_getbalance ") + taddr1 + std::string(" 0")));
|
||||
// don't have the spending key
|
||||
BOOST_CHECK_THROW(CallRPC("z_getbalance tnRZ8bPq2pff3xBWhTJhNkVUkm2uhzksDeW5PvEa7aFKGT9Qi3YgTALZfjaY4jU3HLVKBtHdSXxoPoLA3naMPcHBcY88FcF 1"), runtime_error);
|
||||
|
||||
|
||||
BOOST_CHECK_THROW(CallRPC("z_gettotalbalance too manyargs"), runtime_error);
|
||||
BOOST_CHECK_THROW(CallRPC("z_gettotalbalance -1"), runtime_error);
|
||||
BOOST_CHECK_NO_THROW(CallRPC("z_gettotalbalance 0"));
|
||||
|
||||
|
||||
BOOST_CHECK_THROW(CallRPC("z_listreceivedbyaddress too many args"), runtime_error);
|
||||
// negative minconf not allowed
|
||||
BOOST_CHECK_THROW(CallRPC("z_listreceivedbyaddress tmC6YZnCUhm19dEXxh3Jb7srdBJxDawaCab -1"), runtime_error);
|
||||
|
@ -602,15 +607,16 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_importwallet)
|
|||
BOOST_CHECK(addrs.size()==1);
|
||||
|
||||
// check that we have the spending key for the address
|
||||
auto address = keyIO.DecodePaymentAddress(testAddr);
|
||||
BOOST_CHECK(IsValidPaymentAddress(address));
|
||||
BOOST_ASSERT(std::get_if<libzcash::SproutPaymentAddress>(&address) != nullptr);
|
||||
auto addr = std::get<libzcash::SproutPaymentAddress>(address);
|
||||
BOOST_CHECK(pwalletMain->HaveSproutSpendingKey(addr));
|
||||
auto decoded = keyIO.DecodePaymentAddress(testAddr);
|
||||
BOOST_CHECK(decoded.has_value());
|
||||
libzcash::PaymentAddress address(decoded.value());
|
||||
BOOST_ASSERT(std::holds_alternative<libzcash::SproutPaymentAddress>(address));
|
||||
auto sprout_addr = std::get<libzcash::SproutPaymentAddress>(address);
|
||||
BOOST_CHECK(pwalletMain->HaveSproutSpendingKey(sprout_addr));
|
||||
|
||||
// Verify the spending key is the same as the test data
|
||||
libzcash::SproutSpendingKey k;
|
||||
BOOST_CHECK(pwalletMain->GetSproutSpendingKey(addr, k));
|
||||
BOOST_CHECK(pwalletMain->GetSproutSpendingKey(sprout_addr, k));
|
||||
BOOST_CHECK_EQUAL(testKey, keyIO.EncodeSpendingKey(k));
|
||||
}
|
||||
|
||||
|
@ -776,10 +782,9 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_importexport)
|
|||
|
||||
// Check if address is of given type and spendable from our wallet.
|
||||
template <typename ADDR_TYPE>
|
||||
void CheckHaveAddr(const libzcash::PaymentAddress& addr) {
|
||||
|
||||
BOOST_CHECK(IsValidPaymentAddress(addr));
|
||||
auto addr_of_type = std::get_if<ADDR_TYPE>(&addr);
|
||||
void CheckHaveAddr(const std::optional<libzcash::PaymentAddress>& addr) {
|
||||
BOOST_CHECK(addr.has_value());
|
||||
auto addr_of_type = std::get_if<ADDR_TYPE>(&(addr.value()));
|
||||
BOOST_ASSERT(addr_of_type != nullptr);
|
||||
|
||||
HaveSpendingKeyForPaymentAddress test(pwalletMain);
|
||||
|
@ -1217,7 +1222,7 @@ BOOST_AUTO_TEST_CASE(rpc_z_sendmany_parameters)
|
|||
std::vector<SendManyRecipient> recipients = { SendManyRecipient("dummy", 1*COIN, "") };
|
||||
std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany(std::nullopt, mtx, "ztjiDe569DPNbyTE6TSdJTaSDhoXEHLGvYoUnBU1wfVNU52TEyT6berYtySkd21njAeEoh8fFJUT42kua9r8EnhBaEKqCpP", recipients, {}, 1) );
|
||||
} catch (const UniValue& objError) {
|
||||
BOOST_CHECK( find_error(objError, "no spending key found for zaddr"));
|
||||
BOOST_CHECK( find_error(objError, "no spending key found for address"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1765,8 +1770,8 @@ BOOST_AUTO_TEST_CASE(rpc_z_shieldcoinbase_parameters)
|
|||
}
|
||||
|
||||
// Test constructor of AsyncRPCOperation_shieldcoinbase
|
||||
std::string testnetzaddr = "ztjiDe569DPNbyTE6TSdJTaSDhoXEHLGvYoUnBU1wfVNU52TEyT6berYtySkd21njAeEoh8fFJUT42kua9r8EnhBaEKqCpP";
|
||||
std::string mainnetzaddr = "zcMuhvq8sEkHALuSU2i4NbNQxshSAYrpCExec45ZjtivYPbuiFPwk6WHy4SvsbeZ4siy1WheuRGjtaJmoD1J8bFqNXhsG6U";
|
||||
KeyIO keyIO(Params());
|
||||
auto testnetzaddr = std::get<libzcash::SproutPaymentAddress>(keyIO.DecodePaymentAddress("ztjiDe569DPNbyTE6TSdJTaSDhoXEHLGvYoUnBU1wfVNU52TEyT6berYtySkd21njAeEoh8fFJUT42kua9r8EnhBaEKqCpP").value());
|
||||
|
||||
try {
|
||||
std::shared_ptr<AsyncRPCOperation> operation(new AsyncRPCOperation_shieldcoinbase(TransactionBuilder(), mtx, {}, testnetzaddr, -1 ));
|
||||
|
@ -1779,15 +1784,6 @@ BOOST_AUTO_TEST_CASE(rpc_z_shieldcoinbase_parameters)
|
|||
} catch (const UniValue& objError) {
|
||||
BOOST_CHECK( find_error(objError, "Empty inputs"));
|
||||
}
|
||||
|
||||
// Testnet payment addresses begin with 'zt'. This test detects an incorrect prefix.
|
||||
try {
|
||||
std::vector<ShieldCoinbaseUTXO> inputs = { ShieldCoinbaseUTXO{uint256(),0,0} };
|
||||
std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_shieldcoinbase(TransactionBuilder(), mtx, inputs, mainnetzaddr, 1) );
|
||||
} catch (const UniValue& objError) {
|
||||
BOOST_CHECK( find_error(objError, "Invalid to address"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -1805,14 +1801,12 @@ BOOST_AUTO_TEST_CASE(rpc_z_shieldcoinbase_internals)
|
|||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(consensusParams, nHeight + 1);
|
||||
|
||||
// Add keys manually
|
||||
KeyIO keyIO(Params());
|
||||
auto pa = pwalletMain->GenerateNewSproutZKey();
|
||||
std::string zaddr = keyIO.EncodePaymentAddress(pa);
|
||||
|
||||
// Insufficient funds
|
||||
{
|
||||
std::vector<ShieldCoinbaseUTXO> inputs = { ShieldCoinbaseUTXO{uint256(),0,0} };
|
||||
std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_shieldcoinbase(TransactionBuilder(), mtx, inputs, zaddr) );
|
||||
std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_shieldcoinbase(TransactionBuilder(), mtx, inputs, pa) );
|
||||
operation->main();
|
||||
BOOST_CHECK(operation->isFailed());
|
||||
std::string msg = operation->getErrorMessage();
|
||||
|
@ -1823,7 +1817,7 @@ BOOST_AUTO_TEST_CASE(rpc_z_shieldcoinbase_internals)
|
|||
{
|
||||
// Dummy input so the operation object can be instantiated.
|
||||
std::vector<ShieldCoinbaseUTXO> inputs = { ShieldCoinbaseUTXO{uint256(),0,100000} };
|
||||
std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_shieldcoinbase(TransactionBuilder(), mtx, inputs, zaddr) );
|
||||
std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_shieldcoinbase(TransactionBuilder(), mtx, inputs, pa) );
|
||||
std::shared_ptr<AsyncRPCOperation_shieldcoinbase> ptr = std::dynamic_pointer_cast<AsyncRPCOperation_shieldcoinbase> (operation);
|
||||
TEST_FRIEND_AsyncRPCOperation_shieldcoinbase proxy(ptr);
|
||||
static_cast<AsyncRPCOperation_shieldcoinbase *>(operation.get())->testmode = true;
|
||||
|
@ -1932,12 +1926,10 @@ BOOST_AUTO_TEST_CASE(rpc_z_mergetoaddress_parameters)
|
|||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), nHeight + 1);
|
||||
|
||||
// Test constructor of AsyncRPCOperation_mergetoaddress
|
||||
KeyIO keyIO(Params());
|
||||
MergeToAddressRecipient testnetzaddr(
|
||||
"ztjiDe569DPNbyTE6TSdJTaSDhoXEHLGvYoUnBU1wfVNU52TEyT6berYtySkd21njAeEoh8fFJUT42kua9r8EnhBaEKqCpP",
|
||||
keyIO.DecodePaymentAddress("ztjiDe569DPNbyTE6TSdJTaSDhoXEHLGvYoUnBU1wfVNU52TEyT6berYtySkd21njAeEoh8fFJUT42kua9r8EnhBaEKqCpP").value(),
|
||||
"testnet memo");
|
||||
MergeToAddressRecipient mainnetzaddr(
|
||||
"zcMuhvq8sEkHALuSU2i4NbNQxshSAYrpCExec45ZjtivYPbuiFPwk6WHy4SvsbeZ4siy1WheuRGjtaJmoD1J8bFqNXhsG6U",
|
||||
"mainnet memo");
|
||||
|
||||
try {
|
||||
std::shared_ptr<AsyncRPCOperation> operation(new AsyncRPCOperation_mergetoaddress(std::nullopt, mtx, {}, {}, {}, testnetzaddr, -1 ));
|
||||
|
@ -1955,14 +1947,6 @@ BOOST_AUTO_TEST_CASE(rpc_z_mergetoaddress_parameters)
|
|||
|
||||
std::vector<MergeToAddressInputUTXO> inputs = { MergeToAddressInputUTXO{ COutPoint{uint256(), 0}, 0, CScript()} };
|
||||
|
||||
try {
|
||||
MergeToAddressRecipient badaddr("", "memo");
|
||||
std::shared_ptr<AsyncRPCOperation> operation(new AsyncRPCOperation_mergetoaddress(std::nullopt, mtx, inputs, {}, {}, badaddr, 1));
|
||||
BOOST_FAIL("Should have caused an error");
|
||||
} catch (const UniValue& objError) {
|
||||
BOOST_CHECK( find_error(objError, "Recipient parameter missing"));
|
||||
}
|
||||
|
||||
std::vector<MergeToAddressInputSproutNote> sproutNoteInputs =
|
||||
{MergeToAddressInputSproutNote{JSOutPoint(), SproutNote(), 0, SproutSpendingKey()}};
|
||||
std::vector<MergeToAddressInputSaplingNote> saplingNoteInputs =
|
||||
|
@ -1982,15 +1966,6 @@ BOOST_AUTO_TEST_CASE(rpc_z_mergetoaddress_parameters)
|
|||
} catch (const UniValue& objError) {
|
||||
BOOST_CHECK(find_error(objError, "Sprout notes are not supported by the TransactionBuilder"));
|
||||
}
|
||||
|
||||
// Testnet payment addresses begin with 'zt'. This test detects an incorrect prefix.
|
||||
try {
|
||||
std::vector<MergeToAddressInputUTXO> inputs = { MergeToAddressInputUTXO{ COutPoint{uint256(), 0}, 0, CScript()} };
|
||||
std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_mergetoaddress(std::nullopt, mtx, inputs, {}, {}, mainnetzaddr, 1) );
|
||||
BOOST_FAIL("Should have caused an error");
|
||||
} catch (const UniValue& objError) {
|
||||
BOOST_CHECK( find_error(objError, "Invalid recipient address"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1999,6 +1974,7 @@ BOOST_AUTO_TEST_CASE(rpc_z_mergetoaddress_internals)
|
|||
{
|
||||
SelectParams(CBaseChainParams::TESTNET);
|
||||
const Consensus::Params& consensusParams = Params().GetConsensus();
|
||||
KeyIO keyIO(Params());
|
||||
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
|
@ -2012,10 +1988,9 @@ BOOST_AUTO_TEST_CASE(rpc_z_mergetoaddress_internals)
|
|||
|
||||
// Add keys manually
|
||||
BOOST_CHECK_NO_THROW(retValue = CallRPC("getnewaddress"));
|
||||
MergeToAddressRecipient taddr1(retValue.get_str(), "");
|
||||
MergeToAddressRecipient taddr1(keyIO.DecodePaymentAddress(retValue.get_str()).value(), "");
|
||||
auto pa = pwalletMain->GenerateNewSproutZKey();
|
||||
KeyIO keyIO(Params());
|
||||
MergeToAddressRecipient zaddr1(keyIO.EncodePaymentAddress(pa), "DEADBEEF");
|
||||
MergeToAddressRecipient zaddr1(pa, "DEADBEEF");
|
||||
|
||||
// Insufficient funds
|
||||
{
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "script/sign.h"
|
||||
#include "timedata.h"
|
||||
#include "utilmoneystr.h"
|
||||
#include "util/match.h"
|
||||
#include "zcash/JoinSplit.hpp"
|
||||
#include "zcash/Note.hpp"
|
||||
#include "crypter.h"
|
||||
|
@ -683,49 +684,58 @@ void CWallet::SetBestChain(const CBlockLocator& loc)
|
|||
SetBestChainINTERNAL(walletdb, loc);
|
||||
}
|
||||
|
||||
std::set<std::pair<libzcash::RawAddress, uint256>> CWallet::GetNullifiersForAddresses(
|
||||
const std::set<libzcash::RawAddress> & addresses)
|
||||
{
|
||||
std::set<std::pair<libzcash::RawAddress, uint256>> nullifierSet;
|
||||
// Sapling ivk -> list of addrs map
|
||||
// (There may be more than one diversified address for a given ivk.)
|
||||
std::map<libzcash::SaplingIncomingViewingKey, std::vector<libzcash::SaplingPaymentAddress>> ivkMap;
|
||||
for (const auto & addr : addresses) {
|
||||
auto saplingAddr = std::get_if<libzcash::SaplingPaymentAddress>(&addr);
|
||||
if (saplingAddr != nullptr) {
|
||||
libzcash::SaplingIncomingViewingKey ivk;
|
||||
this->GetSaplingIncomingViewingKey(*saplingAddr, ivk);
|
||||
ivkMap[ivk].push_back(*saplingAddr);
|
||||
}
|
||||
}
|
||||
for (const auto & txPair : mapWallet) {
|
||||
// Sprout
|
||||
for (const auto & noteDataPair : txPair.second.mapSproutNoteData) {
|
||||
auto & noteData = noteDataPair.second;
|
||||
auto & nullifier = noteData.nullifier;
|
||||
auto & address = noteData.address;
|
||||
if (nullifier && addresses.count(address)) {
|
||||
nullifierSet.insert(std::make_pair(address, nullifier.value()));
|
||||
}
|
||||
}
|
||||
// Sapling
|
||||
for (const auto & noteDataPair : txPair.second.mapSaplingNoteData) {
|
||||
auto & noteData = noteDataPair.second;
|
||||
auto & nullifier = noteData.nullifier;
|
||||
auto & ivk = noteData.ivk;
|
||||
if (nullifier && ivkMap.count(ivk)) {
|
||||
for (const auto & addr : ivkMap[ivk]) {
|
||||
nullifierSet.insert(std::make_pair(addr, nullifier.value()));
|
||||
std::set<std::pair<libzcash::SproutPaymentAddress, uint256>> CWallet::GetSproutNullifiers(
|
||||
const std::set<libzcash::SproutPaymentAddress>& addresses) {
|
||||
std::set<std::pair<libzcash::SproutPaymentAddress, uint256>> nullifierSet;
|
||||
if (!addresses.empty()) {
|
||||
for (const auto& txPair : mapWallet) {
|
||||
for (const auto & noteDataPair : txPair.second.mapSproutNoteData) {
|
||||
auto & noteData = noteDataPair.second;
|
||||
auto & nullifier = noteData.nullifier;
|
||||
auto & address = noteData.address;
|
||||
if (nullifier && addresses.count(address) > 0) {
|
||||
nullifierSet.insert(std::make_pair(address, nullifier.value()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nullifierSet;
|
||||
}
|
||||
|
||||
std::set<std::pair<libzcash::SaplingPaymentAddress, uint256>> CWallet::GetSaplingNullifiers(
|
||||
const std::set<libzcash::SaplingPaymentAddress>& addresses) {
|
||||
std::set<std::pair<libzcash::SaplingPaymentAddress, uint256>> nullifierSet;
|
||||
if (!addresses.empty()) {
|
||||
// Sapling ivk -> list of addrs map
|
||||
// (There may be more than one diversified address for a given ivk.)
|
||||
std::map<libzcash::SaplingIncomingViewingKey, std::vector<libzcash::SaplingPaymentAddress>> ivkMap;
|
||||
for (const auto & addr : addresses) {
|
||||
libzcash::SaplingIncomingViewingKey ivk;
|
||||
this->GetSaplingIncomingViewingKey(addr, ivk);
|
||||
ivkMap[ivk].push_back(addr);
|
||||
}
|
||||
|
||||
for (const auto& txPair : mapWallet) {
|
||||
for (const auto& noteDataPair : txPair.second.mapSaplingNoteData) {
|
||||
auto & noteData = noteDataPair.second;
|
||||
auto & nullifier = noteData.nullifier;
|
||||
auto & ivk = noteData.ivk;
|
||||
if (nullifier && ivkMap.count(ivk) > 0) {
|
||||
for (const auto & addr : ivkMap[ivk]) {
|
||||
nullifierSet.insert(std::make_pair(addr, nullifier.value()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nullifierSet;
|
||||
}
|
||||
|
||||
bool CWallet::IsNoteSproutChange(
|
||||
const std::set<std::pair<libzcash::RawAddress, uint256>> & nullifierSet,
|
||||
const libzcash::RawAddress & address,
|
||||
const std::set<std::pair<libzcash::SproutPaymentAddress, uint256>> & nullifierSet,
|
||||
const libzcash::SproutPaymentAddress& address,
|
||||
const JSOutPoint & jsop)
|
||||
{
|
||||
// A Note is marked as "change" if the address that received it
|
||||
|
@ -747,8 +757,9 @@ bool CWallet::IsNoteSproutChange(
|
|||
return false;
|
||||
}
|
||||
|
||||
bool CWallet::IsNoteSaplingChange(const std::set<std::pair<libzcash::RawAddress, uint256>> & nullifierSet,
|
||||
const libzcash::RawAddress & address,
|
||||
bool CWallet::IsNoteSaplingChange(
|
||||
const std::set<std::pair<libzcash::SaplingPaymentAddress, uint256>> & nullifierSet,
|
||||
const libzcash::SaplingPaymentAddress& address,
|
||||
const SaplingOutPoint & op)
|
||||
{
|
||||
// A Note is marked as "change" if the address that received it
|
||||
|
@ -759,6 +770,8 @@ bool CWallet::IsNoteSaplingChange(const std::set<std::pair<libzcash::RawAddress,
|
|||
// - Notes created by consolidation transactions (e.g. using
|
||||
// z_mergetoaddress).
|
||||
// - Notes sent from one address to itself.
|
||||
// FIXME: This also needs to check against the wallet's change address
|
||||
// for the associated unified account when we add UA support
|
||||
for (const SpendDescription &spend : mapWallet[op.hash].vShieldedSpend) {
|
||||
if (nullifierSet.count(std::make_pair(address, spend.nullifier))) {
|
||||
return true;
|
||||
|
@ -4927,8 +4940,8 @@ bool CWallet::ParameterInteraction(const CChainParams& params)
|
|||
// Check Sapling migration address if set and is a valid Sapling address
|
||||
if (mapArgs.count("-migrationdestaddress")) {
|
||||
std::string migrationDestAddress = mapArgs["-migrationdestaddress"];
|
||||
libzcash::PaymentAddress address = keyIO.DecodePaymentAddress(migrationDestAddress);
|
||||
if (std::get_if<libzcash::SaplingPaymentAddress>(&address) == nullptr) {
|
||||
std::optional<libzcash::PaymentAddress> address = keyIO.DecodePaymentAddress(migrationDestAddress);
|
||||
if (!address.has_value() || std::get_if<libzcash::SaplingPaymentAddress>(&address.value()) == nullptr) {
|
||||
return UIError(_("-migrationdestaddress must be a valid Sapling address."));
|
||||
}
|
||||
}
|
||||
|
@ -5025,31 +5038,48 @@ bool CMerkleTx::AcceptToMemoryPool(bool fLimitFree, bool fRejectAbsurdFee)
|
|||
return ::AcceptToMemoryPool(Params(), mempool, state, *this, fLimitFree, NULL, fRejectAbsurdFee);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find notes in the wallet filtered by payment address, min depth and ability to spend.
|
||||
* These notes are decrypted and added to the output parameter vector, outEntries.
|
||||
*/
|
||||
void CWallet::GetFilteredNotes(
|
||||
std::vector<SproutNoteEntry>& sproutEntries,
|
||||
std::vector<SaplingNoteEntry>& saplingEntries,
|
||||
std::string address,
|
||||
int minDepth,
|
||||
bool ignoreSpent,
|
||||
bool requireSpendingKey)
|
||||
{
|
||||
std::set<libzcash::RawAddress> filterAddresses;
|
||||
AddrSet AddrSet::ForPaymentAddresses(const std::vector<libzcash::PaymentAddress>& paymentAddrs) {
|
||||
AddrSet addrs;
|
||||
for (const auto& addr: paymentAddrs) {
|
||||
std::visit(match {
|
||||
[&](const CKeyID& keyId) { },
|
||||
[&](const CScriptID& scriptId) { },
|
||||
[&](const libzcash::SproutPaymentAddress& addr) {
|
||||
addrs.sproutAddresses.insert(addr);
|
||||
},
|
||||
[&](const libzcash::SaplingPaymentAddress& addr) {
|
||||
addrs.saplingAddresses.insert(addr);
|
||||
},
|
||||
[&](const libzcash::UnifiedAddress& uaddr) {
|
||||
for (auto& receiver : uaddr) {
|
||||
std::visit(match {
|
||||
[&](const libzcash::SaplingPaymentAddress& addr) {
|
||||
addrs.saplingAddresses.insert(addr);
|
||||
},
|
||||
[&](const auto& other) { }
|
||||
}, receiver);
|
||||
}
|
||||
},
|
||||
}, addr);
|
||||
}
|
||||
return addrs;
|
||||
}
|
||||
|
||||
KeyIO keyIO(Params());
|
||||
if (address.length() > 0) {
|
||||
auto addr = keyIO.DecodePaymentAddress(address);
|
||||
for (const auto ra : std::visit(GetRawAddresses(), addr)) {
|
||||
filterAddresses.insert(ra);
|
||||
bool CWallet::HasSpendingKeys(const AddrSet& addrSet) const {
|
||||
for (const auto& zaddr : addrSet.GetSproutAddresses()) {
|
||||
if (!HaveSproutSpendingKey(zaddr)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
GetFilteredNotes(sproutEntries, saplingEntries, filterAddresses, minDepth, INT_MAX, ignoreSpent, requireSpendingKey);
|
||||
for (const auto& zaddr : addrSet.GetSaplingAddresses()) {
|
||||
if (!HaveSaplingSpendingKeyForAddress(zaddr)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Find notes in the wallet filtered by payment addresses, min depth, max depth,
|
||||
* if the note is spent, if a spending key is required, and if the notes are locked.
|
||||
|
@ -5058,7 +5088,7 @@ void CWallet::GetFilteredNotes(
|
|||
void CWallet::GetFilteredNotes(
|
||||
std::vector<SproutNoteEntry>& sproutEntries,
|
||||
std::vector<SaplingNoteEntry>& saplingEntries,
|
||||
std::set<libzcash::RawAddress>& filterAddresses,
|
||||
const std::optional<AddrSet>& noteFilter,
|
||||
int minDepth,
|
||||
int maxDepth,
|
||||
bool ignoreSpent,
|
||||
|
@ -5088,8 +5118,8 @@ void CWallet::GetFilteredNotes(
|
|||
SproutNoteData nd = pair.second;
|
||||
SproutPaymentAddress pa = nd.address;
|
||||
|
||||
// skip notes which belong to a different payment address in the wallet
|
||||
if (!(filterAddresses.empty() || filterAddresses.count(pa))) {
|
||||
// skip notes which do not conform to the filter, if supplied
|
||||
if (noteFilter.has_value() && !noteFilter.value().HasSproutAddress(pa)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -5158,8 +5188,8 @@ void CWallet::GetFilteredNotes(
|
|||
assert(static_cast<bool>(maybe_pa));
|
||||
auto pa = maybe_pa.value();
|
||||
|
||||
// skip notes which belong to a different payment address in the wallet
|
||||
if (!(filterAddresses.empty() || filterAddresses.count(pa))) {
|
||||
// skip notes which do not conform to the filter, if supplied
|
||||
if (noteFilter.has_value() && !noteFilter.value().HasSaplingAddress(pa)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -5168,7 +5198,7 @@ void CWallet::GetFilteredNotes(
|
|||
}
|
||||
|
||||
// skip notes which cannot be spent
|
||||
if (requireSpendingKey && !HaveSpendingKeyForPaymentAddress(this)(pa)) {
|
||||
if (requireSpendingKey && !HaveSaplingSpendingKeyForAddress(pa)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -5186,42 +5216,57 @@ void CWallet::GetFilteredNotes(
|
|||
|
||||
|
||||
//
|
||||
// Shielded key and address generalizations
|
||||
// Payment address operations
|
||||
//
|
||||
|
||||
// PaymentAddressBelongsToWallet
|
||||
|
||||
bool PaymentAddressBelongsToWallet::operator()(const CKeyID &addr) const
|
||||
{
|
||||
CScript script = GetScriptForDestination(addr);
|
||||
return m_wallet->HaveKey(addr) || m_wallet->HaveWatchOnly(script);
|
||||
}
|
||||
bool PaymentAddressBelongsToWallet::operator()(const CScriptID &addr) const
|
||||
{
|
||||
CScript script = GetScriptForDestination(addr);
|
||||
return m_wallet->HaveCScript(addr) || m_wallet->HaveWatchOnly(script);
|
||||
}
|
||||
bool PaymentAddressBelongsToWallet::operator()(const libzcash::SproutPaymentAddress &zaddr) const
|
||||
{
|
||||
return m_wallet->HaveSproutSpendingKey(zaddr) || m_wallet->HaveSproutViewingKey(zaddr);
|
||||
}
|
||||
|
||||
bool PaymentAddressBelongsToWallet::operator()(const libzcash::SaplingPaymentAddress &zaddr) const
|
||||
{
|
||||
libzcash::SaplingIncomingViewingKey ivk;
|
||||
|
||||
// If we have a SaplingExtendedSpendingKey in the wallet, then we will
|
||||
// also have the corresponding SaplingExtendedFullViewingKey.
|
||||
return m_wallet->GetSaplingIncomingViewingKey(zaddr, ivk) &&
|
||||
return
|
||||
m_wallet->GetSaplingIncomingViewingKey(zaddr, ivk) &&
|
||||
m_wallet->HaveSaplingFullViewingKey(ivk);
|
||||
}
|
||||
|
||||
bool PaymentAddressBelongsToWallet::operator()(const libzcash::UnifiedAddress &uaddr) const
|
||||
{
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PaymentAddressBelongsToWallet::operator()(const libzcash::InvalidEncoding& no) const
|
||||
// GetSourceForPaymentAddress
|
||||
|
||||
PaymentAddressSource GetSourceForPaymentAddress::operator()(const CKeyID &zaddr) const
|
||||
{
|
||||
return false;
|
||||
// TODO
|
||||
return AddressNotFound;
|
||||
}
|
||||
PaymentAddressSource GetSourceForPaymentAddress::operator()(const CScriptID &zaddr) const
|
||||
{
|
||||
// TODO
|
||||
return AddressNotFound;
|
||||
}
|
||||
|
||||
///
|
||||
|
||||
PaymentAddressSource GetSourceForPaymentAddress::operator()(const libzcash::SproutPaymentAddress &zaddr) const
|
||||
{
|
||||
return Random;
|
||||
}
|
||||
|
||||
PaymentAddressSource GetSourceForPaymentAddress::operator()(const libzcash::SaplingPaymentAddress &zaddr) const
|
||||
{
|
||||
libzcash::SaplingIncomingViewingKey ivk;
|
||||
|
@ -5234,7 +5279,7 @@ PaymentAddressSource GetSourceForPaymentAddress::operator()(const libzcash::Sapl
|
|||
if (m_wallet->mapSaplingZKeyMetadata.count(ivk) > 0 &&
|
||||
m_wallet->mapSaplingZKeyMetadata[ivk].hdKeypath != "") {
|
||||
return LegacyHDSeed;
|
||||
} else if (HaveSpendingKeyForPaymentAddress(m_wallet)(zaddr)) {
|
||||
} else if (m_wallet->HaveSaplingSpendingKeyForAddress(zaddr)) {
|
||||
return Imported;
|
||||
} else {
|
||||
return ImportedWatchOnly;
|
||||
|
@ -5246,21 +5291,24 @@ PaymentAddressSource GetSourceForPaymentAddress::operator()(const libzcash::Sapl
|
|||
return AddressNotFound;
|
||||
}
|
||||
}
|
||||
|
||||
PaymentAddressSource GetSourceForPaymentAddress::operator()(const libzcash::UnifiedAddress &uaddr) const
|
||||
{
|
||||
// TODO
|
||||
return AddressNotFound;
|
||||
}
|
||||
|
||||
PaymentAddressSource GetSourceForPaymentAddress::operator()(const libzcash::InvalidEncoding& no) const
|
||||
// GetViewingKeyForPaymentAddress
|
||||
|
||||
std::optional<libzcash::ViewingKey> GetViewingKeyForPaymentAddress::operator()(
|
||||
const CKeyID &zaddr) const
|
||||
{
|
||||
return AddressNotFound;
|
||||
return std::nullopt;
|
||||
}
|
||||
std::optional<libzcash::ViewingKey> GetViewingKeyForPaymentAddress::operator()(
|
||||
const CScriptID &zaddr) const
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
|
||||
///
|
||||
|
||||
std::optional<libzcash::ViewingKey> GetViewingKeyForPaymentAddress::operator()(
|
||||
const libzcash::SproutPaymentAddress &zaddr) const
|
||||
{
|
||||
|
@ -5274,7 +5322,6 @@ std::optional<libzcash::ViewingKey> GetViewingKeyForPaymentAddress::operator()(
|
|||
}
|
||||
return libzcash::ViewingKey(vk);
|
||||
}
|
||||
|
||||
std::optional<libzcash::ViewingKey> GetViewingKeyForPaymentAddress::operator()(
|
||||
const libzcash::SaplingPaymentAddress &zaddr) const
|
||||
{
|
||||
|
@ -5289,26 +5336,27 @@ std::optional<libzcash::ViewingKey> GetViewingKeyForPaymentAddress::operator()(
|
|||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<libzcash::ViewingKey> GetViewingKeyForPaymentAddress::operator()(
|
||||
const libzcash::UnifiedAddress &uaddr) const
|
||||
{
|
||||
// TODO
|
||||
return libzcash::ViewingKey();
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<libzcash::ViewingKey> GetViewingKeyForPaymentAddress::operator()(
|
||||
const libzcash::InvalidEncoding& no) const
|
||||
// HaveSpendingKeyForPaymentAddress
|
||||
|
||||
bool HaveSpendingKeyForPaymentAddress::operator()(const CKeyID &addr) const
|
||||
{
|
||||
// Defaults to InvalidEncoding
|
||||
return libzcash::ViewingKey();
|
||||
return m_wallet->HaveKey(addr);
|
||||
}
|
||||
bool HaveSpendingKeyForPaymentAddress::operator()(const CScriptID &addr) const
|
||||
{
|
||||
return m_wallet->HaveCScript(addr);
|
||||
}
|
||||
|
||||
bool HaveSpendingKeyForPaymentAddress::operator()(const libzcash::SproutPaymentAddress &zaddr) const
|
||||
{
|
||||
return m_wallet->HaveSproutSpendingKey(zaddr);
|
||||
}
|
||||
|
||||
bool HaveSpendingKeyForPaymentAddress::operator()(const libzcash::SaplingPaymentAddress &zaddr) const
|
||||
{
|
||||
libzcash::SaplingIncomingViewingKey ivk;
|
||||
|
@ -5318,53 +5366,88 @@ bool HaveSpendingKeyForPaymentAddress::operator()(const libzcash::SaplingPayment
|
|||
m_wallet->GetSaplingFullViewingKey(ivk, extfvk) &&
|
||||
m_wallet->HaveSaplingSpendingKey(extfvk);
|
||||
}
|
||||
|
||||
bool HaveSpendingKeyForPaymentAddress::operator()(const libzcash::UnifiedAddress &uaddr) const
|
||||
{
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
|
||||
bool HaveSpendingKeyForPaymentAddress::operator()(const libzcash::InvalidEncoding& no) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// GetSproutKeyForPaymentAddress
|
||||
|
||||
std::optional<libzcash::SpendingKey> GetSpendingKeyForPaymentAddress::operator()(
|
||||
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 libzcash::SpendingKey(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;
|
||||
}
|
||||
|
||||
std::optional<libzcash::SpendingKey> GetSpendingKeyForPaymentAddress::operator()(
|
||||
// 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 libzcash::SpendingKey(extsk);
|
||||
return extsk;
|
||||
} else {
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<libzcash::SpendingKey> GetSpendingKeyForPaymentAddress::operator()(
|
||||
std::optional<libzcash::SaplingExtendedSpendingKey> GetSaplingKeyForPaymentAddress::operator()(
|
||||
const libzcash::UnifiedAddress &uaddr) const
|
||||
{
|
||||
// TODO
|
||||
return libzcash::SpendingKey();
|
||||
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;
|
||||
}
|
||||
|
||||
std::optional<libzcash::SpendingKey> GetSpendingKeyForPaymentAddress::operator()(
|
||||
const libzcash::InvalidEncoding& no) const
|
||||
{
|
||||
// Defaults to InvalidEncoding
|
||||
return libzcash::SpendingKey();
|
||||
}
|
||||
// AddViewingKeyToWallet
|
||||
|
||||
KeyAddResult AddViewingKeyToWallet::operator()(const libzcash::SproutViewingKey &vkey) const {
|
||||
auto addr = vkey.address();
|
||||
|
@ -5379,7 +5462,6 @@ KeyAddResult AddViewingKeyToWallet::operator()(const libzcash::SproutViewingKey
|
|||
return KeyNotAdded;
|
||||
}
|
||||
}
|
||||
|
||||
KeyAddResult AddViewingKeyToWallet::operator()(const libzcash::SaplingExtendedFullViewingKey &extfvk) const {
|
||||
if (m_wallet->HaveSaplingSpendingKey(extfvk)) {
|
||||
return SpendingKeyExists;
|
||||
|
@ -5392,9 +5474,7 @@ KeyAddResult AddViewingKeyToWallet::operator()(const libzcash::SaplingExtendedFu
|
|||
}
|
||||
}
|
||||
|
||||
KeyAddResult AddViewingKeyToWallet::operator()(const libzcash::InvalidEncoding& no) const {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid viewing key");
|
||||
}
|
||||
// AddSpendingKeyToWallet
|
||||
|
||||
KeyAddResult AddSpendingKeyToWallet::operator()(const libzcash::SproutSpendingKey &sk) const {
|
||||
auto addr = sk.address();
|
||||
|
@ -5411,7 +5491,6 @@ KeyAddResult AddSpendingKeyToWallet::operator()(const libzcash::SproutSpendingKe
|
|||
return KeyNotAdded;
|
||||
}
|
||||
}
|
||||
|
||||
KeyAddResult AddSpendingKeyToWallet::operator()(const libzcash::SaplingExtendedSpendingKey &sk) const {
|
||||
auto extfvk = sk.ToXFVK();
|
||||
auto ivk = extfvk.fvk.in_viewing_key();
|
||||
|
@ -5447,7 +5526,3 @@ KeyAddResult AddSpendingKeyToWallet::operator()(const libzcash::SaplingExtendedS
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
KeyAddResult AddSpendingKeyToWallet::operator()(const libzcash::InvalidEncoding& no) const {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid spending key");
|
||||
}
|
||||
|
|
|
@ -623,7 +623,31 @@ public:
|
|||
};
|
||||
|
||||
|
||||
class AddrSet {
|
||||
private:
|
||||
std::set<libzcash::SproutPaymentAddress> sproutAddresses;
|
||||
std::set<libzcash::SaplingPaymentAddress> saplingAddresses;
|
||||
|
||||
AddrSet() {}
|
||||
public:
|
||||
static AddrSet ForPaymentAddresses(const std::vector<libzcash::PaymentAddress>& addrs);
|
||||
|
||||
const std::set<libzcash::SproutPaymentAddress>& GetSproutAddresses() const {
|
||||
return sproutAddresses;
|
||||
}
|
||||
|
||||
const std::set<libzcash::SaplingPaymentAddress>& GetSaplingAddresses() const {
|
||||
return saplingAddresses;
|
||||
}
|
||||
|
||||
bool HasSproutAddress(libzcash::SproutPaymentAddress addr) const {
|
||||
return sproutAddresses.count(addr) > 0;
|
||||
}
|
||||
|
||||
bool HasSaplingAddress(libzcash::SaplingPaymentAddress addr) const {
|
||||
return saplingAddresses.count(addr) > 0;
|
||||
}
|
||||
};
|
||||
|
||||
class COutput
|
||||
{
|
||||
|
@ -1194,9 +1218,20 @@ public:
|
|||
void AddPendingSaplingMigrationTx(const CTransaction& tx);
|
||||
/** Saves witness caches and best block locator to disk. */
|
||||
void SetBestChain(const CBlockLocator& loc);
|
||||
std::set<std::pair<libzcash::RawAddress, uint256>> GetNullifiersForAddresses(const std::set<libzcash::RawAddress> & addresses);
|
||||
bool IsNoteSproutChange(const std::set<std::pair<libzcash::RawAddress, uint256>> & nullifierSet, const libzcash::RawAddress & address, const JSOutPoint & entry);
|
||||
bool IsNoteSaplingChange(const std::set<std::pair<libzcash::RawAddress, uint256>> & nullifierSet, const libzcash::RawAddress & address, const SaplingOutPoint & entry);
|
||||
|
||||
std::set<std::pair<libzcash::SproutPaymentAddress, uint256>> GetSproutNullifiers(
|
||||
const std::set<libzcash::SproutPaymentAddress>& addresses);
|
||||
bool IsNoteSproutChange(
|
||||
const std::set<std::pair<libzcash::SproutPaymentAddress, uint256>> & nullifierSet,
|
||||
const libzcash::SproutPaymentAddress& address,
|
||||
const JSOutPoint & entry);
|
||||
|
||||
std::set<std::pair<libzcash::SaplingPaymentAddress, uint256>> GetSaplingNullifiers(
|
||||
const std::set<libzcash::SaplingPaymentAddress>& addresses);
|
||||
bool IsNoteSaplingChange(
|
||||
const std::set<std::pair<libzcash::SaplingPaymentAddress, uint256>> & nullifierSet,
|
||||
const libzcash::SaplingPaymentAddress& address,
|
||||
const SaplingOutPoint & entry);
|
||||
|
||||
DBErrors LoadWallet(bool& fFirstRunRet);
|
||||
DBErrors ZapWalletTx(std::vector<CWalletTx>& vWtx);
|
||||
|
@ -1304,19 +1339,13 @@ public:
|
|||
/* Set the current encrypted HD seed, without saving it to disk (used by LoadWallet) */
|
||||
bool LoadCryptedHDSeed(const uint256& seedFp, const std::vector<unsigned char>& seed);
|
||||
|
||||
/* Find notes filtered by payment address, min depth, ability to spend */
|
||||
void GetFilteredNotes(std::vector<SproutNoteEntry>& sproutEntries,
|
||||
std::vector<SaplingNoteEntry>& saplingEntries,
|
||||
std::string address,
|
||||
int minDepth=1,
|
||||
bool ignoreSpent=true,
|
||||
bool requireSpendingKey=true);
|
||||
bool HasSpendingKeys(const AddrSet& noteFilter) const;
|
||||
|
||||
/* Find notes filtered by payment addresses, min depth, max depth, if they are spent,
|
||||
if a spending key is required, and if they are locked */
|
||||
void GetFilteredNotes(std::vector<SproutNoteEntry>& sproutEntries,
|
||||
std::vector<SaplingNoteEntry>& saplingEntries,
|
||||
std::set<libzcash::RawAddress>& filterAddresses,
|
||||
const std::optional<AddrSet>& noteFilter,
|
||||
int minDepth=1,
|
||||
int maxDepth=INT_MAX,
|
||||
bool ignoreSpent=true,
|
||||
|
@ -1369,10 +1398,11 @@ private:
|
|||
public:
|
||||
PaymentAddressBelongsToWallet(CWallet *wallet) : m_wallet(wallet) {}
|
||||
|
||||
bool operator()(const CKeyID &zaddr) const;
|
||||
bool operator()(const CScriptID &zaddr) const;
|
||||
bool operator()(const libzcash::SproutPaymentAddress &zaddr) const;
|
||||
bool operator()(const libzcash::SaplingPaymentAddress &zaddr) const;
|
||||
bool operator()(const libzcash::UnifiedAddress &uaddr) const;
|
||||
bool operator()(const libzcash::InvalidEncoding& no) const;
|
||||
};
|
||||
|
||||
class GetViewingKeyForPaymentAddress
|
||||
|
@ -1382,10 +1412,11 @@ private:
|
|||
public:
|
||||
GetViewingKeyForPaymentAddress(CWallet *wallet) : m_wallet(wallet) {}
|
||||
|
||||
std::optional<libzcash::ViewingKey> operator()(const CKeyID &zaddr) const;
|
||||
std::optional<libzcash::ViewingKey> operator()(const CScriptID &zaddr) const;
|
||||
std::optional<libzcash::ViewingKey> operator()(const libzcash::SproutPaymentAddress &zaddr) const;
|
||||
std::optional<libzcash::ViewingKey> operator()(const libzcash::SaplingPaymentAddress &zaddr) const;
|
||||
std::optional<libzcash::ViewingKey> operator()(const libzcash::UnifiedAddress &uaddr) const;
|
||||
std::optional<libzcash::ViewingKey> operator()(const libzcash::InvalidEncoding& no) const;
|
||||
};
|
||||
|
||||
class HaveSpendingKeyForPaymentAddress
|
||||
|
@ -1395,23 +1426,39 @@ private:
|
|||
public:
|
||||
HaveSpendingKeyForPaymentAddress(CWallet *wallet) : m_wallet(wallet) {}
|
||||
|
||||
bool operator()(const CKeyID &addr) const;
|
||||
bool operator()(const CScriptID &addr) const;
|
||||
bool operator()(const libzcash::SproutPaymentAddress &zaddr) const;
|
||||
bool operator()(const libzcash::SaplingPaymentAddress &zaddr) const;
|
||||
bool operator()(const libzcash::UnifiedAddress &uaddr) const;
|
||||
bool operator()(const libzcash::InvalidEncoding& no) const;
|
||||
};
|
||||
|
||||
class GetSpendingKeyForPaymentAddress
|
||||
class GetSproutKeyForPaymentAddress
|
||||
{
|
||||
private:
|
||||
CWallet *m_wallet;
|
||||
public:
|
||||
GetSpendingKeyForPaymentAddress(CWallet *wallet) : m_wallet(wallet) {}
|
||||
GetSproutKeyForPaymentAddress(CWallet *wallet) : m_wallet(wallet) {}
|
||||
|
||||
std::optional<libzcash::SpendingKey> operator()(const libzcash::SproutPaymentAddress &zaddr) const;
|
||||
std::optional<libzcash::SpendingKey> operator()(const libzcash::SaplingPaymentAddress &zaddr) const;
|
||||
std::optional<libzcash::SpendingKey> operator()(const libzcash::UnifiedAddress &uaddr) const;
|
||||
std::optional<libzcash::SpendingKey> operator()(const libzcash::InvalidEncoding& no) const;
|
||||
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 {
|
||||
|
@ -1430,10 +1477,11 @@ private:
|
|||
public:
|
||||
GetSourceForPaymentAddress(CWallet *wallet) : m_wallet(wallet) {}
|
||||
|
||||
PaymentAddressSource operator()(const CKeyID &zaddr) const;
|
||||
PaymentAddressSource operator()(const CScriptID &zaddr) const;
|
||||
PaymentAddressSource operator()(const libzcash::SproutPaymentAddress &zaddr) const;
|
||||
PaymentAddressSource operator()(const libzcash::SaplingPaymentAddress &zaddr) const;
|
||||
PaymentAddressSource operator()(const libzcash::UnifiedAddress &uaddr) const;
|
||||
PaymentAddressSource operator()(const libzcash::InvalidEncoding& no) const;
|
||||
};
|
||||
|
||||
enum KeyAddResult {
|
||||
|
@ -1452,7 +1500,6 @@ public:
|
|||
|
||||
KeyAddResult operator()(const libzcash::SproutViewingKey &sk) const;
|
||||
KeyAddResult operator()(const libzcash::SaplingExtendedFullViewingKey &sk) const;
|
||||
KeyAddResult operator()(const libzcash::InvalidEncoding& no) const;
|
||||
};
|
||||
|
||||
class AddSpendingKeyToWallet
|
||||
|
@ -1479,7 +1526,6 @@ public:
|
|||
|
||||
KeyAddResult operator()(const libzcash::SproutSpendingKey &sk) const;
|
||||
KeyAddResult operator()(const libzcash::SaplingExtendedSpendingKey &sk) const;
|
||||
KeyAddResult operator()(const libzcash::InvalidEncoding& no) const;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -24,8 +24,8 @@ bool UnifiedAddress::AddReceiver(Receiver receiver) {
|
|||
auto t = std::visit(TypecodeForReceiver(), r);
|
||||
if (
|
||||
(t == typecode) ||
|
||||
(std::holds_alternative<P2PKHAddress>(r) && std::holds_alternative<P2SHAddress>(receiver)) ||
|
||||
(std::holds_alternative<P2SHAddress>(r) && std::holds_alternative<P2PKHAddress>(receiver))
|
||||
(std::holds_alternative<CKeyID>(r) && std::holds_alternative<CScriptID>(receiver)) ||
|
||||
(std::holds_alternative<CScriptID>(r) && std::holds_alternative<CKeyID>(receiver))
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
@ -41,9 +41,6 @@ std::pair<std::string, PaymentAddress> AddressInfoFromSpendingKey::operator()(co
|
|||
std::pair<std::string, PaymentAddress> AddressInfoFromSpendingKey::operator()(const SaplingExtendedSpendingKey &sk) const {
|
||||
return std::make_pair("sapling", sk.DefaultAddress());
|
||||
}
|
||||
std::pair<std::string, PaymentAddress> AddressInfoFromSpendingKey::operator()(const InvalidEncoding&) const {
|
||||
throw std::invalid_argument("Cannot derive default address from invalid spending key");
|
||||
}
|
||||
|
||||
std::pair<std::string, PaymentAddress> AddressInfoFromViewingKey::operator()(const SproutViewingKey &sk) const {
|
||||
return std::make_pair("sprout", sk.address());
|
||||
|
@ -51,128 +48,26 @@ std::pair<std::string, PaymentAddress> AddressInfoFromViewingKey::operator()(con
|
|||
std::pair<std::string, PaymentAddress> AddressInfoFromViewingKey::operator()(const SaplingExtendedFullViewingKey &sk) const {
|
||||
return std::make_pair("sapling", sk.DefaultAddress());
|
||||
}
|
||||
std::pair<std::string, PaymentAddress> AddressInfoFromViewingKey::operator()(const InvalidEncoding&) const {
|
||||
throw std::invalid_argument("Cannot derive default address from invalid viewing key");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool IsValidPaymentAddress(const libzcash::PaymentAddress& zaddr) {
|
||||
return !std::holds_alternative<libzcash::InvalidEncoding>(zaddr);
|
||||
}
|
||||
|
||||
bool IsValidViewingKey(const libzcash::ViewingKey& vk) {
|
||||
return !std::holds_alternative<libzcash::InvalidEncoding>(vk);
|
||||
}
|
||||
|
||||
bool IsValidSpendingKey(const libzcash::SpendingKey& zkey) {
|
||||
return !std::holds_alternative<libzcash::InvalidEncoding>(zkey);
|
||||
}
|
||||
} // namespace libzcash
|
||||
|
||||
uint32_t TypecodeForReceiver::operator()(
|
||||
const libzcash::SaplingPaymentAddress &zaddr) const
|
||||
{
|
||||
return ZCASH_UA_TYPECODE_SAPLING;
|
||||
}
|
||||
|
||||
uint32_t TypecodeForReceiver::operator()(
|
||||
const libzcash::P2SHAddress &p2sh) const
|
||||
const CScriptID &p2sh) const
|
||||
{
|
||||
return ZCASH_UA_TYPECODE_P2SH;
|
||||
}
|
||||
|
||||
uint32_t TypecodeForReceiver::operator()(
|
||||
const libzcash::P2PKHAddress &p2sh) const
|
||||
const CKeyID &p2sh) const
|
||||
{
|
||||
return ZCASH_UA_TYPECODE_P2PKH;
|
||||
}
|
||||
|
||||
uint32_t TypecodeForReceiver::operator()(
|
||||
const libzcash::UnknownReceiver &unknown) const
|
||||
{
|
||||
return unknown.typecode;
|
||||
}
|
||||
|
||||
std::optional<libzcash::RawAddress> ReceiverToRawAddress::operator()(
|
||||
const libzcash::SaplingPaymentAddress &zaddr) const
|
||||
{
|
||||
return zaddr;
|
||||
}
|
||||
|
||||
std::optional<libzcash::RawAddress> ReceiverToRawAddress::operator()(
|
||||
const libzcash::P2SHAddress &p2sh) const
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<libzcash::RawAddress> ReceiverToRawAddress::operator()(
|
||||
const libzcash::P2PKHAddress &p2sh) const
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<libzcash::RawAddress> ReceiverToRawAddress::operator()(
|
||||
const libzcash::UnknownReceiver &p2sh) const
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<libzcash::RawAddress> RecipientForPaymentAddress::operator()(
|
||||
const libzcash::InvalidEncoding& no) const
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<libzcash::RawAddress> RecipientForPaymentAddress::operator()(
|
||||
const libzcash::SproutPaymentAddress &zaddr) const
|
||||
{
|
||||
return zaddr;
|
||||
}
|
||||
|
||||
std::optional<libzcash::RawAddress> RecipientForPaymentAddress::operator()(
|
||||
const libzcash::SaplingPaymentAddress &zaddr) const
|
||||
{
|
||||
return zaddr;
|
||||
}
|
||||
|
||||
std::optional<libzcash::RawAddress> RecipientForPaymentAddress::operator()(
|
||||
const libzcash::UnifiedAddress &uaddr) const
|
||||
{
|
||||
for (auto& receiver : uaddr) {
|
||||
// Return the first one.
|
||||
return std::visit(ReceiverToRawAddress(), receiver);
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::set<libzcash::RawAddress> GetRawAddresses::operator()(
|
||||
const libzcash::InvalidEncoding& no) const
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
std::set<libzcash::RawAddress> GetRawAddresses::operator()(
|
||||
const libzcash::SproutPaymentAddress &zaddr) const
|
||||
{
|
||||
return {zaddr};
|
||||
}
|
||||
|
||||
std::set<libzcash::RawAddress> GetRawAddresses::operator()(
|
||||
const libzcash::SaplingPaymentAddress &zaddr) const
|
||||
{
|
||||
return {zaddr};
|
||||
}
|
||||
|
||||
std::set<libzcash::RawAddress> GetRawAddresses::operator()(
|
||||
const libzcash::UnifiedAddress &uaddr) const
|
||||
{
|
||||
std::set<libzcash::RawAddress> ret;
|
||||
for (auto& receiver : uaddr) {
|
||||
auto ra = std::visit(ReceiverToRawAddress(), receiver);
|
||||
if (ra) {
|
||||
ret.insert(*ra);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
#define ZC_ADDRESS_H_
|
||||
|
||||
#include "uint256.h"
|
||||
#include "pubkey.h"
|
||||
#include "script/script.h"
|
||||
#include "zcash/address/sapling.hpp"
|
||||
#include "zcash/address/sprout.hpp"
|
||||
#include "zcash/address/zip32.h"
|
||||
|
@ -9,26 +11,6 @@
|
|||
#include <variant>
|
||||
|
||||
namespace libzcash {
|
||||
// We use new classes here instead of CKeyID and CScriptID to prevent a cyclic dependency.
|
||||
class P2PKHAddress: public uint160 {
|
||||
public:
|
||||
P2PKHAddress() {}
|
||||
explicit P2PKHAddress(const std::vector<unsigned char>& vch) : uint160(vch) {}
|
||||
};
|
||||
class P2SHAddress: public uint160 {
|
||||
public:
|
||||
P2SHAddress() {}
|
||||
explicit P2SHAddress(const std::vector<unsigned char>& vch) : uint160(vch) {}
|
||||
};
|
||||
|
||||
/** Protocol addresses that can receive funds in a transaction. */
|
||||
typedef std::variant<SproutPaymentAddress, SaplingPaymentAddress> RawAddress;
|
||||
|
||||
class InvalidEncoding {
|
||||
public:
|
||||
friend bool operator==(const InvalidEncoding &a, const InvalidEncoding &b) { return true; }
|
||||
friend bool operator<(const InvalidEncoding &a, const InvalidEncoding &b) { return true; }
|
||||
};
|
||||
|
||||
class UnknownReceiver {
|
||||
public:
|
||||
|
@ -59,8 +41,8 @@ public:
|
|||
*/
|
||||
typedef std::variant<
|
||||
SaplingPaymentAddress,
|
||||
P2SHAddress,
|
||||
P2PKHAddress,
|
||||
CScriptID,
|
||||
CKeyID,
|
||||
UnknownReceiver> Receiver;
|
||||
|
||||
struct ReceiverIterator {
|
||||
|
@ -137,38 +119,34 @@ public:
|
|||
|
||||
/** Addresses that can appear in a string encoding. */
|
||||
typedef std::variant<
|
||||
InvalidEncoding,
|
||||
CKeyID,
|
||||
CScriptID,
|
||||
SproutPaymentAddress,
|
||||
SaplingPaymentAddress,
|
||||
UnifiedAddress> PaymentAddress;
|
||||
typedef std::variant<InvalidEncoding, SproutViewingKey, SaplingExtendedFullViewingKey> ViewingKey;
|
||||
typedef std::variant<InvalidEncoding, SproutSpendingKey, SaplingExtendedSpendingKey> SpendingKey;
|
||||
/** Viewing keys that can be decoded from a string representation. */
|
||||
typedef std::variant<
|
||||
SproutViewingKey,
|
||||
SaplingExtendedFullViewingKey> ViewingKey;
|
||||
/** Spending keys that can have a string encoding. */
|
||||
typedef std::variant<
|
||||
SproutSpendingKey,
|
||||
SaplingExtendedSpendingKey> SpendingKey;
|
||||
|
||||
class AddressInfoFromSpendingKey {
|
||||
public:
|
||||
std::pair<std::string, PaymentAddress> operator()(const SproutSpendingKey&) const;
|
||||
std::pair<std::string, PaymentAddress> operator()(const struct SaplingExtendedSpendingKey&) const;
|
||||
std::pair<std::string, PaymentAddress> operator()(const InvalidEncoding&) const;
|
||||
};
|
||||
|
||||
class AddressInfoFromViewingKey {
|
||||
public:
|
||||
std::pair<std::string, PaymentAddress> operator()(const SproutViewingKey&) const;
|
||||
std::pair<std::string, PaymentAddress> operator()(const struct SaplingExtendedFullViewingKey&) const;
|
||||
std::pair<std::string, PaymentAddress> operator()(const InvalidEncoding&) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/** Check whether a PaymentAddress is not an InvalidEncoding. */
|
||||
bool IsValidPaymentAddress(const libzcash::PaymentAddress& zaddr);
|
||||
|
||||
/** Check whether a ViewingKey is not an InvalidEncoding. */
|
||||
bool IsValidViewingKey(const libzcash::ViewingKey& vk);
|
||||
|
||||
/** Check whether a SpendingKey is not an InvalidEncoding. */
|
||||
bool IsValidSpendingKey(const libzcash::SpendingKey& zkey);
|
||||
|
||||
/**
|
||||
* Gets the typecode for the given UA receiver.
|
||||
*/
|
||||
|
@ -177,48 +155,9 @@ public:
|
|||
TypecodeForReceiver() {}
|
||||
|
||||
uint32_t operator()(const libzcash::SaplingPaymentAddress &zaddr) const;
|
||||
uint32_t operator()(const libzcash::P2SHAddress &p2sh) const;
|
||||
uint32_t operator()(const libzcash::P2PKHAddress &p2pkh) const;
|
||||
uint32_t operator()(const CScriptID &p2sh) const;
|
||||
uint32_t operator()(const CKeyID &p2pkh) const;
|
||||
uint32_t operator()(const libzcash::UnknownReceiver &p2pkh) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts the given UA receiver to a protocol address, if it is a shielded receiver.
|
||||
*/
|
||||
class ReceiverToRawAddress {
|
||||
public:
|
||||
ReceiverToRawAddress() {}
|
||||
|
||||
std::optional<libzcash::RawAddress> operator()(const libzcash::SaplingPaymentAddress &zaddr) const;
|
||||
std::optional<libzcash::RawAddress> operator()(const libzcash::P2SHAddress &p2sh) const;
|
||||
std::optional<libzcash::RawAddress> operator()(const libzcash::P2PKHAddress &p2pkh) const;
|
||||
std::optional<libzcash::RawAddress> operator()(const libzcash::UnknownReceiver &p2pkh) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the protocol address that should be used in transaction outputs.
|
||||
*/
|
||||
class RecipientForPaymentAddress {
|
||||
public:
|
||||
RecipientForPaymentAddress() {}
|
||||
|
||||
std::optional<libzcash::RawAddress> operator()(const libzcash::InvalidEncoding& no) const;
|
||||
std::optional<libzcash::RawAddress> operator()(const libzcash::SproutPaymentAddress &zaddr) const;
|
||||
std::optional<libzcash::RawAddress> operator()(const libzcash::SaplingPaymentAddress &zaddr) const;
|
||||
std::optional<libzcash::RawAddress> operator()(const libzcash::UnifiedAddress &uaddr) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns all protocol addresses contained within the given payment address.
|
||||
*/
|
||||
class GetRawAddresses {
|
||||
public:
|
||||
GetRawAddresses() {}
|
||||
|
||||
std::set<libzcash::RawAddress> operator()(const libzcash::InvalidEncoding& no) const;
|
||||
std::set<libzcash::RawAddress> operator()(const libzcash::SproutPaymentAddress &zaddr) const;
|
||||
std::set<libzcash::RawAddress> operator()(const libzcash::SaplingPaymentAddress &zaddr) const;
|
||||
std::set<libzcash::RawAddress> operator()(const libzcash::UnifiedAddress &uaddr) const;
|
||||
};
|
||||
|
||||
#endif // ZC_ADDRESS_H_
|
||||
|
|
Loading…
Reference in New Issue