diff --git a/doc/payment-api.md b/doc/payment-api.md
index e639cc429..5d43ed4ac 100644
--- a/doc/payment-api.md
+++ b/doc/payment-api.md
@@ -55,7 +55,7 @@ Command | Parameters | Description
--- | --- | ---
z_getnewaddress | | Return a new zaddr for sending and receiving payments. The spending key for this zaddr will be added to the node’s wallet.
Output:
zN68D8hSs3...
z_listaddresses | | Returns a list of all the zaddrs in this node’s wallet for which you have a spending key.
Output:
{ [“z123…”, “z456...”, “z789...”] }
-z_validateaddress | zaddr | Return information about a given zaddr.
Output:
{"isvalid" : true,
"address" : "zcWsmq...",
"payingkey" : "f5bb3c...",
"transmissionkey" : "7a58c7...",
"ismine" : true}
+z_validateaddress | zaddr | Return information about a given zaddr.
Output:
{"isvalid" : true,
"address" : "zcWsmq...",
"type" : "sprout",
"payingkey" : "f5bb3c...",
"transmissionkey" : "7a58c7...",
"ismine" : true}
### Key Management
diff --git a/src/rpcmisc.cpp b/src/rpcmisc.cpp
index 6359e507c..7f1a41a8c 100644
--- a/src/rpcmisc.cpp
+++ b/src/rpcmisc.cpp
@@ -206,6 +206,43 @@ UniValue validateaddress(const UniValue& params, bool fHelp)
}
+class DescribePaymentAddressVisitor : public boost::static_visitor
+{
+public:
+ UniValue operator()(const libzcash::InvalidEncoding &zaddr) const { return UniValue(UniValue::VOBJ); }
+
+ UniValue operator()(const libzcash::SproutPaymentAddress &zaddr) const {
+ UniValue obj(UniValue::VOBJ);
+ obj.push_back(Pair("type", "sprout"));
+ obj.push_back(Pair("payingkey", zaddr.a_pk.GetHex()));
+ obj.push_back(Pair("transmissionkey", zaddr.pk_enc.GetHex()));
+#ifdef ENABLE_WALLET
+ if (pwalletMain) {
+ obj.push_back(Pair("ismine", pwalletMain->HaveSpendingKey(zaddr)));
+ }
+#endif
+ return obj;
+ }
+
+ UniValue operator()(const libzcash::SaplingPaymentAddress &zaddr) const {
+ UniValue obj(UniValue::VOBJ);
+ obj.push_back(Pair("type", "sapling"));
+ obj.push_back(Pair("diversifier", HexStr(zaddr.d)));
+ obj.push_back(Pair("diversifiedtransmissionkey", zaddr.pk_d.GetHex()));
+#ifdef ENABLE_WALLET
+ if (pwalletMain) {
+ libzcash::SaplingIncomingViewingKey ivk;
+ libzcash::SaplingFullViewingKey fvk;
+ bool isMine = pwalletMain->GetSaplingIncomingViewingKey(zaddr, ivk) &&
+ pwalletMain->GetSaplingFullViewingKey(ivk, fvk) &&
+ pwalletMain->HaveSaplingSpendingKey(fvk);
+ obj.push_back(Pair("ismine", isMine));
+ }
+#endif
+ return obj;
+ }
+};
+
UniValue z_validateaddress(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 1)
@@ -218,9 +255,12 @@ UniValue z_validateaddress(const UniValue& params, bool fHelp)
"{\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"
- " \"payingkey\" : \"hex\", (string) The hex value of the paying key, a_pk\n"
- " \"transmissionkey\" : \"hex\", (string) The hex value of the transmission key, pk_enc\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"
+ " \"diversifiedtransmissionkey\" : \"hex\", (string) [sapling] The hex value of pk_d\n"
"}\n"
"\nExamples:\n"
@@ -235,34 +275,17 @@ UniValue z_validateaddress(const UniValue& params, bool fHelp)
LOCK(cs_main);
#endif
- bool isMine = false;
- std::string payingKey, transmissionKey;
-
string strAddress = params[0].get_str();
auto address = DecodePaymentAddress(strAddress);
bool isValid = IsValidPaymentAddress(address);
- if (isValid) {
- // TODO: Add Sapling support
- assert(boost::get(&address) != nullptr);
- libzcash::SproutPaymentAddress addr = boost::get(address);
-
-#ifdef ENABLE_WALLET
- isMine = pwalletMain->HaveSpendingKey(addr);
-#endif
- payingKey = addr.a_pk.GetHex();
- transmissionKey = addr.pk_enc.GetHex();
- }
UniValue ret(UniValue::VOBJ);
- ret.push_back(Pair("isvalid", static_cast(isValid)));
+ ret.push_back(Pair("isvalid", isValid));
if (isValid)
{
ret.push_back(Pair("address", strAddress));
- ret.push_back(Pair("payingkey", payingKey));
- ret.push_back(Pair("transmissionkey", transmissionKey));
-#ifdef ENABLE_WALLET
- ret.push_back(Pair("ismine", isMine));
-#endif
+ UniValue detail = boost::apply_visitor(DescribePaymentAddressVisitor(), address);
+ ret.pushKVs(detail);
}
return ret;
}
diff --git a/src/test/rpc_wallet_tests.cpp b/src/test/rpc_wallet_tests.cpp
index 42590c39e..8925c36fb 100644
--- a/src/test/rpc_wallet_tests.cpp
+++ b/src/test/rpc_wallet_tests.cpp
@@ -359,6 +359,7 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_validateaddress)
resultObj = retValue.get_obj();
b = find_value(resultObj, "isvalid").get_bool();
BOOST_CHECK_EQUAL(b, true);
+ BOOST_CHECK_EQUAL(find_value(resultObj, "type").get_str(), "sprout");
b = find_value(resultObj, "ismine").get_bool();
BOOST_CHECK_EQUAL(b, false);
@@ -368,10 +369,28 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_validateaddress)
resultObj = retValue.get_obj();
b = find_value(resultObj, "isvalid").get_bool();
BOOST_CHECK_EQUAL(b, true);
+ BOOST_CHECK_EQUAL(find_value(resultObj, "type").get_str(), "sprout");
b = find_value(resultObj, "ismine").get_bool();
BOOST_CHECK_EQUAL(b, true);
BOOST_CHECK_EQUAL(find_value(resultObj, "payingkey").get_str(), "f5bb3c888ccc9831e3f6ba06e7528e26a312eec3acc1823be8918b6a3a5e20ad");
BOOST_CHECK_EQUAL(find_value(resultObj, "transmissionkey").get_str(), "7a58c7132446564e6b810cf895c20537b3528357dc00150a8e201f491efa9c1a");
+
+ // This Sapling address is not valid, it belongs to another network
+ BOOST_CHECK_NO_THROW(retValue = CallRPC("z_validateaddress ztestsapling1knww2nyjc62njkard0jmx7hlsj6twxmxwprn7anvrv4dc2zxanl3nemc0qx2hvplxmd2uau8gyw"));
+ resultObj = retValue.get_obj();
+ b = find_value(resultObj, "isvalid").get_bool();
+ BOOST_CHECK_EQUAL(b, false);
+
+ // This Sapling address is valid, but the spending key is not in this wallet
+ BOOST_CHECK_NO_THROW(retValue = CallRPC("z_validateaddress zs1z7rejlpsa98s2rrrfkwmaxu53e4ue0ulcrw0h4x5g8jl04tak0d3mm47vdtahatqrlkngh9slya"));
+ resultObj = retValue.get_obj();
+ b = find_value(resultObj, "isvalid").get_bool();
+ BOOST_CHECK_EQUAL(b, true);
+ BOOST_CHECK_EQUAL(find_value(resultObj, "type").get_str(), "sapling");
+ b = find_value(resultObj, "ismine").get_bool();
+ BOOST_CHECK_EQUAL(b, false);
+ BOOST_CHECK_EQUAL(find_value(resultObj, "diversifier").get_str(), "1787997c30e94f050c634d");
+ BOOST_CHECK_EQUAL(find_value(resultObj, "diversifiedtransmissionkey").get_str(), "34ed1f60f5db5763beee1ddbb37dd5f7e541d4d4fbdcc09fbfcc6b8e949bbe9d");
}
/*