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"); } /*