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