Add RPC methods for exporting/importing viewing keys
This commit is contained in:
@@ -82,10 +82,14 @@ _zcash_cli() {
|
|||||||
COMPREPLY=( $( compgen -W "add remove" -- "$cur" ) )
|
COMPREPLY=( $( compgen -W "add remove" -- "$cur" ) )
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
fundrawtransaction|getblock|getblockheader|getmempoolancestors|getmempooldescendants|getrawtransaction|gettransaction|listaccounts|listreceivedbyaccount|listreceivedbyaddress|sendrawtransaction|z_importkey)
|
fundrawtransaction|getblock|getblockheader|getmempoolancestors|getmempooldescendants|getrawtransaction|gettransaction|listaccounts|listreceivedbyaccount|listreceivedbyaddress|sendrawtransaction)
|
||||||
COMPREPLY=( $( compgen -W "true false" -- "$cur" ) )
|
COMPREPLY=( $( compgen -W "true false" -- "$cur" ) )
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
|
z_importkey|z_importviewingkey)
|
||||||
|
COMPREPLY=( $( compgen -W "yes no whenkeyisnew" -- "$cur" ) )
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
move|setaccount)
|
move|setaccount)
|
||||||
_zcash_accounts
|
_zcash_accounts
|
||||||
return 0
|
return 0
|
||||||
|
|||||||
@@ -114,6 +114,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
|
|||||||
{ "z_getoperationstatus", 0},
|
{ "z_getoperationstatus", 0},
|
||||||
{ "z_getoperationresult", 0},
|
{ "z_getoperationresult", 0},
|
||||||
{ "z_importkey", 2 },
|
{ "z_importkey", 2 },
|
||||||
|
{ "z_importviewingkey", 2 },
|
||||||
{ "z_getpaymentdisclosure", 1},
|
{ "z_getpaymentdisclosure", 1},
|
||||||
{ "z_getpaymentdisclosure", 2}
|
{ "z_getpaymentdisclosure", 2}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -395,6 +395,8 @@ static const CRPCCommand vRPCCommands[] =
|
|||||||
{ "wallet", "z_listaddresses", &z_listaddresses, true },
|
{ "wallet", "z_listaddresses", &z_listaddresses, true },
|
||||||
{ "wallet", "z_exportkey", &z_exportkey, true },
|
{ "wallet", "z_exportkey", &z_exportkey, true },
|
||||||
{ "wallet", "z_importkey", &z_importkey, true },
|
{ "wallet", "z_importkey", &z_importkey, true },
|
||||||
|
{ "wallet", "z_exportviewingkey", &z_exportviewingkey, true },
|
||||||
|
{ "wallet", "z_importviewingkey", &z_importviewingkey, true },
|
||||||
{ "wallet", "z_exportwallet", &z_exportwallet, true },
|
{ "wallet", "z_exportwallet", &z_exportwallet, true },
|
||||||
{ "wallet", "z_importwallet", &z_importwallet, true },
|
{ "wallet", "z_importwallet", &z_importwallet, true },
|
||||||
|
|
||||||
|
|||||||
@@ -279,6 +279,8 @@ extern UniValue getblocksubsidy(const UniValue& params, bool fHelp);
|
|||||||
|
|
||||||
extern UniValue z_exportkey(const UniValue& params, bool fHelp); // in rpcdump.cpp
|
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_importkey(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
|
extern UniValue z_getnewaddress(const UniValue& params, bool fHelp); // in rpcwallet.cpp
|
||||||
extern UniValue z_listaddresses(const UniValue& params, bool fHelp); // in rpcwallet.cpp
|
extern UniValue z_listaddresses(const UniValue& params, bool fHelp); // in rpcwallet.cpp
|
||||||
extern UniValue z_exportwallet(const UniValue& params, bool fHelp); // in rpcdump.cpp
|
extern UniValue z_exportwallet(const UniValue& params, bool fHelp); // in rpcdump.cpp
|
||||||
|
|||||||
@@ -644,6 +644,91 @@ UniValue z_importkey(const UniValue& params, bool fHelp)
|
|||||||
return NullUniValue;
|
return NullUniValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UniValue z_importviewingkey(const UniValue& params, bool fHelp)
|
||||||
|
{
|
||||||
|
if (!EnsureWalletIsAvailable(fHelp))
|
||||||
|
return NullUniValue;
|
||||||
|
|
||||||
|
if (fHelp || params.size() < 1 || params.size() > 2)
|
||||||
|
throw runtime_error(
|
||||||
|
"z_importviewingkey \"vkey\" ( rescan startHeight )\n"
|
||||||
|
"\nAdds a viewing key (as returned by z_exportviewingkey) to your wallet.\n"
|
||||||
|
"\nArguments:\n"
|
||||||
|
"1. \"vkey\" (string, required) The viewing key (see z_exportviewingkey)\n"
|
||||||
|
"2. rescan (string, optional, default=\"whenkeyisnew\") Rescan the wallet for transactions - can be \"yes\", \"no\" or \"whenkeyisnew\"\n"
|
||||||
|
"3. startHeight (numeric, optional, default=0) Block height to start rescan from\n"
|
||||||
|
"\nNote: This call can take minutes to complete if rescan is true.\n"
|
||||||
|
"\nExamples:\n"
|
||||||
|
"\nImport a viewing key\n"
|
||||||
|
+ HelpExampleCli("z_importviewingkey", "\"vkey\"") +
|
||||||
|
"\nImport the viewing key without rescan\n"
|
||||||
|
+ HelpExampleCli("z_importviewingkey", "\"vkey\", no") +
|
||||||
|
"\nImport the viewing key with partial rescan\n"
|
||||||
|
+ HelpExampleCli("z_importviewingkey", "\"vkey\" whenkeyisnew 30000") +
|
||||||
|
"\nRe-import the viewing key with longer partial rescan\n"
|
||||||
|
+ HelpExampleCli("z_importviewingkey", "\"vkey\" yes 20000") +
|
||||||
|
"\nAs a JSON-RPC call\n"
|
||||||
|
+ HelpExampleRpc("z_importviewingkey", "\"vkey\", \"no\"")
|
||||||
|
);
|
||||||
|
|
||||||
|
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||||
|
|
||||||
|
EnsureWalletIsUnlocked();
|
||||||
|
|
||||||
|
// Whether to perform rescan after import
|
||||||
|
bool fRescan = true;
|
||||||
|
bool fIgnoreExistingKey = true;
|
||||||
|
if (params.size() > 1) {
|
||||||
|
auto rescan = params[1].get_str();
|
||||||
|
if (rescan.compare("whenkeyisnew") != 0) {
|
||||||
|
fIgnoreExistingKey = false;
|
||||||
|
if (rescan.compare("no") == 0) {
|
||||||
|
fRescan = false;
|
||||||
|
} else if (rescan.compare("yes") != 0) {
|
||||||
|
throw JSONRPCError(
|
||||||
|
RPC_INVALID_PARAMETER,
|
||||||
|
"rescan must be \"yes\", \"no\" or \"whenkeyisnew\"");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Height to rescan from
|
||||||
|
int nRescanHeight = 0;
|
||||||
|
if (params.size() > 2)
|
||||||
|
nRescanHeight = params[2].get_int();
|
||||||
|
if (nRescanHeight < 0 || nRescanHeight > chainActive.Height()) {
|
||||||
|
throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range");
|
||||||
|
}
|
||||||
|
|
||||||
|
string strVKey = params[0].get_str();
|
||||||
|
CZCViewingKey viewingkey(strVKey);
|
||||||
|
auto vkey = viewingkey.Get();
|
||||||
|
auto addr = vkey.address();
|
||||||
|
|
||||||
|
{
|
||||||
|
if (pwalletMain->HaveSpendingKey(addr))
|
||||||
|
throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this viewing key");
|
||||||
|
|
||||||
|
// Don't throw error in case a viewing key is already there
|
||||||
|
if (pwalletMain->HaveViewingKey(addr)) {
|
||||||
|
if (fIgnoreExistingKey) {
|
||||||
|
return NullUniValue;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pwalletMain->MarkDirty();
|
||||||
|
|
||||||
|
if (!pwalletMain->AddViewingKey(vkey))
|
||||||
|
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding viewing key to wallet");
|
||||||
|
}
|
||||||
|
|
||||||
|
// We want to scan for transactions and notes
|
||||||
|
if (fRescan) {
|
||||||
|
pwalletMain->ScanForWalletTransactions(chainActive[nRescanHeight], true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NullUniValue;
|
||||||
|
}
|
||||||
|
|
||||||
UniValue z_exportkey(const UniValue& params, bool fHelp)
|
UniValue z_exportkey(const UniValue& params, bool fHelp)
|
||||||
{
|
{
|
||||||
@@ -682,3 +767,43 @@ UniValue z_exportkey(const UniValue& params, bool fHelp)
|
|||||||
return spendingkey.ToString();
|
return spendingkey.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UniValue z_exportviewingkey(const UniValue& params, bool fHelp)
|
||||||
|
{
|
||||||
|
if (!EnsureWalletIsAvailable(fHelp))
|
||||||
|
return NullUniValue;
|
||||||
|
|
||||||
|
if (fHelp || params.size() != 1)
|
||||||
|
throw runtime_error(
|
||||||
|
"z_exportviewingkey \"zaddr\"\n"
|
||||||
|
"\nReveals the viewing key corresponding to 'zaddr'.\n"
|
||||||
|
"Then the z_importviewingkey can be used with this output\n"
|
||||||
|
"\nArguments:\n"
|
||||||
|
"1. \"zaddr\" (string, required) The zaddr for the viewing key\n"
|
||||||
|
"\nResult:\n"
|
||||||
|
"\"vkey\" (string) The viewing key\n"
|
||||||
|
"\nExamples:\n"
|
||||||
|
+ HelpExampleCli("z_exportviewingkey", "\"myaddress\"")
|
||||||
|
+ HelpExampleRpc("z_exportviewingkey", "\"myaddress\"")
|
||||||
|
);
|
||||||
|
|
||||||
|
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||||
|
|
||||||
|
EnsureWalletIsUnlocked();
|
||||||
|
|
||||||
|
string strAddress = params[0].get_str();
|
||||||
|
|
||||||
|
CZCPaymentAddress address(strAddress);
|
||||||
|
auto addr = address.Get();
|
||||||
|
|
||||||
|
libzcash::ViewingKey vk;
|
||||||
|
if (!pwalletMain->GetViewingKey(addr, vk)) {
|
||||||
|
libzcash::SpendingKey k;
|
||||||
|
if (!pwalletMain->GetSpendingKey(addr, k)) {
|
||||||
|
throw JSONRPCError(RPC_WALLET_ERROR, "Wallet does not hold private key or viewing key for this zaddr");
|
||||||
|
}
|
||||||
|
vk = k.viewing_key();
|
||||||
|
}
|
||||||
|
|
||||||
|
CZCViewingKey viewingkey(vk);
|
||||||
|
return viewingkey.ToString();
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user