diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index e337bb16a..e9bca20ff 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -406,6 +406,7 @@ static const CRPCCommand vRPCCommands[] = { "wallet", "z_listaddresses", &z_listaddresses, true }, { "wallet", "z_exportkey", &z_exportkey, true }, { "wallet", "z_importkey", &z_importkey, true }, + { "wallet", "z_validateviewingkey", &z_validateviewingkey, true }, { "wallet", "z_exportviewingkey", &z_exportviewingkey, true }, { "wallet", "z_importviewingkey", &z_importviewingkey, true }, { "wallet", "z_exportwallet", &z_exportwallet, true }, diff --git a/src/rpcserver.h b/src/rpcserver.h index fd4094d55..c2dfa4a3c 100644 --- a/src/rpcserver.h +++ b/src/rpcserver.h @@ -291,6 +291,7 @@ extern UniValue getblocksubsidy(const UniValue& params, bool fHelp); extern UniValue z_exportkey(const UniValue& params, bool fHelp); // in rpcdump.cpp extern UniValue z_importkey(const UniValue& params, bool fHelp); // in rpcdump.cpp +extern UniValue z_validateviewingkey(const UniValue& params, bool fHelp); // in rpcdump.cpp extern UniValue z_exportviewingkey(const UniValue& params, bool fHelp); // in rpcdump.cpp extern UniValue z_importviewingkey(const UniValue& params, bool fHelp); // in rpcdump.cpp extern UniValue z_getnewaddress(const UniValue& params, bool fHelp); // in rpcwallet.cpp diff --git a/src/test/rpc_wallet_tests.cpp b/src/test/rpc_wallet_tests.cpp index 07ac4cf62..b4241e4a6 100644 --- a/src/test/rpc_wallet_tests.cpp +++ b/src/test/rpc_wallet_tests.cpp @@ -314,6 +314,29 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_getbalance) BOOST_CHECK_THROW(CallRPC("z_listreceivedbyaddress tnRZ8bPq2pff3xBWhTJhNkVUkm2uhzksDeW5PvEa7aFKGT9Qi3YgTALZfjaY4jU3HLVKBtHdSXxoPoLA3naMPcHBcY88FcF 1"), runtime_error); } +/** + * This test covers RPC command z_validateviewingkey + */ +BOOST_AUTO_TEST_CASE(rpc_wallet_z_validateviewingkey) +{ + SelectParams(CBaseChainParams::MAIN); + + LOCK2(cs_main, pwalletMain->cs_wallet); + + UniValue retValue; + + // Check number of args + BOOST_CHECK_THROW(CallRPC("z_validateviewingkey"), runtime_error); + BOOST_CHECK_THROW(CallRPC("z_validateviewingkey toomany args"), runtime_error); + + BOOST_CHECK_NO_THROW(retValue = CallRPC("z_validateviewingkey VKstuff")); + UniValue resultObj = retValue.get_obj(); + bool b = find_value(resultObj, "isvalid").get_bool(); + BOOST_CHECK_EQUAL(b, false); + b = find_value(resultObj, "ismine").get_bool(); + BOOST_CHECK_EQUAL(b, false); +} + /** * This test covers RPC command z_validateaddress */ diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index e06c8dde7..f74504b3f 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -649,6 +649,51 @@ UniValue z_importkey(const UniValue& params, bool fHelp) return NullUniValue; } +UniValue z_validateviewingkey(const UniValue& params, bool fHelp) +{ + if (!EnsureWalletIsAvailable(fHelp)) + return NullUniValue; + + if (fHelp || params.size() != 1) + throw runtime_error( + "z_validateviewingkey \"vkey\"\n" + "\nReturn information about the given Zcash viewing key.\n" + "\nArguments:\n" + "1. \"vkey\" (string, required) The viewing key (see z_exportviewingkey)\n" + "\nExamples:\n" + "\nValidate a viewing key\n" + + HelpExampleCli("z_validateviewingkey", "\"vkey\"") + + "\nAs a JSON-RPC call\n" + + HelpExampleRpc("z_validateviewingkey", "\"vkey\"") + ); + + LOCK2(cs_main, pwalletMain->cs_wallet); + + EnsureWalletIsUnlocked(); + + string strVKey = params[0].get_str(); + auto viewingkey = DecodeViewingKey(strVKey); + + // TODO: Add Sapling support. For now, ensure we can freely convert. + assert(boost::get(&viewingkey) != nullptr); + + auto vkey = boost::get(viewingkey); + auto addr = vkey.address(); + bool isValid = IsValidViewingKey(viewingkey); + bool isMine = pwalletMain->HaveSpendingKey(addr); + + UniValue ret(UniValue::VOBJ); + ret.push_back(Pair("isvalid", isValid)); + + if (isValid) { + ret.push_back(Pair("address", addr.GetHash().ToString() )); + ret.push_back(Pair("viewingkey", strVKey)); + ret.push_back(Pair("ismine", isMine)); + } + + return ret; +} + UniValue z_importviewingkey(const UniValue& params, bool fHelp) { if (!EnsureWalletIsAvailable(fHelp))