Auto merge of #2143 - str4d:1997-viewing-keys, r=str4d

Implement incoming viewing keys

Closes #1997.
This commit is contained in:
Homu
2017-12-20 14:11:05 -08:00
28 changed files with 698 additions and 123 deletions

View File

@@ -2667,7 +2667,7 @@ UniValue zc_raw_receive(const UniValue& params, bool fHelp)
}
}
ZCNoteDecryption decryptor(k.viewing_key());
ZCNoteDecryption decryptor(k.receiving_key());
NotePlaintext npt = NotePlaintext::decrypt(
decryptor,
@@ -2902,6 +2902,7 @@ UniValue zc_raw_keygen(const UniValue& params, bool fHelp)
"Output: {\n"
" \"zcaddress\": zcaddr,\n"
" \"zcsecretkey\": zcsecretkey,\n"
" \"zcviewingkey\": zcviewingkey,\n"
"}\n"
);
}
@@ -2910,18 +2911,14 @@ UniValue zc_raw_keygen(const UniValue& params, bool fHelp)
auto addr = k.address();
auto viewing_key = k.viewing_key();
CDataStream viewing(SER_NETWORK, PROTOCOL_VERSION);
viewing << viewing_key;
CZCPaymentAddress pubaddr(addr);
CZCSpendingKey spendingkey(k);
std::string viewing_hex = HexStr(viewing.begin(), viewing.end());
CZCViewingKey viewingkey(viewing_key);
UniValue result(UniValue::VOBJ);
result.push_back(Pair("zcaddress", pubaddr.ToString()));
result.push_back(Pair("zcsecretkey", spendingkey.ToString()));
result.push_back(Pair("zcviewingkey", viewing_hex));
result.push_back(Pair("zcviewingkey", viewingkey.ToString()));
return result;
}
@@ -2960,9 +2957,10 @@ UniValue z_listaddresses(const UniValue& params, bool fHelp)
if (fHelp || params.size() > 1)
throw runtime_error(
"z_listaddresses\n"
"z_listaddresses ( includeWatchonly )\n"
"\nReturns the list of zaddr belonging to the wallet.\n"
"\nArguments:\n"
"1. includeWatchonly (bool, optional, default=false) Also include watchonly addresses (see 'z_importviewingkey')\n"
"\nResult:\n"
"[ (json array of string)\n"
" \"zaddr\" (string) a zaddr belonging to the wallet\n"
@@ -2975,16 +2973,23 @@ UniValue z_listaddresses(const UniValue& params, bool fHelp)
LOCK2(cs_main, pwalletMain->cs_wallet);
bool fIncludeWatchonly = false;
if (params.size() > 0) {
fIncludeWatchonly = params[0].get_bool();
}
UniValue ret(UniValue::VARR);
std::set<libzcash::PaymentAddress> addresses;
pwalletMain->GetPaymentAddresses(addresses);
for (auto addr : addresses ) {
ret.push_back(CZCPaymentAddress(addr).ToString());
if (fIncludeWatchonly || pwalletMain->HaveSpendingKey(addr)) {
ret.push_back(CZCPaymentAddress(addr).ToString());
}
}
return ret;
}
CAmount getBalanceTaddr(std::string transparentAddress, int minDepth=1) {
CAmount getBalanceTaddr(std::string transparentAddress, int minDepth=1, bool ignoreUnspendable=true) {
set<CBitcoinAddress> setAddress;
vector<COutput> vecOutputs;
CAmount balance = 0;
@@ -3006,6 +3011,10 @@ CAmount getBalanceTaddr(std::string transparentAddress, int minDepth=1) {
continue;
}
if (ignoreUnspendable && !out.fSpendable) {
continue;
}
if (setAddress.size()) {
CTxDestination address;
if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) {
@@ -3023,11 +3032,11 @@ CAmount getBalanceTaddr(std::string transparentAddress, int minDepth=1) {
return balance;
}
CAmount getBalanceZaddr(std::string address, int minDepth = 1) {
CAmount getBalanceZaddr(std::string address, int minDepth = 1, bool ignoreUnspendable=true) {
CAmount balance = 0;
std::vector<CNotePlaintextEntry> entries;
LOCK2(cs_main, pwalletMain->cs_wallet);
pwalletMain->GetFilteredNotes(entries, address, minDepth);
pwalletMain->GetFilteredNotes(entries, address, minDepth, true, ignoreUnspendable);
for (auto & entry : entries) {
balance += CAmount(entry.plaintext.value);
}
@@ -3079,14 +3088,14 @@ UniValue z_listreceivedbyaddress(const UniValue& params, bool fHelp)
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid zaddr.");
}
if (!pwalletMain->HaveSpendingKey(zaddr)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key not found.");
if (!(pwalletMain->HaveSpendingKey(zaddr) || pwalletMain->HaveViewingKey(zaddr))) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key or viewing key not found.");
}
UniValue result(UniValue::VARR);
std::vector<CNotePlaintextEntry> entries;
pwalletMain->GetFilteredNotes(entries, fromaddress, nMinDepth, false);
pwalletMain->GetFilteredNotes(entries, fromaddress, nMinDepth, false, false);
for (CNotePlaintextEntry & entry : entries) {
UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("txid",entry.jsop.hash.ToString()));
@@ -3108,6 +3117,8 @@ UniValue z_getbalance(const UniValue& params, bool fHelp)
throw runtime_error(
"z_getbalance \"address\" ( minconf )\n"
"\nReturns the balance of a taddr or zaddr belonging to the nodes wallet.\n"
"\nCAUTION: If address is a watch-only zaddr, the returned balance may be larger than the actual balance,"
"\nbecause spends cannot be detected with incoming viewing keys.\n"
"\nArguments:\n"
"1. \"address\" (string) The selected address. It may be a transparent or private address.\n"
"2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
@@ -3145,16 +3156,16 @@ UniValue z_getbalance(const UniValue& params, bool fHelp)
} catch (const std::runtime_error&) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or zaddr.");
}
if (!pwalletMain->HaveSpendingKey(zaddr)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key not found.");
if (!(pwalletMain->HaveSpendingKey(zaddr) || pwalletMain->HaveViewingKey(zaddr))) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key or viewing key not found.");
}
}
CAmount nBalance = 0;
if (fromTaddr) {
nBalance = getBalanceTaddr(fromaddress, nMinDepth);
nBalance = getBalanceTaddr(fromaddress, nMinDepth, false);
} else {
nBalance = getBalanceZaddr(fromaddress, nMinDepth);
nBalance = getBalanceZaddr(fromaddress, nMinDepth, false);
}
return ValueFromAmount(nBalance);
@@ -3166,12 +3177,15 @@ UniValue z_gettotalbalance(const UniValue& params, bool fHelp)
if (!EnsureWalletIsAvailable(fHelp))
return NullUniValue;
if (fHelp || params.size() > 1)
if (fHelp || params.size() > 2)
throw runtime_error(
"z_gettotalbalance ( minconf )\n"
"z_gettotalbalance ( minconf includeWatchonly )\n"
"\nReturn the total value of funds stored in the nodes wallet.\n"
"\nCAUTION: If the wallet contains watch-only zaddrs, the returned private balance may be larger than the actual balance,"
"\nbecause spends cannot be detected with incoming viewing keys.\n"
"\nArguments:\n"
"1. minconf (numeric, optional, default=1) Only include private and transparent transactions confirmed at least this many times.\n"
"2. includeWatchonly (bool, optional, default=false) Also include balance in watchonly addresses (see 'importaddress' and 'z_importviewingkey')\n"
"\nResult:\n"
"{\n"
" \"transparent\": xxxxx, (numeric) the total balance of transparent funds\n"
@@ -3190,19 +3204,24 @@ UniValue z_gettotalbalance(const UniValue& params, bool fHelp)
LOCK2(cs_main, pwalletMain->cs_wallet);
int nMinDepth = 1;
if (params.size() == 1) {
if (params.size() > 0) {
nMinDepth = params[0].get_int();
}
if (nMinDepth < 0) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
}
bool fIncludeWatchonly = false;
if (params.size() > 1) {
fIncludeWatchonly = params[1].get_bool();
}
// getbalance and "getbalance * 1 true" should return the same number
// but they don't because wtx.GetAmounts() does not handle tx where there are no outputs
// pwalletMain->GetBalance() does not accept min depth parameter
// so we use our own method to get balance of utxos.
CAmount nBalance = getBalanceTaddr("", nMinDepth);
CAmount nPrivateBalance = getBalanceZaddr("", nMinDepth);
CAmount nBalance = getBalanceTaddr("", nMinDepth, !fIncludeWatchonly);
CAmount nPrivateBalance = getBalanceZaddr("", nMinDepth, !fIncludeWatchonly);
CAmount nTotalBalance = nBalance + nPrivateBalance;
UniValue result(UniValue::VOBJ);
result.push_back(Pair("transparent", FormatMoney(nBalance)));