diff --git a/doc/payment-api.md b/doc/payment-api.md
index dd10c3497..7ea8ae238 100644
--- a/doc/payment-api.md
+++ b/doc/payment-api.md
@@ -29,7 +29,7 @@ Optional parameters are denoted in [square brackets].
RPC calls by category:
* Accounting: z_getbalance, z_gettotalbalance
-* Addresses : z_getnewaddress, z_listaddresses
+* Addresses : z_getnewaddress, z_listaddresses, z_validateaddress
* Keys : z_exportkey, z_importkey, z_exportwallet, z_importwallet
* Operation: z_getoperationresult, z_getoperationstatus, z_listoperationids
* Payment : z_listreceivedbyaddress, z_sendmany
@@ -55,6 +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 | | Return information about a given zaddr.
Output:
{"isvalid" : true,
"address" : "zcWsmq...",
"payingkey" : "f5bb3c...",
"transmissionkey" : "7a58c7...",
"ismine" : true}
### Key Management
diff --git a/src/rpcmisc.cpp b/src/rpcmisc.cpp
index f5bef2a07..d5770fc47 100644
--- a/src/rpcmisc.cpp
+++ b/src/rpcmisc.cpp
@@ -23,6 +23,8 @@
#include "json/json_spirit_utils.h"
#include "json/json_spirit_value.h"
+#include "zcash/Address.hpp"
+
using namespace json_spirit;
using namespace std;
@@ -213,6 +215,69 @@ Value validateaddress(const Array& params, bool fHelp)
return ret;
}
+
+Value z_validateaddress(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() != 1)
+ throw runtime_error(
+ "z_validateaddress \"zaddr\"\n"
+ "\nReturn information about the given z address.\n"
+ "\nArguments:\n"
+ "1. \"zaddr\" (string, required) The z 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"
+ " \"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"
+
+ "}\n"
+ "\nExamples:\n"
+ + HelpExampleCli("validateaddress", "\"zcWsmqT4X2V4jgxbgiCzyrAfRT1vi1F4sn7M5Pkh66izzw8Uk7LBGAH3DtcSMJeUb2pi3W4SQF8LMKkU2cUuVP68yAGcomL\"")
+ );
+
+
+#ifdef ENABLE_WALLET
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+#else
+ LOCK(cs_main);
+#endif
+
+ bool isValid = false;
+ bool isMine = false;
+ std::string payingKey, transmissionKey;
+
+ string strAddress = params[0].get_str();
+ try {
+ CZCPaymentAddress address(strAddress);
+ libzcash::PaymentAddress addr = address.Get();
+
+#ifdef ENABLE_WALLET
+ isMine = pwalletMain->HaveSpendingKey(addr);
+#endif
+ payingKey = addr.a_pk.GetHex();
+ transmissionKey = addr.pk_enc.GetHex();
+ isValid = true;
+ } catch (std::runtime_error e) {
+ // address is invalid, nop here as isValid is false.
+ }
+
+ Object ret;
+ 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
+ }
+ return ret;
+}
+
+
/**
* Used by addmultisigaddress / createmultisig:
*/
diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp
index 99e529ef3..b990f2040 100644
--- a/src/rpcserver.cpp
+++ b/src/rpcserver.cpp
@@ -330,6 +330,7 @@ static const CRPCCommand vRPCCommands[] =
{ "util", "verifymessage", &verifymessage, true },
{ "util", "estimatefee", &estimatefee, true },
{ "util", "estimatepriority", &estimatepriority, true },
+ { "util", "z_validateaddress", &z_validateaddress, true }, /* uses wallet if enabled */
/* Not shown in help */
{ "hidden", "invalidateblock", &invalidateblock, true },
diff --git a/src/rpcserver.h b/src/rpcserver.h
index 6402a7a16..b8eac08c4 100644
--- a/src/rpcserver.h
+++ b/src/rpcserver.h
@@ -263,6 +263,7 @@ extern json_spirit::Value z_sendmany(const json_spirit::Array& params, bool fHel
extern json_spirit::Value z_getoperationstatus(const json_spirit::Array& params, bool fHelp); // in rpcwallet.cpp
extern json_spirit::Value z_getoperationresult(const json_spirit::Array& params, bool fHelp); // in rpcwallet.cpp
extern json_spirit::Value z_listoperationids(const json_spirit::Array& params, bool fHelp); // in rpcwallet.cpp
+extern json_spirit::Value z_validateaddress(const json_spirit::Array& params, bool fHelp); // in rpcmisc.cpp
// in rest.cpp
diff --git a/src/test/rpc_wallet_tests.cpp b/src/test/rpc_wallet_tests.cpp
index 2f674df0f..2eaeb7e61 100644
--- a/src/test/rpc_wallet_tests.cpp
+++ b/src/test/rpc_wallet_tests.cpp
@@ -295,13 +295,59 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_getbalance)
BOOST_CHECK_THROW(CallRPC("z_listreceivedbyaddress tnRZ8bPq2pff3xBWhTJhNkVUkm2uhzksDeW5PvEa7aFKGT9Qi3YgTALZfjaY4jU3HLVKBtHdSXxoPoLA3naMPcHBcY88FcF 1"), runtime_error);
}
+/**
+ * This test covers RPC command z_validateaddress
+ */
+BOOST_AUTO_TEST_CASE(rpc_wallet_z_validateaddress)
+{
+ SelectParams(CBaseChainParams::MAIN);
+
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
+ Value retValue;
+
+ // Check number of args
+ BOOST_CHECK_THROW(CallRPC("z_validateaddress"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("z_validateaddress toomany args"), runtime_error);
+
+ // Wallet should be empty
+ std::set addrs;
+ pwalletMain->GetPaymentAddresses(addrs);
+ BOOST_CHECK(addrs.size()==0);
+
+ // This address is not valid, it belongs to another network
+ BOOST_CHECK_NO_THROW(retValue = CallRPC("z_validateaddress ztaaga95QAPyp1kSQ1hD2kguCpzyMHjxWZqaYDEkzbvo7uYQYAw2S8X4Kx98AvhhofMtQL8PAXKHuZsmhRcanavKRKmdCzk"));
+ Object resultObj = retValue.get_obj();
+ bool b = find_value(resultObj, "isvalid").get_bool();
+ BOOST_CHECK_EQUAL(b, false);
+
+ // This address is valid, but the spending key is not in this wallet
+ BOOST_CHECK_NO_THROW(retValue = CallRPC("z_validateaddress zcfA19SDAKRYHLoRDoShcoz4nPohqWxuHcqg8WAxsiB2jFrrs6k7oSvst3UZvMYqpMNSRBkxBsnyjjngX5L55FxMzLKach8"));
+ resultObj = retValue.get_obj();
+ b = find_value(resultObj, "isvalid").get_bool();
+ BOOST_CHECK_EQUAL(b, true);
+ b = find_value(resultObj, "ismine").get_bool();
+ BOOST_CHECK_EQUAL(b, false);
+
+ // Let's import a spending key to the wallet and validate its payment address
+ BOOST_CHECK_NO_THROW(CallRPC("z_importkey SKxoWv77WGwFnUJitQKNEcD636bL4X5Gd6wWmgaA4Q9x8jZBPJXT"));
+ BOOST_CHECK_NO_THROW(retValue = CallRPC("z_validateaddress zcWsmqT4X2V4jgxbgiCzyrAfRT1vi1F4sn7M5Pkh66izzw8Uk7LBGAH3DtcSMJeUb2pi3W4SQF8LMKkU2cUuVP68yAGcomL"));
+ resultObj = retValue.get_obj();
+ b = find_value(resultObj, "isvalid").get_bool();
+ BOOST_CHECK_EQUAL(b, true);
+ 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 test covers RPC command z_exportwallet
*/
BOOST_AUTO_TEST_CASE(rpc_wallet_z_exportwallet)
{
LOCK2(cs_main, pwalletMain->cs_wallet);
-
+
// wallet should be empty
std::set addrs;
pwalletMain->GetPaymentAddresses(addrs);