@@ -68,6 +68,10 @@ Files: src/secp256k1/build-aux/m4/ax_prog_cc_for_build.m4
|
|||||||
Copyright: 2008 Paolo Bonzini <bonzini@gnu.org>
|
Copyright: 2008 Paolo Bonzini <bonzini@gnu.org>
|
||||||
License: GNU-All-permissive-License
|
License: GNU-All-permissive-License
|
||||||
|
|
||||||
|
Files: depends/sources/utfcpp-*.tar.gz
|
||||||
|
Copyright: 2006 Nemanja Trifunovic
|
||||||
|
License: Boost-Software-License-1.0
|
||||||
|
|
||||||
License: Boost-Software-License-1.0
|
License: Boost-Software-License-1.0
|
||||||
Permission is hereby granted, free of charge, to any person or organization
|
Permission is hereby granted, free of charge, to any person or organization
|
||||||
obtaining a copy of the software and accompanying documentation covered by
|
obtaining a copy of the software and accompanying documentation covered by
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
rust_packages := rust librustzcash
|
rust_packages := rust librustzcash
|
||||||
|
|
||||||
ifeq ($(build_os),darwin)
|
ifeq ($(build_os),darwin)
|
||||||
zcash_packages := libsnark libgmp libsodium
|
zcash_packages := libsnark libgmp libsodium utfcpp
|
||||||
else
|
else
|
||||||
proton_packages := proton
|
proton_packages := proton
|
||||||
zcash_packages := libgmp libsodium
|
zcash_packages := libgmp libsodium utfcpp
|
||||||
endif
|
endif
|
||||||
|
|
||||||
rust_crates := \
|
rust_crates := \
|
||||||
|
|||||||
@@ -80,10 +80,10 @@ static int AppInitRawTx(int argc, char* argv[])
|
|||||||
if (argc<2 || mapArgs.count("-?") || mapArgs.count("-h") || mapArgs.count("-help"))
|
if (argc<2 || mapArgs.count("-?") || mapArgs.count("-h") || mapArgs.count("-help"))
|
||||||
{
|
{
|
||||||
// First part of help message is specific to this utility
|
// First part of help message is specific to this utility
|
||||||
std::string strUsage = _("Zcash zcash-tx utility version") + " " + FormatFullVersion() + "\n\n" +
|
std::string strUsage = _("Hush komodo-tx utility version") + " " + FormatFullVersion() + "\n\n" +
|
||||||
_("Usage:") + "\n" +
|
_("Usage:") + "\n" +
|
||||||
" zcash-tx [options] <hex-tx> [commands] " + _("Update hex-encoded zcash transaction") + "\n" +
|
" komodo-tx [options] <hex-tx> [commands] " + _("Update hex-encoded zcash transaction") + "\n" +
|
||||||
" zcash-tx [options] -create [commands] " + _("Create hex-encoded zcash transaction") + "\n" +
|
" komodo-tx [options] -create [commands] " + _("Create hex-encoded zcash transaction") + "\n" +
|
||||||
"\n";
|
"\n";
|
||||||
|
|
||||||
fprintf(stdout, "%s", strUsage.c_str());
|
fprintf(stdout, "%s", strUsage.c_str());
|
||||||
|
|||||||
@@ -151,6 +151,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
|
|||||||
{ "z_mergetoaddress", 2},
|
{ "z_mergetoaddress", 2},
|
||||||
{ "z_mergetoaddress", 3},
|
{ "z_mergetoaddress", 3},
|
||||||
{ "z_mergetoaddress", 4},
|
{ "z_mergetoaddress", 4},
|
||||||
|
{ "z_viewtransaction", 1},
|
||||||
{ "z_sendmany", 1},
|
{ "z_sendmany", 1},
|
||||||
{ "z_sendmany", 2},
|
{ "z_sendmany", 2},
|
||||||
{ "z_sendmany", 3},
|
{ "z_sendmany", 3},
|
||||||
|
|||||||
@@ -53,6 +53,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include <boost/assign/list_of.hpp>
|
#include <boost/assign/list_of.hpp>
|
||||||
|
#include <utf8.h>
|
||||||
|
|
||||||
#include <univalue.h>
|
#include <univalue.h>
|
||||||
|
|
||||||
@@ -342,7 +343,7 @@ UniValue setaccount(const UniValue& params, bool fHelp)
|
|||||||
|
|
||||||
CTxDestination dest = DecodeDestination(params[0].get_str());
|
CTxDestination dest = DecodeDestination(params[0].get_str());
|
||||||
if (!IsValidDestination(dest)) {
|
if (!IsValidDestination(dest)) {
|
||||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address");
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Hush address!");
|
||||||
}
|
}
|
||||||
|
|
||||||
string strAccount;
|
string strAccount;
|
||||||
@@ -389,7 +390,7 @@ UniValue getaccount(const UniValue& params, bool fHelp)
|
|||||||
|
|
||||||
CTxDestination dest = DecodeDestination(params[0].get_str());
|
CTxDestination dest = DecodeDestination(params[0].get_str());
|
||||||
if (!IsValidDestination(dest)) {
|
if (!IsValidDestination(dest)) {
|
||||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address");
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Hush address!");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string strAccount;
|
std::string strAccount;
|
||||||
@@ -449,7 +450,7 @@ static void SendMoney(const CTxDestination &address, CAmount nValue, bool fSubtr
|
|||||||
if (nValue > curBalance)
|
if (nValue > curBalance)
|
||||||
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds");
|
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds");
|
||||||
|
|
||||||
// Parse Zcash address
|
// Parse Hush address
|
||||||
CScript scriptPubKey = GetScriptForDestination(address);
|
CScript scriptPubKey = GetScriptForDestination(address);
|
||||||
|
|
||||||
// Create and send the transaction
|
// Create and send the transaction
|
||||||
@@ -523,7 +524,7 @@ UniValue sendtoaddress(const UniValue& params, bool fHelp)
|
|||||||
|
|
||||||
CTxDestination dest = DecodeDestination(params[0].get_str());
|
CTxDestination dest = DecodeDestination(params[0].get_str());
|
||||||
if (!IsValidDestination(dest)) {
|
if (!IsValidDestination(dest)) {
|
||||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address");
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Hush address!");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Amount
|
// Amount
|
||||||
@@ -935,7 +936,7 @@ UniValue getreceivedbyaddress(const UniValue& params, bool fHelp)
|
|||||||
// Bitcoin address
|
// Bitcoin address
|
||||||
CTxDestination dest = DecodeDestination(params[0].get_str());
|
CTxDestination dest = DecodeDestination(params[0].get_str());
|
||||||
if (!IsValidDestination(dest)) {
|
if (!IsValidDestination(dest)) {
|
||||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address");
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Hush address!");
|
||||||
}
|
}
|
||||||
CScript scriptPubKey = GetScriptForDestination(dest);
|
CScript scriptPubKey = GetScriptForDestination(dest);
|
||||||
if (!IsMine(*pwalletMain, scriptPubKey)) {
|
if (!IsMine(*pwalletMain, scriptPubKey)) {
|
||||||
@@ -1389,7 +1390,7 @@ UniValue sendfrom(const UniValue& params, bool fHelp)
|
|||||||
std::string strAccount = AccountFromValue(params[0]);
|
std::string strAccount = AccountFromValue(params[0]);
|
||||||
CTxDestination dest = DecodeDestination(params[1].get_str());
|
CTxDestination dest = DecodeDestination(params[1].get_str());
|
||||||
if (!IsValidDestination(dest)) {
|
if (!IsValidDestination(dest)) {
|
||||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address");
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Hush address!");
|
||||||
}
|
}
|
||||||
CAmount nAmount = AmountFromValue(params[2]);
|
CAmount nAmount = AmountFromValue(params[2]);
|
||||||
if (nAmount <= 0)
|
if (nAmount <= 0)
|
||||||
@@ -1486,7 +1487,7 @@ UniValue sendmany(const UniValue& params, bool fHelp)
|
|||||||
for (const std::string& name_ : keys) {
|
for (const std::string& name_ : keys) {
|
||||||
CTxDestination dest = DecodeDestination(name_);
|
CTxDestination dest = DecodeDestination(name_);
|
||||||
if (!IsValidDestination(dest)) {
|
if (!IsValidDestination(dest)) {
|
||||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Zcash address: ") + name_);
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Hush address: ") + name_);
|
||||||
}
|
}
|
||||||
|
|
||||||
CScript scriptPubKey = GetScriptForDestination(dest);
|
CScript scriptPubKey = GetScriptForDestination(dest);
|
||||||
@@ -2859,7 +2860,7 @@ UniValue listunspent(const UniValue& params, bool fHelp)
|
|||||||
" \"txid\" : \"txid\", (string) the transaction id \n"
|
" \"txid\" : \"txid\", (string) the transaction id \n"
|
||||||
" \"vout\" : n, (numeric) the vout value\n"
|
" \"vout\" : n, (numeric) the vout value\n"
|
||||||
" \"generated\" : true|false (boolean) true if txout is a coinbase transaction output\n"
|
" \"generated\" : true|false (boolean) true if txout is a coinbase transaction output\n"
|
||||||
" \"address\" : \"address\", (string) the Zcash address\n"
|
" \"address\" : \"address\", (string) the Hush address\n"
|
||||||
" \"account\" : \"account\", (string) DEPRECATED. The associated account, or \"\" for the default account\n"
|
" \"account\" : \"account\", (string) DEPRECATED. The associated account, or \"\" for the default account\n"
|
||||||
" \"scriptPubKey\" : \"key\", (string) the script key\n"
|
" \"scriptPubKey\" : \"key\", (string) the script key\n"
|
||||||
" \"amount\" : x.xxx, (numeric) the transaction amount in " + CURRENCY_UNIT + "\n"
|
" \"amount\" : x.xxx, (numeric) the transaction amount in " + CURRENCY_UNIT + "\n"
|
||||||
@@ -2893,7 +2894,7 @@ UniValue listunspent(const UniValue& params, bool fHelp)
|
|||||||
const UniValue& input = inputs[idx];
|
const UniValue& input = inputs[idx];
|
||||||
CTxDestination dest = DecodeDestination(input.get_str());
|
CTxDestination dest = DecodeDestination(input.get_str());
|
||||||
if (!IsValidDestination(dest)) {
|
if (!IsValidDestination(dest)) {
|
||||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Zcash address: ") + input.get_str());
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Hush address: ") + input.get_str());
|
||||||
}
|
}
|
||||||
if (!destinations.insert(dest).second) {
|
if (!destinations.insert(dest).second) {
|
||||||
throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ") + input.get_str());
|
throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ") + input.get_str());
|
||||||
@@ -3017,13 +3018,12 @@ UniValue z_listunspent(const UniValue& params, bool fHelp)
|
|||||||
"Optionally filter to only include notes sent to specified addresses.\n"
|
"Optionally filter to only include notes sent to specified addresses.\n"
|
||||||
"When minconf is 0, unspent notes with zero confirmations are returned, even though they are not immediately spendable.\n"
|
"When minconf is 0, unspent notes with zero confirmations are returned, even though they are not immediately spendable.\n"
|
||||||
"Results are an array of Objects, each of which has:\n"
|
"Results are an array of Objects, each of which has:\n"
|
||||||
"{txid, jsindex, jsoutindex, confirmations, address, amount, memo} (Sprout)\n"
|
|
||||||
"{txid, outindex, confirmations, address, amount, memo} (Sapling)\n"
|
"{txid, outindex, confirmations, address, amount, memo} (Sapling)\n"
|
||||||
"\nArguments:\n"
|
"\nArguments:\n"
|
||||||
"1. minconf (numeric, optional, default=1) The minimum confirmations to filter\n"
|
"1. minconf (numeric, optional, default=1) The minimum confirmations to filter\n"
|
||||||
"2. maxconf (numeric, optional, default=9999999) The maximum confirmations to filter\n"
|
"2. maxconf (numeric, optional, default=9999999) The maximum confirmations to filter\n"
|
||||||
"3. includeWatchonly (bool, optional, default=false) Also include watchonly addresses (see 'z_importviewingkey')\n"
|
"3. includeWatchonly (bool, optional, default=false) Also include watchonly addresses (see 'z_importviewingkey')\n"
|
||||||
"4. \"addresses\" (string) A json array of zaddrs (both Sprout and Sapling) to filter on. Duplicate addresses not allowed.\n"
|
"4. \"addresses\" (string) A json array of zaddrs to filter on. Duplicate addresses not allowed.\n"
|
||||||
" [\n"
|
" [\n"
|
||||||
" \"address\" (string) zaddr\n"
|
" \"address\" (string) zaddr\n"
|
||||||
" ,...\n"
|
" ,...\n"
|
||||||
@@ -3033,7 +3033,6 @@ UniValue z_listunspent(const UniValue& params, bool fHelp)
|
|||||||
" {\n"
|
" {\n"
|
||||||
" \"txid\" : \"txid\", (string) the transaction id \n"
|
" \"txid\" : \"txid\", (string) the transaction id \n"
|
||||||
" \"jsindex\" : n (numeric) the joinsplit index\n"
|
" \"jsindex\" : n (numeric) the joinsplit index\n"
|
||||||
" \"jsoutindex\" (sprout) : n (numeric) the output index of the joinsplit\n"
|
|
||||||
" \"outindex\" (sapling) : n (numeric) the output index\n"
|
" \"outindex\" (sapling) : n (numeric) the output index\n"
|
||||||
" \"confirmations\" : n (numeric) the number of confirmations\n"
|
" \"confirmations\" : n (numeric) the number of confirmations\n"
|
||||||
" \"spendable\" : true|false (boolean) true if note can be spent by wallet, false if note has zero confirmations, false if address is watchonly\n"
|
" \"spendable\" : true|false (boolean) true if note can be spent by wallet, false if note has zero confirmations, false if address is watchonly\n"
|
||||||
@@ -3095,7 +3094,7 @@ UniValue z_listunspent(const UniValue& params, bool fHelp)
|
|||||||
string address = o.get_str();
|
string address = o.get_str();
|
||||||
auto zaddr = DecodePaymentAddress(address);
|
auto zaddr = DecodePaymentAddress(address);
|
||||||
if (!IsValidPaymentAddress(zaddr)) {
|
if (!IsValidPaymentAddress(zaddr)) {
|
||||||
throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, address is not a valid zaddr: ") + address);
|
throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, address is not a valid Hush zaddr: ") + address);
|
||||||
}
|
}
|
||||||
auto hasSpendingKey = boost::apply_visitor(HaveSpendingKeyForPaymentAddress(pwalletMain), zaddr);
|
auto hasSpendingKey = boost::apply_visitor(HaveSpendingKeyForPaymentAddress(pwalletMain), zaddr);
|
||||||
if (!fIncludeWatchonly && !hasSpendingKey) {
|
if (!fIncludeWatchonly && !hasSpendingKey) {
|
||||||
@@ -3111,14 +3110,9 @@ UniValue z_listunspent(const UniValue& params, bool fHelp)
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// User did not provide zaddrs, so use default i.e. all addresses
|
// User did not provide zaddrs, so use default i.e. all addresses
|
||||||
std::set<libzcash::SproutPaymentAddress> sproutzaddrs = {};
|
|
||||||
pwalletMain->GetSproutPaymentAddresses(sproutzaddrs);
|
|
||||||
|
|
||||||
// Sapling support
|
|
||||||
std::set<libzcash::SaplingPaymentAddress> saplingzaddrs = {};
|
std::set<libzcash::SaplingPaymentAddress> saplingzaddrs = {};
|
||||||
pwalletMain->GetSaplingPaymentAddresses(saplingzaddrs);
|
pwalletMain->GetSaplingPaymentAddresses(saplingzaddrs);
|
||||||
|
|
||||||
zaddrs.insert(sproutzaddrs.begin(), sproutzaddrs.end());
|
|
||||||
zaddrs.insert(saplingzaddrs.begin(), saplingzaddrs.end());
|
zaddrs.insert(saplingzaddrs.begin(), saplingzaddrs.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3130,32 +3124,6 @@ UniValue z_listunspent(const UniValue& params, bool fHelp)
|
|||||||
pwalletMain->GetFilteredNotes(sproutEntries, saplingEntries, zaddrs, nMinDepth, nMaxDepth, true, !fIncludeWatchonly, false);
|
pwalletMain->GetFilteredNotes(sproutEntries, saplingEntries, zaddrs, nMinDepth, nMaxDepth, true, !fIncludeWatchonly, false);
|
||||||
std::set<std::pair<PaymentAddress, uint256>> nullifierSet = pwalletMain->GetNullifiersForAddresses(zaddrs);
|
std::set<std::pair<PaymentAddress, uint256>> nullifierSet = pwalletMain->GetNullifiersForAddresses(zaddrs);
|
||||||
|
|
||||||
for (auto & entry : sproutEntries) {
|
|
||||||
UniValue obj(UniValue::VOBJ);
|
|
||||||
|
|
||||||
int nHeight = tx_height(entry.jsop.hash);
|
|
||||||
int dpowconfs = komodo_dpowconfs(nHeight, entry.confirmations);
|
|
||||||
// Only return notarized results when minconf>1
|
|
||||||
if (nMinDepth > 1 && dpowconfs == 1)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
obj.push_back(Pair("txid", entry.jsop.hash.ToString()));
|
|
||||||
obj.push_back(Pair("jsindex", (int)entry.jsop.js ));
|
|
||||||
obj.push_back(Pair("jsoutindex", (int)entry.jsop.n));
|
|
||||||
obj.push_back(Pair("confirmations", dpowconfs));
|
|
||||||
obj.push_back(Pair("rawconfirmations", entry.confirmations));
|
|
||||||
bool hasSproutSpendingKey = pwalletMain->HaveSproutSpendingKey(boost::get<libzcash::SproutPaymentAddress>(entry.address));
|
|
||||||
obj.push_back(Pair("spendable", hasSproutSpendingKey));
|
|
||||||
obj.push_back(Pair("address", EncodePaymentAddress(entry.address)));
|
|
||||||
obj.push_back(Pair("amount", ValueFromAmount(CAmount(entry.plaintext.value()))));
|
|
||||||
std::string data(entry.plaintext.memo().begin(), entry.plaintext.memo().end());
|
|
||||||
obj.push_back(Pair("memo", HexStr(data)));
|
|
||||||
if (hasSproutSpendingKey) {
|
|
||||||
obj.push_back(Pair("change", pwalletMain->IsNoteSproutChange(nullifierSet, entry.address, entry.jsop)));
|
|
||||||
}
|
|
||||||
results.push_back(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto & entry : saplingEntries) {
|
for (auto & entry : saplingEntries) {
|
||||||
UniValue obj(UniValue::VOBJ);
|
UniValue obj(UniValue::VOBJ);
|
||||||
|
|
||||||
@@ -4121,6 +4089,158 @@ UniValue z_gettotalbalance(const UniValue& params, bool fHelp)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UniValue z_viewtransaction(const UniValue& params, bool fHelp)
|
||||||
|
{
|
||||||
|
if (!EnsureWalletIsAvailable(fHelp))
|
||||||
|
return NullUniValue;
|
||||||
|
|
||||||
|
if (fHelp || params.size() != 1)
|
||||||
|
throw runtime_error(
|
||||||
|
"z_viewtransaction \"txid\"\n"
|
||||||
|
"\nGet detailed shielded information about in-wallet transaction <txid>\n"
|
||||||
|
"\nArguments:\n"
|
||||||
|
"1. \"txid\" (string, required) The transaction id\n"
|
||||||
|
"\nResult:\n"
|
||||||
|
"{\n"
|
||||||
|
" \"txid\" : \"transactionid\", (string) The transaction id\n"
|
||||||
|
" \"spends\" : [\n"
|
||||||
|
" {\n"
|
||||||
|
" \"type\" : \"sapling\", (string) The type of address\n"
|
||||||
|
" \"spend\" : n, (numeric) the index of the spend within vShieldedSpend\n"
|
||||||
|
" \"txidPrev\" : \"transactionid\", (string) The id for the transaction this note was created in\n"
|
||||||
|
" \"outputPrev\" : n, (numeric) the index of the output within the vShieldedOutput\n"
|
||||||
|
" \"address\" : \"zcashaddress\", (string) The Hush shielded address involved in the transaction\n"
|
||||||
|
" \"value\" : x.xxx (numeric) The amount in " + CURRENCY_UNIT + "\n"
|
||||||
|
" \"valueZat\" : xxxx (numeric) The amount in zatoshis\n"
|
||||||
|
" }\n"
|
||||||
|
" ,...\n"
|
||||||
|
" ],\n"
|
||||||
|
" \"outputs\" : [\n"
|
||||||
|
" {\n"
|
||||||
|
" \"type\" : \"sapling\", (string) The type of address\n"
|
||||||
|
" \"output\" : n, (numeric) the index of the output within the vShieldedOutput\n"
|
||||||
|
" \"address\" : \"hushaddress\", (string) The Hush address involved in the transaction\n"
|
||||||
|
" \"recovered\" : true|false (boolean) True if the output is not for an address in the wallet\n"
|
||||||
|
" \"value\" : x.xxx (numeric) The amount in " + CURRENCY_UNIT + "\n"
|
||||||
|
" \"valueZat\" : xxxx (numeric) The amount in zatoshis\n"
|
||||||
|
" \"memo\" : \"hexmemo\", (string) Hexademical string representation of the memo field\n"
|
||||||
|
" \"memoStr\" : \"memo\", (string) Only returned if memo contains valid UTF-8 text.\n"
|
||||||
|
" }\n"
|
||||||
|
" ,...\n"
|
||||||
|
" ],\n"
|
||||||
|
"}\n"
|
||||||
|
|
||||||
|
"\nExamples:\n"
|
||||||
|
+ HelpExampleCli("z_viewtransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
|
||||||
|
+ HelpExampleCli("z_viewtransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\" true")
|
||||||
|
+ HelpExampleRpc("z_viewtransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
|
||||||
|
);
|
||||||
|
|
||||||
|
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||||
|
|
||||||
|
uint256 hash;
|
||||||
|
hash.SetHex(params[0].get_str());
|
||||||
|
|
||||||
|
UniValue entry(UniValue::VOBJ);
|
||||||
|
|
||||||
|
if (!pwalletMain->mapWallet.count(hash))
|
||||||
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet Hush transaction id!");
|
||||||
|
const CWalletTx& wtx = pwalletMain->mapWallet[hash];
|
||||||
|
|
||||||
|
entry.push_back(Pair("txid", hash.GetHex()));
|
||||||
|
|
||||||
|
UniValue spends(UniValue::VARR);
|
||||||
|
UniValue outputs(UniValue::VARR);
|
||||||
|
char str[64];
|
||||||
|
|
||||||
|
// Sapling spends
|
||||||
|
std::set<uint256> ovks;
|
||||||
|
for (size_t i = 0; i < wtx.vShieldedSpend.size(); ++i) {
|
||||||
|
auto spend = wtx.vShieldedSpend[i];
|
||||||
|
|
||||||
|
// Fetch the note that is being spent
|
||||||
|
auto res = pwalletMain->mapSaplingNullifiersToNotes.find(spend.nullifier);
|
||||||
|
if (res == pwalletMain->mapSaplingNullifiersToNotes.end()) {
|
||||||
|
fprintf(stderr,"Could not find spending note %s", uint256_str(str, spend.nullifier));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto op = res->second;
|
||||||
|
auto wtxPrev = pwalletMain->mapWallet.at(op.hash);
|
||||||
|
auto decrypted = wtxPrev.DecryptSaplingNote(op).get();
|
||||||
|
auto notePt = decrypted.first;
|
||||||
|
auto pa = decrypted.second;
|
||||||
|
|
||||||
|
// Store the OutgoingViewingKey for recovering outputs
|
||||||
|
libzcash::SaplingFullViewingKey fvk;
|
||||||
|
assert(pwalletMain->GetSaplingFullViewingKey(wtxPrev.mapSaplingNoteData.at(op).ivk, fvk));
|
||||||
|
ovks.insert(fvk.ovk);
|
||||||
|
|
||||||
|
UniValue entry(UniValue::VOBJ);
|
||||||
|
entry.push_back(Pair("type", ADDR_TYPE_SAPLING));
|
||||||
|
entry.push_back(Pair("spend", (int)i));
|
||||||
|
entry.push_back(Pair("nullifier", uint256_str(str,spend.nullifier)));
|
||||||
|
entry.push_back(Pair("anchor", uint256_str(str,spend.anchor)));
|
||||||
|
entry.push_back(Pair("commitment", uint256_str(str,spend.cv)));
|
||||||
|
entry.push_back(Pair("rk", uint256_str(str,spend.rk)));
|
||||||
|
entry.push_back(Pair("txidPrev", op.hash.GetHex()));
|
||||||
|
entry.push_back(Pair("outputPrev", (int)op.n));
|
||||||
|
entry.push_back(Pair("address", EncodePaymentAddress(pa)));
|
||||||
|
entry.push_back(Pair("value", ValueFromAmount(notePt.value())));
|
||||||
|
entry.push_back(Pair("valueZat", notePt.value()));
|
||||||
|
spends.push_back(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sapling outputs
|
||||||
|
for (uint32_t i = 0; i < wtx.vShieldedOutput.size(); ++i) {
|
||||||
|
auto op = SaplingOutPoint(hash, i);
|
||||||
|
|
||||||
|
SaplingNotePlaintext notePt;
|
||||||
|
SaplingPaymentAddress pa;
|
||||||
|
bool isRecovered;
|
||||||
|
|
||||||
|
auto decrypted = wtx.DecryptSaplingNote(op);
|
||||||
|
if (decrypted) {
|
||||||
|
notePt = decrypted->first;
|
||||||
|
pa = decrypted->second;
|
||||||
|
isRecovered = false;
|
||||||
|
} else {
|
||||||
|
// Try recovering the output
|
||||||
|
auto recovered = wtx.RecoverSaplingNote(op, ovks);
|
||||||
|
if (recovered) {
|
||||||
|
notePt = recovered->first;
|
||||||
|
pa = recovered->second;
|
||||||
|
isRecovered = true;
|
||||||
|
} else {
|
||||||
|
// Unreadable
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
auto memo = notePt.memo();
|
||||||
|
|
||||||
|
UniValue entry(UniValue::VOBJ);
|
||||||
|
entry.push_back(Pair("type", ADDR_TYPE_SAPLING));
|
||||||
|
entry.push_back(Pair("output", (int)op.n));
|
||||||
|
entry.push_back(Pair("recovered", isRecovered));
|
||||||
|
entry.push_back(Pair("address", EncodePaymentAddress(pa)));
|
||||||
|
entry.push_back(Pair("value", ValueFromAmount(notePt.value())));
|
||||||
|
entry.push_back(Pair("valueZat", notePt.value()));
|
||||||
|
entry.push_back(Pair("memo", HexStr(memo)));
|
||||||
|
if (memo[0] <= 0xf4) {
|
||||||
|
auto end = std::find_if(memo.rbegin(), memo.rend(), [](unsigned char v) { return v != 0; });
|
||||||
|
std::string memoStr(memo.begin(), end.base());
|
||||||
|
if (utf8::is_valid(memoStr)) {
|
||||||
|
entry.push_back(Pair("memoStr", memoStr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
outputs.push_back(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
entry.push_back(Pair("spends", spends));
|
||||||
|
entry.push_back(Pair("outputs", outputs));
|
||||||
|
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
UniValue z_getoperationresult(const UniValue& params, bool fHelp)
|
UniValue z_getoperationresult(const UniValue& params, bool fHelp)
|
||||||
{
|
{
|
||||||
if (!EnsureWalletIsAvailable(fHelp))
|
if (!EnsureWalletIsAvailable(fHelp))
|
||||||
@@ -8287,6 +8407,7 @@ static const CRPCCommand commands[] =
|
|||||||
{ "wallet", "z_importviewingkey", &z_importviewingkey, 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 },
|
||||||
|
{ "wallet", "z_viewtransaction", &z_viewtransaction, true },
|
||||||
// TODO: rearrange into another category
|
// TODO: rearrange into another category
|
||||||
{ "disclosure", "z_getpaymentdisclosure", &z_getpaymentdisclosure, true },
|
{ "disclosure", "z_getpaymentdisclosure", &z_getpaymentdisclosure, true },
|
||||||
{ "disclosure", "z_validatepaymentdisclosure", &z_validatepaymentdisclosure, true }
|
{ "disclosure", "z_validatepaymentdisclosure", &z_validatepaymentdisclosure, true }
|
||||||
|
|||||||
@@ -2487,6 +2487,68 @@ void CWalletTx::SetSaplingNoteData(mapSaplingNoteData_t ¬eData)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
boost::optional<std::pair<
|
||||||
|
SaplingNotePlaintext,
|
||||||
|
SaplingPaymentAddress>> CWalletTx::DecryptSaplingNote(SaplingOutPoint op) const
|
||||||
|
{
|
||||||
|
// Check whether we can decrypt this SaplingOutPoint
|
||||||
|
if (this->mapSaplingNoteData.count(op) == 0) {
|
||||||
|
return boost::none;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto output = this->vShieldedOutput[op.n];
|
||||||
|
auto nd = this->mapSaplingNoteData.at(op);
|
||||||
|
|
||||||
|
auto maybe_pt = SaplingNotePlaintext::decrypt(
|
||||||
|
output.encCiphertext,
|
||||||
|
nd.ivk,
|
||||||
|
output.ephemeralKey,
|
||||||
|
output.cm);
|
||||||
|
assert(static_cast<bool>(maybe_pt));
|
||||||
|
auto notePt = maybe_pt.get();
|
||||||
|
|
||||||
|
auto maybe_pa = nd.ivk.address(notePt.d);
|
||||||
|
assert(static_cast<bool>(maybe_pa));
|
||||||
|
auto pa = maybe_pa.get();
|
||||||
|
|
||||||
|
return std::make_pair(notePt, pa);
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::optional<std::pair<
|
||||||
|
SaplingNotePlaintext,
|
||||||
|
SaplingPaymentAddress>> CWalletTx::RecoverSaplingNote(
|
||||||
|
SaplingOutPoint op, std::set<uint256>& ovks) const
|
||||||
|
{
|
||||||
|
auto output = this->vShieldedOutput[op.n];
|
||||||
|
|
||||||
|
for (auto ovk : ovks) {
|
||||||
|
auto outPt = SaplingOutgoingPlaintext::decrypt(
|
||||||
|
output.outCiphertext,
|
||||||
|
ovk,
|
||||||
|
output.cv,
|
||||||
|
output.cm,
|
||||||
|
output.ephemeralKey);
|
||||||
|
if (!outPt) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto maybe_pt = SaplingNotePlaintext::decrypt(
|
||||||
|
output.encCiphertext,
|
||||||
|
output.ephemeralKey,
|
||||||
|
outPt->esk,
|
||||||
|
outPt->pk_d,
|
||||||
|
output.cm);
|
||||||
|
assert(static_cast<bool>(maybe_pt));
|
||||||
|
auto notePt = maybe_pt.get();
|
||||||
|
|
||||||
|
return std::make_pair(notePt, SaplingPaymentAddress(notePt.d, outPt->pk_d));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Couldn't recover with any of the provided OutgoingViewingKeys
|
||||||
|
return boost::none;
|
||||||
|
}
|
||||||
|
|
||||||
int64_t CWalletTx::GetTxTime() const
|
int64_t CWalletTx::GetTxTime() const
|
||||||
{
|
{
|
||||||
int64_t n = nTimeSmart;
|
int64_t n = nTimeSmart;
|
||||||
|
|||||||
@@ -567,6 +567,16 @@ public:
|
|||||||
void SetSproutNoteData(mapSproutNoteData_t ¬eData);
|
void SetSproutNoteData(mapSproutNoteData_t ¬eData);
|
||||||
void SetSaplingNoteData(mapSaplingNoteData_t ¬eData);
|
void SetSaplingNoteData(mapSaplingNoteData_t ¬eData);
|
||||||
|
|
||||||
|
std::pair<libzcash::SproutNotePlaintext, libzcash::SproutPaymentAddress> DecryptSproutNote(
|
||||||
|
JSOutPoint jsop) const;
|
||||||
|
boost::optional<std::pair<
|
||||||
|
libzcash::SaplingNotePlaintext,
|
||||||
|
libzcash::SaplingPaymentAddress>> DecryptSaplingNote(SaplingOutPoint op) const;
|
||||||
|
boost::optional<std::pair<
|
||||||
|
libzcash::SaplingNotePlaintext,
|
||||||
|
libzcash::SaplingPaymentAddress>> RecoverSaplingNote(
|
||||||
|
SaplingOutPoint op, std::set<uint256>& ovks) const;
|
||||||
|
|
||||||
//! filter decides which addresses will count towards the debit
|
//! filter decides which addresses will count towards the debit
|
||||||
CAmount GetDebit(const isminefilter& filter) const;
|
CAmount GetDebit(const isminefilter& filter) const;
|
||||||
CAmount GetCredit(const isminefilter& filter) const;
|
CAmount GetCredit(const isminefilter& filter) const;
|
||||||
|
|||||||
Reference in New Issue
Block a user