]> Git Repo - VerusCoin.git/blame - src/wallet/rpcwallet.cpp
Add mempool_tx_expiry.py test
[VerusCoin.git] / src / wallet / rpcwallet.cpp
CommitLineData
e3bc5698 1// Copyright (c) 2010 Satoshi Nakamoto
f914f1a7 2// Copyright (c) 2009-2014 The Bitcoin Core developers
72fb3d29 3// Distributed under the MIT software license, see the accompanying
e3bc5698
JG
4// file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
eda37330 6#include "amount.h"
51ed9ec9 7#include "base58.h"
be126699 8#include "consensus/upgrades.h"
ae775b5b 9#include "core_io.h"
e3bc5698 10#include "init.h"
8a893c94 11#include "main.h"
51ed9ec9
BD
12#include "net.h"
13#include "netbase.h"
8a893c94 14#include "rpcserver.h"
14f888ca 15#include "timedata.h"
51ed9ec9 16#include "util.h"
b93173de 17#include "utilmoneystr.h"
51ed9ec9
BD
18#include "wallet.h"
19#include "walletdb.h"
8cb25088 20#include "primitives/transaction.h"
6962bb3d 21#include "zcbenchmarks.h"
6aae9d1a 22#include "script/interpreter.h"
51ed9ec9 23
fc72c078
S
24#include "utiltime.h"
25#include "asyncrpcoperation.h"
ed21d5bd 26#include "asyncrpcqueue.h"
6e9c7629 27#include "wallet/asyncrpcoperation_mergetoaddress.h"
fc72c078 28#include "wallet/asyncrpcoperation_sendmany.h"
06c19063 29#include "wallet/asyncrpcoperation_shieldcoinbase.h"
fc72c078 30
320f2cc7
SB
31#include "sodium.h"
32
51ed9ec9
BD
33#include <stdint.h>
34
35#include <boost/assign/list_of.hpp>
25cf6f3d 36
a10a6e2a 37#include <univalue.h>
e3bc5698 38
bcbde86a
S
39#include <numeric>
40
e3bc5698
JG
41using namespace std;
42
2dc35992
SB
43using namespace libzcash;
44
0d37ae3a 45extern UniValue TxJoinSplitToJSON(const CTransaction& tx);
f7cfb52d 46
51ed9ec9 47int64_t nWalletUnlockTime;
e3bc5698
JG
48static CCriticalSection cs_nWalletUnlockTime;
49
c1eae280 50// Private method:
0d37ae3a 51UniValue z_getoperationstatus_IMPL(const UniValue&, bool);
c1eae280 52
bdab0cf5 53std::string HelpRequiringPassphrase()
e3bc5698 54{
b0730874 55 return pwalletMain && pwalletMain->IsCrypted()
a6099ef3 56 ? "\nRequires wallet passphrase to be set with walletpassphrase call."
e3bc5698
JG
57 : "";
58}
59
b9fb692d
JS
60bool EnsureWalletIsAvailable(bool avoidException)
61{
62 if (!pwalletMain)
63 {
64 if (!avoidException)
65 throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found (disabled)");
66 else
67 return false;
68 }
69 return true;
70}
71
bdab0cf5 72void EnsureWalletIsUnlocked()
e3bc5698
JG
73{
74 if (pwalletMain->IsLocked())
738835d7 75 throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
e3bc5698
JG
76}
77
d014114d 78void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry)
e3bc5698
JG
79{
80 int confirms = wtx.GetDepthInMainChain();
81 entry.push_back(Pair("confirmations", confirms));
e07c8e91
LD
82 if (wtx.IsCoinBase())
83 entry.push_back(Pair("generated", true));
2b72d46f 84 if (confirms > 0)
e3bc5698
JG
85 {
86 entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex()));
87 entry.push_back(Pair("blockindex", wtx.nIndex));
209377a7 88 entry.push_back(Pair("blocktime", mapBlockIndex[wtx.hashBlock]->GetBlockTime()));
9bb37bf0 89 entry.push_back(Pair("expiryheight", (int64_t)wtx.nExpiryHeight));
e3bc5698 90 }
805344dc 91 uint256 hash = wtx.GetHash();
731b89b8 92 entry.push_back(Pair("txid", hash.GetHex()));
38fc4b70 93 UniValue conflicts(UniValue::VARR);
731b89b8
GA
94 BOOST_FOREACH(const uint256& conflict, wtx.GetConflicts())
95 conflicts.push_back(conflict.GetHex());
96 entry.push_back(Pair("walletconflicts", conflicts));
d56e30ca 97 entry.push_back(Pair("time", wtx.GetTxTime()));
4b61a6a4 98 entry.push_back(Pair("timereceived", (int64_t)wtx.nTimeReceived));
e3bc5698
JG
99 BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
100 entry.push_back(Pair(item.first, item.second));
f7cfb52d
S
101
102 entry.push_back(Pair("vjoinsplit", TxJoinSplitToJSON(wtx)));
e3bc5698
JG
103}
104
d014114d 105string AccountFromValue(const UniValue& value)
e3bc5698
JG
106{
107 string strAccount = value.get_str();
3c31eb24 108 if (strAccount != "")
7b3351ff 109 throw JSONRPCError(RPC_WALLET_ACCOUNTS_UNSUPPORTED, "Accounts are unsupported");
e3bc5698
JG
110 return strAccount;
111}
112
d014114d 113UniValue getnewaddress(const UniValue& params, bool fHelp)
e3bc5698 114{
b9fb692d 115 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 116 return NullUniValue;
70454796 117
e3bc5698
JG
118 if (fHelp || params.size() > 1)
119 throw runtime_error(
a6099ef3 120 "getnewaddress ( \"account\" )\n"
58c4c0bb 121 "\nReturns a new Zcash address for receiving payments.\n"
a6099ef3 122 "\nArguments:\n"
3c31eb24 123 "1. \"account\" (string, optional) DEPRECATED. If provided, it MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
a6099ef3 124 "\nResult:\n"
d2c1e4a8 125 "\"zcashaddress\" (string) The new Zcash address\n"
a6099ef3 126 "\nExamples:\n"
127 + HelpExampleCli("getnewaddress", "")
7b782f5b 128 + HelpExampleRpc("getnewaddress", "")
a6099ef3 129 );
e3bc5698 130
4401b2d7
EL
131 LOCK2(cs_main, pwalletMain->cs_wallet);
132
e3bc5698
JG
133 // Parse the account first so we don't generate a key if there's an error
134 string strAccount;
135 if (params.size() > 0)
136 strAccount = AccountFromValue(params[0]);
137
138 if (!pwalletMain->IsLocked())
139 pwalletMain->TopUpKeyPool();
140
141 // Generate a new key that is added to wallet
142 CPubKey newKey;
71ac5052 143 if (!pwalletMain->GetKeyFromPool(newKey))
738835d7 144 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
e3bc5698
JG
145 CKeyID keyID = newKey.GetID();
146
a41d5fe0 147 pwalletMain->SetAddressBook(keyID, strAccount, "receive");
e3bc5698
JG
148
149 return CBitcoinAddress(keyID).ToString();
150}
151
152
153CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
154{
155 CWalletDB walletdb(pwalletMain->strWalletFile);
156
157 CAccount account;
158 walletdb.ReadAccount(strAccount, account);
159
160 bool bKeyUsed = false;
161
162 // Check if the current key has been used
163 if (account.vchPubKey.IsValid())
164 {
0be990ba 165 CScript scriptPubKey = GetScriptForDestination(account.vchPubKey.GetID());
e3bc5698
JG
166 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
167 it != pwalletMain->mapWallet.end() && account.vchPubKey.IsValid();
168 ++it)
169 {
170 const CWalletTx& wtx = (*it).second;
171 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
172 if (txout.scriptPubKey == scriptPubKey)
173 bKeyUsed = true;
174 }
175 }
176
177 // Generate a new key
178 if (!account.vchPubKey.IsValid() || bForceNew || bKeyUsed)
179 {
71ac5052 180 if (!pwalletMain->GetKeyFromPool(account.vchPubKey))
738835d7 181 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
e3bc5698 182
a41d5fe0 183 pwalletMain->SetAddressBook(account.vchPubKey.GetID(), strAccount, "receive");
e3bc5698
JG
184 walletdb.WriteAccount(strAccount, account);
185 }
186
187 return CBitcoinAddress(account.vchPubKey.GetID());
188}
189
d014114d 190UniValue getaccountaddress(const UniValue& params, bool fHelp)
e3bc5698 191{
b9fb692d 192 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 193 return NullUniValue;
70454796 194
e3bc5698
JG
195 if (fHelp || params.size() != 1)
196 throw runtime_error(
a6099ef3 197 "getaccountaddress \"account\"\n"
58c4c0bb 198 "\nDEPRECATED. Returns the current Zcash address for receiving payments to this account.\n"
a6099ef3 199 "\nArguments:\n"
3c31eb24 200 "1. \"account\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
a6099ef3 201 "\nResult:\n"
d2c1e4a8 202 "\"zcashaddress\" (string) The account Zcash address\n"
a6099ef3 203 "\nExamples:\n"
204 + HelpExampleCli("getaccountaddress", "")
205 + HelpExampleCli("getaccountaddress", "\"\"")
206 + HelpExampleCli("getaccountaddress", "\"myaccount\"")
207 + HelpExampleRpc("getaccountaddress", "\"myaccount\"")
208 );
e3bc5698 209
4401b2d7
EL
210 LOCK2(cs_main, pwalletMain->cs_wallet);
211
e3bc5698
JG
212 // Parse the account first so we don't generate a key if there's an error
213 string strAccount = AccountFromValue(params[0]);
214
d014114d 215 UniValue ret(UniValue::VSTR);
e3bc5698
JG
216
217 ret = GetAccountAddress(strAccount).ToString();
e3bc5698
JG
218 return ret;
219}
220
221
d014114d 222UniValue getrawchangeaddress(const UniValue& params, bool fHelp)
e5e9904c 223{
b9fb692d 224 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 225 return NullUniValue;
70454796 226
e5e9904c
JG
227 if (fHelp || params.size() > 1)
228 throw runtime_error(
229 "getrawchangeaddress\n"
58c4c0bb 230 "\nReturns a new Zcash address, for receiving change.\n"
a6099ef3 231 "This is for use with raw transactions, NOT normal use.\n"
232 "\nResult:\n"
233 "\"address\" (string) The address\n"
234 "\nExamples:\n"
235 + HelpExampleCli("getrawchangeaddress", "")
236 + HelpExampleRpc("getrawchangeaddress", "")
237 );
e5e9904c 238
4401b2d7
EL
239 LOCK2(cs_main, pwalletMain->cs_wallet);
240
e5e9904c
JG
241 if (!pwalletMain->IsLocked())
242 pwalletMain->TopUpKeyPool();
243
244 CReserveKey reservekey(pwalletMain);
245 CPubKey vchPubKey;
246 if (!reservekey.GetReservedKey(vchPubKey))
6c37f7fd 247 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
e5e9904c
JG
248
249 reservekey.KeepKey();
250
251 CKeyID keyID = vchPubKey.GetID();
252
253 return CBitcoinAddress(keyID).ToString();
254}
255
e3bc5698 256
d014114d 257UniValue setaccount(const UniValue& params, bool fHelp)
e3bc5698 258{
b9fb692d 259 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 260 return NullUniValue;
70454796 261
e3bc5698
JG
262 if (fHelp || params.size() < 1 || params.size() > 2)
263 throw runtime_error(
58c4c0bb 264 "setaccount \"zcashaddress\" \"account\"\n"
7b782f5b 265 "\nDEPRECATED. Sets the account associated with the given address.\n"
a6099ef3 266 "\nArguments:\n"
d2c1e4a8 267 "1. \"zcashaddress\" (string, required) The Zcash address to be associated with an account.\n"
3c31eb24 268 "2. \"account\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
a6099ef3 269 "\nExamples:\n"
70454796
JG
270 + HelpExampleCli("setaccount", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\" \"tabby\"")
271 + HelpExampleRpc("setaccount", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\", \"tabby\"")
a6099ef3 272 );
e3bc5698 273
4401b2d7
EL
274 LOCK2(cs_main, pwalletMain->cs_wallet);
275
e3bc5698
JG
276 CBitcoinAddress address(params[0].get_str());
277 if (!address.IsValid())
58c4c0bb 278 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address");
e3bc5698 279
e3bc5698
JG
280 string strAccount;
281 if (params.size() > 1)
282 strAccount = AccountFromValue(params[1]);
283
31d6390f
ES
284 // Only add the account if the address is yours.
285 if (IsMine(*pwalletMain, address.Get()))
e3bc5698 286 {
31d6390f
ES
287 // Detect when changing the account of an address that is the 'unused current key' of another account:
288 if (pwalletMain->mapAddressBook.count(address.Get()))
289 {
290 string strOldAccount = pwalletMain->mapAddressBook[address.Get()].name;
291 if (address == GetAccountAddress(strOldAccount))
292 GetAccountAddress(strOldAccount, true);
293 }
294 pwalletMain->SetAddressBook(address.Get(), strAccount, "receive");
e3bc5698 295 }
31d6390f
ES
296 else
297 throw JSONRPCError(RPC_MISC_ERROR, "setaccount can only be used with own address");
e3bc5698 298
ed21d5bd 299 return NullUniValue;
e3bc5698
JG
300}
301
302
d014114d 303UniValue getaccount(const UniValue& params, bool fHelp)
e3bc5698 304{
b9fb692d 305 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 306 return NullUniValue;
70454796 307
e3bc5698
JG
308 if (fHelp || params.size() != 1)
309 throw runtime_error(
58c4c0bb 310 "getaccount \"zcashaddress\"\n"
7b782f5b 311 "\nDEPRECATED. Returns the account associated with the given address.\n"
a6099ef3 312 "\nArguments:\n"
d2c1e4a8 313 "1. \"zcashaddress\" (string, required) The Zcash address for account lookup.\n"
a6099ef3 314 "\nResult:\n"
315 "\"accountname\" (string) the account address\n"
316 "\nExamples:\n"
70454796
JG
317 + HelpExampleCli("getaccount", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\"")
318 + HelpExampleRpc("getaccount", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\"")
a6099ef3 319 );
e3bc5698 320
4401b2d7
EL
321 LOCK2(cs_main, pwalletMain->cs_wallet);
322
e3bc5698
JG
323 CBitcoinAddress address(params[0].get_str());
324 if (!address.IsValid())
58c4c0bb 325 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address");
e3bc5698
JG
326
327 string strAccount;
61885513
GA
328 map<CTxDestination, CAddressBookData>::iterator mi = pwalletMain->mapAddressBook.find(address.Get());
329 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.name.empty())
330 strAccount = (*mi).second.name;
e3bc5698
JG
331 return strAccount;
332}
333
334
d014114d 335UniValue getaddressesbyaccount(const UniValue& params, bool fHelp)
e3bc5698 336{
b9fb692d 337 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 338 return NullUniValue;
70454796 339
e3bc5698
JG
340 if (fHelp || params.size() != 1)
341 throw runtime_error(
a6099ef3 342 "getaddressesbyaccount \"account\"\n"
7b782f5b 343 "\nDEPRECATED. Returns the list of addresses for the given account.\n"
a6099ef3 344 "\nArguments:\n"
3c31eb24 345 "1. \"account\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
a6099ef3 346 "\nResult:\n"
347 "[ (json array of string)\n"
d2c1e4a8 348 " \"zcashaddress\" (string) a Zcash address associated with the given account\n"
a6099ef3 349 " ,...\n"
350 "]\n"
351 "\nExamples:\n"
352 + HelpExampleCli("getaddressesbyaccount", "\"tabby\"")
353 + HelpExampleRpc("getaddressesbyaccount", "\"tabby\"")
354 );
e3bc5698 355
4401b2d7
EL
356 LOCK2(cs_main, pwalletMain->cs_wallet);
357
e3bc5698
JG
358 string strAccount = AccountFromValue(params[0]);
359
360 // Find all addresses that have the given account
38fc4b70 361 UniValue ret(UniValue::VARR);
61885513 362 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, CAddressBookData)& item, pwalletMain->mapAddressBook)
e3bc5698
JG
363 {
364 const CBitcoinAddress& address = item.first;
61885513 365 const string& strName = item.second.name;
e3bc5698
JG
366 if (strName == strAccount)
367 ret.push_back(address.ToString());
368 }
369 return ret;
370}
371
292623ad 372static void SendMoney(const CTxDestination &address, CAmount nValue, bool fSubtractFeeFromAmount, CWalletTx& wtxNew)
b93173de 373{
25cf6f3d
PK
374 CAmount curBalance = pwalletMain->GetBalance();
375
b93173de
PJ
376 // Check amount
377 if (nValue <= 0)
4be639ea 378 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid amount");
b93173de 379
25cf6f3d 380 if (nValue > curBalance)
b93173de
PJ
381 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds");
382
58c4c0bb 383 // Parse Zcash address
b93173de
PJ
384 CScript scriptPubKey = GetScriptForDestination(address);
385
386 // Create and send the transaction
387 CReserveKey reservekey(pwalletMain);
388 CAmount nFeeRequired;
25cf6f3d 389 std::string strError;
292623ad
CL
390 vector<CRecipient> vecSend;
391 int nChangePosRet = -1;
392 CRecipient recipient = {scriptPubKey, nValue, fSubtractFeeFromAmount};
393 vecSend.push_back(recipient);
394 if (!pwalletMain->CreateTransaction(vecSend, wtxNew, reservekey, nFeeRequired, nChangePosRet, strError)) {
395 if (!fSubtractFeeFromAmount && nValue + nFeeRequired > pwalletMain->GetBalance())
396 strError = strprintf("Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds!", FormatMoney(nFeeRequired));
397 throw JSONRPCError(RPC_WALLET_ERROR, strError);
b93173de
PJ
398 }
399 if (!pwalletMain->CommitTransaction(wtxNew, reservekey))
400 throw JSONRPCError(RPC_WALLET_ERROR, "Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here.");
b93173de
PJ
401}
402
d014114d 403UniValue sendtoaddress(const UniValue& params, bool fHelp)
e3bc5698 404{
b9fb692d 405 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 406 return NullUniValue;
70454796 407
292623ad 408 if (fHelp || params.size() < 2 || params.size() > 5)
e3bc5698 409 throw runtime_error(
58c4c0bb 410 "sendtoaddress \"zcashaddress\" amount ( \"comment\" \"comment-to\" subtractfeefromamount )\n"
e743678d 411 "\nSend an amount to a given address. The amount is a real and is rounded to the nearest 0.00000001\n"
a6099ef3 412 + HelpRequiringPassphrase() +
413 "\nArguments:\n"
58c4c0bb 414 "1. \"zcashaddress\" (string, required) The zcash address to send to.\n"
091b2116 415 "2. \"amount\" (numeric, required) The amount in " + CURRENCY_UNIT + " to send. eg 0.1\n"
a6099ef3 416 "3. \"comment\" (string, optional) A comment used to store what the transaction is for. \n"
417 " This is not part of the transaction, just kept in your wallet.\n"
418 "4. \"comment-to\" (string, optional) A comment to store the name of the person or organization \n"
419 " to which you're sending the transaction. This is not part of the \n"
420 " transaction, just kept in your wallet.\n"
292623ad 421 "5. subtractfeefromamount (boolean, optional, default=false) The fee will be deducted from the amount being sent.\n"
c1652849 422 " The recipient will receive less Zcash than you enter in the amount field.\n"
a6099ef3 423 "\nResult:\n"
b5ef85c7 424 "\"transactionid\" (string) The transaction id.\n"
a6099ef3 425 "\nExamples:\n"
70454796
JG
426 + HelpExampleCli("sendtoaddress", "\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1")
427 + HelpExampleCli("sendtoaddress", "\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1 \"donation\" \"seans outpost\"")
428 + HelpExampleCli("sendtoaddress", "\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1 \"\" \"\" true")
429 + HelpExampleRpc("sendtoaddress", "\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", 0.1, \"donation\", \"seans outpost\"")
a6099ef3 430 );
e3bc5698 431
4401b2d7
EL
432 LOCK2(cs_main, pwalletMain->cs_wallet);
433
e3bc5698
JG
434 CBitcoinAddress address(params[0].get_str());
435 if (!address.IsValid())
58c4c0bb 436 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address");
e3bc5698
JG
437
438 // Amount
a372168e 439 CAmount nAmount = AmountFromValue(params[1]);
e76a3849
WL
440 if (nAmount <= 0)
441 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
e3bc5698
JG
442
443 // Wallet comments
444 CWalletTx wtx;
ed21d5bd 445 if (params.size() > 2 && !params[2].isNull() && !params[2].get_str().empty())
e3bc5698 446 wtx.mapValue["comment"] = params[2].get_str();
ed21d5bd 447 if (params.size() > 3 && !params[3].isNull() && !params[3].get_str().empty())
e3bc5698
JG
448 wtx.mapValue["to"] = params[3].get_str();
449
292623ad
CL
450 bool fSubtractFeeFromAmount = false;
451 if (params.size() > 4)
452 fSubtractFeeFromAmount = params[4].get_bool();
453
f914c7a1 454 EnsureWalletIsUnlocked();
e3bc5698 455
292623ad 456 SendMoney(address.Get(), nAmount, fSubtractFeeFromAmount, wtx);
e3bc5698 457
805344dc 458 return wtx.GetHash().GetHex();
e3bc5698
JG
459}
460
d014114d 461UniValue listaddressgroupings(const UniValue& params, bool fHelp)
22dfd735 462{
b9fb692d 463 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 464 return NullUniValue;
70454796 465
22dfd735 466 if (fHelp)
b1093efa
GM
467 throw runtime_error(
468 "listaddressgroupings\n"
a6099ef3 469 "\nLists groups of addresses which have had their common ownership\n"
b1093efa 470 "made public by common use as inputs or as the resulting change\n"
a6099ef3 471 "in past transactions\n"
472 "\nResult:\n"
473 "[\n"
474 " [\n"
475 " [\n"
58c4c0bb 476 " \"zcashaddress\", (string) The zcash address\n"
091b2116 477 " amount, (numeric) The amount in " + CURRENCY_UNIT + "\n"
7b782f5b 478 " \"account\" (string, optional) The account (DEPRECATED)\n"
a6099ef3 479 " ]\n"
480 " ,...\n"
481 " ]\n"
482 " ,...\n"
483 "]\n"
484 "\nExamples:\n"
485 + HelpExampleCli("listaddressgroupings", "")
486 + HelpExampleRpc("listaddressgroupings", "")
487 );
22dfd735 488
4401b2d7
EL
489 LOCK2(cs_main, pwalletMain->cs_wallet);
490
38fc4b70 491 UniValue jsonGroupings(UniValue::VARR);
a372168e 492 map<CTxDestination, CAmount> balances = pwalletMain->GetAddressBalances();
b1093efa 493 BOOST_FOREACH(set<CTxDestination> grouping, pwalletMain->GetAddressGroupings())
22dfd735 494 {
38fc4b70 495 UniValue jsonGrouping(UniValue::VARR);
b1093efa 496 BOOST_FOREACH(CTxDestination address, grouping)
22dfd735 497 {
38fc4b70 498 UniValue addressInfo(UniValue::VARR);
b1093efa 499 addressInfo.push_back(CBitcoinAddress(address).ToString());
22dfd735 500 addressInfo.push_back(ValueFromAmount(balances[address]));
501 {
22dfd735 502 if (pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get()) != pwalletMain->mapAddressBook.end())
61885513 503 addressInfo.push_back(pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get())->second.name);
22dfd735 504 }
505 jsonGrouping.push_back(addressInfo);
506 }
507 jsonGroupings.push_back(jsonGrouping);
508 }
509 return jsonGroupings;
510}
511
d014114d 512UniValue signmessage(const UniValue& params, bool fHelp)
e3bc5698 513{
b9fb692d 514 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 515 return NullUniValue;
70454796 516
e3bc5698
JG
517 if (fHelp || params.size() != 2)
518 throw runtime_error(
58c4c0bb 519 "signmessage \"zcashaddress\" \"message\"\n"
a6099ef3 520 "\nSign a message with the private key of an address"
521 + HelpRequiringPassphrase() + "\n"
522 "\nArguments:\n"
d2c1e4a8 523 "1. \"zcashaddress\" (string, required) The Zcash address to use for the private key.\n"
a6099ef3 524 "2. \"message\" (string, required) The message to create a signature of.\n"
525 "\nResult:\n"
526 "\"signature\" (string) The signature of the message encoded in base 64\n"
527 "\nExamples:\n"
528 "\nUnlock the wallet for 30 seconds\n"
529 + HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") +
530 "\nCreate the signature\n"
70454796 531 + HelpExampleCli("signmessage", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\" \"my message\"") +
a6099ef3 532 "\nVerify the signature\n"
70454796 533 + HelpExampleCli("verifymessage", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\" \"signature\" \"my message\"") +
a6099ef3 534 "\nAs json rpc\n"
70454796 535 + HelpExampleRpc("signmessage", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\", \"my message\"")
a6099ef3 536 );
e3bc5698 537
4401b2d7
EL
538 LOCK2(cs_main, pwalletMain->cs_wallet);
539
e3bc5698
JG
540 EnsureWalletIsUnlocked();
541
542 string strAddress = params[0].get_str();
543 string strMessage = params[1].get_str();
544
545 CBitcoinAddress addr(strAddress);
546 if (!addr.IsValid())
738835d7 547 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
e3bc5698
JG
548
549 CKeyID keyID;
550 if (!addr.GetKeyID(keyID))
738835d7 551 throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
e3bc5698
JG
552
553 CKey key;
554 if (!pwalletMain->GetKey(keyID, key))
738835d7 555 throw JSONRPCError(RPC_WALLET_ERROR, "Private key not available");
e3bc5698 556
8980a509 557 CHashWriter ss(SER_GETHASH, 0);
e3bc5698
JG
558 ss << strMessageMagic;
559 ss << strMessage;
560
561 vector<unsigned char> vchSig;
8980a509 562 if (!key.SignCompact(ss.GetHash(), vchSig))
738835d7 563 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed");
e3bc5698
JG
564
565 return EncodeBase64(&vchSig[0], vchSig.size());
566}
567
d014114d 568UniValue getreceivedbyaddress(const UniValue& params, bool fHelp)
e3bc5698 569{
b9fb692d 570 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 571 return NullUniValue;
70454796 572
e3bc5698
JG
573 if (fHelp || params.size() < 1 || params.size() > 2)
574 throw runtime_error(
58c4c0bb 575 "getreceivedbyaddress \"zcashaddress\" ( minconf )\n"
c1652849 576 "\nReturns the total amount received by the given Zcash address in transactions with at least minconf confirmations.\n"
a6099ef3 577 "\nArguments:\n"
d2c1e4a8 578 "1. \"zcashaddress\" (string, required) The Zcash address for transactions.\n"
a6099ef3 579 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
580 "\nResult:\n"
091b2116 581 "amount (numeric) The total amount in " + CURRENCY_UNIT + " received at this address.\n"
a6099ef3 582 "\nExamples:\n"
583 "\nThe amount from transactions with at least 1 confirmation\n"
70454796 584 + HelpExampleCli("getreceivedbyaddress", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\"") +
a6099ef3 585 "\nThe amount including unconfirmed transactions, zero confirmations\n"
70454796 586 + HelpExampleCli("getreceivedbyaddress", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\" 0") +
a6099ef3 587 "\nThe amount with at least 6 confirmation, very safe\n"
70454796 588 + HelpExampleCli("getreceivedbyaddress", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\" 6") +
a6099ef3 589 "\nAs a json rpc call\n"
70454796 590 + HelpExampleRpc("getreceivedbyaddress", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\", 6")
a6099ef3 591 );
e3bc5698 592
4401b2d7
EL
593 LOCK2(cs_main, pwalletMain->cs_wallet);
594
e3bc5698
JG
595 // Bitcoin address
596 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
e3bc5698 597 if (!address.IsValid())
58c4c0bb 598 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address");
0be990ba 599 CScript scriptPubKey = GetScriptForDestination(address.Get());
e3bc5698
JG
600 if (!IsMine(*pwalletMain,scriptPubKey))
601 return (double)0.0;
602
603 // Minimum confirmations
604 int nMinDepth = 1;
605 if (params.size() > 1)
606 nMinDepth = params[1].get_int();
607
608 // Tally
a372168e 609 CAmount nAmount = 0;
e3bc5698
JG
610 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
611 {
612 const CWalletTx& wtx = (*it).second;
75a4d512 613 if (wtx.IsCoinBase() || !CheckFinalTx(wtx))
e3bc5698
JG
614 continue;
615
616 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
617 if (txout.scriptPubKey == scriptPubKey)
618 if (wtx.GetDepthInMainChain() >= nMinDepth)
619 nAmount += txout.nValue;
620 }
621
622 return ValueFromAmount(nAmount);
623}
624
625
d014114d 626UniValue getreceivedbyaccount(const UniValue& params, bool fHelp)
e3bc5698 627{
b9fb692d 628 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 629 return NullUniValue;
70454796 630
e3bc5698
JG
631 if (fHelp || params.size() < 1 || params.size() > 2)
632 throw runtime_error(
a6099ef3 633 "getreceivedbyaccount \"account\" ( minconf )\n"
7b782f5b 634 "\nDEPRECATED. Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.\n"
a6099ef3 635 "\nArguments:\n"
3c31eb24 636 "1. \"account\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
a6099ef3 637 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
638 "\nResult:\n"
091b2116 639 "amount (numeric) The total amount in " + CURRENCY_UNIT + " received for this account.\n"
a6099ef3 640 "\nExamples:\n"
641 "\nAmount received by the default account with at least 1 confirmation\n"
642 + HelpExampleCli("getreceivedbyaccount", "\"\"") +
643 "\nAmount received at the tabby account including unconfirmed amounts with zero confirmations\n"
644 + HelpExampleCli("getreceivedbyaccount", "\"tabby\" 0") +
645 "\nThe amount with at least 6 confirmation, very safe\n"
646 + HelpExampleCli("getreceivedbyaccount", "\"tabby\" 6") +
647 "\nAs a json rpc call\n"
648 + HelpExampleRpc("getreceivedbyaccount", "\"tabby\", 6")
649 );
e3bc5698 650
4401b2d7
EL
651 LOCK2(cs_main, pwalletMain->cs_wallet);
652
e3bc5698
JG
653 // Minimum confirmations
654 int nMinDepth = 1;
655 if (params.size() > 1)
656 nMinDepth = params[1].get_int();
657
658 // Get the set of pub keys assigned to account
659 string strAccount = AccountFromValue(params[0]);
3624356e 660 set<CTxDestination> setAddress = pwalletMain->GetAccountAddresses(strAccount);
e3bc5698
JG
661
662 // Tally
a372168e 663 CAmount nAmount = 0;
e3bc5698
JG
664 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
665 {
666 const CWalletTx& wtx = (*it).second;
75a4d512 667 if (wtx.IsCoinBase() || !CheckFinalTx(wtx))
e3bc5698
JG
668 continue;
669
670 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
671 {
672 CTxDestination address;
673 if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*pwalletMain, address) && setAddress.count(address))
674 if (wtx.GetDepthInMainChain() >= nMinDepth)
675 nAmount += txout.nValue;
676 }
677 }
678
679 return (double)nAmount / (double)COIN;
680}
681
682
a372168e 683CAmount GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth, const isminefilter& filter)
e3bc5698 684{
a372168e 685 CAmount nBalance = 0;
e3bc5698
JG
686
687 // Tally wallet transactions
688 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
689 {
690 const CWalletTx& wtx = (*it).second;
75a4d512 691 if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < 0)
e3bc5698
JG
692 continue;
693
a372168e 694 CAmount nReceived, nSent, nFee;
d4640d7d 695 wtx.GetAccountAmounts(strAccount, nReceived, nSent, nFee, filter);
e3bc5698
JG
696
697 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
698 nBalance += nReceived;
e07c8e91 699 nBalance -= nSent + nFee;
e3bc5698
JG
700 }
701
702 // Tally internal accounting entries
703 nBalance += walletdb.GetAccountCreditDebit(strAccount);
704
705 return nBalance;
706}
707
a372168e 708CAmount GetAccountBalance(const string& strAccount, int nMinDepth, const isminefilter& filter)
e3bc5698
JG
709{
710 CWalletDB walletdb(pwalletMain->strWalletFile);
d4640d7d 711 return GetAccountBalance(walletdb, strAccount, nMinDepth, filter);
e3bc5698
JG
712}
713
714
d014114d 715UniValue getbalance(const UniValue& params, bool fHelp)
e3bc5698 716{
b9fb692d 717 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 718 return NullUniValue;
70454796 719
d4640d7d 720 if (fHelp || params.size() > 3)
e3bc5698 721 throw runtime_error(
d4640d7d 722 "getbalance ( \"account\" minconf includeWatchonly )\n"
3c31eb24 723 "\nReturns the server's total available balance.\n"
a6099ef3 724 "\nArguments:\n"
715e5bbe 725 "1. \"account\" (string, optional) DEPRECATED. If provided, it MUST be set to the empty string \"\" or to the string \"*\", either of which will give the total available balance. Passing any other string will result in an error.\n"
a6099ef3 726 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
d4640d7d 727 "3. includeWatchonly (bool, optional, default=false) Also include balance in watchonly addresses (see 'importaddress')\n"
a6099ef3 728 "\nResult:\n"
091b2116 729 "amount (numeric) The total amount in " + CURRENCY_UNIT + " received for this account.\n"
a6099ef3 730 "\nExamples:\n"
7b782f5b 731 "\nThe total amount in the wallet\n"
a6099ef3 732 + HelpExampleCli("getbalance", "") +
7b782f5b 733 "\nThe total amount in the wallet at least 5 blocks confirmed\n"
3cf1f436 734 + HelpExampleCli("getbalance", "\"*\" 6") +
a6099ef3 735 "\nAs a json rpc call\n"
7b782f5b 736 + HelpExampleRpc("getbalance", "\"*\", 6")
a6099ef3 737 );
e3bc5698 738
4401b2d7
EL
739 LOCK2(cs_main, pwalletMain->cs_wallet);
740
e3bc5698
JG
741 if (params.size() == 0)
742 return ValueFromAmount(pwalletMain->GetBalance());
743
744 int nMinDepth = 1;
745 if (params.size() > 1)
746 nMinDepth = params[1].get_int();
a3e192a3 747 isminefilter filter = ISMINE_SPENDABLE;
a5c6c5d6
J
748 if(params.size() > 2)
749 if(params[2].get_bool())
a3e192a3 750 filter = filter | ISMINE_WATCH_ONLY;
e3bc5698
JG
751
752 if (params[0].get_str() == "*") {
753 // Calculate total balance a different way from GetBalance()
754 // (GetBalance() sums up all unspent TxOuts)
c9fd9078 755 // getbalance and "getbalance * 1 true" should return the same number
a372168e 756 CAmount nBalance = 0;
e3bc5698
JG
757 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
758 {
759 const CWalletTx& wtx = (*it).second;
c9fd9078 760 if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < 0)
e3bc5698
JG
761 continue;
762
a372168e 763 CAmount allFee;
e3bc5698 764 string strSentAccount;
1b4568cb
CL
765 list<COutputEntry> listReceived;
766 list<COutputEntry> listSent;
d4640d7d 767 wtx.GetAmounts(listReceived, listSent, allFee, strSentAccount, filter);
e3bc5698
JG
768 if (wtx.GetDepthInMainChain() >= nMinDepth)
769 {
1b4568cb
CL
770 BOOST_FOREACH(const COutputEntry& r, listReceived)
771 nBalance += r.amount;
e3bc5698 772 }
1b4568cb
CL
773 BOOST_FOREACH(const COutputEntry& s, listSent)
774 nBalance -= s.amount;
e3bc5698 775 nBalance -= allFee;
e3bc5698
JG
776 }
777 return ValueFromAmount(nBalance);
778 }
779
780 string strAccount = AccountFromValue(params[0]);
781
a372168e 782 CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, filter);
e3bc5698
JG
783
784 return ValueFromAmount(nBalance);
785}
786
d014114d 787UniValue getunconfirmedbalance(const UniValue &params, bool fHelp)
6027b460 788{
b9fb692d 789 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 790 return NullUniValue;
70454796 791
6027b460
MB
792 if (fHelp || params.size() > 0)
793 throw runtime_error(
794 "getunconfirmedbalance\n"
795 "Returns the server's total unconfirmed balance\n");
4401b2d7
EL
796
797 LOCK2(cs_main, pwalletMain->cs_wallet);
798
6027b460
MB
799 return ValueFromAmount(pwalletMain->GetUnconfirmedBalance());
800}
801
e3bc5698 802
d014114d 803UniValue movecmd(const UniValue& params, bool fHelp)
e3bc5698 804{
b9fb692d 805 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 806 return NullUniValue;
70454796 807
e3bc5698
JG
808 if (fHelp || params.size() < 3 || params.size() > 5)
809 throw runtime_error(
a6099ef3 810 "move \"fromaccount\" \"toaccount\" amount ( minconf \"comment\" )\n"
7b782f5b 811 "\nDEPRECATED. Move a specified amount from one account in your wallet to another.\n"
a6099ef3 812 "\nArguments:\n"
3c31eb24
JG
813 "1. \"fromaccount\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
814 "2. \"toaccount\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
091b2116
RN
815 "3. amount (numeric) Quantity of " + CURRENCY_UNIT + " to move between accounts.\n"
816 "4. minconf (numeric, optional, default=1) Only use funds with at least this many confirmations.\n"
817 "5. \"comment\" (string, optional) An optional comment, stored in the wallet only.\n"
a6099ef3 818 "\nResult:\n"
45bfa137 819 "true|false (boolean) true if successful.\n"
a6099ef3 820 "\nExamples:\n"
091b2116 821 "\nMove 0.01 " + CURRENCY_UNIT + " from the default account to the account named tabby\n"
a6099ef3 822 + HelpExampleCli("move", "\"\" \"tabby\" 0.01") +
091b2116 823 "\nMove 0.01 " + CURRENCY_UNIT + " timotei to akiko with a comment and funds have 6 confirmations\n"
a6099ef3 824 + HelpExampleCli("move", "\"timotei\" \"akiko\" 0.01 6 \"happy birthday!\"") +
825 "\nAs a json rpc call\n"
826 + HelpExampleRpc("move", "\"timotei\", \"akiko\", 0.01, 6, \"happy birthday!\"")
827 );
e3bc5698 828
4401b2d7
EL
829 LOCK2(cs_main, pwalletMain->cs_wallet);
830
e3bc5698
JG
831 string strFrom = AccountFromValue(params[0]);
832 string strTo = AccountFromValue(params[1]);
a372168e 833 CAmount nAmount = AmountFromValue(params[2]);
e76a3849
WL
834 if (nAmount <= 0)
835 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
e3bc5698
JG
836 if (params.size() > 3)
837 // unused parameter, used to be nMinDepth, keep type-checking it though
838 (void)params[3].get_int();
839 string strComment;
840 if (params.size() > 4)
841 strComment = params[4].get_str();
842
843 CWalletDB walletdb(pwalletMain->strWalletFile);
844 if (!walletdb.TxnBegin())
738835d7 845 throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
e3bc5698 846
51ed9ec9 847 int64_t nNow = GetAdjustedTime();
e3bc5698
JG
848
849 // Debit
850 CAccountingEntry debit;
4291e8fe 851 debit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
e3bc5698
JG
852 debit.strAccount = strFrom;
853 debit.nCreditDebit = -nAmount;
854 debit.nTime = nNow;
855 debit.strOtherAccount = strTo;
856 debit.strComment = strComment;
857 walletdb.WriteAccountingEntry(debit);
858
859 // Credit
860 CAccountingEntry credit;
4291e8fe 861 credit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
e3bc5698
JG
862 credit.strAccount = strTo;
863 credit.nCreditDebit = nAmount;
864 credit.nTime = nNow;
865 credit.strOtherAccount = strFrom;
866 credit.strComment = strComment;
867 walletdb.WriteAccountingEntry(credit);
868
869 if (!walletdb.TxnCommit())
738835d7 870 throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
e3bc5698
JG
871
872 return true;
873}
874
875
d014114d 876UniValue sendfrom(const UniValue& params, bool fHelp)
e3bc5698 877{
b9fb692d 878 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 879 return NullUniValue;
70454796 880
e3bc5698
JG
881 if (fHelp || params.size() < 3 || params.size() > 6)
882 throw runtime_error(
58c4c0bb 883 "sendfrom \"fromaccount\" \"tozcashaddress\" amount ( minconf \"comment\" \"comment-to\" )\n"
d2c1e4a8 884 "\nDEPRECATED (use sendtoaddress). Sent an amount from an account to a Zcash address.\n"
a6099ef3 885 "The amount is a real and is rounded to the nearest 0.00000001."
886 + HelpRequiringPassphrase() + "\n"
887 "\nArguments:\n"
3c31eb24 888 "1. \"fromaccount\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
58c4c0bb 889 "2. \"tozcashaddress\" (string, required) The zcash address to send funds to.\n"
091b2116 890 "3. amount (numeric, required) The amount in " + CURRENCY_UNIT + " (transaction fee is added on top).\n"
a6099ef3 891 "4. minconf (numeric, optional, default=1) Only use funds with at least this many confirmations.\n"
892 "5. \"comment\" (string, optional) A comment used to store what the transaction is for. \n"
893 " This is not part of the transaction, just kept in your wallet.\n"
894 "6. \"comment-to\" (string, optional) An optional comment to store the name of the person or organization \n"
895 " to which you're sending the transaction. This is not part of the transaction, \n"
896 " it is just kept in your wallet.\n"
897 "\nResult:\n"
b5ef85c7 898 "\"transactionid\" (string) The transaction id.\n"
a6099ef3 899 "\nExamples:\n"
091b2116 900 "\nSend 0.01 " + CURRENCY_UNIT + " from the default account to the address, must have at least 1 confirmation\n"
70454796 901 + HelpExampleCli("sendfrom", "\"\" \"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.01") +
a6099ef3 902 "\nSend 0.01 from the tabby account to the given address, funds must have at least 6 confirmations\n"
70454796 903 + HelpExampleCli("sendfrom", "\"tabby\" \"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.01 6 \"donation\" \"seans outpost\"") +
a6099ef3 904 "\nAs a json rpc call\n"
70454796 905 + HelpExampleRpc("sendfrom", "\"tabby\", \"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", 0.01, 6, \"donation\", \"seans outpost\"")
a6099ef3 906 );
e3bc5698 907
4401b2d7
EL
908 LOCK2(cs_main, pwalletMain->cs_wallet);
909
e3bc5698
JG
910 string strAccount = AccountFromValue(params[0]);
911 CBitcoinAddress address(params[1].get_str());
912 if (!address.IsValid())
58c4c0bb 913 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address");
a372168e 914 CAmount nAmount = AmountFromValue(params[2]);
e76a3849
WL
915 if (nAmount <= 0)
916 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
e3bc5698
JG
917 int nMinDepth = 1;
918 if (params.size() > 3)
919 nMinDepth = params[3].get_int();
920
921 CWalletTx wtx;
922 wtx.strFromAccount = strAccount;
ed21d5bd 923 if (params.size() > 4 && !params[4].isNull() && !params[4].get_str().empty())
e3bc5698 924 wtx.mapValue["comment"] = params[4].get_str();
ed21d5bd 925 if (params.size() > 5 && !params[5].isNull() && !params[5].get_str().empty())
e3bc5698
JG
926 wtx.mapValue["to"] = params[5].get_str();
927
928 EnsureWalletIsUnlocked();
929
930 // Check funds
a372168e 931 CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE);
e3bc5698 932 if (nAmount > nBalance)
738835d7 933 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
e3bc5698 934
292623ad 935 SendMoney(address.Get(), nAmount, false, wtx);
e3bc5698 936
805344dc 937 return wtx.GetHash().GetHex();
e3bc5698
JG
938}
939
940
d014114d 941UniValue sendmany(const UniValue& params, bool fHelp)
e3bc5698 942{
b9fb692d 943 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 944 return NullUniValue;
70454796 945
292623ad 946 if (fHelp || params.size() < 2 || params.size() > 5)
e3bc5698 947 throw runtime_error(
40a75733 948 "sendmany \"fromaccount\" {\"address\":amount,...} ( minconf \"comment\" [\"address\",...] )\n"
a6099ef3 949 "\nSend multiple times. Amounts are double-precision floating point numbers."
950 + HelpRequiringPassphrase() + "\n"
951 "\nArguments:\n"
3c31eb24 952 "1. \"fromaccount\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
a6099ef3 953 "2. \"amounts\" (string, required) A json object with addresses and amounts\n"
954 " {\n"
091b2116 955 " \"address\":amount (numeric) The zcash address is the key, the numeric amount in " + CURRENCY_UNIT + " is the value\n"
a6099ef3 956 " ,...\n"
957 " }\n"
958 "3. minconf (numeric, optional, default=1) Only use the balance confirmed at least this many times.\n"
959 "4. \"comment\" (string, optional) A comment\n"
40a75733 960 "5. subtractfeefromamount (string, optional) A json array with addresses.\n"
292623ad 961 " The fee will be equally deducted from the amount of each selected address.\n"
c1652849 962 " Those recipients will receive less Zcash than you enter in their corresponding amount field.\n"
40a75733
LD
963 " If no addresses are specified here, the sender pays the fee.\n"
964 " [\n"
965 " \"address\" (string) Subtract fee from this address\n"
292623ad 966 " ,...\n"
40a75733 967 " ]\n"
a6099ef3 968 "\nResult:\n"
969 "\"transactionid\" (string) The transaction id for the send. Only 1 transaction is created regardless of \n"
b5ef85c7 970 " the number of addresses.\n"
a6099ef3 971 "\nExamples:\n"
972 "\nSend two amounts to two different addresses:\n"
70454796 973 + HelpExampleCli("sendmany", "\"\" \"{\\\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\\\":0.01,\\\"t1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\"") +
a6099ef3 974 "\nSend two amounts to two different addresses setting the confirmation and comment:\n"
70454796 975 + HelpExampleCli("sendmany", "\"\" \"{\\\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\\\":0.01,\\\"t1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\" 6 \"testing\"") +
292623ad 976 "\nSend two amounts to two different addresses, subtract fee from amount:\n"
70454796 977 + HelpExampleCli("sendmany", "\"\" \"{\\\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\\\":0.01,\\\"t1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\" 1 \"\" \"[\\\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\\\",\\\"t1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\"]\"") +
a6099ef3 978 "\nAs a json rpc call\n"
70454796 979 + HelpExampleRpc("sendmany", "\"\", \"{\\\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\\\":0.01,\\\"t1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\", 6, \"testing\"")
a6099ef3 980 );
e3bc5698 981
4401b2d7
EL
982 LOCK2(cs_main, pwalletMain->cs_wallet);
983
e3bc5698 984 string strAccount = AccountFromValue(params[0]);
851f58f9 985 UniValue sendTo = params[1].get_obj();
e3bc5698
JG
986 int nMinDepth = 1;
987 if (params.size() > 2)
988 nMinDepth = params[2].get_int();
989
990 CWalletTx wtx;
991 wtx.strFromAccount = strAccount;
ed21d5bd 992 if (params.size() > 3 && !params[3].isNull() && !params[3].get_str().empty())
e3bc5698
JG
993 wtx.mapValue["comment"] = params[3].get_str();
994
38fc4b70 995 UniValue subtractFeeFromAmount(UniValue::VARR);
292623ad 996 if (params.size() > 4)
40a75733 997 subtractFeeFromAmount = params[4].get_array();
292623ad 998
e3bc5698 999 set<CBitcoinAddress> setAddress;
292623ad 1000 vector<CRecipient> vecSend;
e3bc5698 1001
a372168e 1002 CAmount totalAmount = 0;
ed21d5bd
JG
1003 vector<string> keys = sendTo.getKeys();
1004 BOOST_FOREACH(const string& name_, keys)
e3bc5698 1005 {
ed21d5bd 1006 CBitcoinAddress address(name_);
e3bc5698 1007 if (!address.IsValid())
ed21d5bd 1008 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Zcash address: ")+name_);
e3bc5698
JG
1009
1010 if (setAddress.count(address))
ed21d5bd 1011 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+name_);
e3bc5698
JG
1012 setAddress.insert(address);
1013
0be990ba 1014 CScript scriptPubKey = GetScriptForDestination(address.Get());
ed21d5bd 1015 CAmount nAmount = AmountFromValue(sendTo[name_]);
e76a3849
WL
1016 if (nAmount <= 0)
1017 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
e3bc5698
JG
1018 totalAmount += nAmount;
1019
292623ad 1020 bool fSubtractFeeFromAmount = false;
cc71666a 1021 for (size_t idx = 0; idx < subtractFeeFromAmount.size(); idx++) {
d014114d 1022 const UniValue& addr = subtractFeeFromAmount[idx];
9756b7bd 1023 if (addr.get_str() == name_)
292623ad 1024 fSubtractFeeFromAmount = true;
9756b7bd 1025 }
292623ad
CL
1026
1027 CRecipient recipient = {scriptPubKey, nAmount, fSubtractFeeFromAmount};
1028 vecSend.push_back(recipient);
e3bc5698
JG
1029 }
1030
1031 EnsureWalletIsUnlocked();
1032
1033 // Check funds
a372168e 1034 CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE);
e3bc5698 1035 if (totalAmount > nBalance)
738835d7 1036 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
e3bc5698
JG
1037
1038 // Send
1039 CReserveKey keyChange(pwalletMain);
a372168e 1040 CAmount nFeeRequired = 0;
292623ad 1041 int nChangePosRet = -1;
1f00f4e9 1042 string strFailReason;
292623ad 1043 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, nChangePosRet, strFailReason);
e3bc5698 1044 if (!fCreated)
1f00f4e9 1045 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason);
e3bc5698 1046 if (!pwalletMain->CommitTransaction(wtx, keyChange))
738835d7 1047 throw JSONRPCError(RPC_WALLET_ERROR, "Transaction commit failed");
e3bc5698 1048
805344dc 1049 return wtx.GetHash().GetHex();
e3bc5698
JG
1050}
1051
723a03d2 1052// Defined in rpcmisc.cpp
d014114d 1053extern CScript _createmultisig_redeemScript(const UniValue& params);
34226be7 1054
d014114d 1055UniValue addmultisigaddress(const UniValue& params, bool fHelp)
34226be7 1056{
b9fb692d 1057 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 1058 return NullUniValue;
70454796 1059
34226be7
GA
1060 if (fHelp || params.size() < 2 || params.size() > 3)
1061 {
a6099ef3 1062 string msg = "addmultisigaddress nrequired [\"key\",...] ( \"account\" )\n"
1063 "\nAdd a nrequired-to-sign multisignature address to the wallet.\n"
58c4c0bb 1064 "Each key is a Zcash address or hex-encoded public key.\n"
7b782f5b 1065 "If 'account' is specified (DEPRECATED), assign address to that account.\n"
a6099ef3 1066
1067 "\nArguments:\n"
1068 "1. nrequired (numeric, required) The number of required signatures out of the n keys or addresses.\n"
d2c1e4a8 1069 "2. \"keysobject\" (string, required) A json array of Zcash addresses or hex-encoded public keys\n"
a6099ef3 1070 " [\n"
d2c1e4a8 1071 " \"address\" (string) Zcash address or hex-encoded public key\n"
a6099ef3 1072 " ...,\n"
1073 " ]\n"
3c31eb24 1074 "3. \"account\" (string, optional) DEPRECATED. If provided, MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
a6099ef3 1075
1076 "\nResult:\n"
d2c1e4a8 1077 "\"zcashaddress\" (string) A Zcash address associated with the keys.\n"
a6099ef3 1078
1079 "\nExamples:\n"
1080 "\nAdd a multisig address from 2 addresses\n"
70454796 1081 + HelpExampleCli("addmultisigaddress", "2 \"[\\\"t16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"t171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"") +
a6099ef3 1082 "\nAs json rpc call\n"
70454796 1083 + HelpExampleRpc("addmultisigaddress", "2, \"[\\\"t16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"t171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"")
a6099ef3 1084 ;
34226be7
GA
1085 throw runtime_error(msg);
1086 }
1087
4401b2d7
EL
1088 LOCK2(cs_main, pwalletMain->cs_wallet);
1089
34226be7
GA
1090 string strAccount;
1091 if (params.size() > 2)
1092 strAccount = AccountFromValue(params[2]);
e3bc5698
JG
1093
1094 // Construct using pay-to-script-hash:
787ee0c9 1095 CScript inner = _createmultisig_redeemScript(params);
066e2a14 1096 CScriptID innerID(inner);
e3bc5698
JG
1097 pwalletMain->AddCScript(inner);
1098
a41d5fe0 1099 pwalletMain->SetAddressBook(innerID, strAccount, "send");
e3bc5698
JG
1100 return CBitcoinAddress(innerID).ToString();
1101}
1102
1103
1104struct tallyitem
1105{
a372168e 1106 CAmount nAmount;
e3bc5698 1107 int nConf;
62c9b115 1108 vector<uint256> txids;
0fa2f889 1109 bool fIsWatchonly;
e3bc5698
JG
1110 tallyitem()
1111 {
1112 nAmount = 0;
1113 nConf = std::numeric_limits<int>::max();
0fa2f889 1114 fIsWatchonly = false;
e3bc5698
JG
1115 }
1116};
1117
d014114d 1118UniValue ListReceived(const UniValue& params, bool fByAccounts)
e3bc5698
JG
1119{
1120 // Minimum confirmations
1121 int nMinDepth = 1;
1122 if (params.size() > 0)
1123 nMinDepth = params[0].get_int();
1124
1125 // Whether to include empty accounts
1126 bool fIncludeEmpty = false;
1127 if (params.size() > 1)
1128 fIncludeEmpty = params[1].get_bool();
1129
a3e192a3 1130 isminefilter filter = ISMINE_SPENDABLE;
0fa2f889
J
1131 if(params.size() > 2)
1132 if(params[2].get_bool())
a3e192a3 1133 filter = filter | ISMINE_WATCH_ONLY;
0fa2f889 1134
e3bc5698
JG
1135 // Tally
1136 map<CBitcoinAddress, tallyitem> mapTally;
1137 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1138 {
1139 const CWalletTx& wtx = (*it).second;
1140
75a4d512 1141 if (wtx.IsCoinBase() || !CheckFinalTx(wtx))
e3bc5698
JG
1142 continue;
1143
1144 int nDepth = wtx.GetDepthInMainChain();
1145 if (nDepth < nMinDepth)
1146 continue;
1147
1148 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
1149 {
1150 CTxDestination address;
0fa2f889
J
1151 if (!ExtractDestination(txout.scriptPubKey, address))
1152 continue;
1153
1154 isminefilter mine = IsMine(*pwalletMain, address);
f28707a8 1155 if(!(mine & filter))
e3bc5698
JG
1156 continue;
1157
1158 tallyitem& item = mapTally[address];
1159 item.nAmount += txout.nValue;
1160 item.nConf = min(item.nConf, nDepth);
805344dc 1161 item.txids.push_back(wtx.GetHash());
a3e192a3 1162 if (mine & ISMINE_WATCH_ONLY)
0fa2f889 1163 item.fIsWatchonly = true;
e3bc5698
JG
1164 }
1165 }
1166
1167 // Reply
38fc4b70 1168 UniValue ret(UniValue::VARR);
e3bc5698 1169 map<string, tallyitem> mapAccountTally;
61885513 1170 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, CAddressBookData)& item, pwalletMain->mapAddressBook)
e3bc5698
JG
1171 {
1172 const CBitcoinAddress& address = item.first;
61885513 1173 const string& strAccount = item.second.name;
e3bc5698
JG
1174 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
1175 if (it == mapTally.end() && !fIncludeEmpty)
1176 continue;
1177
a372168e 1178 CAmount nAmount = 0;
e3bc5698 1179 int nConf = std::numeric_limits<int>::max();
0fa2f889 1180 bool fIsWatchonly = false;
e3bc5698
JG
1181 if (it != mapTally.end())
1182 {
1183 nAmount = (*it).second.nAmount;
1184 nConf = (*it).second.nConf;
0fa2f889 1185 fIsWatchonly = (*it).second.fIsWatchonly;
e3bc5698
JG
1186 }
1187
1188 if (fByAccounts)
1189 {
1190 tallyitem& item = mapAccountTally[strAccount];
1191 item.nAmount += nAmount;
1192 item.nConf = min(item.nConf, nConf);
0fa2f889 1193 item.fIsWatchonly = fIsWatchonly;
e3bc5698
JG
1194 }
1195 else
1196 {
38fc4b70 1197 UniValue obj(UniValue::VOBJ);
0fa2f889
J
1198 if(fIsWatchonly)
1199 obj.push_back(Pair("involvesWatchonly", true));
e3bc5698
JG
1200 obj.push_back(Pair("address", address.ToString()));
1201 obj.push_back(Pair("account", strAccount));
1202 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1203 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
38fc4b70 1204 UniValue transactions(UniValue::VARR);
1a204694 1205 if (it != mapTally.end())
62c9b115 1206 {
1a204694
A
1207 BOOST_FOREACH(const uint256& item, (*it).second.txids)
1208 {
1209 transactions.push_back(item.GetHex());
1210 }
62c9b115
A
1211 }
1212 obj.push_back(Pair("txids", transactions));
e3bc5698
JG
1213 ret.push_back(obj);
1214 }
1215 }
1216
1217 if (fByAccounts)
1218 {
1219 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
1220 {
a372168e 1221 CAmount nAmount = (*it).second.nAmount;
e3bc5698 1222 int nConf = (*it).second.nConf;
38fc4b70 1223 UniValue obj(UniValue::VOBJ);
0fa2f889
J
1224 if((*it).second.fIsWatchonly)
1225 obj.push_back(Pair("involvesWatchonly", true));
e3bc5698
JG
1226 obj.push_back(Pair("account", (*it).first));
1227 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1228 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1229 ret.push_back(obj);
1230 }
1231 }
1232
1233 return ret;
1234}
1235
d014114d 1236UniValue listreceivedbyaddress(const UniValue& params, bool fHelp)
e3bc5698 1237{
b9fb692d 1238 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 1239 return NullUniValue;
70454796 1240
0fa2f889 1241 if (fHelp || params.size() > 3)
e3bc5698 1242 throw runtime_error(
0fa2f889 1243 "listreceivedbyaddress ( minconf includeempty includeWatchonly)\n"
a6099ef3 1244 "\nList balances by receiving address.\n"
1245 "\nArguments:\n"
1246 "1. minconf (numeric, optional, default=1) The minimum number of confirmations before payments are included.\n"
5617267c 1247 "2. includeempty (numeric, optional, default=false) Whether to include addresses that haven't received any payments.\n"
0fa2f889 1248 "3. includeWatchonly (bool, optional, default=false) Whether to include watchonly addresses (see 'importaddress').\n"
a6099ef3 1249
1250 "\nResult:\n"
1251 "[\n"
1252 " {\n"
8f6860a0 1253 " \"involvesWatchonly\" : true, (bool) Only returned if imported addresses were involved in transaction\n"
a6099ef3 1254 " \"address\" : \"receivingaddress\", (string) The receiving address\n"
7b782f5b 1255 " \"account\" : \"accountname\", (string) DEPRECATED. The account of the receiving address. The default account is \"\".\n"
091b2116 1256 " \"amount\" : x.xxx, (numeric) The total amount in " + CURRENCY_UNIT + " received by the address\n"
a6099ef3 1257 " \"confirmations\" : n (numeric) The number of confirmations of the most recent transaction included\n"
1258 " }\n"
1259 " ,...\n"
1260 "]\n"
1261
1262 "\nExamples:\n"
1263 + HelpExampleCli("listreceivedbyaddress", "")
1264 + HelpExampleCli("listreceivedbyaddress", "6 true")
0fa2f889 1265 + HelpExampleRpc("listreceivedbyaddress", "6, true, true")
a6099ef3 1266 );
e3bc5698 1267
4401b2d7
EL
1268 LOCK2(cs_main, pwalletMain->cs_wallet);
1269
e3bc5698
JG
1270 return ListReceived(params, false);
1271}
1272
d014114d 1273UniValue listreceivedbyaccount(const UniValue& params, bool fHelp)
e3bc5698 1274{
b9fb692d 1275 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 1276 return NullUniValue;
70454796 1277
0fa2f889 1278 if (fHelp || params.size() > 3)
e3bc5698 1279 throw runtime_error(
0fa2f889 1280 "listreceivedbyaccount ( minconf includeempty includeWatchonly)\n"
7b782f5b 1281 "\nDEPRECATED. List balances by account.\n"
a6099ef3 1282 "\nArguments:\n"
1283 "1. minconf (numeric, optional, default=1) The minimum number of confirmations before payments are included.\n"
1284 "2. includeempty (boolean, optional, default=false) Whether to include accounts that haven't received any payments.\n"
0fa2f889 1285 "3. includeWatchonly (bool, optional, default=false) Whether to include watchonly addresses (see 'importaddress').\n"
a6099ef3 1286
1287 "\nResult:\n"
1288 "[\n"
1289 " {\n"
8f6860a0 1290 " \"involvesWatchonly\" : true, (bool) Only returned if imported addresses were involved in transaction\n"
a6099ef3 1291 " \"account\" : \"accountname\", (string) The account name of the receiving account\n"
1292 " \"amount\" : x.xxx, (numeric) The total amount received by addresses with this account\n"
1293 " \"confirmations\" : n (numeric) The number of confirmations of the most recent transaction included\n"
1294 " }\n"
1295 " ,...\n"
1296 "]\n"
1297
1298 "\nExamples:\n"
1299 + HelpExampleCli("listreceivedbyaccount", "")
1300 + HelpExampleCli("listreceivedbyaccount", "6 true")
0fa2f889 1301 + HelpExampleRpc("listreceivedbyaccount", "6, true, true")
a6099ef3 1302 );
e3bc5698 1303
4401b2d7
EL
1304 LOCK2(cs_main, pwalletMain->cs_wallet);
1305
e3bc5698
JG
1306 return ListReceived(params, true);
1307}
1308
851f58f9 1309static void MaybePushAddress(UniValue & entry, const CTxDestination &dest)
cc6cfab3
LD
1310{
1311 CBitcoinAddress addr;
1312 if (addr.Set(dest))
1313 entry.push_back(Pair("address", addr.ToString()));
1314}
1315
d014114d 1316void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, UniValue& ret, const isminefilter& filter)
e3bc5698 1317{
a372168e 1318 CAmount nFee;
e3bc5698 1319 string strSentAccount;
1b4568cb
CL
1320 list<COutputEntry> listReceived;
1321 list<COutputEntry> listSent;
e3bc5698 1322
d7d5d23b 1323 wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount, filter);
e3bc5698
JG
1324
1325 bool fAllAccounts = (strAccount == string("*"));
a3e192a3 1326 bool involvesWatchonly = wtx.IsFromMe(ISMINE_WATCH_ONLY);
e3bc5698 1327
e3bc5698
JG
1328 // Sent
1329 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1330 {
1b4568cb 1331 BOOST_FOREACH(const COutputEntry& s, listSent)
e3bc5698 1332 {
38fc4b70 1333 UniValue entry(UniValue::VOBJ);
1b4568cb 1334 if(involvesWatchonly || (::IsMine(*pwalletMain, s.destination) & ISMINE_WATCH_ONLY))
952877e0 1335 entry.push_back(Pair("involvesWatchonly", true));
e3bc5698 1336 entry.push_back(Pair("account", strSentAccount));
1b4568cb 1337 MaybePushAddress(entry, s.destination);
b96f6a77 1338 entry.push_back(Pair("category", "send"));
1b4568cb
CL
1339 entry.push_back(Pair("amount", ValueFromAmount(-s.amount)));
1340 entry.push_back(Pair("vout", s.vout));
e3bc5698
JG
1341 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1342 if (fLong)
1343 WalletTxToJSON(wtx, entry);
f32cade8 1344 entry.push_back(Pair("size", static_cast<CTransaction>(wtx).GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION)));
e3bc5698
JG
1345 ret.push_back(entry);
1346 }
1347 }
1348
1349 // Received
1350 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1351 {
1b4568cb 1352 BOOST_FOREACH(const COutputEntry& r, listReceived)
e3bc5698
JG
1353 {
1354 string account;
1b4568cb
CL
1355 if (pwalletMain->mapAddressBook.count(r.destination))
1356 account = pwalletMain->mapAddressBook[r.destination].name;
e3bc5698
JG
1357 if (fAllAccounts || (account == strAccount))
1358 {
38fc4b70 1359 UniValue entry(UniValue::VOBJ);
1b4568cb 1360 if(involvesWatchonly || (::IsMine(*pwalletMain, r.destination) & ISMINE_WATCH_ONLY))
952877e0 1361 entry.push_back(Pair("involvesWatchonly", true));
e3bc5698 1362 entry.push_back(Pair("account", account));
1b4568cb 1363 MaybePushAddress(entry, r.destination);
e07c8e91
LD
1364 if (wtx.IsCoinBase())
1365 {
1366 if (wtx.GetDepthInMainChain() < 1)
1367 entry.push_back(Pair("category", "orphan"));
1368 else if (wtx.GetBlocksToMaturity() > 0)
1369 entry.push_back(Pair("category", "immature"));
1370 else
1371 entry.push_back(Pair("category", "generate"));
1372 }
1373 else
2b72d46f 1374 {
b96f6a77 1375 entry.push_back(Pair("category", "receive"));
2b72d46f 1376 }
1b4568cb
CL
1377 entry.push_back(Pair("amount", ValueFromAmount(r.amount)));
1378 entry.push_back(Pair("vout", r.vout));
e3bc5698
JG
1379 if (fLong)
1380 WalletTxToJSON(wtx, entry);
f32cade8 1381 entry.push_back(Pair("size", static_cast<CTransaction>(wtx).GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION)));
e3bc5698
JG
1382 ret.push_back(entry);
1383 }
1384 }
1385 }
1386}
1387
d014114d 1388void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, UniValue& ret)
e3bc5698
JG
1389{
1390 bool fAllAccounts = (strAccount == string("*"));
1391
1392 if (fAllAccounts || acentry.strAccount == strAccount)
1393 {
38fc4b70 1394 UniValue entry(UniValue::VOBJ);
e3bc5698
JG
1395 entry.push_back(Pair("account", acentry.strAccount));
1396 entry.push_back(Pair("category", "move"));
d56e30ca 1397 entry.push_back(Pair("time", acentry.nTime));
e3bc5698
JG
1398 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1399 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1400 entry.push_back(Pair("comment", acentry.strComment));
1401 ret.push_back(entry);
1402 }
1403}
1404
d014114d 1405UniValue listtransactions(const UniValue& params, bool fHelp)
e3bc5698 1406{
b9fb692d 1407 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 1408 return NullUniValue;
70454796 1409
d7d5d23b 1410 if (fHelp || params.size() > 4)
e3bc5698 1411 throw runtime_error(
d7d5d23b 1412 "listtransactions ( \"account\" count from includeWatchonly)\n"
a6099ef3 1413 "\nReturns up to 'count' most recent transactions skipping the first 'from' transactions for account 'account'.\n"
1414 "\nArguments:\n"
7b782f5b 1415 "1. \"account\" (string, optional) DEPRECATED. The account name. Should be \"*\".\n"
a6099ef3 1416 "2. count (numeric, optional, default=10) The number of transactions to return\n"
1417 "3. from (numeric, optional, default=0) The number of transactions to skip\n"
d7d5d23b 1418 "4. includeWatchonly (bool, optional, default=false) Include transactions to watchonly addresses (see 'importaddress')\n"
a6099ef3 1419 "\nResult:\n"
1420 "[\n"
1421 " {\n"
7b782f5b 1422 " \"account\":\"accountname\", (string) DEPRECATED. The account name associated with the transaction. \n"
a6099ef3 1423 " It will be \"\" for the default account.\n"
d2c1e4a8 1424 " \"address\":\"zcashaddress\", (string) The Zcash address of the transaction. Not present for \n"
a6099ef3 1425 " move transactions (category = move).\n"
1426 " \"category\":\"send|receive|move\", (string) The transaction category. 'move' is a local (off blockchain)\n"
1427 " transaction between accounts, and not associated with an address,\n"
1428 " transaction id or block. 'send' and 'receive' transactions are \n"
1429 " associated with an address, transaction id and block details\n"
091b2116 1430 " \"amount\": x.xxx, (numeric) The amount in " + CURRENCY_UNIT + ". This is negative for the 'send' category, and for the\n"
a6099ef3 1431 " 'move' category for moves outbound. It is positive for the 'receive' category,\n"
1432 " and for the 'move' category for inbound funds.\n"
1b4568cb 1433 " \"vout\" : n, (numeric) the vout value\n"
091b2116 1434 " \"fee\": x.xxx, (numeric) The amount of the fee in " + CURRENCY_UNIT + ". This is negative and only available for the \n"
a6099ef3 1435 " 'send' category of transactions.\n"
1436 " \"confirmations\": n, (numeric) The number of confirmations for the transaction. Available for 'send' and \n"
1437 " 'receive' category of transactions.\n"
1438 " \"blockhash\": \"hashvalue\", (string) The block hash containing the transaction. Available for 'send' and 'receive'\n"
1439 " category of transactions.\n"
1440 " \"blockindex\": n, (numeric) The block index containing the transaction. Available for 'send' and 'receive'\n"
1441 " category of transactions.\n"
b5ef85c7 1442 " \"txid\": \"transactionid\", (string) The transaction id. Available for 'send' and 'receive' category of transactions.\n"
a6099ef3 1443 " \"time\": xxx, (numeric) The transaction time in seconds since epoch (midnight Jan 1 1970 GMT).\n"
1444 " \"timereceived\": xxx, (numeric) The time received in seconds since epoch (midnight Jan 1 1970 GMT). Available \n"
1445 " for 'send' and 'receive' category of transactions.\n"
1446 " \"comment\": \"...\", (string) If a comment is associated with the transaction.\n"
1447 " \"otheraccount\": \"accountname\", (string) For the 'move' category of transactions, the account the funds came \n"
1448 " from (for receiving funds, positive amounts), or went to (for sending funds,\n"
1449 " negative amounts).\n"
f32cade8 1450 " \"size\": n, (numeric) Transaction size in bytes\n"
a6099ef3 1451 " }\n"
1452 "]\n"
1453
1454 "\nExamples:\n"
1455 "\nList the most recent 10 transactions in the systems\n"
1456 + HelpExampleCli("listtransactions", "") +
7b782f5b
LD
1457 "\nList transactions 100 to 120\n"
1458 + HelpExampleCli("listtransactions", "\"*\" 20 100") +
a6099ef3 1459 "\nAs a json rpc call\n"
7b782f5b 1460 + HelpExampleRpc("listtransactions", "\"*\", 20, 100")
a6099ef3 1461 );
e3bc5698 1462
4401b2d7
EL
1463 LOCK2(cs_main, pwalletMain->cs_wallet);
1464
e3bc5698
JG
1465 string strAccount = "*";
1466 if (params.size() > 0)
1467 strAccount = params[0].get_str();
1468 int nCount = 10;
1469 if (params.size() > 1)
1470 nCount = params[1].get_int();
1471 int nFrom = 0;
1472 if (params.size() > 2)
1473 nFrom = params[2].get_int();
a3e192a3 1474 isminefilter filter = ISMINE_SPENDABLE;
a5c6c5d6
J
1475 if(params.size() > 3)
1476 if(params[3].get_bool())
a3e192a3 1477 filter = filter | ISMINE_WATCH_ONLY;
e3bc5698
JG
1478
1479 if (nCount < 0)
738835d7 1480 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count");
e3bc5698 1481 if (nFrom < 0)
738835d7 1482 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative from");
e3bc5698 1483
38fc4b70 1484 UniValue ret(UniValue::VARR);
e3bc5698 1485
ddb709e9
LD
1486 std::list<CAccountingEntry> acentries;
1487 CWallet::TxItems txOrdered = pwalletMain->OrderedTxItems(acentries, strAccount);
e3bc5698
JG
1488
1489 // iterate backwards until we have nCount items to return:
c3f95ef1 1490 for (CWallet::TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
e3bc5698
JG
1491 {
1492 CWalletTx *const pwtx = (*it).second.first;
1493 if (pwtx != 0)
d7d5d23b 1494 ListTransactions(*pwtx, strAccount, 0, true, ret, filter);
e3bc5698
JG
1495 CAccountingEntry *const pacentry = (*it).second.second;
1496 if (pacentry != 0)
1497 AcentryToJSON(*pacentry, strAccount, ret);
1498
1499 if ((int)ret.size() >= (nCount+nFrom)) break;
1500 }
1501 // ret is newest to oldest
1502
1503 if (nFrom > (int)ret.size())
1504 nFrom = ret.size();
1505 if ((nFrom + nCount) > (int)ret.size())
1506 nCount = ret.size() - nFrom;
ed21d5bd
JG
1507
1508 vector<UniValue> arrTmp = ret.getValues();
1509
1510 vector<UniValue>::iterator first = arrTmp.begin();
e3bc5698 1511 std::advance(first, nFrom);
ed21d5bd 1512 vector<UniValue>::iterator last = arrTmp.begin();
e3bc5698
JG
1513 std::advance(last, nFrom+nCount);
1514
ed21d5bd
JG
1515 if (last != arrTmp.end()) arrTmp.erase(last, arrTmp.end());
1516 if (first != arrTmp.begin()) arrTmp.erase(arrTmp.begin(), first);
1517
1518 std::reverse(arrTmp.begin(), arrTmp.end()); // Return oldest to newest
e3bc5698 1519
ed21d5bd 1520 ret.clear();
38fc4b70 1521 ret.setArray();
ed21d5bd 1522 ret.push_backV(arrTmp);
e3bc5698
JG
1523
1524 return ret;
1525}
1526
d014114d 1527UniValue listaccounts(const UniValue& params, bool fHelp)
e3bc5698 1528{
b9fb692d 1529 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 1530 return NullUniValue;
70454796 1531
83f3543f 1532 if (fHelp || params.size() > 2)
e3bc5698 1533 throw runtime_error(
83f3543f 1534 "listaccounts ( minconf includeWatchonly)\n"
7b782f5b 1535 "\nDEPRECATED. Returns Object that has account names as keys, account balances as values.\n"
a6099ef3 1536 "\nArguments:\n"
5617267c 1537 "1. minconf (numeric, optional, default=1) Only include transactions with at least this many confirmations\n"
83f3543f 1538 "2. includeWatchonly (bool, optional, default=false) Include balances in watchonly addresses (see 'importaddress')\n"
a6099ef3 1539 "\nResult:\n"
1540 "{ (json object where keys are account names, and values are numeric balances\n"
1541 " \"account\": x.xxx, (numeric) The property name is the account name, and the value is the total balance for the account.\n"
1542 " ...\n"
1543 "}\n"
1544 "\nExamples:\n"
1545 "\nList account balances where there at least 1 confirmation\n"
1546 + HelpExampleCli("listaccounts", "") +
1547 "\nList account balances including zero confirmation transactions\n"
1548 + HelpExampleCli("listaccounts", "0") +
1549 "\nList account balances for 6 or more confirmations\n"
1550 + HelpExampleCli("listaccounts", "6") +
1551 "\nAs json rpc call\n"
1552 + HelpExampleRpc("listaccounts", "6")
1553 );
e3bc5698 1554
4401b2d7
EL
1555 LOCK2(cs_main, pwalletMain->cs_wallet);
1556
e3bc5698
JG
1557 int nMinDepth = 1;
1558 if (params.size() > 0)
1559 nMinDepth = params[0].get_int();
a3e192a3 1560 isminefilter includeWatchonly = ISMINE_SPENDABLE;
a5c6c5d6
J
1561 if(params.size() > 1)
1562 if(params[1].get_bool())
a3e192a3 1563 includeWatchonly = includeWatchonly | ISMINE_WATCH_ONLY;
e3bc5698 1564
a372168e 1565 map<string, CAmount> mapAccountBalances;
61885513 1566 BOOST_FOREACH(const PAIRTYPE(CTxDestination, CAddressBookData)& entry, pwalletMain->mapAddressBook) {
83f3543f 1567 if (IsMine(*pwalletMain, entry.first) & includeWatchonly) // This address belongs to me
61885513 1568 mapAccountBalances[entry.second.name] = 0;
e3bc5698
JG
1569 }
1570
1571 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1572 {
1573 const CWalletTx& wtx = (*it).second;
a372168e 1574 CAmount nFee;
e3bc5698 1575 string strSentAccount;
1b4568cb
CL
1576 list<COutputEntry> listReceived;
1577 list<COutputEntry> listSent;
93a18a36
GA
1578 int nDepth = wtx.GetDepthInMainChain();
1579 if (wtx.GetBlocksToMaturity() > 0 || nDepth < 0)
731b89b8 1580 continue;
83f3543f 1581 wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount, includeWatchonly);
e3bc5698 1582 mapAccountBalances[strSentAccount] -= nFee;
1b4568cb
CL
1583 BOOST_FOREACH(const COutputEntry& s, listSent)
1584 mapAccountBalances[strSentAccount] -= s.amount;
93a18a36 1585 if (nDepth >= nMinDepth)
e3bc5698 1586 {
1b4568cb
CL
1587 BOOST_FOREACH(const COutputEntry& r, listReceived)
1588 if (pwalletMain->mapAddressBook.count(r.destination))
1589 mapAccountBalances[pwalletMain->mapAddressBook[r.destination].name] += r.amount;
e3bc5698 1590 else
1b4568cb 1591 mapAccountBalances[""] += r.amount;
e3bc5698
JG
1592 }
1593 }
1594
1595 list<CAccountingEntry> acentries;
1596 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1597 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1598 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1599
38fc4b70 1600 UniValue ret(UniValue::VOBJ);
a372168e 1601 BOOST_FOREACH(const PAIRTYPE(string, CAmount)& accountBalance, mapAccountBalances) {
e3bc5698
JG
1602 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1603 }
1604 return ret;
1605}
1606
d014114d 1607UniValue listsinceblock(const UniValue& params, bool fHelp)
e3bc5698 1608{
b9fb692d 1609 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 1610 return NullUniValue;
70454796 1611
e3bc5698
JG
1612 if (fHelp)
1613 throw runtime_error(
d7d5d23b 1614 "listsinceblock ( \"blockhash\" target-confirmations includeWatchonly)\n"
a6099ef3 1615 "\nGet all transactions in blocks since block [blockhash], or all transactions if omitted\n"
1616 "\nArguments:\n"
1617 "1. \"blockhash\" (string, optional) The block hash to list transactions since\n"
1618 "2. target-confirmations: (numeric, optional) The confirmations required, must be 1 or more\n"
d7d5d23b 1619 "3. includeWatchonly: (bool, optional, default=false) Include transactions to watchonly addresses (see 'importaddress')"
a6099ef3 1620 "\nResult:\n"
1621 "{\n"
1622 " \"transactions\": [\n"
7b782f5b 1623 " \"account\":\"accountname\", (string) DEPRECATED. The account name associated with the transaction. Will be \"\" for the default account.\n"
d2c1e4a8 1624 " \"address\":\"zcashaddress\", (string) The Zcash address of the transaction. Not present for move transactions (category = move).\n"
a6099ef3 1625 " \"category\":\"send|receive\", (string) The transaction category. 'send' has negative amounts, 'receive' has positive amounts.\n"
091b2116 1626 " \"amount\": x.xxx, (numeric) The amount in " + CURRENCY_UNIT + ". This is negative for the 'send' category, and for the 'move' category for moves \n"
a6099ef3 1627 " outbound. It is positive for the 'receive' category, and for the 'move' category for inbound funds.\n"
1b4568cb 1628 " \"vout\" : n, (numeric) the vout value\n"
091b2116 1629 " \"fee\": x.xxx, (numeric) The amount of the fee in " + CURRENCY_UNIT + ". This is negative and only available for the 'send' category of transactions.\n"
a6099ef3 1630 " \"confirmations\": n, (numeric) The number of confirmations for the transaction. Available for 'send' and 'receive' category of transactions.\n"
1631 " \"blockhash\": \"hashvalue\", (string) The block hash containing the transaction. Available for 'send' and 'receive' category of transactions.\n"
1632 " \"blockindex\": n, (numeric) The block index containing the transaction. Available for 'send' and 'receive' category of transactions.\n"
1633 " \"blocktime\": xxx, (numeric) The block time in seconds since epoch (1 Jan 1970 GMT).\n"
b5ef85c7 1634 " \"txid\": \"transactionid\", (string) The transaction id. Available for 'send' and 'receive' category of transactions.\n"
a6099ef3 1635 " \"time\": xxx, (numeric) The transaction time in seconds since epoch (Jan 1 1970 GMT).\n"
1636 " \"timereceived\": xxx, (numeric) The time received in seconds since epoch (Jan 1 1970 GMT). Available for 'send' and 'receive' category of transactions.\n"
1637 " \"comment\": \"...\", (string) If a comment is associated with the transaction.\n"
1638 " \"to\": \"...\", (string) If a comment to is associated with the transaction.\n"
1639 " ],\n"
1640 " \"lastblock\": \"lastblockhash\" (string) The hash of the last block\n"
1641 "}\n"
1642 "\nExamples:\n"
1643 + HelpExampleCli("listsinceblock", "")
1644 + HelpExampleCli("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\" 6")
1645 + HelpExampleRpc("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\", 6")
1646 );
e3bc5698 1647
4401b2d7
EL
1648 LOCK2(cs_main, pwalletMain->cs_wallet);
1649
e3bc5698
JG
1650 CBlockIndex *pindex = NULL;
1651 int target_confirms = 1;
a3e192a3 1652 isminefilter filter = ISMINE_SPENDABLE;
e3bc5698
JG
1653
1654 if (params.size() > 0)
1655 {
4f152496 1656 uint256 blockId;
e3bc5698
JG
1657
1658 blockId.SetHex(params[0].get_str());
145d5be8 1659 BlockMap::iterator it = mapBlockIndex.find(blockId);
e4daecda
PW
1660 if (it != mapBlockIndex.end())
1661 pindex = it->second;
e3bc5698
JG
1662 }
1663
1664 if (params.size() > 1)
1665 {
1666 target_confirms = params[1].get_int();
1667
1668 if (target_confirms < 1)
738835d7 1669 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter");
e3bc5698
JG
1670 }
1671
a5c6c5d6
J
1672 if(params.size() > 2)
1673 if(params[2].get_bool())
a3e192a3 1674 filter = filter | ISMINE_WATCH_ONLY;
a5c6c5d6 1675
4c6d41b8 1676 int depth = pindex ? (1 + chainActive.Height() - pindex->nHeight) : -1;
e3bc5698 1677
38fc4b70 1678 UniValue transactions(UniValue::VARR);
e3bc5698
JG
1679
1680 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1681 {
1682 CWalletTx tx = (*it).second;
1683
1684 if (depth == -1 || tx.GetDepthInMainChain() < depth)
d7d5d23b 1685 ListTransactions(tx, "*", 0, true, transactions, filter);
e3bc5698
JG
1686 }
1687
4c6d41b8 1688 CBlockIndex *pblockLast = chainActive[chainActive.Height() + 1 - target_confirms];
4f152496 1689 uint256 lastblock = pblockLast ? pblockLast->GetBlockHash() : uint256();
e3bc5698 1690
38fc4b70 1691 UniValue ret(UniValue::VOBJ);
e3bc5698
JG
1692 ret.push_back(Pair("transactions", transactions));
1693 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1694
1695 return ret;
1696}
1697
d014114d 1698UniValue gettransaction(const UniValue& params, bool fHelp)
e3bc5698 1699{
b9fb692d 1700 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 1701 return NullUniValue;
70454796 1702
f87ba3df 1703 if (fHelp || params.size() < 1 || params.size() > 2)
e3bc5698 1704 throw runtime_error(
57e1716d 1705 "gettransaction \"txid\" ( includeWatchonly )\n"
a6099ef3 1706 "\nGet detailed information about in-wallet transaction <txid>\n"
1707 "\nArguments:\n"
1708 "1. \"txid\" (string, required) The transaction id\n"
f87ba3df 1709 "2. \"includeWatchonly\" (bool, optional, default=false) Whether to include watchonly addresses in balance calculation and details[]\n"
a6099ef3 1710 "\nResult:\n"
1711 "{\n"
091b2116 1712 " \"amount\" : x.xxx, (numeric) The transaction amount in " + CURRENCY_UNIT + "\n"
a6099ef3 1713 " \"confirmations\" : n, (numeric) The number of confirmations\n"
1714 " \"blockhash\" : \"hash\", (string) The block hash\n"
1715 " \"blockindex\" : xx, (numeric) The block index\n"
1716 " \"blocktime\" : ttt, (numeric) The time in seconds since epoch (1 Jan 1970 GMT)\n"
b5ef85c7 1717 " \"txid\" : \"transactionid\", (string) The transaction id.\n"
a6099ef3 1718 " \"time\" : ttt, (numeric) The transaction time in seconds since epoch (1 Jan 1970 GMT)\n"
1719 " \"timereceived\" : ttt, (numeric) The time received in seconds since epoch (1 Jan 1970 GMT)\n"
1720 " \"details\" : [\n"
1721 " {\n"
7b782f5b 1722 " \"account\" : \"accountname\", (string) DEPRECATED. The account name involved in the transaction, can be \"\" for the default account.\n"
d2c1e4a8 1723 " \"address\" : \"zcashaddress\", (string) The Zcash address involved in the transaction\n"
a6099ef3 1724 " \"category\" : \"send|receive\", (string) The category, either 'send' or 'receive'\n"
091b2116 1725 " \"amount\" : x.xxx (numeric) The amount in " + CURRENCY_UNIT + "\n"
1b4568cb 1726 " \"vout\" : n, (numeric) the vout value\n"
a6099ef3 1727 " }\n"
1728 " ,...\n"
3a1c20b7 1729 " ],\n"
f7cfb52d
S
1730 " \"vjoinsplit\" : [\n"
1731 " {\n"
1732 " \"anchor\" : \"treestateref\", (string) Merkle root of note commitment tree\n"
1733 " \"nullifiers\" : [ string, ... ] (string) Nullifiers of input notes\n"
1734 " \"commitments\" : [ string, ... ] (string) Note commitments for note outputs\n"
1735 " \"macs\" : [ string, ... ] (string) Message authentication tags\n"
1736 " \"vpub_old\" : x.xxx (numeric) The amount removed from the transparent value pool\n"
1737 " \"vpub_new\" : x.xxx, (numeric) The amount added to the transparent value pool\n"
1738 " }\n"
1739 " ,...\n"
1740 " ],\n"
3a1c20b7 1741 " \"hex\" : \"data\" (string) Raw data for transaction\n"
a6099ef3 1742 "}\n"
1743
ab45ddb5 1744 "\nExamples:\n"
a6099ef3 1745 + HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
57e1716d 1746 + HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\" true")
a6099ef3 1747 + HelpExampleRpc("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
1748 );
e3bc5698 1749
4401b2d7
EL
1750 LOCK2(cs_main, pwalletMain->cs_wallet);
1751
e3bc5698
JG
1752 uint256 hash;
1753 hash.SetHex(params[0].get_str());
1754
a3e192a3 1755 isminefilter filter = ISMINE_SPENDABLE;
f87ba3df
J
1756 if(params.size() > 1)
1757 if(params[1].get_bool())
a3e192a3 1758 filter = filter | ISMINE_WATCH_ONLY;
f87ba3df 1759
38fc4b70 1760 UniValue entry(UniValue::VOBJ);
e3bc5698 1761 if (!pwalletMain->mapWallet.count(hash))
738835d7 1762 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id");
e3bc5698
JG
1763 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1764
ccca27a7 1765 CAmount nCredit = wtx.GetCredit(filter);
a372168e
MF
1766 CAmount nDebit = wtx.GetDebit(filter);
1767 CAmount nNet = nCredit - nDebit;
1768 CAmount nFee = (wtx.IsFromMe(filter) ? wtx.GetValueOut() - nDebit : 0);
e3bc5698
JG
1769
1770 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
80dda36a 1771 if (wtx.IsFromMe(filter))
e3bc5698
JG
1772 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1773
1774 WalletTxToJSON(wtx, entry);
1775
38fc4b70 1776 UniValue details(UniValue::VARR);
f87ba3df 1777 ListTransactions(wtx, "*", 0, false, details, filter);
e3bc5698
JG
1778 entry.push_back(Pair("details", details));
1779
ae775b5b 1780 string strHex = EncodeHexTx(static_cast<CTransaction>(wtx));
3a1c20b7
WL
1781 entry.push_back(Pair("hex", strHex));
1782
e3bc5698
JG
1783 return entry;
1784}
1785
1786
d014114d 1787UniValue backupwallet(const UniValue& params, bool fHelp)
e3bc5698 1788{
b9fb692d 1789 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 1790 return NullUniValue;
70454796 1791
e3bc5698
JG
1792 if (fHelp || params.size() != 1)
1793 throw runtime_error(
a6099ef3 1794 "backupwallet \"destination\"\n"
9064d73b 1795 "\nSafely copies wallet.dat to destination filename\n"
a6099ef3 1796 "\nArguments:\n"
9064d73b
S
1797 "1. \"destination\" (string, required) The destination filename, saved in the directory set by -exportdir option.\n"
1798 "\nResult:\n"
1799 "\"path\" (string) The full path of the destination file\n"
a6099ef3 1800 "\nExamples:\n"
9064d73b
S
1801 + HelpExampleCli("backupwallet", "\"backupdata\"")
1802 + HelpExampleRpc("backupwallet", "\"backupdata\"")
a6099ef3 1803 );
e3bc5698 1804
4401b2d7
EL
1805 LOCK2(cs_main, pwalletMain->cs_wallet);
1806
9064d73b
S
1807 boost::filesystem::path exportdir;
1808 try {
1809 exportdir = GetExportDir();
1810 } catch (const std::runtime_error& e) {
1811 throw JSONRPCError(RPC_INTERNAL_ERROR, e.what());
1812 }
1813 if (exportdir.empty()) {
1814 throw JSONRPCError(RPC_WALLET_ERROR, "Cannot backup wallet until the -exportdir option has been set");
1815 }
1816 std::string unclean = params[0].get_str();
1817 std::string clean = SanitizeFilename(unclean);
1818 if (clean.compare(unclean) != 0) {
1819 throw JSONRPCError(RPC_WALLET_ERROR, strprintf("Filename is invalid as only alphanumeric characters are allowed. Try '%s' instead.", clean));
1820 }
1821 boost::filesystem::path exportfilepath = exportdir / clean;
1822
1823 if (!BackupWallet(*pwalletMain, exportfilepath.string()))
ad525e9c 1824 throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!");
e3bc5698 1825
9064d73b 1826 return exportfilepath.string();
e3bc5698
JG
1827}
1828
1829
d014114d 1830UniValue keypoolrefill(const UniValue& params, bool fHelp)
e3bc5698 1831{
b9fb692d 1832 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 1833 return NullUniValue;
70454796 1834
36bd46f1 1835 if (fHelp || params.size() > 1)
e3bc5698 1836 throw runtime_error(
a6099ef3 1837 "keypoolrefill ( newsize )\n"
1838 "\nFills the keypool."
1839 + HelpRequiringPassphrase() + "\n"
1840 "\nArguments\n"
1841 "1. newsize (numeric, optional, default=100) The new keypool size\n"
1842 "\nExamples:\n"
1843 + HelpExampleCli("keypoolrefill", "")
1844 + HelpExampleRpc("keypoolrefill", "")
1845 );
e3bc5698 1846
4401b2d7
EL
1847 LOCK2(cs_main, pwalletMain->cs_wallet);
1848
f914c7a1
PK
1849 // 0 is interpreted by TopUpKeyPool() as the default keypool size given by -keypool
1850 unsigned int kpSize = 0;
36bd46f1
JG
1851 if (params.size() > 0) {
1852 if (params[0].get_int() < 0)
f914c7a1
PK
1853 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size.");
1854 kpSize = (unsigned int)params[0].get_int();
36bd46f1
JG
1855 }
1856
e3bc5698 1857 EnsureWalletIsUnlocked();
36bd46f1 1858 pwalletMain->TopUpKeyPool(kpSize);
e3bc5698 1859
36bd46f1 1860 if (pwalletMain->GetKeyPoolSize() < kpSize)
738835d7 1861 throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool.");
e3bc5698 1862
ed21d5bd 1863 return NullUniValue;
e3bc5698
JG
1864}
1865
1866
92f2c1fe 1867static void LockWallet(CWallet* pWallet)
e3bc5698 1868{
92f2c1fe
GA
1869 LOCK(cs_nWalletUnlockTime);
1870 nWalletUnlockTime = 0;
1871 pWallet->Lock();
e3bc5698
JG
1872}
1873
d014114d 1874UniValue walletpassphrase(const UniValue& params, bool fHelp)
e3bc5698 1875{
b9fb692d 1876 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 1877 return NullUniValue;
70454796 1878
e3bc5698
JG
1879 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1880 throw runtime_error(
a6099ef3 1881 "walletpassphrase \"passphrase\" timeout\n"
1882 "\nStores the wallet decryption key in memory for 'timeout' seconds.\n"
c1652849 1883 "This is needed prior to performing transactions related to private keys such as sending Zcash\n"
a6099ef3 1884 "\nArguments:\n"
1885 "1. \"passphrase\" (string, required) The wallet passphrase\n"
1886 "2. timeout (numeric, required) The time to keep the decryption key in seconds.\n"
6c0db81c
WL
1887 "\nNote:\n"
1888 "Issuing the walletpassphrase command while the wallet is already unlocked will set a new unlock\n"
1889 "time that overrides the old one.\n"
a6099ef3 1890 "\nExamples:\n"
1891 "\nunlock the wallet for 60 seconds\n"
1892 + HelpExampleCli("walletpassphrase", "\"my pass phrase\" 60") +
1893 "\nLock the wallet again (before 60 seconds)\n"
1894 + HelpExampleCli("walletlock", "") +
1895 "\nAs json rpc call\n"
1896 + HelpExampleRpc("walletpassphrase", "\"my pass phrase\", 60")
1897 );
1898
4401b2d7
EL
1899 LOCK2(cs_main, pwalletMain->cs_wallet);
1900
e3bc5698
JG
1901 if (fHelp)
1902 return true;
1903 if (!pwalletMain->IsCrypted())
738835d7 1904 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
e3bc5698 1905
e3bc5698
JG
1906 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1907 SecureString strWalletPass;
1908 strWalletPass.reserve(100);
1909 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1910 // Alternately, find a way to make params[0] mlock()'d to begin with.
1911 strWalletPass = params[0].get_str().c_str();
1912
1913 if (strWalletPass.length() > 0)
1914 {
1915 if (!pwalletMain->Unlock(strWalletPass))
738835d7 1916 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
e3bc5698
JG
1917 }
1918 else
1919 throw runtime_error(
1920 "walletpassphrase <passphrase> <timeout>\n"
1921 "Stores the wallet decryption key in memory for <timeout> seconds.");
1922
6e263a5f 1923 // No need to check return values, because the wallet was unlocked above
1a62587e 1924 pwalletMain->UpdateNullifierNoteMap();
92f2c1fe
GA
1925 pwalletMain->TopUpKeyPool();
1926
51ed9ec9 1927 int64_t nSleepTime = params[1].get_int64();
92f2c1fe
GA
1928 LOCK(cs_nWalletUnlockTime);
1929 nWalletUnlockTime = GetTime() + nSleepTime;
1930 RPCRunLater("lockwallet", boost::bind(LockWallet, pwalletMain), nSleepTime);
e3bc5698 1931
ed21d5bd 1932 return NullUniValue;
e3bc5698
JG
1933}
1934
1935
d014114d 1936UniValue walletpassphrasechange(const UniValue& params, bool fHelp)
e3bc5698 1937{
b9fb692d 1938 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 1939 return NullUniValue;
70454796 1940
e3bc5698
JG
1941 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1942 throw runtime_error(
a6099ef3 1943 "walletpassphrasechange \"oldpassphrase\" \"newpassphrase\"\n"
1944 "\nChanges the wallet passphrase from 'oldpassphrase' to 'newpassphrase'.\n"
1945 "\nArguments:\n"
1946 "1. \"oldpassphrase\" (string) The current passphrase\n"
1947 "2. \"newpassphrase\" (string) The new passphrase\n"
1948 "\nExamples:\n"
1949 + HelpExampleCli("walletpassphrasechange", "\"old one\" \"new one\"")
1950 + HelpExampleRpc("walletpassphrasechange", "\"old one\", \"new one\"")
1951 );
1952
4401b2d7
EL
1953 LOCK2(cs_main, pwalletMain->cs_wallet);
1954
e3bc5698
JG
1955 if (fHelp)
1956 return true;
1957 if (!pwalletMain->IsCrypted())
738835d7 1958 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
e3bc5698
JG
1959
1960 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1961 // Alternately, find a way to make params[0] mlock()'d to begin with.
1962 SecureString strOldWalletPass;
1963 strOldWalletPass.reserve(100);
1964 strOldWalletPass = params[0].get_str().c_str();
1965
1966 SecureString strNewWalletPass;
1967 strNewWalletPass.reserve(100);
1968 strNewWalletPass = params[1].get_str().c_str();
1969
1970 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1971 throw runtime_error(
1972 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1973 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1974
1975 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
738835d7 1976 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
e3bc5698 1977
ed21d5bd 1978 return NullUniValue;
e3bc5698
JG
1979}
1980
1981
d014114d 1982UniValue walletlock(const UniValue& params, bool fHelp)
e3bc5698 1983{
b9fb692d 1984 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 1985 return NullUniValue;
70454796 1986
e3bc5698
JG
1987 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1988 throw runtime_error(
1989 "walletlock\n"
a6099ef3 1990 "\nRemoves the wallet encryption key from memory, locking the wallet.\n"
e3bc5698 1991 "After calling this method, you will need to call walletpassphrase again\n"
a6099ef3 1992 "before being able to call any methods which require the wallet to be unlocked.\n"
1993 "\nExamples:\n"
1994 "\nSet the passphrase for 2 minutes to perform a transaction\n"
1995 + HelpExampleCli("walletpassphrase", "\"my pass phrase\" 120") +
1996 "\nPerform a send (requires passphrase set)\n"
70454796 1997 + HelpExampleCli("sendtoaddress", "\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 1.0") +
a6099ef3 1998 "\nClear the passphrase since we are done before 2 minutes is up\n"
1999 + HelpExampleCli("walletlock", "") +
2000 "\nAs json rpc call\n"
2001 + HelpExampleRpc("walletlock", "")
2002 );
2003
4401b2d7
EL
2004 LOCK2(cs_main, pwalletMain->cs_wallet);
2005
e3bc5698
JG
2006 if (fHelp)
2007 return true;
2008 if (!pwalletMain->IsCrypted())
738835d7 2009 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletlock was called.");
e3bc5698
JG
2010
2011 {
2012 LOCK(cs_nWalletUnlockTime);
2013 pwalletMain->Lock();
2014 nWalletUnlockTime = 0;
2015 }
2016
ed21d5bd 2017 return NullUniValue;
e3bc5698
JG
2018}
2019
2020
d014114d 2021UniValue encryptwallet(const UniValue& params, bool fHelp)
e3bc5698 2022{
b9fb692d 2023 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 2024 return NullUniValue;
62c0aa9e 2025
b8eb3775 2026 auto fEnableWalletEncryption = fExperimentalMode && GetBoolArg("-developerencryptwallet", false);
62c0aa9e
JG
2027
2028 std::string strWalletEncryptionDisabledMsg = "";
2029 if (!fEnableWalletEncryption) {
1532cb75 2030 strWalletEncryptionDisabledMsg = "\nWARNING: Wallet encryption is DISABLED. This call always fails.\n";
62c0aa9e
JG
2031 }
2032
e3bc5698
JG
2033 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
2034 throw runtime_error(
a6099ef3 2035 "encryptwallet \"passphrase\"\n"
62c0aa9e 2036 + strWalletEncryptionDisabledMsg +
a6099ef3 2037 "\nEncrypts the wallet with 'passphrase'. This is for first time encryption.\n"
2038 "After this, any calls that interact with private keys such as sending or signing \n"
2039 "will require the passphrase to be set prior the making these calls.\n"
2040 "Use the walletpassphrase call for this, and then walletlock call.\n"
2041 "If the wallet is already encrypted, use the walletpassphrasechange call.\n"
2042 "Note that this will shutdown the server.\n"
2043 "\nArguments:\n"
2044 "1. \"passphrase\" (string) The pass phrase to encrypt the wallet with. It must be at least 1 character, but should be long.\n"
2045 "\nExamples:\n"
2046 "\nEncrypt you wallet\n"
2047 + HelpExampleCli("encryptwallet", "\"my pass phrase\"") +
c1652849 2048 "\nNow set the passphrase to use the wallet, such as for signing or sending Zcash\n"
a6099ef3 2049 + HelpExampleCli("walletpassphrase", "\"my pass phrase\"") +
2050 "\nNow we can so something like sign\n"
58c4c0bb 2051 + HelpExampleCli("signmessage", "\"zcashaddress\" \"test message\"") +
a6099ef3 2052 "\nNow lock the wallet again by removing the passphrase\n"
2053 + HelpExampleCli("walletlock", "") +
2054 "\nAs a json rpc call\n"
2055 + HelpExampleRpc("encryptwallet", "\"my pass phrase\"")
2056 );
2057
4401b2d7
EL
2058 LOCK2(cs_main, pwalletMain->cs_wallet);
2059
e3bc5698
JG
2060 if (fHelp)
2061 return true;
62c0aa9e 2062 if (!fEnableWalletEncryption) {
1532cb75 2063 throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: wallet encryption is disabled.");
62c0aa9e 2064 }
e3bc5698 2065 if (pwalletMain->IsCrypted())
738835d7 2066 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an encrypted wallet, but encryptwallet was called.");
e3bc5698
JG
2067
2068 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
2069 // Alternately, find a way to make params[0] mlock()'d to begin with.
2070 SecureString strWalletPass;
2071 strWalletPass.reserve(100);
2072 strWalletPass = params[0].get_str().c_str();
2073
2074 if (strWalletPass.length() < 1)
2075 throw runtime_error(
2076 "encryptwallet <passphrase>\n"
2077 "Encrypts the wallet with <passphrase>.");
2078
2079 if (!pwalletMain->EncryptWallet(strWalletPass))
738835d7 2080 throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: Failed to encrypt the wallet.");
e3bc5698
JG
2081
2082 // BDB seems to have a bad habit of writing old data into
2083 // slack space in .dat files; that is bad if the old data is
331544bc 2084 // unencrypted private keys. So:
e3bc5698 2085 StartShutdown();
58c4c0bb 2086 return "wallet encrypted; Zcash server stopping, restart to run with encrypted wallet. The keypool has been flushed, you need to make a new backup.";
e3bc5698
JG
2087}
2088
d014114d 2089UniValue lockunspent(const UniValue& params, bool fHelp)
fdbb537d 2090{
b9fb692d 2091 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 2092 return NullUniValue;
70454796 2093
fdbb537d
JG
2094 if (fHelp || params.size() < 1 || params.size() > 2)
2095 throw runtime_error(
a6099ef3 2096 "lockunspent unlock [{\"txid\":\"txid\",\"vout\":n},...]\n"
2097 "\nUpdates list of temporarily unspendable outputs.\n"
90fd8737 2098 "Temporarily lock (unlock=false) or unlock (unlock=true) specified transaction outputs.\n"
c1652849 2099 "A locked transaction output will not be chosen by automatic coin selection, when spending Zcash.\n"
a6099ef3 2100 "Locks are stored in memory only. Nodes start with zero locked outputs, and the locked output list\n"
2101 "is always cleared (by virtue of process exit) when a node stops or fails.\n"
2102 "Also see the listunspent call\n"
2103 "\nArguments:\n"
2104 "1. unlock (boolean, required) Whether to unlock (true) or lock (false) the specified transactions\n"
2105 "2. \"transactions\" (string, required) A json array of objects. Each object the txid (string) vout (numeric)\n"
2106 " [ (json array of json objects)\n"
2107 " {\n"
2108 " \"txid\":\"id\", (string) The transaction id\n"
2109 " \"vout\": n (numeric) The output number\n"
2110 " }\n"
2111 " ,...\n"
2112 " ]\n"
2113
2114 "\nResult:\n"
2115 "true|false (boolean) Whether the command was successful or not\n"
2116
2117 "\nExamples:\n"
2118 "\nList the unspent transactions\n"
2119 + HelpExampleCli("listunspent", "") +
2120 "\nLock an unspent transaction\n"
2121 + HelpExampleCli("lockunspent", "false \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2122 "\nList the locked transactions\n"
2123 + HelpExampleCli("listlockunspent", "") +
2124 "\nUnlock the transaction again\n"
2125 + HelpExampleCli("lockunspent", "true \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2126 "\nAs a json rpc call\n"
2127 + HelpExampleRpc("lockunspent", "false, \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"")
2128 );
fdbb537d 2129
4401b2d7
EL
2130 LOCK2(cs_main, pwalletMain->cs_wallet);
2131
fdbb537d 2132 if (params.size() == 1)
ed21d5bd 2133 RPCTypeCheck(params, boost::assign::list_of(UniValue::VBOOL));
fdbb537d 2134 else
ed21d5bd 2135 RPCTypeCheck(params, boost::assign::list_of(UniValue::VBOOL)(UniValue::VARR));
fdbb537d
JG
2136
2137 bool fUnlock = params[0].get_bool();
2138
2139 if (params.size() == 1) {
2140 if (fUnlock)
2141 pwalletMain->UnlockAllCoins();
2142 return true;
2143 }
2144
851f58f9 2145 UniValue outputs = params[1].get_array();
cc71666a 2146 for (size_t idx = 0; idx < outputs.size(); idx++) {
ed21d5bd
JG
2147 const UniValue& output = outputs[idx];
2148 if (!output.isObject())
15117692 2149 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected object");
d014114d 2150 const UniValue& o = output.get_obj();
fdbb537d 2151
ed21d5bd 2152 RPCTypeCheckObj(o, boost::assign::map_list_of("txid", UniValue::VSTR)("vout", UniValue::VNUM));
fdbb537d
JG
2153
2154 string txid = find_value(o, "txid").get_str();
2155 if (!IsHex(txid))
15117692 2156 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex txid");
fdbb537d
JG
2157
2158 int nOutput = find_value(o, "vout").get_int();
2159 if (nOutput < 0)
15117692 2160 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive");
fdbb537d 2161
34cdc411 2162 COutPoint outpt(uint256S(txid), nOutput);
fdbb537d
JG
2163
2164 if (fUnlock)
2165 pwalletMain->UnlockCoin(outpt);
2166 else
2167 pwalletMain->LockCoin(outpt);
2168 }
2169
2170 return true;
2171}
2172
d014114d 2173UniValue listlockunspent(const UniValue& params, bool fHelp)
fdbb537d 2174{
b9fb692d 2175 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 2176 return NullUniValue;
70454796 2177
fdbb537d
JG
2178 if (fHelp || params.size() > 0)
2179 throw runtime_error(
2180 "listlockunspent\n"
a6099ef3 2181 "\nReturns list of temporarily unspendable outputs.\n"
2182 "See the lockunspent call to lock and unlock transactions for spending.\n"
2183 "\nResult:\n"
2184 "[\n"
2185 " {\n"
2186 " \"txid\" : \"transactionid\", (string) The transaction id locked\n"
2187 " \"vout\" : n (numeric) The vout value\n"
2188 " }\n"
2189 " ,...\n"
2190 "]\n"
2191 "\nExamples:\n"
2192 "\nList the unspent transactions\n"
2193 + HelpExampleCli("listunspent", "") +
2194 "\nLock an unspent transaction\n"
2195 + HelpExampleCli("lockunspent", "false \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2196 "\nList the locked transactions\n"
2197 + HelpExampleCli("listlockunspent", "") +
2198 "\nUnlock the transaction again\n"
2199 + HelpExampleCli("lockunspent", "true \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2200 "\nAs a json rpc call\n"
2201 + HelpExampleRpc("listlockunspent", "")
2202 );
fdbb537d 2203
4401b2d7
EL
2204 LOCK2(cs_main, pwalletMain->cs_wallet);
2205
fdbb537d
JG
2206 vector<COutPoint> vOutpts;
2207 pwalletMain->ListLockedCoins(vOutpts);
2208
38fc4b70 2209 UniValue ret(UniValue::VARR);
fdbb537d
JG
2210
2211 BOOST_FOREACH(COutPoint &outpt, vOutpts) {
38fc4b70 2212 UniValue o(UniValue::VOBJ);
fdbb537d
JG
2213
2214 o.push_back(Pair("txid", outpt.hash.GetHex()));
2215 o.push_back(Pair("vout", (int)outpt.n));
2216 ret.push_back(o);
2217 }
2218
2219 return ret;
2220}
2221
d014114d 2222UniValue settxfee(const UniValue& params, bool fHelp)
a943bde6 2223{
b9fb692d 2224 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 2225 return NullUniValue;
70454796 2226
a943bde6
WL
2227 if (fHelp || params.size() < 1 || params.size() > 1)
2228 throw runtime_error(
2229 "settxfee amount\n"
6943cb9b 2230 "\nSet the transaction fee per kB.\n"
a943bde6 2231 "\nArguments:\n"
091b2116 2232 "1. amount (numeric, required) The transaction fee in " + CURRENCY_UNIT + "/kB rounded to the nearest 0.00000001\n"
a943bde6
WL
2233 "\nResult\n"
2234 "true|false (boolean) Returns true if successful\n"
2235 "\nExamples:\n"
2236 + HelpExampleCli("settxfee", "0.00001")
2237 + HelpExampleRpc("settxfee", "0.00001")
2238 );
2239
4401b2d7
EL
2240 LOCK2(cs_main, pwalletMain->cs_wallet);
2241
a943bde6 2242 // Amount
e76a3849 2243 CAmount nAmount = AmountFromValue(params[0]);
a943bde6 2244
c6cb21d1 2245 payTxFee = CFeeRate(nAmount, 1000);
a943bde6
WL
2246 return true;
2247}
2248
d014114d 2249UniValue getwalletinfo(const UniValue& params, bool fHelp)
a00ebb51 2250{
b9fb692d 2251 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 2252 return NullUniValue;
70454796 2253
a00ebb51
DN
2254 if (fHelp || params.size() != 0)
2255 throw runtime_error(
2256 "getwalletinfo\n"
2257 "Returns an object containing various wallet state info.\n"
2258 "\nResult:\n"
2259 "{\n"
2260 " \"walletversion\": xxxxx, (numeric) the wallet version\n"
091b2116
RN
2261 " \"balance\": xxxxxxx, (numeric) the total confirmed balance of the wallet in " + CURRENCY_UNIT + "\n"
2262 " \"unconfirmed_balance\": xxx, (numeric) the total unconfirmed balance of the wallet in " + CURRENCY_UNIT + "\n"
2263 " \"immature_balance\": xxxxxx, (numeric) the total immature balance of the wallet in " + CURRENCY_UNIT + "\n"
a00ebb51
DN
2264 " \"txcount\": xxxxxxx, (numeric) the total number of transactions in the wallet\n"
2265 " \"keypoololdest\": xxxxxx, (numeric) the timestamp (seconds since GMT epoch) of the oldest pre-generated key in the key pool\n"
2266 " \"keypoolsize\": xxxx, (numeric) how many new keys are pre-generated\n"
2267 " \"unlocked_until\": ttt, (numeric) the timestamp in seconds since epoch (midnight Jan 1 1970 GMT) that the wallet is unlocked for transfers, or 0 if the wallet is locked\n"
091b2116 2268 " \"paytxfee\": x.xxxx, (numeric) the transaction fee configuration, set in " + CURRENCY_UNIT + "/kB\n"
a00ebb51
DN
2269 "}\n"
2270 "\nExamples:\n"
2271 + HelpExampleCli("getwalletinfo", "")
2272 + HelpExampleRpc("getwalletinfo", "")
2273 );
2274
4401b2d7
EL
2275 LOCK2(cs_main, pwalletMain->cs_wallet);
2276
38fc4b70 2277 UniValue obj(UniValue::VOBJ);
a00ebb51
DN
2278 obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
2279 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
8024d67d
GM
2280 obj.push_back(Pair("unconfirmed_balance", ValueFromAmount(pwalletMain->GetUnconfirmedBalance())));
2281 obj.push_back(Pair("immature_balance", ValueFromAmount(pwalletMain->GetImmatureBalance())));
a00ebb51 2282 obj.push_back(Pair("txcount", (int)pwalletMain->mapWallet.size()));
d56e30ca 2283 obj.push_back(Pair("keypoololdest", pwalletMain->GetOldestKeyPoolTime()));
a00ebb51
DN
2284 obj.push_back(Pair("keypoolsize", (int)pwalletMain->GetKeyPoolSize()));
2285 if (pwalletMain->IsCrypted())
d56e30ca 2286 obj.push_back(Pair("unlocked_until", nWalletUnlockTime));
6699b425 2287 obj.push_back(Pair("paytxfee", ValueFromAmount(payTxFee.GetFeePerK())));
a00ebb51
DN
2288 return obj;
2289}
0f5954c4 2290
d014114d 2291UniValue resendwallettransactions(const UniValue& params, bool fHelp)
0f5954c4 2292{
b9fb692d 2293 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 2294 return NullUniValue;
70454796 2295
0f5954c4
GA
2296 if (fHelp || params.size() != 0)
2297 throw runtime_error(
2298 "resendwallettransactions\n"
2299 "Immediately re-broadcast unconfirmed wallet transactions to all peers.\n"
2300 "Intended only for testing; the wallet code periodically re-broadcasts\n"
2301 "automatically.\n"
2302 "Returns array of transaction ids that were re-broadcast.\n"
2303 );
2304
2305 LOCK2(cs_main, pwalletMain->cs_wallet);
2306
2307 std::vector<uint256> txids = pwalletMain->ResendWalletTransactionsBefore(GetTime());
38fc4b70 2308 UniValue result(UniValue::VARR);
0f5954c4
GA
2309 BOOST_FOREACH(const uint256& txid, txids)
2310 {
2311 result.push_back(txid.ToString());
2312 }
2313 return result;
2314}
0b9dc9c8 2315
d014114d 2316UniValue listunspent(const UniValue& params, bool fHelp)
0b9dc9c8
JS
2317{
2318 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 2319 return NullUniValue;
70454796 2320
0b9dc9c8 2321 if (fHelp || params.size() > 3)
ea9e82df
JS
2322 throw runtime_error(
2323 "listunspent ( minconf maxconf [\"address\",...] )\n"
2324 "\nReturns array of unspent transaction outputs\n"
2325 "with between minconf and maxconf (inclusive) confirmations.\n"
2326 "Optionally filter to only include txouts paid to specified addresses.\n"
2327 "Results are an array of Objects, each of which has:\n"
2328 "{txid, vout, scriptPubKey, amount, confirmations}\n"
2329 "\nArguments:\n"
2330 "1. minconf (numeric, optional, default=1) The minimum confirmations to filter\n"
2331 "2. maxconf (numeric, optional, default=9999999) The maximum confirmations to filter\n"
d2c1e4a8 2332 "3. \"addresses\" (string) A json array of Zcash addresses to filter\n"
ea9e82df 2333 " [\n"
d2c1e4a8 2334 " \"address\" (string) Zcash address\n"
ea9e82df
JS
2335 " ,...\n"
2336 " ]\n"
2337 "\nResult\n"
2338 "[ (array of json object)\n"
2339 " {\n"
2340 " \"txid\" : \"txid\", (string) the transaction id \n"
2341 " \"vout\" : n, (numeric) the vout value\n"
d77a0ac4 2342 " \"generated\" : true|false (boolean) true if txout is a coinbase transaction output\n"
58c4c0bb 2343 " \"address\" : \"address\", (string) the zcash address\n"
ea9e82df
JS
2344 " \"account\" : \"account\", (string) DEPRECATED. The associated account, or \"\" for the default account\n"
2345 " \"scriptPubKey\" : \"key\", (string) the script key\n"
091b2116 2346 " \"amount\" : x.xxx, (numeric) the transaction amount in " + CURRENCY_UNIT + "\n"
ea9e82df
JS
2347 " \"confirmations\" : n (numeric) The number of confirmations\n"
2348 " }\n"
2349 " ,...\n"
2350 "]\n"
2351
2352 "\nExamples\n"
2353 + HelpExampleCli("listunspent", "")
70454796
JG
2354 + HelpExampleCli("listunspent", "6 9999999 \"[\\\"t1PGFqEzfmQch1gKD3ra4k18PNj3tTUUSqg\\\",\\\"t1LtvqCaApEdUGFkpKMM4MstjcaL4dKg8SP\\\"]\"")
2355 + HelpExampleRpc("listunspent", "6, 9999999 \"[\\\"t1PGFqEzfmQch1gKD3ra4k18PNj3tTUUSqg\\\",\\\"t1LtvqCaApEdUGFkpKMM4MstjcaL4dKg8SP\\\"]\"")
ea9e82df
JS
2356 );
2357
9756b7bd 2358 RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM)(UniValue::VNUM)(UniValue::VARR));
ea9e82df 2359
0b9dc9c8
JS
2360 int nMinDepth = 1;
2361 if (params.size() > 0)
ea9e82df
JS
2362 nMinDepth = params[0].get_int();
2363
0b9dc9c8
JS
2364 int nMaxDepth = 9999999;
2365 if (params.size() > 1)
ea9e82df
JS
2366 nMaxDepth = params[1].get_int();
2367
0b9dc9c8
JS
2368 set<CBitcoinAddress> setAddress;
2369 if (params.size() > 2) {
851f58f9 2370 UniValue inputs = params[2].get_array();
cc71666a 2371 for (size_t idx = 0; idx < inputs.size(); idx++) {
d014114d 2372 const UniValue& input = inputs[idx];
0b9dc9c8
JS
2373 CBitcoinAddress address(input.get_str());
2374 if (!address.IsValid())
58c4c0bb 2375 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Zcash address: ")+input.get_str());
0b9dc9c8 2376 if (setAddress.count(address))
ea9e82df
JS
2377 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+input.get_str());
2378 setAddress.insert(address);
0b9dc9c8
JS
2379 }
2380 }
ea9e82df 2381
38fc4b70 2382 UniValue results(UniValue::VARR);
0b9dc9c8
JS
2383 vector<COutput> vecOutputs;
2384 assert(pwalletMain != NULL);
2385 LOCK2(cs_main, pwalletMain->cs_wallet);
219953ce 2386 pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
0b9dc9c8
JS
2387 BOOST_FOREACH(const COutput& out, vecOutputs) {
2388 if (out.nDepth < nMinDepth || out.nDepth > nMaxDepth)
ea9e82df
JS
2389 continue;
2390
0b9dc9c8
JS
2391 if (setAddress.size()) {
2392 CTxDestination address;
2393 if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
ea9e82df
JS
2394 continue;
2395
0b9dc9c8 2396 if (!setAddress.count(address))
ea9e82df 2397 continue;
0b9dc9c8 2398 }
ea9e82df 2399
0b9dc9c8
JS
2400 CAmount nValue = out.tx->vout[out.i].nValue;
2401 const CScript& pk = out.tx->vout[out.i].scriptPubKey;
38fc4b70 2402 UniValue entry(UniValue::VOBJ);
805344dc 2403 entry.push_back(Pair("txid", out.tx->GetHash().GetHex()));
0b9dc9c8 2404 entry.push_back(Pair("vout", out.i));
d77a0ac4 2405 entry.push_back(Pair("generated", out.tx->IsCoinBase()));
0b9dc9c8
JS
2406 CTxDestination address;
2407 if (ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) {
2408 entry.push_back(Pair("address", CBitcoinAddress(address).ToString()));
2409 if (pwalletMain->mapAddressBook.count(address))
ea9e82df 2410 entry.push_back(Pair("account", pwalletMain->mapAddressBook[address].name));
0b9dc9c8
JS
2411 }
2412 entry.push_back(Pair("scriptPubKey", HexStr(pk.begin(), pk.end())));
2413 if (pk.IsPayToScriptHash()) {
2414 CTxDestination address;
2415 if (ExtractDestination(pk, address)) {
8b08d953 2416 const CScriptID& hash = boost::get<CScriptID>(address);
0b9dc9c8
JS
2417 CScript redeemScript;
2418 if (pwalletMain->GetCScript(hash, redeemScript))
ea9e82df 2419 entry.push_back(Pair("redeemScript", HexStr(redeemScript.begin(), redeemScript.end())));
0b9dc9c8
JS
2420 }
2421 }
2422 entry.push_back(Pair("amount",ValueFromAmount(nValue)));
2423 entry.push_back(Pair("confirmations",out.nDepth));
2424 entry.push_back(Pair("spendable", out.fSpendable));
2425 results.push_back(entry);
2426 }
ea9e82df 2427
0b9dc9c8 2428 return results;
c9fd9078 2429}
730790f7 2430
3d8013a0
MC
2431UniValue fundrawtransaction(const UniValue& params, bool fHelp)
2432{
2433 if (!EnsureWalletIsAvailable(fHelp))
2434 return NullUniValue;
2435
2436 if (fHelp || params.size() != 1)
2437 throw runtime_error(
2438 "fundrawtransaction \"hexstring\"\n"
2439 "\nAdd inputs to a transaction until it has enough in value to meet its out value.\n"
2440 "This will not modify existing inputs, and will add one change output to the outputs.\n"
2441 "Note that inputs which were signed may need to be resigned after completion since in/outputs have been added.\n"
2442 "The inputs added will not be signed, use signrawtransaction for that.\n"
2443 "\nArguments:\n"
2444 "1. \"hexstring\" (string, required) The hex string of the raw transaction\n"
2445 "\nResult:\n"
2446 "{\n"
2447 " \"hex\": \"value\", (string) The resulting raw transaction (hex-encoded string)\n"
2448 " \"fee\": n, (numeric) The fee added to the transaction\n"
2449 " \"changepos\": n (numeric) The position of the added change output, or -1\n"
2450 "}\n"
2451 "\"hex\" \n"
2452 "\nExamples:\n"
2453 "\nCreate a transaction with no inputs\n"
2454 + HelpExampleCli("createrawtransaction", "\"[]\" \"{\\\"myaddress\\\":0.01}\"") +
2455 "\nAdd sufficient unsigned inputs to meet the output value\n"
2456 + HelpExampleCli("fundrawtransaction", "\"rawtransactionhex\"") +
2457 "\nSign the transaction\n"
2458 + HelpExampleCli("signrawtransaction", "\"fundedtransactionhex\"") +
2459 "\nSend the transaction\n"
2460 + HelpExampleCli("sendrawtransaction", "\"signedtransactionhex\"")
2461 );
2462
2463 RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR));
2464
2465 // parse hex string from parameter
2466 CTransaction origTx;
2467 if (!DecodeHexTx(origTx, params[0].get_str()))
2468 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
2469
2470 CMutableTransaction tx(origTx);
2471 CAmount nFee;
2472 string strFailReason;
2473 int nChangePos = -1;
2474 if(!pwalletMain->FundTransaction(tx, nFee, nChangePos, strFailReason))
2475 throw JSONRPCError(RPC_INTERNAL_ERROR, strFailReason);
2476
2477 UniValue result(UniValue::VOBJ);
2478 result.push_back(Pair("hex", EncodeHexTx(tx)));
2479 result.push_back(Pair("changepos", nChangePos));
2480 result.push_back(Pair("fee", ValueFromAmount(nFee)));
2481
2482 return result;
2483}
2484
0d37ae3a 2485UniValue zc_sample_joinsplit(const UniValue& params, bool fHelp)
1737627c
SB
2486{
2487 if (fHelp) {
2488 throw runtime_error(
2489 "zcsamplejoinsplit\n"
2490 "\n"
2491 "Perform a joinsplit and return the JSDescription.\n"
2492 );
2493 }
2494
2495 LOCK(cs_main);
2496
2497 uint256 pubKeyHash;
2498 uint256 anchor = ZCIncrementalMerkleTree().root();
2499 JSDescription samplejoinsplit(*pzcashParams,
2500 pubKeyHash,
2501 anchor,
2502 {JSInput(), JSInput()},
2503 {JSOutput(), JSOutput()},
2504 0,
2505 0);
2506
2507 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
2508 ss << samplejoinsplit;
2509
2510 return HexStr(ss.begin(), ss.end());
2511}
2512
0d37ae3a 2513UniValue zc_benchmark(const UniValue& params, bool fHelp)
6962bb3d
TH
2514{
2515 if (!EnsureWalletIsAvailable(fHelp)) {
0d37ae3a 2516 return NullUniValue;
6962bb3d
TH
2517 }
2518
2519 if (fHelp || params.size() < 2) {
2520 throw runtime_error(
2521 "zcbenchmark benchmarktype samplecount\n"
2522 "\n"
2523 "Runs a benchmark of the selected type samplecount times,\n"
2524 "returning the running times of each sample.\n"
2525 "\n"
2526 "Output: [\n"
2527 " {\n"
2528 " \"runningtime\": runningtime\n"
2529 " },\n"
2530 " {\n"
2531 " \"runningtime\": runningtime\n"
2532 " }\n"
2533 " ...\n"
2534 "]\n"
2535 );
2536 }
2537
2538 LOCK(cs_main);
2539
2540 std::string benchmarktype = params[0].get_str();
2541 int samplecount = params[1].get_int();
2542
2543 if (samplecount <= 0) {
2544 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid samplecount");
2545 }
2546
2547 std::vector<double> sample_times;
2548
1737627c 2549 JSDescription samplejoinsplit;
2fbbde59
SB
2550
2551 if (benchmarktype == "verifyjoinsplit") {
1737627c
SB
2552 CDataStream ss(ParseHexV(params[2].get_str(), "js"), SER_NETWORK, PROTOCOL_VERSION);
2553 ss >> samplejoinsplit;
2fbbde59
SB
2554 }
2555
6962bb3d
TH
2556 for (int i = 0; i < samplecount; i++) {
2557 if (benchmarktype == "sleep") {
2558 sample_times.push_back(benchmark_sleep());
2559 } else if (benchmarktype == "parameterloading") {
2560 sample_times.push_back(benchmark_parameter_loading());
2561 } else if (benchmarktype == "createjoinsplit") {
4082dcb1
JG
2562 if (params.size() < 3) {
2563 sample_times.push_back(benchmark_create_joinsplit());
2564 } else {
2565 int nThreads = params[2].get_int();
2566 std::vector<double> vals = benchmark_create_joinsplit_threaded(nThreads);
2567 // Divide by nThreads^2 to get average seconds per JoinSplit because
2568 // we are running one JoinSplit per thread.
2569 sample_times.push_back(std::accumulate(vals.begin(), vals.end(), 0.0) / (nThreads*nThreads));
2570 }
6962bb3d 2571 } else if (benchmarktype == "verifyjoinsplit") {
1737627c 2572 sample_times.push_back(benchmark_verify_joinsplit(samplejoinsplit));
2cc0a252 2573#ifdef ENABLE_MINING
bf8def97 2574 } else if (benchmarktype == "solveequihash") {
f7478de6 2575 if (params.size() < 3) {
9e52ca32 2576 sample_times.push_back(benchmark_solve_equihash());
f7478de6
JG
2577 } else {
2578 int nThreads = params[2].get_int();
9e52ca32
JG
2579 std::vector<double> vals = benchmark_solve_equihash_threaded(nThreads);
2580 sample_times.insert(sample_times.end(), vals.begin(), vals.end());
f7478de6 2581 }
2cc0a252 2582#endif
bf8def97 2583 } else if (benchmarktype == "verifyequihash") {
a1cd1a27 2584 sample_times.push_back(benchmark_verify_equihash());
f5edc37f 2585 } else if (benchmarktype == "validatelargetx") {
818b94f9
JG
2586 // Number of inputs in the spending transaction that we will simulate
2587 int nInputs = 555;
2588 if (params.size() >= 3) {
2589 nInputs = params[2].get_int();
2590 }
2591 sample_times.push_back(benchmark_large_tx(nInputs));
0fbab55b 2592 } else if (benchmarktype == "trydecryptnotes") {
88b7f3c2
JG
2593 int nAddrs = params[2].get_int();
2594 sample_times.push_back(benchmark_try_decrypt_notes(nAddrs));
0bb3d40f
JG
2595 } else if (benchmarktype == "incnotewitnesses") {
2596 int nTxs = params[2].get_int();
2597 sample_times.push_back(benchmark_increment_note_witnesses(nTxs));
c66c731a
JG
2598 } else if (benchmarktype == "connectblockslow") {
2599 if (Params().NetworkIDString() != "regtest") {
2600 throw JSONRPCError(RPC_TYPE_ERROR, "Benchmark must be run in regtest mode");
2601 }
2602 sample_times.push_back(benchmark_connectblock_slow());
a76174b7
JG
2603 } else if (benchmarktype == "sendtoaddress") {
2604 if (Params().NetworkIDString() != "regtest") {
2605 throw JSONRPCError(RPC_TYPE_ERROR, "Benchmark must be run in regtest mode");
2606 }
2607 auto amount = AmountFromValue(params[2]);
2608 sample_times.push_back(benchmark_sendtoaddress(amount));
2e8aefdc
AG
2609 } else if (benchmarktype == "loadwallet") {
2610 if (Params().NetworkIDString() != "regtest") {
2611 throw JSONRPCError(RPC_TYPE_ERROR, "Benchmark must be run in regtest mode");
2612 }
2613 sample_times.push_back(benchmark_loadwallet());
99dd50c3
JG
2614 } else if (benchmarktype == "listunspent") {
2615 sample_times.push_back(benchmark_listunspent());
6962bb3d
TH
2616 } else {
2617 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid benchmarktype");
2618 }
2619 }
2620
0d37ae3a 2621 UniValue results(UniValue::VARR);
9e52ca32 2622 for (auto time : sample_times) {
0d37ae3a 2623 UniValue result(UniValue::VOBJ);
9e52ca32 2624 result.push_back(Pair("runningtime", time));
6962bb3d
TH
2625 results.push_back(result);
2626 }
2627
2628 return results;
2629}
2630
0d37ae3a 2631UniValue zc_raw_receive(const UniValue& params, bool fHelp)
a8ac403d 2632{
f15b9549 2633 if (!EnsureWalletIsAvailable(fHelp)) {
0d37ae3a 2634 return NullUniValue;
f15b9549
NW
2635 }
2636
2637 if (fHelp || params.size() != 2) {
2638 throw runtime_error(
eae37941 2639 "zcrawreceive zcsecretkey encryptednote\n"
f15b9549 2640 "\n"
ca0ec80b 2641 "DEPRECATED. Decrypts encryptednote and checks if the coin commitments\n"
f15b9549
NW
2642 "are in the blockchain as indicated by the \"exists\" result.\n"
2643 "\n"
2644 "Output: {\n"
2645 " \"amount\": value,\n"
4bc00dc1 2646 " \"note\": noteplaintext,\n"
f15b9549
NW
2647 " \"exists\": exists\n"
2648 "}\n"
2649 );
2650 }
2651
0d37ae3a 2652 RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR)(UniValue::VSTR));
f15b9549 2653
a8ac403d
SB
2654 LOCK(cs_main);
2655
0d6864e4
SB
2656 CZCSpendingKey spendingkey(params[0].get_str());
2657 SpendingKey k = spendingkey.Get();
a8ac403d 2658
6c36a9fe
SB
2659 uint256 epk;
2660 unsigned char nonce;
2661 ZCNoteEncryption::Ciphertext ct;
2dc35992 2662 uint256 h_sig;
6c36a9fe
SB
2663
2664 {
4bc00dc1 2665 CDataStream ssData(ParseHexV(params[1], "encrypted_note"), SER_NETWORK, PROTOCOL_VERSION);
6c36a9fe
SB
2666 try {
2667 ssData >> nonce;
2668 ssData >> epk;
2669 ssData >> ct;
2dc35992 2670 ssData >> h_sig;
6c36a9fe
SB
2671 } catch(const std::exception &) {
2672 throw runtime_error(
4bc00dc1 2673 "encrypted_note could not be decoded"
6c36a9fe
SB
2674 );
2675 }
2676 }
2677
642a1caf 2678 ZCNoteDecryption decryptor(k.receiving_key());
a8ac403d 2679
2dc35992
SB
2680 NotePlaintext npt = NotePlaintext::decrypt(
2681 decryptor,
2682 ct,
2683 epk,
2684 h_sig,
2685 nonce
2686 );
2687 PaymentAddress payment_addr = k.address();
2688 Note decrypted_note = npt.note(payment_addr);
a8ac403d
SB
2689
2690 assert(pwalletMain != NULL);
2dc35992 2691 std::vector<boost::optional<ZCIncrementalWitness>> witnesses;
a8ac403d 2692 uint256 anchor;
2dc35992 2693 uint256 commitment = decrypted_note.cm();
4bc00dc1 2694 pwalletMain->WitnessNoteCommitment(
2dc35992
SB
2695 {commitment},
2696 witnesses,
2697 anchor
2698 );
a8ac403d
SB
2699
2700 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
2dc35992 2701 ss << npt;
a8ac403d 2702
0d37ae3a 2703 UniValue result(UniValue::VOBJ);
2dc35992 2704 result.push_back(Pair("amount", ValueFromAmount(decrypted_note.value)));
4bc00dc1 2705 result.push_back(Pair("note", HexStr(ss.begin(), ss.end())));
2dc35992 2706 result.push_back(Pair("exists", (bool) witnesses[0]));
a8ac403d
SB
2707 return result;
2708}
2709
2dc35992
SB
2710
2711
0d37ae3a 2712UniValue zc_raw_joinsplit(const UniValue& params, bool fHelp)
730790f7 2713{
f15b9549 2714 if (!EnsureWalletIsAvailable(fHelp)) {
0d37ae3a 2715 return NullUniValue;
f15b9549
NW
2716 }
2717
2718 if (fHelp || params.size() != 5) {
2719 throw runtime_error(
eae37941 2720 "zcrawjoinsplit rawtx inputs outputs vpub_old vpub_new\n"
4bc00dc1 2721 " inputs: a JSON object mapping {note: zcsecretkey, ...}\n"
f15b9549
NW
2722 " outputs: a JSON object mapping {zcaddr: value, ...}\n"
2723 "\n"
ca0ec80b 2724 "DEPRECATED. Splices a joinsplit into rawtx. Inputs are unilaterally confidential.\n"
f15b9549
NW
2725 "Outputs are confidential between sender/receiver. The vpub_old and\n"
2726 "vpub_new values are globally public and move transparent value into\n"
2727 "or out of the confidential value store, respectively.\n"
2728 "\n"
2729 "Note: The caller is responsible for delivering the output enc1 and\n"
2730 "enc2 to the appropriate recipients, as well as signing rawtxout and\n"
2731 "ensuring it is mined. (A future RPC call will deliver the confidential\n"
2732 "payments in-band on the blockchain.)\n"
2733 "\n"
2734 "Output: {\n"
4bc00dc1
DH
2735 " \"encryptednote1\": enc1,\n"
2736 " \"encryptednote2\": enc2,\n"
f15b9549
NW
2737 " \"rawtxn\": rawtxout\n"
2738 "}\n"
2739 );
2740 }
2741
a8ac403d 2742 LOCK(cs_main);
730790f7
SB
2743
2744 CTransaction tx;
2745 if (!DecodeHexTx(tx, params[0].get_str()))
2746 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
2747
0d37ae3a
JG
2748 UniValue inputs = params[1].get_obj();
2749 UniValue outputs = params[2].get_obj();
730790f7
SB
2750
2751 CAmount vpub_old(0);
2752 CAmount vpub_new(0);
2753
2754 if (params[3].get_real() != 0.0)
2755 vpub_old = AmountFromValue(params[3]);
2756
2757 if (params[4].get_real() != 0.0)
2758 vpub_new = AmountFromValue(params[4]);
2759
b7e4abd6
SB
2760 std::vector<JSInput> vjsin;
2761 std::vector<JSOutput> vjsout;
2dc35992
SB
2762 std::vector<Note> notes;
2763 std::vector<SpendingKey> keys;
2764 std::vector<uint256> commitments;
a8ac403d 2765
0d37ae3a
JG
2766 for (const string& name_ : inputs.getKeys()) {
2767 CZCSpendingKey spendingkey(inputs[name_].get_str());
0d6864e4 2768 SpendingKey k = spendingkey.Get();
a8ac403d 2769
2dc35992 2770 keys.push_back(k);
a8ac403d 2771
2dc35992 2772 NotePlaintext npt;
a8ac403d 2773
2dc35992 2774 {
0d37ae3a 2775 CDataStream ssData(ParseHexV(name_, "note"), SER_NETWORK, PROTOCOL_VERSION);
2dc35992 2776 ssData >> npt;
a8ac403d
SB
2777 }
2778
2dc35992
SB
2779 PaymentAddress addr = k.address();
2780 Note note = npt.note(addr);
2781 notes.push_back(note);
2782 commitments.push_back(note.cm());
2783 }
2784
2785 uint256 anchor;
2786 std::vector<boost::optional<ZCIncrementalWitness>> witnesses;
4bc00dc1 2787 pwalletMain->WitnessNoteCommitment(commitments, witnesses, anchor);
2dc35992
SB
2788
2789 assert(witnesses.size() == notes.size());
2790 assert(notes.size() == keys.size());
2791
2792 {
2793 for (size_t i = 0; i < witnesses.size(); i++) {
2794 if (!witnesses[i]) {
2795 throw runtime_error(
b7e4abd6 2796 "joinsplit input could not be found in tree"
2dc35992
SB
2797 );
2798 }
2799
b7e4abd6 2800 vjsin.push_back(JSInput(*witnesses[i], notes[i], keys[i]));
2dc35992 2801 }
730790f7 2802 }
730790f7 2803
b7e4abd6
SB
2804 while (vjsin.size() < ZC_NUM_JS_INPUTS) {
2805 vjsin.push_back(JSInput());
a8ac403d 2806 }
730790f7 2807
0d37ae3a
JG
2808 for (const string& name_ : outputs.getKeys()) {
2809 CZCPaymentAddress pubaddr(name_);
e104fcdd 2810 PaymentAddress addrTo = pubaddr.Get();
0d37ae3a 2811 CAmount nAmount = AmountFromValue(outputs[name_]);
730790f7 2812
b7e4abd6 2813 vjsout.push_back(JSOutput(addrTo, nAmount));
730790f7
SB
2814 }
2815
b7e4abd6
SB
2816 while (vjsout.size() < ZC_NUM_JS_OUTPUTS) {
2817 vjsout.push_back(JSOutput());
730790f7
SB
2818 }
2819
2820 // TODO
b7e4abd6
SB
2821 if (vjsout.size() != ZC_NUM_JS_INPUTS || vjsin.size() != ZC_NUM_JS_OUTPUTS) {
2822 throw runtime_error("unsupported joinsplit input/output counts");
730790f7
SB
2823 }
2824
320f2cc7
SB
2825 uint256 joinSplitPubKey;
2826 unsigned char joinSplitPrivKey[crypto_sign_SECRETKEYBYTES];
2827 crypto_sign_keypair(joinSplitPubKey.begin(), joinSplitPrivKey);
6aae9d1a
TH
2828
2829 CMutableTransaction mtx(tx);
2830 mtx.nVersion = 2;
2831 mtx.joinSplitPubKey = joinSplitPubKey;
2832
22de1602
SB
2833 JSDescription jsdesc(*pzcashParams,
2834 joinSplitPubKey,
2835 anchor,
2836 {vjsin[0], vjsin[1]},
2837 {vjsout[0], vjsout[1]},
2838 vpub_old,
2839 vpub_new);
320f2cc7 2840
bc59f537
SB
2841 {
2842 auto verifier = libzcash::ProofVerifier::Strict();
2843 assert(jsdesc.Verify(*pzcashParams, verifier, joinSplitPubKey));
2844 }
730790f7 2845
22de1602 2846 mtx.vjoinsplit.push_back(jsdesc);
730790f7 2847
6aae9d1a
TH
2848 // Empty output script.
2849 CScript scriptCode;
2850 CTransaction signTx(mtx);
be126699
JG
2851 auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus());
2852 uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId);
6aae9d1a
TH
2853
2854 // Add the signature
320f2cc7
SB
2855 assert(crypto_sign_detached(&mtx.joinSplitSig[0], NULL,
2856 dataToBeSigned.begin(), 32,
2857 joinSplitPrivKey
2858 ) == 0);
2859
2860 // Sanity check
2861 assert(crypto_sign_verify_detached(&mtx.joinSplitSig[0],
2862 dataToBeSigned.begin(), 32,
2863 mtx.joinSplitPubKey.begin()
2864 ) == 0);
6aae9d1a 2865
730790f7
SB
2866 CTransaction rawTx(mtx);
2867
2868 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
2869 ss << rawTx;
2870
4bc00dc1
DH
2871 std::string encryptedNote1;
2872 std::string encryptedNote2;
6c36a9fe
SB
2873 {
2874 CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION);
2875 ss2 << ((unsigned char) 0x00);
22de1602
SB
2876 ss2 << jsdesc.ephemeralKey;
2877 ss2 << jsdesc.ciphertexts[0];
2878 ss2 << jsdesc.h_sig(*pzcashParams, joinSplitPubKey);
6c36a9fe 2879
4bc00dc1 2880 encryptedNote1 = HexStr(ss2.begin(), ss2.end());
6c36a9fe
SB
2881 }
2882 {
2883 CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION);
2884 ss2 << ((unsigned char) 0x01);
22de1602
SB
2885 ss2 << jsdesc.ephemeralKey;
2886 ss2 << jsdesc.ciphertexts[1];
2887 ss2 << jsdesc.h_sig(*pzcashParams, joinSplitPubKey);
6c36a9fe 2888
4bc00dc1 2889 encryptedNote2 = HexStr(ss2.begin(), ss2.end());
6c36a9fe
SB
2890 }
2891
0d37ae3a 2892 UniValue result(UniValue::VOBJ);
4bc00dc1
DH
2893 result.push_back(Pair("encryptednote1", encryptedNote1));
2894 result.push_back(Pair("encryptednote2", encryptedNote2));
730790f7
SB
2895 result.push_back(Pair("rawtxn", HexStr(ss.begin(), ss.end())));
2896 return result;
2897}
2898
0d37ae3a 2899UniValue zc_raw_keygen(const UniValue& params, bool fHelp)
730790f7 2900{
f15b9549 2901 if (!EnsureWalletIsAvailable(fHelp)) {
0d37ae3a 2902 return NullUniValue;
f15b9549
NW
2903 }
2904
2905 if (fHelp || params.size() != 0) {
2906 throw runtime_error(
eae37941 2907 "zcrawkeygen\n"
f15b9549 2908 "\n"
ca0ec80b 2909 "DEPRECATED. Generate a zcaddr which can send and receive confidential values.\n"
f15b9549
NW
2910 "\n"
2911 "Output: {\n"
2912 " \"zcaddress\": zcaddr,\n"
2913 " \"zcsecretkey\": zcsecretkey,\n"
7b8d4f87 2914 " \"zcviewingkey\": zcviewingkey,\n"
f15b9549
NW
2915 "}\n"
2916 );
2917 }
2918
2dc35992
SB
2919 auto k = SpendingKey::random();
2920 auto addr = k.address();
2921 auto viewing_key = k.viewing_key();
730790f7 2922
e104fcdd 2923 CZCPaymentAddress pubaddr(addr);
0d6864e4 2924 CZCSpendingKey spendingkey(k);
7b8d4f87 2925 CZCViewingKey viewingkey(viewing_key);
730790f7 2926
0d37ae3a 2927 UniValue result(UniValue::VOBJ);
e104fcdd 2928 result.push_back(Pair("zcaddress", pubaddr.ToString()));
0d6864e4 2929 result.push_back(Pair("zcsecretkey", spendingkey.ToString()));
7b8d4f87 2930 result.push_back(Pair("zcviewingkey", viewingkey.ToString()));
730790f7 2931 return result;
f15b9549 2932}
c1c45943
S
2933
2934
0d37ae3a 2935UniValue z_getnewaddress(const UniValue& params, bool fHelp)
c1c45943
S
2936{
2937 if (!EnsureWalletIsAvailable(fHelp))
0d37ae3a 2938 return NullUniValue;
c1c45943 2939
49e591eb 2940 if (fHelp || params.size() > 0)
c1c45943
S
2941 throw runtime_error(
2942 "z_getnewaddress\n"
2943 "\nReturns a new zaddr for receiving payments.\n"
2944 "\nArguments:\n"
2945 "\nResult:\n"
2946 "\"zcashaddress\" (string) The new zaddr\n"
2947 "\nExamples:\n"
2948 + HelpExampleCli("z_getnewaddress", "")
2949 + HelpExampleRpc("z_getnewaddress", "")
2950 );
2951
2952 LOCK2(cs_main, pwalletMain->cs_wallet);
2953
73699cea
S
2954 EnsureWalletIsUnlocked();
2955
c1c45943
S
2956 CZCPaymentAddress pubaddr = pwalletMain->GenerateNewZKey();
2957 std::string result = pubaddr.ToString();
2958 return result;
2959}
2960
e709997f 2961
0d37ae3a 2962UniValue z_listaddresses(const UniValue& params, bool fHelp)
e709997f
S
2963{
2964 if (!EnsureWalletIsAvailable(fHelp))
0d37ae3a 2965 return NullUniValue;
e709997f
S
2966
2967 if (fHelp || params.size() > 1)
2968 throw runtime_error(
44e37656 2969 "z_listaddresses ( includeWatchonly )\n"
e709997f
S
2970 "\nReturns the list of zaddr belonging to the wallet.\n"
2971 "\nArguments:\n"
44e37656 2972 "1. includeWatchonly (bool, optional, default=false) Also include watchonly addresses (see 'z_importviewingkey')\n"
e709997f
S
2973 "\nResult:\n"
2974 "[ (json array of string)\n"
2975 " \"zaddr\" (string) a zaddr belonging to the wallet\n"
2976 " ,...\n"
2977 "]\n"
2978 "\nExamples:\n"
2979 + HelpExampleCli("z_listaddresses", "")
2980 + HelpExampleRpc("z_listaddresses", "")
2981 );
2982
2983 LOCK2(cs_main, pwalletMain->cs_wallet);
2984
44e37656
JG
2985 bool fIncludeWatchonly = false;
2986 if (params.size() > 0) {
2987 fIncludeWatchonly = params[0].get_bool();
2988 }
2989
0d37ae3a 2990 UniValue ret(UniValue::VARR);
e709997f
S
2991 std::set<libzcash::PaymentAddress> addresses;
2992 pwalletMain->GetPaymentAddresses(addresses);
2993 for (auto addr : addresses ) {
44e37656
JG
2994 if (fIncludeWatchonly || pwalletMain->HaveSpendingKey(addr)) {
2995 ret.push_back(CZCPaymentAddress(addr).ToString());
2996 }
e709997f
S
2997 }
2998 return ret;
2999}
3000
44e37656 3001CAmount getBalanceTaddr(std::string transparentAddress, int minDepth=1, bool ignoreUnspendable=true) {
a0a3334c
S
3002 set<CBitcoinAddress> setAddress;
3003 vector<COutput> vecOutputs;
70454796
JG
3004 CAmount balance = 0;
3005
a0a3334c
S
3006 if (transparentAddress.length() > 0) {
3007 CBitcoinAddress taddr = CBitcoinAddress(transparentAddress);
3008 if (!taddr.IsValid()) {
3009 throw std::runtime_error("invalid transparent address");
3010 }
3011 setAddress.insert(taddr);
3012 }
70454796 3013
a0a3334c
S
3014 LOCK2(cs_main, pwalletMain->cs_wallet);
3015
3016 pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
3017
3018 BOOST_FOREACH(const COutput& out, vecOutputs) {
3019 if (out.nDepth < minDepth) {
3020 continue;
3021 }
3022
44e37656
JG
3023 if (ignoreUnspendable && !out.fSpendable) {
3024 continue;
3025 }
3026
a0a3334c
S
3027 if (setAddress.size()) {
3028 CTxDestination address;
3029 if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) {
3030 continue;
3031 }
3032
3033 if (!setAddress.count(address)) {
3034 continue;
3035 }
3036 }
70454796 3037
a0a3334c
S
3038 CAmount nValue = out.tx->vout[out.i].nValue;
3039 balance += nValue;
3040 }
3041 return balance;
3042}
3043
44e37656 3044CAmount getBalanceZaddr(std::string address, int minDepth = 1, bool ignoreUnspendable=true) {
a0a3334c 3045 CAmount balance = 0;
a9743bc8 3046 std::vector<CNotePlaintextEntry> entries;
a0a3334c 3047 LOCK2(cs_main, pwalletMain->cs_wallet);
44e37656 3048 pwalletMain->GetFilteredNotes(entries, address, minDepth, true, ignoreUnspendable);
a9743bc8
S
3049 for (auto & entry : entries) {
3050 balance += CAmount(entry.plaintext.value);
a0a3334c 3051 }
a0a3334c
S
3052 return balance;
3053}
3054
3055
0d37ae3a 3056UniValue z_listreceivedbyaddress(const UniValue& params, bool fHelp)
6c41028f
S
3057{
3058 if (!EnsureWalletIsAvailable(fHelp))
0d37ae3a 3059 return NullUniValue;
6c41028f
S
3060
3061 if (fHelp || params.size()==0 || params.size() >2)
3062 throw runtime_error(
3063 "z_listreceivedbyaddress \"address\" ( minconf )\n"
3064 "\nReturn a list of amounts received by a zaddr belonging to the node’s wallet.\n"
3065 "\nArguments:\n"
3066 "1. \"address\" (string) The private address.\n"
3067 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
3068 "\nResult:\n"
3069 "{\n"
3070 " \"txid\": xxxxx, (string) the transaction id\n"
3071 " \"amount\": xxxxx, (numeric) the amount of value in the note\n"
3072 " \"memo\": xxxxx, (string) hexademical string representation of memo field\n"
3073 "}\n"
337a99a2
JG
3074 "\nExamples:\n"
3075 + HelpExampleCli("z_listreceivedbyaddress", "\"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\"")
3076 + HelpExampleRpc("z_listreceivedbyaddress", "\"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\"")
6c41028f
S
3077 );
3078
3079 LOCK2(cs_main, pwalletMain->cs_wallet);
3080
3081 int nMinDepth = 1;
3082 if (params.size() > 1) {
3083 nMinDepth = params[1].get_int();
3084 }
3085 if (nMinDepth < 0) {
3086 throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
3087 }
70454796 3088
6c41028f
S
3089 // Check that the from address is valid.
3090 auto fromaddress = params[0].get_str();
3091
3092 libzcash::PaymentAddress zaddr;
3093 CZCPaymentAddress address(fromaddress);
3094 try {
3095 zaddr = address.Get();
fce72608 3096 } catch (const std::runtime_error&) {
6c41028f
S
3097 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid zaddr.");
3098 }
3099
44e37656
JG
3100 if (!(pwalletMain->HaveSpendingKey(zaddr) || pwalletMain->HaveViewingKey(zaddr))) {
3101 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key or viewing key not found.");
6c41028f 3102 }
70454796
JG
3103
3104
0d37ae3a 3105 UniValue result(UniValue::VARR);
6c41028f 3106 std::vector<CNotePlaintextEntry> entries;
44e37656 3107 pwalletMain->GetFilteredNotes(entries, fromaddress, nMinDepth, false, false);
6c41028f 3108 for (CNotePlaintextEntry & entry : entries) {
0d37ae3a 3109 UniValue obj(UniValue::VOBJ);
6c41028f
S
3110 obj.push_back(Pair("txid",entry.jsop.hash.ToString()));
3111 obj.push_back(Pair("amount", ValueFromAmount(CAmount(entry.plaintext.value))));
3112 std::string data(entry.plaintext.memo.begin(), entry.plaintext.memo.end());
3113 obj.push_back(Pair("memo", HexStr(data)));
3114 result.push_back(obj);
3115 }
3116 return result;
3117}
3118
3119
0d37ae3a 3120UniValue z_getbalance(const UniValue& params, bool fHelp)
a0a3334c
S
3121{
3122 if (!EnsureWalletIsAvailable(fHelp))
0d37ae3a 3123 return NullUniValue;
a0a3334c
S
3124
3125 if (fHelp || params.size()==0 || params.size() >2)
3126 throw runtime_error(
3127 "z_getbalance \"address\" ( minconf )\n"
3128 "\nReturns the balance of a taddr or zaddr belonging to the node’s wallet.\n"
2bbfe6c4
JG
3129 "\nCAUTION: If address is a watch-only zaddr, the returned balance may be larger than the actual balance,"
3130 "\nbecause spends cannot be detected with incoming viewing keys.\n"
a0a3334c
S
3131 "\nArguments:\n"
3132 "1. \"address\" (string) The selected address. It may be a transparent or private address.\n"
3133 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
3134 "\nResult:\n"
6dec2d03 3135 "amount (numeric) The total amount in " + CURRENCY_UNIT + " received for this address.\n"
a0a3334c
S
3136 "\nExamples:\n"
3137 "\nThe total amount received by address \"myaddress\"\n"
3138 + HelpExampleCli("z_getbalance", "\"myaddress\"") +
3139 "\nThe total amount received by address \"myaddress\" at least 5 blocks confirmed\n"
3140 + HelpExampleCli("z_getbalance", "\"myaddress\" 5") +
3141 "\nAs a json rpc call\n"
3142 + HelpExampleRpc("z_getbalance", "\"myaddress\", 5")
3143 );
3144
3145 LOCK2(cs_main, pwalletMain->cs_wallet);
3146
3147 int nMinDepth = 1;
3148 if (params.size() > 1) {
3149 nMinDepth = params[1].get_int();
3150 }
12448b64
S
3151 if (nMinDepth < 0) {
3152 throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
3153 }
70454796 3154
a0a3334c
S
3155 // Check that the from address is valid.
3156 auto fromaddress = params[0].get_str();
3157 bool fromTaddr = false;
3158 CBitcoinAddress taddr(fromaddress);
3159 fromTaddr = taddr.IsValid();
3160 libzcash::PaymentAddress zaddr;
3161 if (!fromTaddr) {
3162 CZCPaymentAddress address(fromaddress);
3163 try {
3164 zaddr = address.Get();
fce72608 3165 } catch (const std::runtime_error&) {
a0a3334c
S
3166 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or zaddr.");
3167 }
44e37656
JG
3168 if (!(pwalletMain->HaveSpendingKey(zaddr) || pwalletMain->HaveViewingKey(zaddr))) {
3169 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key or viewing key not found.");
12448b64 3170 }
a0a3334c
S
3171 }
3172
3173 CAmount nBalance = 0;
3174 if (fromTaddr) {
44e37656 3175 nBalance = getBalanceTaddr(fromaddress, nMinDepth, false);
a0a3334c 3176 } else {
44e37656 3177 nBalance = getBalanceZaddr(fromaddress, nMinDepth, false);
a0a3334c
S
3178 }
3179
3180 return ValueFromAmount(nBalance);
3181}
3182
3183
0d37ae3a 3184UniValue z_gettotalbalance(const UniValue& params, bool fHelp)
a0a3334c
S
3185{
3186 if (!EnsureWalletIsAvailable(fHelp))
0d37ae3a 3187 return NullUniValue;
a0a3334c 3188
44e37656 3189 if (fHelp || params.size() > 2)
a0a3334c 3190 throw runtime_error(
44e37656 3191 "z_gettotalbalance ( minconf includeWatchonly )\n"
a0a3334c 3192 "\nReturn the total value of funds stored in the node’s wallet.\n"
2bbfe6c4
JG
3193 "\nCAUTION: If the wallet contains watch-only zaddrs, the returned private balance may be larger than the actual balance,"
3194 "\nbecause spends cannot be detected with incoming viewing keys.\n"
a0a3334c
S
3195 "\nArguments:\n"
3196 "1. minconf (numeric, optional, default=1) Only include private and transparent transactions confirmed at least this many times.\n"
44e37656 3197 "2. includeWatchonly (bool, optional, default=false) Also include balance in watchonly addresses (see 'importaddress' and 'z_importviewingkey')\n"
a0a3334c
S
3198 "\nResult:\n"
3199 "{\n"
3200 " \"transparent\": xxxxx, (numeric) the total balance of transparent funds\n"
3201 " \"private\": xxxxx, (numeric) the total balance of private funds\n"
3202 " \"total\": xxxxx, (numeric) the total balance of both transparent and private funds\n"
3203 "}\n"
3204 "\nExamples:\n"
3205 "\nThe total amount in the wallet\n"
3206 + HelpExampleCli("z_gettotalbalance", "") +
3207 "\nThe total amount in the wallet at least 5 blocks confirmed\n"
3208 + HelpExampleCli("z_gettotalbalance", "5") +
3209 "\nAs a json rpc call\n"
3210 + HelpExampleRpc("z_gettotalbalance", "5")
3211 );
3212
3213 LOCK2(cs_main, pwalletMain->cs_wallet);
3214
3215 int nMinDepth = 1;
44e37656 3216 if (params.size() > 0) {
a0a3334c
S
3217 nMinDepth = params[0].get_int();
3218 }
12448b64
S
3219 if (nMinDepth < 0) {
3220 throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
3221 }
a0a3334c 3222
44e37656
JG
3223 bool fIncludeWatchonly = false;
3224 if (params.size() > 1) {
3225 fIncludeWatchonly = params[1].get_bool();
3226 }
3227
a0a3334c 3228 // getbalance and "getbalance * 1 true" should return the same number
70454796 3229 // but they don't because wtx.GetAmounts() does not handle tx where there are no outputs
a0a3334c
S
3230 // pwalletMain->GetBalance() does not accept min depth parameter
3231 // so we use our own method to get balance of utxos.
44e37656
JG
3232 CAmount nBalance = getBalanceTaddr("", nMinDepth, !fIncludeWatchonly);
3233 CAmount nPrivateBalance = getBalanceZaddr("", nMinDepth, !fIncludeWatchonly);
a0a3334c 3234 CAmount nTotalBalance = nBalance + nPrivateBalance;
0d37ae3a 3235 UniValue result(UniValue::VOBJ);
f54db399
JG
3236 result.push_back(Pair("transparent", FormatMoney(nBalance)));
3237 result.push_back(Pair("private", FormatMoney(nPrivateBalance)));
3238 result.push_back(Pair("total", FormatMoney(nTotalBalance)));
a0a3334c
S
3239 return result;
3240}
3241
0d37ae3a 3242UniValue z_getoperationresult(const UniValue& params, bool fHelp)
c1eae280
S
3243{
3244 if (!EnsureWalletIsAvailable(fHelp))
0d37ae3a 3245 return NullUniValue;
c1eae280
S
3246
3247 if (fHelp || params.size() > 1)
3248 throw runtime_error(
3249 "z_getoperationresult ([\"operationid\", ... ]) \n"
3250 "\nRetrieve the result and status of an operation which has finished, and then remove the operation from memory."
3251 + HelpRequiringPassphrase() + "\n"
3252 "\nArguments:\n"
3253 "1. \"operationid\" (array, optional) A list of operation ids we are interested in. If not provided, examine all operations known to the node.\n"
3254 "\nResult:\n"
3255 "\" [object, ...]\" (array) A list of JSON objects\n"
337a99a2
JG
3256 "\nExamples:\n"
3257 + HelpExampleCli("z_getoperationresult", "'[\"operationid\", ... ]'")
3258 + HelpExampleRpc("z_getoperationresult", "'[\"operationid\", ... ]'")
c1eae280 3259 );
70454796 3260
c1eae280
S
3261 // This call will remove finished operations
3262 return z_getoperationstatus_IMPL(params, true);
3263}
fc72c078 3264
0d37ae3a 3265UniValue z_getoperationstatus(const UniValue& params, bool fHelp)
fc72c078
S
3266{
3267 if (!EnsureWalletIsAvailable(fHelp))
0d37ae3a 3268 return NullUniValue;
fc72c078 3269
34f0001c 3270 if (fHelp || params.size() > 1)
fc72c078 3271 throw runtime_error(
34f0001c 3272 "z_getoperationstatus ([\"operationid\", ... ]) \n"
c1eae280 3273 "\nGet operation status and any associated result or error data. The operation will remain in memory."
fc72c078
S
3274 + HelpRequiringPassphrase() + "\n"
3275 "\nArguments:\n"
c1eae280 3276 "1. \"operationid\" (array, optional) A list of operation ids we are interested in. If not provided, examine all operations known to the node.\n"
fc72c078 3277 "\nResult:\n"
34f0001c 3278 "\" [object, ...]\" (array) A list of JSON objects\n"
337a99a2
JG
3279 "\nExamples:\n"
3280 + HelpExampleCli("z_getoperationstatus", "'[\"operationid\", ... ]'")
3281 + HelpExampleRpc("z_getoperationstatus", "'[\"operationid\", ... ]'")
fc72c078 3282 );
70454796 3283
c1eae280
S
3284 // This call is idempotent so we don't want to remove finished operations
3285 return z_getoperationstatus_IMPL(params, false);
3286}
fc72c078 3287
0d37ae3a 3288UniValue z_getoperationstatus_IMPL(const UniValue& params, bool fRemoveFinishedOperations=false)
c1eae280 3289{
fc72c078
S
3290 LOCK2(cs_main, pwalletMain->cs_wallet);
3291
34f0001c
S
3292 std::set<AsyncRPCOperationId> filter;
3293 if (params.size()==1) {
0d37ae3a 3294 UniValue ids = params[0].get_array();
c24109ec 3295 for (const UniValue & v : ids.getValues()) {
34f0001c
S
3296 filter.insert(v.get_str());
3297 }
fc72c078 3298 }
34f0001c 3299 bool useFilter = (filter.size()>0);
fc72c078 3300
0d37ae3a 3301 UniValue ret(UniValue::VARR);
34f0001c
S
3302 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
3303 std::vector<AsyncRPCOperationId> ids = q->getAllOperationIds();
3304
3305 for (auto id : ids) {
3306 if (useFilter && !filter.count(id))
3307 continue;
70454796 3308
34f0001c
S
3309 std::shared_ptr<AsyncRPCOperation> operation = q->getOperationForId(id);
3310 if (!operation) {
3311 continue;
3312 // It's possible that the operation was removed from the internal queue and map during this loop
3313 // throw JSONRPCError(RPC_INVALID_PARAMETER, "No operation exists for that id.");
3314 }
fc72c078 3315
2f21206c
S
3316 UniValue obj = operation->getStatus();
3317 std::string s = obj["status"].get_str();
c1eae280
S
3318 if (fRemoveFinishedOperations) {
3319 // Caller is only interested in retrieving finished results
2f21206c
S
3320 if ("success"==s || "failed"==s || "cancelled"==s) {
3321 ret.push_back(obj);
c1eae280
S
3322 q->popOperationForId(id);
3323 }
3324 } else {
2f21206c 3325 ret.push_back(obj);
34f0001c 3326 }
fc72c078
S
3327 }
3328
0d37ae3a
JG
3329 std::vector<UniValue> arrTmp = ret.getValues();
3330
2d2f3d18 3331 // sort results chronologically by creation_time
0d37ae3a 3332 std::sort(arrTmp.begin(), arrTmp.end(), [](UniValue a, UniValue b) -> bool {
2d2f3d18
S
3333 const int64_t t1 = find_value(a.get_obj(), "creation_time").get_int64();
3334 const int64_t t2 = find_value(b.get_obj(), "creation_time").get_int64();
3335 return t1 < t2;
3336 });
3337
0d37ae3a
JG
3338 ret.clear();
3339 ret.setArray();
3340 ret.push_backV(arrTmp);
3341
34f0001c 3342 return ret;
fc72c078
S
3343}
3344
3920292b
S
3345
3346// Here we define the maximum number of zaddr outputs that can be included in a transaction.
3347// If input notes are small, we might actually require more than one joinsplit per zaddr output.
3348// For now though, we assume we use one joinsplit per zaddr output (and the second output note is change).
3349// We reduce the result by 1 to ensure there is room for non-joinsplit CTransaction data.
3350#define Z_SENDMANY_MAX_ZADDR_OUTPUTS ((MAX_TX_SIZE / JSDescription().GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION)) - 1)
3351
3352// transaction.h comment: spending taddr output requires CTxIn >= 148 bytes and typical taddr txout is 34 bytes
3353#define CTXIN_SPEND_DUST_SIZE 148
3354#define CTXOUT_REGULAR_SIZE 34
3355
0d37ae3a 3356UniValue z_sendmany(const UniValue& params, bool fHelp)
fc72c078
S
3357{
3358 if (!EnsureWalletIsAvailable(fHelp))
0d37ae3a 3359 return NullUniValue;
fc72c078 3360
af53da02 3361 if (fHelp || params.size() < 2 || params.size() > 4)
fc72c078 3362 throw runtime_error(
af53da02 3363 "z_sendmany \"fromaddress\" [{\"address\":... ,\"amount\":...},...] ( minconf ) ( fee )\n"
fc72c078 3364 "\nSend multiple times. Amounts are double-precision floating point numbers."
b7d7b2ad 3365 "\nChange from a taddr flows to a new taddr address, while change from zaddr returns to itself."
48f9c65b 3366 "\nWhen sending coinbase UTXOs to a zaddr, change is not allowed. The entire value of the UTXO(s) must be consumed."
3920292b 3367 + strprintf("\nCurrently, the maximum number of zaddr outputs is %d due to transaction size limits.\n", Z_SENDMANY_MAX_ZADDR_OUTPUTS)
fc72c078
S
3368 + HelpRequiringPassphrase() + "\n"
3369 "\nArguments:\n"
3370 "1. \"fromaddress\" (string, required) The taddr or zaddr to send the funds from.\n"
3371 "2. \"amounts\" (array, required) An array of json objects representing the amounts to send.\n"
3372 " [{\n"
3373 " \"address\":address (string, required) The address is a taddr or zaddr\n"
6dec2d03 3374 " \"amount\":amount (numeric, required) The numeric amount in " + CURRENCY_UNIT + " is the value\n"
fc72c078
S
3375 " \"memo\":memo (string, optional) If the address is a zaddr, raw data represented in hexadecimal string format\n"
3376 " }, ... ]\n"
3377 "3. minconf (numeric, optional, default=1) Only use funds confirmed at least this many times.\n"
af53da02
S
3378 "4. fee (numeric, optional, default="
3379 + strprintf("%s", FormatMoney(ASYNC_RPC_OPERATION_DEFAULT_MINERS_FEE)) + ") The fee amount to attach to this transaction.\n"
fc72c078
S
3380 "\nResult:\n"
3381 "\"operationid\" (string) An operationid to pass to z_getoperationstatus to get the result of the operation.\n"
337a99a2
JG
3382 "\nExamples:\n"
3383 + HelpExampleCli("z_sendmany", "\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" '[{\"address\": \"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\" ,\"amount\": 5.0}]'")
3384 + HelpExampleRpc("z_sendmany", "\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", [{\"address\": \"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\" ,\"amount\": 5.0}]")
fc72c078
S
3385 );
3386
3387 LOCK2(cs_main, pwalletMain->cs_wallet);
3388
fc72c078
S
3389 // Check that the from address is valid.
3390 auto fromaddress = params[0].get_str();
3391 bool fromTaddr = false;
3392 CBitcoinAddress taddr(fromaddress);
3393 fromTaddr = taddr.IsValid();
3394 libzcash::PaymentAddress zaddr;
3395 if (!fromTaddr) {
3396 CZCPaymentAddress address(fromaddress);
3397 try {
3398 zaddr = address.Get();
fce72608 3399 } catch (const std::runtime_error&) {
fc72c078
S
3400 // invalid
3401 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or zaddr.");
3402 }
3403 }
3404
dafb8161 3405 // Check that we have the spending key
fc72c078
S
3406 if (!fromTaddr) {
3407 if (!pwalletMain->HaveSpendingKey(zaddr)) {
3408 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key not found.");
3409 }
3410 }
3411
0d37ae3a 3412 UniValue outputs = params[1].get_array();
fc72c078
S
3413
3414 if (outputs.size()==0)
3415 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, amounts array is empty.");
3416
3417 // Keep track of addresses to spot duplicates
3418 set<std::string> setAddress;
3419
3420 // Recipients
dafb8161
S
3421 std::vector<SendManyRecipient> taddrRecipients;
3422 std::vector<SendManyRecipient> zaddrRecipients;
af53da02 3423 CAmount nTotalOut = 0;
fc72c078 3424
0d37ae3a
JG
3425 for (const UniValue& o : outputs.getValues()) {
3426 if (!o.isObject())
fc72c078 3427 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected object");
fc72c078 3428
fc72c078 3429 // sanity check, report error if unknown key-value pairs
0d37ae3a
JG
3430 for (const string& name_ : o.getKeys()) {
3431 std::string s = name_;
fc72c078
S
3432 if (s != "address" && s != "amount" && s!="memo")
3433 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown key: ")+s);
3434 }
3435
3436 string address = find_value(o, "address").get_str();
3437 bool isZaddr = false;
3438 CBitcoinAddress taddr(address);
3439 if (!taddr.IsValid()) {
3440 try {
3441 CZCPaymentAddress zaddr(address);
3442 zaddr.Get();
3443 isZaddr = true;
fce72608 3444 } catch (const std::runtime_error&) {
fc72c078
S
3445 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ")+address );
3446 }
3447 }
3448
3449 if (setAddress.count(address))
3450 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+address);
3451 setAddress.insert(address);
3452
0d37ae3a 3453 UniValue memoValue = find_value(o, "memo");
fc72c078 3454 string memo;
0d37ae3a 3455 if (!memoValue.isNull()) {
fc72c078
S
3456 memo = memoValue.get_str();
3457 if (!isZaddr) {
3458 throw JSONRPCError(RPC_INVALID_PARAMETER, "Memo can not be used with a taddr. It can only be used with a zaddr.");
3459 } else if (!IsHex(memo)) {
3460 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected memo data in hexadecimal format.");
3461 }
6114cfe7 3462 if (memo.length() > ZC_MEMO_SIZE*2) {
dafb8161
S
3463 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid parameter, size of memo is larger than maximum allowed %d", ZC_MEMO_SIZE ));
3464 }
fc72c078
S
3465 }
3466
0d37ae3a 3467 UniValue av = find_value(o, "amount");
fc72c078
S
3468 CAmount nAmount = AmountFromValue( av );
3469 if (nAmount < 0)
3470 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, amount must be positive");
3471
dafb8161
S
3472 if (isZaddr) {
3473 zaddrRecipients.push_back( SendManyRecipient(address, nAmount, memo) );
3474 } else {
3475 taddrRecipients.push_back( SendManyRecipient(address, nAmount, memo) );
3476 }
af53da02
S
3477
3478 nTotalOut += nAmount;
fc72c078
S
3479 }
3480
3920292b
S
3481 // Check the number of zaddr outputs does not exceed the limit.
3482 if (zaddrRecipients.size() > Z_SENDMANY_MAX_ZADDR_OUTPUTS) {
3483 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, too many zaddr outputs");
3484 }
3485
3486 // As a sanity check, estimate and verify that the size of the transaction will be valid.
3487 // Depending on the input notes, the actual tx size may turn out to be larger and perhaps invalid.
3488 size_t txsize = 0;
3489 CMutableTransaction mtx;
3490 mtx.nVersion = 2;
3491 for (int i = 0; i < zaddrRecipients.size(); i++) {
3492 mtx.vjoinsplit.push_back(JSDescription());
3493 }
3494 CTransaction tx(mtx);
3495 txsize += tx.GetSerializeSize(SER_NETWORK, tx.nVersion);
3496 if (fromTaddr) {
3497 txsize += CTXIN_SPEND_DUST_SIZE;
3498 txsize += CTXOUT_REGULAR_SIZE; // There will probably be taddr change
3499 }
3500 txsize += CTXOUT_REGULAR_SIZE * taddrRecipients.size();
3501 if (txsize > MAX_TX_SIZE) {
3502 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Too many outputs, size of raw transaction would be larger than limit of %d bytes", MAX_TX_SIZE ));
3503 }
3504
fc72c078
S
3505 // Minimum confirmations
3506 int nMinDepth = 1;
12448b64 3507 if (params.size() > 2) {
fc72c078 3508 nMinDepth = params[2].get_int();
12448b64
S
3509 }
3510 if (nMinDepth < 0) {
3511 throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
3512 }
fc72c078 3513
af53da02
S
3514 // Fee in Zatoshis, not currency format)
3515 CAmount nFee = ASYNC_RPC_OPERATION_DEFAULT_MINERS_FEE;
3516 if (params.size() > 3) {
7eccce4e
S
3517 if (params[3].get_real() == 0.0) {
3518 nFee = 0;
3519 } else {
3520 nFee = AmountFromValue( params[3] );
3521 }
3522
af53da02
S
3523 // Check that the user specified fee is sane.
3524 if (nFee > nTotalOut) {
3525 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Fee %s is greater than the sum of outputs %s", FormatMoney(nFee), FormatMoney(nTotalOut)));
3526 }
3527 }
3528
8aa7937d 3529 // Use input parameters as the optional context info to be returned by z_getoperationstatus and z_getoperationresult.
0d37ae3a 3530 UniValue o(UniValue::VOBJ);
8aa7937d
S
3531 o.push_back(Pair("fromaddress", params[0]));
3532 o.push_back(Pair("amounts", params[1]));
3533 o.push_back(Pair("minconf", nMinDepth));
3534 o.push_back(Pair("fee", std::stod(FormatMoney(nFee))));
0d37ae3a 3535 UniValue contextInfo = o;
8aa7937d 3536
072099d7 3537 // Contextual transaction we will build on
9bb37bf0
JG
3538 int nextBlockHeight = chainActive.Height() + 1;
3539 CMutableTransaction contextualTx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), nextBlockHeight);
e6cd2a83
S
3540 bool isShielded = !fromTaddr || zaddrRecipients.size() > 0;
3541 if (contextualTx.nVersion == 1 && isShielded) {
072099d7
S
3542 contextualTx.nVersion = 2; // Tx format should support vjoinsplits
3543 }
9bb37bf0
JG
3544 if (NetworkUpgradeActive(nextBlockHeight, Params().GetConsensus(), Consensus::UPGRADE_OVERWINTER)) {
3545 contextualTx.nExpiryHeight = nextBlockHeight + expiryDelta;
3546 }
072099d7 3547
dafb8161 3548 // Create operation and add to global queue
fc72c078 3549 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
072099d7 3550 std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany(contextualTx, fromaddress, taddrRecipients, zaddrRecipients, nMinDepth, nFee, contextInfo) );
fc72c078
S
3551 q->addOperation(operation);
3552 AsyncRPCOperationId operationId = operation->getId();
3553 return operationId;
fc72c078 3554}
34f0001c
S
3555
3556
06c19063
S
3557/**
3558When estimating the number of coinbase utxos we can shield in a single transaction:
35591. Joinsplit description is 1802 bytes.
35602. Transaction overhead ~ 100 bytes
35613. Spending a typical P2PKH is >=148 bytes, as defined in CTXIN_SPEND_DUST_SIZE.
35624. Spending a multi-sig P2SH address can vary greatly:
3563 https://github.com/bitcoin/bitcoin/blob/c3ad56f4e0b587d8d763af03d743fdfc2d180c9b/src/main.cpp#L517
3564 In real-world coinbase utxos, we consider a 3-of-3 multisig, where the size is roughly:
3565 (3*(33+1))+3 = 105 byte redeem script
3566 105 + 1 + 3*(73+1) = 328 bytes of scriptSig, rounded up to 400 based on testnet experiments.
3567*/
3568#define CTXIN_SPEND_P2SH_SIZE 400
3569
c5dabd2b
S
3570#define SHIELD_COINBASE_DEFAULT_LIMIT 50
3571
06c19063
S
3572UniValue z_shieldcoinbase(const UniValue& params, bool fHelp)
3573{
3574 if (!EnsureWalletIsAvailable(fHelp))
3575 return NullUniValue;
3576
c5dabd2b 3577 if (fHelp || params.size() < 2 || params.size() > 4)
06c19063 3578 throw runtime_error(
c5dabd2b 3579 "z_shieldcoinbase \"fromaddress\" \"tozaddress\" ( fee ) ( limit )\n"
06c19063
S
3580 "\nShield transparent coinbase funds by sending to a shielded zaddr. This is an asynchronous operation and utxos"
3581 "\nselected for shielding will be locked. If there is an error, they are unlocked. The RPC call `listlockunspent`"
c5dabd2b
S
3582 "\ncan be used to return a list of locked utxos. The number of coinbase utxos selected for shielding can be limited"
3583 "\nby the caller. If the limit parameter is set to zero, the -mempooltxinputlimit option will determine the number"
3584 "\nof uxtos. Any limit is constrained by the consensus rule defining a maximum transaction size of "
06c19063
S
3585 + strprintf("%d bytes.", MAX_TX_SIZE)
3586 + HelpRequiringPassphrase() + "\n"
3587 "\nArguments:\n"
3588 "1. \"fromaddress\" (string, required) The address is a taddr or \"*\" for all taddrs belonging to the wallet.\n"
3589 "2. \"toaddress\" (string, required) The address is a zaddr.\n"
3590 "3. fee (numeric, optional, default="
3591 + strprintf("%s", FormatMoney(SHIELD_COINBASE_DEFAULT_MINERS_FEE)) + ") The fee amount to attach to this transaction.\n"
c5dabd2b
S
3592 "4. limit (numeric, optional, default="
3593 + strprintf("%d", SHIELD_COINBASE_DEFAULT_LIMIT) + ") Limit on the maximum number of utxos to shield. Set to 0 to use node option -mempooltxinputlimit.\n"
06c19063
S
3594 "\nResult:\n"
3595 "{\n"
06c19063
S
3596 " \"remainingUTXOs\": xxx (numeric) Number of coinbase utxos still available for shielding.\n"
3597 " \"remainingValue\": xxx (numeric) Value of coinbase utxos still available for shielding.\n"
9eb8089e
JG
3598 " \"shieldingUTXOs\": xxx (numeric) Number of coinbase utxos being shielded.\n"
3599 " \"shieldingValue\": xxx (numeric) Value of coinbase utxos being shielded.\n"
3600 " \"opid\": xxx (string) An operationid to pass to z_getoperationstatus to get the result of the operation.\n"
06c19063 3601 "}\n"
337a99a2
JG
3602 "\nExamples:\n"
3603 + HelpExampleCli("z_shieldcoinbase", "\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" \"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\"")
3604 + HelpExampleRpc("z_shieldcoinbase", "\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", \"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\"")
06c19063
S
3605 );
3606
3607 LOCK2(cs_main, pwalletMain->cs_wallet);
3608
3609 // Validate the from address
3610 auto fromaddress = params[0].get_str();
3611 bool isFromWildcard = fromaddress == "*";
3612 CBitcoinAddress taddr;
3613 if (!isFromWildcard) {
3614 taddr = CBitcoinAddress(fromaddress);
3615 if (!taddr.IsValid()) {
3616 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or \"*\".");
3617 }
3618 }
3619
3620 // Validate the destination address
3621 auto destaddress = params[1].get_str();
3622 try {
3623 CZCPaymentAddress pa(destaddress);
3624 libzcash::PaymentAddress zaddr = pa.Get();
3625 } catch (const std::runtime_error&) {
3626 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ") + destaddress );
3627 }
3628
3629 // Convert fee from currency format to zatoshis
3630 CAmount nFee = SHIELD_COINBASE_DEFAULT_MINERS_FEE;
3631 if (params.size() > 2) {
3632 if (params[2].get_real() == 0.0) {
3633 nFee = 0;
3634 } else {
3635 nFee = AmountFromValue( params[2] );
3636 }
3637 }
3638
c5dabd2b
S
3639 int nLimit = SHIELD_COINBASE_DEFAULT_LIMIT;
3640 if (params.size() > 3) {
3641 nLimit = params[3].get_int();
3642 if (nLimit < 0) {
3643 throw JSONRPCError(RPC_INVALID_PARAMETER, "Limit on maximum number of utxos cannot be negative");
3644 }
3645 }
3646
06c19063
S
3647 // Prepare to get coinbase utxos
3648 std::vector<ShieldCoinbaseUTXO> inputs;
3649 CAmount shieldedValue = 0;
3650 CAmount remainingValue = 0;
3651 size_t estimatedTxSize = 2000; // 1802 joinsplit description + tx overhead + wiggle room
3652 size_t utxoCounter = 0;
3653 bool maxedOutFlag = false;
c5dabd2b 3654 size_t mempoolLimit = (nLimit != 0) ? nLimit : (size_t)GetArg("-mempooltxinputlimit", 0);
06c19063
S
3655
3656 // Set of addresses to filter utxos by
3657 set<CBitcoinAddress> setAddress = {};
3658 if (!isFromWildcard) {
3659 setAddress.insert(taddr);
3660 }
3661
3662 // Get available utxos
3663 vector<COutput> vecOutputs;
3664 pwalletMain->AvailableCoins(vecOutputs, true, NULL, false, true);
3665
3666 // Find unspent coinbase utxos and update estimated size
3667 BOOST_FOREACH(const COutput& out, vecOutputs) {
3668 if (!out.fSpendable) {
3669 continue;
3670 }
3671
3672 CTxDestination address;
3673 if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) {
3674 continue;
3675 }
3676 // If taddr is not wildcard "*", filter utxos
3677 if (setAddress.size()>0 && !setAddress.count(address)) {
3678 continue;
3679 }
3680
3681 if (!out.tx->IsCoinBase()) {
3682 continue;
3683 }
3684
3685 utxoCounter++;
3686 CAmount nValue = out.tx->vout[out.i].nValue;
3687
3688 if (!maxedOutFlag) {
3689 CBitcoinAddress ba(address);
3690 size_t increase = (ba.IsScript()) ? CTXIN_SPEND_P2SH_SIZE : CTXIN_SPEND_DUST_SIZE;
3691 if (estimatedTxSize + increase >= MAX_TX_SIZE ||
3692 (mempoolLimit > 0 && utxoCounter > mempoolLimit))
3693 {
3694 maxedOutFlag = true;
3695 } else {
3696 estimatedTxSize += increase;
3697 ShieldCoinbaseUTXO utxo = {out.tx->GetHash(), out.i, nValue};
3698 inputs.push_back(utxo);
3699 shieldedValue += nValue;
3700 }
3701 }
3702
3703 if (maxedOutFlag) {
3704 remainingValue += nValue;
3705 }
3706 }
3707
3708 size_t numUtxos = inputs.size();
3709
3710 if (numUtxos == 0) {
3711 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Could not find any coinbase funds to shield.");
3712 }
3713
3714 if (shieldedValue < nFee) {
3715 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS,
3716 strprintf("Insufficient coinbase funds, have %s, which is less than miners fee %s",
3717 FormatMoney(shieldedValue), FormatMoney(nFee)));
3718 }
3719
3720 // Check that the user specified fee is sane (if too high, it can result in error -25 absurd fee)
3721 CAmount netAmount = shieldedValue - nFee;
3722 if (nFee > netAmount) {
3723 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Fee %s is greater than the net amount to be shielded %s", FormatMoney(nFee), FormatMoney(netAmount)));
3724 }
3725
3726 // Keep record of parameters in context object
3727 UniValue contextInfo(UniValue::VOBJ);
3728 contextInfo.push_back(Pair("fromaddress", params[0]));
3729 contextInfo.push_back(Pair("toaddress", params[1]));
3730 contextInfo.push_back(Pair("fee", ValueFromAmount(nFee)));
3731
072099d7 3732 // Contextual transaction we will build on
9bb37bf0 3733 int nextBlockHeight = chainActive.Height() + 1;
072099d7 3734 CMutableTransaction contextualTx = CreateNewContextualCMutableTransaction(
9bb37bf0 3735 Params().GetConsensus(), nextBlockHeight);
072099d7
S
3736 if (contextualTx.nVersion == 1) {
3737 contextualTx.nVersion = 2; // Tx format should support vjoinsplits
3738 }
9bb37bf0
JG
3739 if (NetworkUpgradeActive(nextBlockHeight, Params().GetConsensus(), Consensus::UPGRADE_OVERWINTER)) {
3740 contextualTx.nExpiryHeight = nextBlockHeight + expiryDelta;
3741 }
072099d7 3742
06c19063
S
3743 // Create operation and add to global queue
3744 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
072099d7 3745 std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_shieldcoinbase(contextualTx, inputs, destaddress, nFee, contextInfo) );
06c19063
S
3746 q->addOperation(operation);
3747 AsyncRPCOperationId operationId = operation->getId();
3748
3749 // Return continuation information
3750 UniValue o(UniValue::VOBJ);
3751 o.push_back(Pair("remainingUTXOs", utxoCounter - numUtxos));
3752 o.push_back(Pair("remainingValue", ValueFromAmount(remainingValue)));
3753 o.push_back(Pair("shieldingUTXOs", numUtxos));
3754 o.push_back(Pair("shieldingValue", ValueFromAmount(shieldedValue)));
3755 o.push_back(Pair("opid", operationId));
3756 return o;
3757}
3758
3759
6e9c7629
JG
3760#define MERGE_TO_ADDRESS_DEFAULT_TRANSPARENT_LIMIT 50
3761#define MERGE_TO_ADDRESS_DEFAULT_SHIELDED_LIMIT 10
3762
3763#define JOINSPLIT_SIZE JSDescription().GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION)
3764
3765UniValue z_mergetoaddress(const UniValue& params, bool fHelp)
3766{
3767 if (!EnsureWalletIsAvailable(fHelp))
3768 return NullUniValue;
3769
553a5c1a
JG
3770 auto fEnableMergeToAddress = fExperimentalMode && GetBoolArg("-zmergetoaddress", false);
3771 std::string strDisabledMsg = "";
3772 if (!fEnableMergeToAddress) {
3773 strDisabledMsg = "\nWARNING: z_mergetoaddress is DISABLED but can be enabled as an experimental feature.\n";
3774 }
3775
6e9c7629
JG
3776 if (fHelp || params.size() < 2 || params.size() > 6)
3777 throw runtime_error(
3778 "z_mergetoaddress [\"fromaddress\", ... ] \"toaddress\" ( fee ) ( transparent_limit ) ( shielded_limit ) ( memo )\n"
553a5c1a 3779 + strDisabledMsg +
6e9c7629
JG
3780 "\nMerge multiple UTXOs and notes into a single UTXO or note. Coinbase UTXOs are ignored; use `z_shieldcoinbase`"
3781 "\nto combine those into a single note."
3782 "\n\nThis is an asynchronous operation, and UTXOs selected for merging will be locked. If there is an error, they"
3783 "\nare unlocked. The RPC call `listlockunspent` can be used to return a list of locked UTXOs."
3784 "\n\nThe number of UTXOs and notes selected for merging can be limited by the caller. If the transparent limit"
3785 "\nparameter is set to zero, the -mempooltxinputlimit option will determine the number of UTXOs. Any limit is"
3786 "\nconstrained by the consensus rule defining a maximum transaction size of "
3787 + strprintf("%d bytes.", MAX_TX_SIZE)
3788 + HelpRequiringPassphrase() + "\n"
3789 "\nArguments:\n"
3790 "1. fromaddresses (string, required) A JSON array with addresses.\n"
3791 " The following special strings are accepted inside the array:\n"
3792 " - \"*\": Merge both UTXOs and notes from all addresses belonging to the wallet.\n"
3793 " - \"ANY_TADDR\": Merge UTXOs from all t-addrs belonging to the wallet.\n"
3794 " - \"ANY_ZADDR\": Merge notes from all z-addrs belonging to the wallet.\n"
3795 " If a special string is given, any given addresses of that type will be ignored.\n"
3796 " [\n"
3797 " \"address\" (string) Can be a t-addr or a z-addr\n"
3798 " ,...\n"
3799 " ]\n"
3800 "2. \"toaddress\" (string, required) The t-addr or z-addr to send the funds to.\n"
3801 "3. fee (numeric, optional, default="
3802 + strprintf("%s", FormatMoney(MERGE_TO_ADDRESS_OPERATION_DEFAULT_MINERS_FEE)) + ") The fee amount to attach to this transaction.\n"
3803 "4. transparent_limit (numeric, optional, default="
3804 + strprintf("%d", MERGE_TO_ADDRESS_DEFAULT_TRANSPARENT_LIMIT) + ") Limit on the maximum number of UTXOs to merge. Set to 0 to use node option -mempooltxinputlimit.\n"
3805 "4. shielded_limit (numeric, optional, default="
3806 + strprintf("%d", MERGE_TO_ADDRESS_DEFAULT_SHIELDED_LIMIT) + ") Limit on the maximum number of notes to merge. Set to 0 to merge as many as will fit in the transaction.\n"
3807 "5. \"memo\" (string, optional) Encoded as hex. When toaddress is a z-addr, this will be stored in the memo field of the new note.\n"
3808 "\nResult:\n"
3809 "{\n"
3810 " \"remainingUTXOs\": xxx (numeric) Number of UTXOs still available for merging.\n"
3811 " \"remainingTransparentValue\": xxx (numeric) Value of UTXOs still available for merging.\n"
3812 " \"remainingNotes\": xxx (numeric) Number of notes still available for merging.\n"
3813 " \"remainingShieldedValue\": xxx (numeric) Value of notes still available for merging.\n"
3814 " \"mergingUTXOs\": xxx (numeric) Number of UTXOs being merged.\n"
3815 " \"mergingTransparentValue\": xxx (numeric) Value of UTXOs being merged.\n"
3816 " \"mergingNotes\": xxx (numeric) Number of notes being merged.\n"
3817 " \"mergingShieldedValue\": xxx (numeric) Value of notes being merged.\n"
3818 " \"opid\": xxx (string) An operationid to pass to z_getoperationstatus to get the result of the operation.\n"
3819 "}\n"
3820 "\nExamples:\n"
3821 + HelpExampleCli("z_mergetoaddress", "'[\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\"]' ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf")
3822 + HelpExampleRpc("z_mergetoaddress", "[\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\"], \"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\"")
3823 );
3824
553a5c1a
JG
3825 if (!fEnableMergeToAddress) {
3826 throw JSONRPCError(RPC_WALLET_ERROR, "Error: z_mergetoaddress is disabled.");
3827 }
3828
6e9c7629
JG
3829 LOCK2(cs_main, pwalletMain->cs_wallet);
3830
3831 bool useAny = false;
3832 bool useAnyUTXO = false;
3833 bool useAnyNote = false;
3834 std::set<CBitcoinAddress> taddrs = {};
3835 std::set<libzcash::PaymentAddress> zaddrs = {};
3836
3837 UniValue addresses = params[0].get_array();
3838 if (addresses.size()==0)
3839 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, fromaddresses array is empty.");
3840
3841 // Keep track of addresses to spot duplicates
3842 std::set<std::string> setAddress;
3843
3844 // Sources
3845 for (const UniValue& o : addresses.getValues()) {
3846 if (!o.isStr())
3847 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected string");
3848
3849 std::string address = o.get_str();
3850 if (address == "*") {
3851 useAny = true;
3852 } else if (address == "ANY_TADDR") {
3853 useAnyUTXO = true;
3854 } else if (address == "ANY_ZADDR") {
3855 useAnyNote = true;
3856 } else {
3857 CBitcoinAddress taddr(address);
3858 if (taddr.IsValid()) {
3859 // Ignore any listed t-addrs if we are using all of them
3860 if (!(useAny || useAnyUTXO)) {
3861 taddrs.insert(taddr);
3862 }
3863 } else {
3864 try {
3865 CZCPaymentAddress zaddr(address);
3866 // Ignore listed z-addrs if we are using all of them
3867 if (!(useAny || useAnyNote)) {
3868 zaddrs.insert(zaddr.Get());
3869 }
3870 } catch (const std::runtime_error&) {
3871 throw JSONRPCError(
3872 RPC_INVALID_PARAMETER,
3873 string("Invalid parameter, unknown address format: ") + address);
3874 }
3875 }
3876 }
3877
3878 if (setAddress.count(address))
3879 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ") + address);
3880 setAddress.insert(address);
3881 }
3882
3883 // Validate the destination address
3884 auto destaddress = params[1].get_str();
3885 bool isToZaddr = false;
3886 CBitcoinAddress taddr(destaddress);
3887 if (!taddr.IsValid()) {
3888 try {
3889 CZCPaymentAddress zaddr(destaddress);
3890 zaddr.Get();
3891 isToZaddr = true;
3892 } catch (const std::runtime_error&) {
3893 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ") + destaddress );
3894 }
3895 }
3896
3897 // Convert fee from currency format to zatoshis
3898 CAmount nFee = SHIELD_COINBASE_DEFAULT_MINERS_FEE;
3899 if (params.size() > 2) {
3900 if (params[2].get_real() == 0.0) {
3901 nFee = 0;
3902 } else {
3903 nFee = AmountFromValue( params[2] );
3904 }
3905 }
3906
3907 int nUTXOLimit = MERGE_TO_ADDRESS_DEFAULT_TRANSPARENT_LIMIT;
3908 if (params.size() > 3) {
3909 nUTXOLimit = params[3].get_int();
3910 if (nUTXOLimit < 0) {
3911 throw JSONRPCError(RPC_INVALID_PARAMETER, "Limit on maximum number of UTXOs cannot be negative");
3912 }
3913 }
3914
3915 int nNoteLimit = MERGE_TO_ADDRESS_DEFAULT_SHIELDED_LIMIT;
3916 if (params.size() > 4) {
3917 nNoteLimit = params[4].get_int();
3918 if (nNoteLimit < 0) {
3919 throw JSONRPCError(RPC_INVALID_PARAMETER, "Limit on maximum number of notes cannot be negative");
3920 }
3921 }
3922
3923 std::string memo;
3924 if (params.size() > 5) {
3925 memo = params[5].get_str();
3926 if (!isToZaddr) {
3927 throw JSONRPCError(RPC_INVALID_PARAMETER, "Memo can not be used with a taddr. It can only be used with a zaddr.");
3928 } else if (!IsHex(memo)) {
3929 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected memo data in hexadecimal format.");
3930 }
3931 if (memo.length() > ZC_MEMO_SIZE*2) {
3932 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid parameter, size of memo is larger than maximum allowed %d", ZC_MEMO_SIZE ));
3933 }
3934 }
3935
3936 MergeToAddressRecipient recipient(destaddress, memo);
3937
3938 // Prepare to get UTXOs and notes
3939 std::vector<MergeToAddressInputUTXO> utxoInputs;
3940 std::vector<MergeToAddressInputNote> noteInputs;
3941 CAmount mergedUTXOValue = 0;
3942 CAmount mergedNoteValue = 0;
3943 CAmount remainingUTXOValue = 0;
3944 CAmount remainingNoteValue = 0;
3945 size_t utxoCounter = 0;
3946 size_t noteCounter = 0;
3947 bool maxedOutUTXOsFlag = false;
3948 bool maxedOutNotesFlag = false;
3949 size_t mempoolLimit = (nUTXOLimit != 0) ? nUTXOLimit : (size_t)GetArg("-mempooltxinputlimit", 0);
3950
3951 size_t estimatedTxSize = 200; // tx overhead + wiggle room
3952 if (isToZaddr) {
3953 estimatedTxSize += JOINSPLIT_SIZE;
3954 }
3955
3956 if (useAny || useAnyUTXO || taddrs.size() > 0) {
3957 // Get available utxos
3958 vector<COutput> vecOutputs;
3959 pwalletMain->AvailableCoins(vecOutputs, true, NULL, false, false);
3960
3961 // Find unspent utxos and update estimated size
3962 for (const COutput& out : vecOutputs) {
3963 if (!out.fSpendable) {
3964 continue;
3965 }
3966
3967 CTxDestination address;
3968 if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) {
3969 continue;
3970 }
3971 // If taddr is not wildcard "*", filter utxos
3972 if (taddrs.size() > 0 && !taddrs.count(address)) {
3973 continue;
3974 }
3975
3976 utxoCounter++;
3977 CAmount nValue = out.tx->vout[out.i].nValue;
3978
3979 if (!maxedOutUTXOsFlag) {
3980 CBitcoinAddress ba(address);
3981 size_t increase = (ba.IsScript()) ? CTXIN_SPEND_P2SH_SIZE : CTXIN_SPEND_DUST_SIZE;
3982 if (estimatedTxSize + increase >= MAX_TX_SIZE ||
3983 (mempoolLimit > 0 && utxoCounter > mempoolLimit))
3984 {
3985 maxedOutUTXOsFlag = true;
3986 } else {
3987 estimatedTxSize += increase;
3988 COutPoint utxo(out.tx->GetHash(), out.i);
3989 utxoInputs.emplace_back(utxo, nValue);
3990 mergedUTXOValue += nValue;
3991 }
3992 }
3993
3994 if (maxedOutUTXOsFlag) {
3995 remainingUTXOValue += nValue;
3996 }
3997 }
3998 }
3999
4000 if (useAny || useAnyNote || zaddrs.size() > 0) {
4001 // Get available notes
4002 std::vector<CNotePlaintextEntry> entries;
4003 pwalletMain->GetFilteredNotes(entries, zaddrs);
4004
4005 // Find unspent notes and update estimated size
4006 for (CNotePlaintextEntry& entry : entries) {
4007 noteCounter++;
4008 CAmount nValue = entry.plaintext.value;
4009
4010 if (!maxedOutNotesFlag) {
4011 // If we haven't added any notes yet and the merge is to a
4012 // z-address, we have already accounted for the first JoinSplit.
4013 size_t increase = (noteInputs.empty() && !isToZaddr) || (noteInputs.size() % 2 == 0) ? JOINSPLIT_SIZE : 0;
4014 if (estimatedTxSize + increase >= MAX_TX_SIZE ||
4015 (nNoteLimit > 0 && noteCounter > nNoteLimit))
4016 {
4017 maxedOutNotesFlag = true;
4018 } else {
4019 estimatedTxSize += increase;
4020 SpendingKey zkey;
4021 pwalletMain->GetSpendingKey(entry.address, zkey);
4022 noteInputs.emplace_back(entry.jsop, entry.plaintext.note(entry.address), nValue, zkey);
4023 mergedNoteValue += nValue;
4024 }
4025 }
4026
4027 if (maxedOutNotesFlag) {
4028 remainingNoteValue += nValue;
4029 }
4030 }
4031 }
4032
4033 size_t numUtxos = utxoInputs.size();
4034 size_t numNotes = noteInputs.size();
4035
4036 if (numUtxos == 0 && numNotes == 0) {
4037 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Could not find any funds to merge.");
4038 }
4039
4040 // Sanity check: Don't do anything if:
4041 // - We only have one from address
4042 // - It's equal to toaddress
4043 // - The address only contains a single UTXO or note
4044 if (setAddress.size() == 1 && setAddress.count(destaddress) && (numUtxos + numNotes) == 1) {
4045 throw JSONRPCError(RPC_INVALID_PARAMETER, "Destination address is also the only source address, and all its funds are already merged.");
4046 }
4047
4048 CAmount mergedValue = mergedUTXOValue + mergedNoteValue;
4049 if (mergedValue < nFee) {
4050 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS,
4051 strprintf("Insufficient funds, have %s, which is less than miners fee %s",
4052 FormatMoney(mergedValue), FormatMoney(nFee)));
4053 }
4054
4055 // Check that the user specified fee is sane (if too high, it can result in error -25 absurd fee)
4056 CAmount netAmount = mergedValue - nFee;
4057 if (nFee > netAmount) {
4058 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Fee %s is greater than the net amount to be shielded %s", FormatMoney(nFee), FormatMoney(netAmount)));
4059 }
4060
4061 // Keep record of parameters in context object
4062 UniValue contextInfo(UniValue::VOBJ);
4063 contextInfo.push_back(Pair("fromaddresses", params[0]));
4064 contextInfo.push_back(Pair("toaddress", params[1]));
4065 contextInfo.push_back(Pair("fee", ValueFromAmount(nFee)));
4066
4067 // Contextual transaction we will build on
4068 CMutableTransaction contextualTx = CreateNewContextualCMutableTransaction(
4069 Params().GetConsensus(),
4070 chainActive.Height() + 1);
4071 bool isShielded = numNotes > 0 || isToZaddr;
4072 if (contextualTx.nVersion == 1 && isShielded) {
4073 contextualTx.nVersion = 2; // Tx format should support vjoinsplit
4074 }
4075
4076 // Create operation and add to global queue
4077 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
4078 std::shared_ptr<AsyncRPCOperation> operation(
4079 new AsyncRPCOperation_mergetoaddress(contextualTx, utxoInputs, noteInputs, recipient, nFee, contextInfo) );
4080 q->addOperation(operation);
4081 AsyncRPCOperationId operationId = operation->getId();
4082
4083 // Return continuation information
4084 UniValue o(UniValue::VOBJ);
4085 o.push_back(Pair("remainingUTXOs", utxoCounter - numUtxos));
4086 o.push_back(Pair("remainingTransparentValue", ValueFromAmount(remainingUTXOValue)));
4087 o.push_back(Pair("remainingNotes", noteCounter - numNotes));
4088 o.push_back(Pair("remainingShieldedValue", ValueFromAmount(remainingNoteValue)));
4089 o.push_back(Pair("mergingUTXOs", numUtxos));
4090 o.push_back(Pair("mergingTransparentValue", ValueFromAmount(mergedUTXOValue)));
4091 o.push_back(Pair("mergingNotes", numNotes));
4092 o.push_back(Pair("mergingShieldedValue", ValueFromAmount(mergedNoteValue)));
4093 o.push_back(Pair("opid", operationId));
4094 return o;
4095}
4096
4097
0d37ae3a 4098UniValue z_listoperationids(const UniValue& params, bool fHelp)
34f0001c
S
4099{
4100 if (!EnsureWalletIsAvailable(fHelp))
0d37ae3a 4101 return NullUniValue;
34f0001c
S
4102
4103 if (fHelp || params.size() > 1)
4104 throw runtime_error(
4105 "z_listoperationids\n"
4106 "\nReturns the list of operation ids currently known to the wallet.\n"
4107 "\nArguments:\n"
4108 "1. \"status\" (string, optional) Filter result by the operation's state state e.g. \"success\".\n"
4109 "\nResult:\n"
4110 "[ (json array of string)\n"
4111 " \"operationid\" (string) an operation id belonging to the wallet\n"
4112 " ,...\n"
4113 "]\n"
4114 "\nExamples:\n"
4115 + HelpExampleCli("z_listoperationids", "")
4116 + HelpExampleRpc("z_listoperationids", "")
4117 );
4118
4119 LOCK2(cs_main, pwalletMain->cs_wallet);
4120
4121 std::string filter;
4122 bool useFilter = false;
4123 if (params.size()==1) {
4124 filter = params[0].get_str();
4125 useFilter = true;
4126 }
4127
0d37ae3a 4128 UniValue ret(UniValue::VARR);
34f0001c
S
4129 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
4130 std::vector<AsyncRPCOperationId> ids = q->getAllOperationIds();
4131 for (auto id : ids) {
4132 std::shared_ptr<AsyncRPCOperation> operation = q->getOperationForId(id);
4133 if (!operation) {
4134 continue;
4135 }
4136 std::string state = operation->getStateAsString();
4137 if (useFilter && filter.compare(state)!=0)
4138 continue;
4139 ret.push_back(id);
4140 }
4141
4142 return ret;
4143}
This page took 0.931186 seconds and 4 git commands to generate.