Fix getbalance() bug
[novacoin.git] / src / rpcwallet.cpp
1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2012 The Bitcoin developers
3 // Distributed under the MIT/X11 software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
6 #include "wallet.h"
7 #include "walletdb.h"
8 #include "bitcoinrpc.h"
9 #include "init.h"
10 #include "timedata.h"
11 #include "util.h"
12 #include "ntp.h"
13 #include "base58.h"
14
15 using namespace json_spirit;
16 using namespace std;
17
18 int64_t nWalletUnlockTime;
19 static CCriticalSection cs_nWalletUnlockTime;
20
21 extern int64_t nReserveBalance;
22 extern void TxToJSON(const CTransaction& tx, const uint256& hashBlock, json_spirit::Object& entry);
23
24 string HelpRequiringPassphrase()
25 {
26     return pwalletMain->IsCrypted()
27         ? "\n\nRequires wallet passphrase to be set with walletpassphrase first"
28         : "";
29 }
30
31 void EnsureWalletIsUnlocked()
32 {
33     if (pwalletMain->IsLocked())
34         throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
35     if (fWalletUnlockMintOnly)
36         throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Wallet unlocked for block minting only.");
37 }
38
39 void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
40 {
41     int confirms = wtx.GetDepthInMainChain();
42     entry.push_back(Pair("confirmations", confirms));
43     if (wtx.IsCoinBase() || wtx.IsCoinStake())
44         entry.push_back(Pair("generated", true));
45     if (confirms)
46     {
47         entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex()));
48         entry.push_back(Pair("blockindex", wtx.nIndex));
49         entry.push_back(Pair("blocktime", (int64_t)(mapBlockIndex[wtx.hashBlock]->nTime)));
50     }
51     entry.push_back(Pair("txid", wtx.GetHash().GetHex()));
52     entry.push_back(Pair("time", (int64_t)wtx.GetTxTime()));
53     entry.push_back(Pair("timereceived", (int64_t)wtx.nTimeReceived));
54     for(const auto& item : wtx.mapValue)
55         entry.push_back(Pair(item.first, item.second));
56 }
57
58 string AccountFromValue(const Value& value)
59 {
60     auto strAccount = value.get_str();
61     if (strAccount == "*")
62         throw JSONRPCError(RPC_WALLET_INVALID_ACCOUNT_NAME, "Invalid account name");
63     return strAccount;
64 }
65
66 Value getinfo(const Array& params, bool fHelp)
67 {
68     if (fHelp || params.size() != 0)
69         throw runtime_error(
70             "getinfo\n"
71             "Returns an object containing various state info.");
72
73     proxyType proxy;
74     GetProxy(NET_IPV4, proxy);
75
76     Object obj, diff, timestamping;
77     obj.push_back(Pair("version",       FormatFullVersion()));
78     obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION));
79     obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
80     obj.push_back(Pair("balance",       ValueFromAmount(pwalletMain->GetBalance())));
81     obj.push_back(Pair("unspendable",       ValueFromAmount(pwalletMain->GetWatchOnlyBalance())));
82     obj.push_back(Pair("newmint",       ValueFromAmount(pwalletMain->GetNewMint())));
83     obj.push_back(Pair("stake",         ValueFromAmount(pwalletMain->GetStake())));
84     obj.push_back(Pair("blocks",        (int)nBestHeight));
85
86     timestamping.push_back(Pair("systemclock", GetTime()));
87     timestamping.push_back(Pair("adjustedtime", GetAdjustedTime()));
88
89     auto nNtpOffset = GetNtpOffset(),
90             nP2POffset = GetNodesOffset();
91
92     timestamping.push_back(Pair("ntpoffset", nNtpOffset != numeric_limits<int64_t>::max() ? nNtpOffset : Value::null));
93     timestamping.push_back(Pair("p2poffset", nP2POffset != numeric_limits<int64_t>::max() ? nP2POffset : Value::null));
94
95     obj.push_back(Pair("timestamping", timestamping));
96
97     obj.push_back(Pair("moneysupply",   ValueFromAmount(pindexBest->nMoneySupply)));
98     obj.push_back(Pair("connections",   (int)vNodes.size()));
99     obj.push_back(Pair("proxy",         (proxy.IsValid() ? proxy.ToStringIPPort() : string())));
100     obj.push_back(Pair("ip",            addrSeenByPeer.ToStringIP()));
101
102     diff.push_back(Pair("proof-of-work",  GetDifficulty()));
103     diff.push_back(Pair("proof-of-stake", GetDifficulty(GetLastBlockIndex(pindexBest, true))));
104     obj.push_back(Pair("difficulty",    diff));
105
106     obj.push_back(Pair("testnet",       fTestNet));
107     obj.push_back(Pair("keypoololdest", (int64_t)pwalletMain->GetOldestKeyPoolTime()));
108     obj.push_back(Pair("keypoolsize",   (int)pwalletMain->GetKeyPoolSize()));
109     obj.push_back(Pair("paytxfee",      ValueFromAmount(nTransactionFee)));
110     obj.push_back(Pair("mininput",      ValueFromAmount(nMinimumInputValue)));
111     if (pwalletMain->IsCrypted())
112         obj.push_back(Pair("unlocked_until", (int64_t)nWalletUnlockTime / 1000));
113     obj.push_back(Pair("errors",        GetWarnings("statusbar")));
114     return obj;
115 }
116
117 Value getnewaddress(const Array& params, bool fHelp)
118 {
119     if (fHelp || params.size() > 1)
120         throw runtime_error(
121             "getnewaddress [account]\n"
122             "Returns a new NovaCoin address for receiving payments.  "
123             "If [account] is specified (recommended), it is added to the address book "
124             "so payments received with the address will be credited to [account].");
125
126     // Parse the account first so we don't generate a key if there's an error
127     string strAccount;
128     if (params.size() > 0)
129         strAccount = AccountFromValue(params[0]);
130
131     if (!pwalletMain->IsLocked())
132         pwalletMain->TopUpKeyPool();
133
134     // Generate a new key that is added to wallet
135     CPubKey newKey;
136     if (!pwalletMain->GetKeyFromPool(newKey, false))
137         throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
138     CBitcoinAddress address(newKey.GetID());
139
140     pwalletMain->SetAddressBookName(address, strAccount);
141
142     return address.ToString();
143 }
144
145
146 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
147 {
148     CWalletDB walletdb(pwalletMain->strWalletFile);
149
150     CAccount account;
151     walletdb.ReadAccount(strAccount, account);
152
153     bool bKeyUsed = false;
154
155     // Check if the current key has been used
156     if (account.vchPubKey.IsValid())
157     {
158         CScript scriptPubKey;
159         scriptPubKey.SetDestination(account.vchPubKey.GetID());
160         for (auto it = pwalletMain->mapWallet.begin();
161              it != pwalletMain->mapWallet.end() && account.vchPubKey.IsValid();
162              ++it)
163         {
164             const CWalletTx& wtx = (*it).second;
165             for(const CTxOut& txout :  wtx.vout)
166                 if (txout.scriptPubKey == scriptPubKey)
167                     bKeyUsed = true;
168         }
169     }
170
171     // Generate a new key
172     if (!account.vchPubKey.IsValid() || bForceNew || bKeyUsed)
173     {
174         if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false))
175             throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
176
177         pwalletMain->SetAddressBookName(account.vchPubKey.GetID(), strAccount);
178         walletdb.WriteAccount(strAccount, account);
179     }
180
181     return CBitcoinAddress(account.vchPubKey.GetID());
182 }
183
184 Value getaccountaddress(const Array& params, bool fHelp)
185 {
186     if (fHelp || params.size() != 1)
187         throw runtime_error(
188             "getaccountaddress <account>\n"
189             "Returns the current NovaCoin address for receiving payments to this account.");
190
191     // Parse the account first so we don't generate a key if there's an error
192     auto strAccount = AccountFromValue(params[0]);
193
194     Value ret;
195
196     ret = GetAccountAddress(strAccount).ToString();
197
198     return ret;
199 }
200
201
202
203 Value setaccount(const Array& params, bool fHelp)
204 {
205     if (fHelp || params.size() < 1 || params.size() > 2)
206         throw runtime_error(
207             "setaccount <novacoinaddress> <account>\n"
208             "Sets the account associated with the given address.");
209
210     CBitcoinAddress address(params[0].get_str());
211     if (!address.IsValid())
212         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
213
214
215     string strAccount;
216     if (params.size() > 1)
217         strAccount = AccountFromValue(params[1]);
218
219     // Detect when changing the account of an address that is the 'unused current key' of another account:
220     if (pwalletMain->mapAddressBook.count(address))
221     {
222         auto strOldAccount = pwalletMain->mapAddressBook[address];
223         if (address == GetAccountAddress(strOldAccount))
224             GetAccountAddress(strOldAccount, true);
225     }
226
227     pwalletMain->SetAddressBookName(address, strAccount);
228
229     return Value::null;
230 }
231
232
233 Value getaccount(const Array& params, bool fHelp)
234 {
235     if (fHelp || params.size() != 1)
236         throw runtime_error(
237             "getaccount <novacoinaddress>\n"
238             "Returns the account associated with the given address.");
239
240     CBitcoinAddress address(params[0].get_str());
241     if (!address.IsValid())
242         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
243
244     string strAccount;
245     auto mi = pwalletMain->mapAddressBook.find(address);
246     if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
247         strAccount = (*mi).second;
248     return strAccount;
249 }
250
251
252 Value getaddressesbyaccount(const Array& params, bool fHelp)
253 {
254     if (fHelp || params.size() != 1)
255         throw runtime_error(
256             "getaddressesbyaccount <account>\n"
257             "Returns the list of addresses for the given account.");
258
259     auto strAccount = AccountFromValue(params[0]);
260
261     // Find all addresses that have the given account
262     Array ret;
263     for(const auto& item : pwalletMain->mapAddressBook)
264     {
265         const CBitcoinAddress& address = item.first;
266         const string& strName = item.second;
267         if (strName == strAccount)
268             ret.push_back(address.ToString());
269     }
270     return ret;
271 }
272
273 Value mergecoins(const Array& params, bool fHelp)
274 {
275     if (fHelp || params.size() != 3)
276         throw runtime_error(
277             "mergecoins <amount> <minvalue> <outputvalue>\n"
278             "<amount> is resulting inputs sum\n"
279             "<minvalue> is minimum value of inputs which are used in join process\n"
280             "<outputvalue> is resulting value of inputs which will be created\n"
281             "All values are real and and rounded to the nearest " + FormatMoney(nMinimumInputValue)
282             + HelpRequiringPassphrase());
283
284     if (pwalletMain->IsLocked())
285         throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
286
287     // Total amount
288     auto nAmount = AmountFromValue(params[0]);
289
290     // Min input amount
291     auto nMinValue = AmountFromValue(params[1]);
292
293     // Output amount
294     auto nOutputValue = AmountFromValue(params[2]);
295
296     if (nAmount < nMinimumInputValue)
297         throw JSONRPCError(-101, "Send amount too small");
298
299     if (nMinValue < nMinimumInputValue)
300         throw JSONRPCError(-101, "Max value too small");
301
302     if (nOutputValue < nMinimumInputValue)
303         throw JSONRPCError(-101, "Output value too small");
304
305     if (nOutputValue < nMinValue)
306         throw JSONRPCError(-101, "Output value is lower than min value");
307
308     list<uint256> listMerged;
309     if (!pwalletMain->MergeCoins(nAmount, nMinValue, nOutputValue, listMerged))
310         return Value::null;
311
312     Array mergedHashes;
313     for(const uint256 txHash :  listMerged)
314         mergedHashes.push_back(txHash.GetHex());
315
316     return mergedHashes;
317 }
318
319 Value sendtoaddress(const Array& params, bool fHelp)
320 {
321     if (fHelp || params.size() < 2 || params.size() > 4)
322         throw runtime_error(
323             "sendtoaddress <novacoinaddress> <amount> [comment] [comment-to]\n"
324             "<amount> is a real and is rounded to the nearest " + FormatMoney(nMinimumInputValue)
325             + HelpRequiringPassphrase());
326
327     // Parse address
328     CScript scriptPubKey;
329     auto strAddress = params[0].get_str();
330
331     CBitcoinAddress address(strAddress);
332     if (address.IsValid())
333         scriptPubKey.SetAddress(address);
334     else
335         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
336
337     // Amount
338     auto nAmount = AmountFromValue(params[1]);
339
340     if (nAmount < nMinimumInputValue)
341         throw JSONRPCError(-101, "Send amount too small");
342
343     // Wallet comments
344     CWalletTx wtx;
345     if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
346         wtx.mapValue["comment"] = params[2].get_str();
347     if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
348         wtx.mapValue["to"]      = params[3].get_str();
349
350     if (pwalletMain->IsLocked())
351         throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
352
353     auto strError = pwalletMain->SendMoney(scriptPubKey, nAmount, wtx);
354     if (!strError.empty())
355         throw JSONRPCError(RPC_WALLET_ERROR, strError);
356
357     return wtx.GetHash().GetHex();
358 }
359
360 Value listaddressgroupings(const Array& params, bool fHelp)
361 {
362     if (fHelp)
363         throw runtime_error(
364             "listaddressgroupings\n"
365             "Lists groups of addresses which have had their common ownership\n"
366             "made public by common use as inputs or as the resulting change\n"
367             "in past transactions");
368
369     Array jsonGroupings;
370     map<CBitcoinAddress, int64_t> balances = pwalletMain->GetAddressBalances();
371     for(auto grouping : pwalletMain->GetAddressGroupings())
372     {
373         Array jsonGrouping;
374         for(CBitcoinAddress address :  grouping)
375         {
376             Array addressInfo;
377             addressInfo.push_back(address.ToString());
378             addressInfo.push_back(ValueFromAmount(balances[address]));
379             {
380                 LOCK(pwalletMain->cs_wallet);
381                 if (pwalletMain->mapAddressBook.find(address) != pwalletMain->mapAddressBook.end())
382                     addressInfo.push_back(pwalletMain->mapAddressBook.find(address)->second);
383             }
384             jsonGrouping.push_back(addressInfo);
385         }
386         jsonGroupings.push_back(jsonGrouping);
387     }
388     return jsonGroupings;
389 }
390
391 Value signmessage(const Array& params, bool fHelp)
392 {
393     if (fHelp || params.size() != 2)
394         throw runtime_error(
395             "signmessage <novacoinaddress> <message>\n"
396             "Sign a message with the private key of an address");
397
398     EnsureWalletIsUnlocked();
399
400     auto strAddress = params[0].get_str();
401     auto strMessage = params[1].get_str();
402
403     CBitcoinAddress addr(strAddress);
404     if (!addr.IsValid())
405         throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
406
407     CKeyID keyID;
408     if (!addr.GetKeyID(keyID))
409         throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
410
411     CKey key;
412     if (!pwalletMain->GetKey(keyID, key))
413         throw JSONRPCError(RPC_WALLET_ERROR, "Private key not available");
414
415     CDataStream ss(SER_GETHASH, 0);
416     ss << strMessageMagic;
417     ss << strMessage;
418
419     vector<unsigned char> vchSig;
420     if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
421         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed");
422
423     return EncodeBase64(&vchSig[0], vchSig.size());
424 }
425
426 Value verifymessage(const Array& params, bool fHelp)
427 {
428     if (fHelp || params.size() != 3)
429         throw runtime_error(
430             "verifymessage <novacoinaddress> <signature> <message>\n"
431             "Verify a signed message");
432
433     auto strAddress  = params[0].get_str();
434     auto strSign     = params[1].get_str();
435     auto strMessage  = params[2].get_str();
436
437     CBitcoinAddress addr(strAddress);
438     if (!addr.IsValid())
439         throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
440
441     CKeyID keyID;
442     if (!addr.GetKeyID(keyID))
443         throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
444
445     bool fInvalid = false;
446     vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
447
448     if (fInvalid)
449         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Malformed base64 encoding");
450
451     CDataStream ss(SER_GETHASH, 0);
452     ss << strMessageMagic;
453     ss << strMessage;
454
455     CPubKey key;
456     if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
457         return false;
458
459     return (key.GetID() == keyID);
460 }
461
462
463 Value getreceivedbyaddress(const Array& params, bool fHelp)
464 {
465     if (fHelp || params.size() < 1 || params.size() > 2)
466         throw runtime_error(
467                 "getreceivedbyaddress <novacoinaddress> [minconf=1]\n"
468                 "Returns the total amount received by <novacoinaddress> in transactions with at least [minconf] confirmations.");
469
470     // Bitcoin address
471     auto address = CBitcoinAddress(params[0].get_str());
472     if (!address.IsValid())
473         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
474     if (!IsMine(*pwalletMain,address))
475         return 0.0;
476
477     // Minimum confirmations
478     int nMinDepth = 1;
479     if (params.size() > 1)
480         nMinDepth = params[1].get_int();
481
482     int64_t nAmount = 0;
483     for (auto it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
484     {
485         const CWalletTx& wtx = (*it).second;
486         if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
487             continue;
488         for(const CTxOut& txout :  wtx.vout)
489         {
490             CBitcoinAddress addressRet;
491             if (!ExtractAddress(*pwalletMain, txout.scriptPubKey, addressRet))
492                 continue;
493             if (addressRet == address)
494                 if (wtx.GetDepthInMainChain() >= nMinDepth)
495                     nAmount += txout.nValue;
496         }
497     }
498
499     return  ValueFromAmount(nAmount);
500 }
501
502 void GetAccountAddresses(string strAccount, set<CBitcoinAddress>& setAddress)
503 {
504     for(const auto& item : pwalletMain->mapAddressBook)
505     {
506         const CBitcoinAddress& address = item.first;
507         const string& strName = item.second;
508         if (strName == strAccount)
509             setAddress.insert(address);
510     }
511 }
512
513 Value getreceivedbyaccount(const Array& params, bool fHelp)
514 {
515     if (fHelp || params.size() < 1 || params.size() > 2)
516         throw runtime_error(
517             "getreceivedbyaccount <account> [minconf=1]\n"
518             "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
519
520     // Minimum confirmations
521     int nMinDepth = 1;
522     if (params.size() > 1)
523         nMinDepth = params[1].get_int();
524
525     // Get the set of pub keys assigned to account
526     auto strAccount = AccountFromValue(params[0]);
527     set<CBitcoinAddress> setAddress;
528     GetAccountAddresses(strAccount, setAddress);
529
530     // Tally
531     int64_t nAmount = 0;
532     for (auto it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
533     {
534         const CWalletTx& wtx = (*it).second;
535         if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
536             continue;
537
538         for(const CTxOut& txout :  wtx.vout)
539         {
540             CBitcoinAddress address;
541             if (ExtractAddress(*pwalletMain, txout.scriptPubKey, address) && IsMine(*pwalletMain, address) && setAddress.count(address))
542                 if (wtx.GetDepthInMainChain() >= nMinDepth)
543                     nAmount += txout.nValue;
544         }
545     }
546
547     return (double)nAmount / (double)COIN;
548 }
549
550
551 int64_t GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth, const isminefilter& filter)
552 {
553     int64_t nBalance = 0;
554
555     // Tally wallet transactions
556     for (auto it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
557     {
558         const CWalletTx& wtx = (*it).second;
559         if (!wtx.IsFinal())
560             continue;
561
562         int64_t nGenerated, nReceived, nSent, nFee;
563         wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee, filter);
564
565         if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
566             nBalance += nReceived;
567         nBalance += nGenerated - nSent - nFee;
568     }
569
570     // Tally internal accounting entries
571     nBalance += walletdb.GetAccountCreditDebit(strAccount);
572
573     return nBalance;
574 }
575
576 int64_t GetAccountBalance(const string& strAccount, int nMinDepth, const isminefilter& filter)
577 {
578     CWalletDB walletdb(pwalletMain->strWalletFile);
579     return GetAccountBalance(walletdb, strAccount, nMinDepth, filter);
580 }
581
582
583 Value getbalance(const Array& params, bool fHelp)
584 {
585     if (fHelp || params.size() > 3)
586         throw runtime_error(
587             "getbalance [account] [minconf=1] [watchonly=0]\n"
588             "If [account] is not specified, returns the server's total available balance.\n"
589             "If [account] is specified, returns the balance in the account.\n"
590             "if [includeWatchonly] is specified, include balance in watchonly addresses (see 'importaddress').");
591
592     if (params.size() == 0)
593         return  ValueFromAmount(pwalletMain->GetBalance());
594
595     int nMinDepth = 1;
596     if (params.size() > 1)
597         nMinDepth = params[1].get_int();
598     isminefilter filter = MINE_SPENDABLE;
599     if(params.size() > 2)
600         if(params[2].get_bool())
601             filter = filter | MINE_WATCH_ONLY;
602
603     if (params[0].get_str() == "*") {
604         // Calculate total balance a different way from GetBalance()
605         // (GetBalance() sums up all unspent TxOuts)
606         // getbalance and getbalance '*' 0 should return the same number.
607         auto nBalance = 0;
608         for (auto it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
609         {
610             const CWalletTx& wtx = (*it).second;
611             if (!wtx.IsTrusted())
612                 continue;
613
614             int64_t allGeneratedImmature, allGeneratedMature, allFee;
615             allGeneratedImmature = allGeneratedMature = allFee = 0;
616
617             string strSentAccount;
618             list<pair<CBitcoinAddress, int64_t> > listReceived;
619             list<pair<CBitcoinAddress, int64_t> > listSent;
620             wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount, filter);
621             if (wtx.GetDepthInMainChain() >= nMinDepth)
622             {
623                 for(const auto& r : listReceived)
624                     nBalance += r.second;
625             }
626             for(const auto& r : listSent)
627                 nBalance -= r.second;
628             nBalance -= allFee;
629             nBalance += allGeneratedMature;
630         }
631         return  ValueFromAmount(nBalance);
632     }
633
634     auto strAccount = AccountFromValue(params[0]);
635
636     auto nBalance = GetAccountBalance(strAccount, nMinDepth, filter);
637
638     return ValueFromAmount(nBalance);
639 }
640
641
642 Value movecmd(const Array& params, bool fHelp)
643 {
644     if (fHelp || params.size() < 3 || params.size() > 5)
645         throw runtime_error(
646             "move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
647             "Move from one account in your wallet to another.");
648
649     auto strFrom = AccountFromValue(params[0]);
650     auto strTo = AccountFromValue(params[1]);
651     auto nAmount = AmountFromValue(params[2]);
652
653     if (nAmount < nMinimumInputValue)
654         throw JSONRPCError(-101, "Send amount too small");
655
656     if (params.size() > 3)
657         // unused parameter, used to be nMinDepth, keep type-checking it though
658         (void)params[3].get_int();
659     string strComment;
660     if (params.size() > 4)
661         strComment = params[4].get_str();
662
663     CWalletDB walletdb(pwalletMain->strWalletFile);
664     if (!walletdb.TxnBegin())
665         throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
666
667     auto nNow = GetAdjustedTime();
668
669     // Debit
670     CAccountingEntry debit;
671     debit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
672     debit.strAccount = strFrom;
673     debit.nCreditDebit = -nAmount;
674     debit.nTime = nNow;
675     debit.strOtherAccount = strTo;
676     debit.strComment = strComment;
677     walletdb.WriteAccountingEntry(debit);
678
679     // Credit
680     CAccountingEntry credit;
681     credit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
682     credit.strAccount = strTo;
683     credit.nCreditDebit = nAmount;
684     credit.nTime = nNow;
685     credit.strOtherAccount = strFrom;
686     credit.strComment = strComment;
687     walletdb.WriteAccountingEntry(credit);
688
689     if (!walletdb.TxnCommit())
690         throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
691
692     return true;
693 }
694
695
696 Value sendfrom(const Array& params, bool fHelp)
697 {
698     if (fHelp || params.size() < 3 || params.size() > 6)
699         throw runtime_error(
700             "sendfrom <fromaccount> <tonovacoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
701             "<amount> is a real and is rounded to the nearest " + FormatMoney(nMinimumInputValue)
702             + HelpRequiringPassphrase());
703
704     auto strAccount = AccountFromValue(params[0]);
705
706     // Parse address
707     CScript scriptPubKey;
708
709     CBitcoinAddress address(params[1].get_str());
710     if (address.IsValid())
711         scriptPubKey.SetAddress(address);
712     else
713         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
714
715
716     auto nAmount = AmountFromValue(params[2]);
717
718     if (nAmount < nMinimumInputValue)
719         throw JSONRPCError(-101, "Send amount too small");
720
721     int nMinDepth = 1;
722     if (params.size() > 3)
723         nMinDepth = params[3].get_int();
724
725     CWalletTx wtx;
726     wtx.strFromAccount = strAccount;
727     if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
728         wtx.mapValue["comment"] = params[4].get_str();
729     if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
730         wtx.mapValue["to"]      = params[5].get_str();
731
732     EnsureWalletIsUnlocked();
733
734     // Check funds
735     auto nBalance = GetAccountBalance(strAccount, nMinDepth, MINE_SPENDABLE);
736     if (nAmount > nBalance)
737         throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
738
739     // Send
740     auto strError = pwalletMain->SendMoney(scriptPubKey, nAmount, wtx);
741     if (!strError.empty())
742         throw JSONRPCError(RPC_WALLET_ERROR, strError);
743
744     return wtx.GetHash().GetHex();
745 }
746
747
748 Value sendmany(const Array& params, bool fHelp)
749 {
750     if (fHelp || params.size() < 2 || params.size() > 4)
751         throw runtime_error(
752             "sendmany <fromaccount> '{address:amount,...}' [minconf=1] [comment]\n"
753             "amounts are double-precision floating point numbers"
754             + HelpRequiringPassphrase());
755
756     auto strAccount = AccountFromValue(params[0]);
757     auto sendTo = params[1].get_obj();
758     int nMinDepth = 1;
759     if (params.size() > 2)
760         nMinDepth = params[2].get_int();
761
762     CWalletTx wtx;
763     wtx.strFromAccount = strAccount;
764     if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
765         wtx.mapValue["comment"] = params[3].get_str();
766
767     set<CBitcoinAddress> setAddress;
768     vector<pair<CScript, int64_t> > vecSend;
769
770     int64_t totalAmount = 0;
771     for(const Pair& s :  sendTo)
772     {
773         CBitcoinAddress address(s.name_);
774         if (!address.IsValid())
775             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid NovaCoin address: ")+s.name_);
776
777         if (!address.IsPair())
778         {
779             if (setAddress.count(address))
780                 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+s.name_);
781             setAddress.insert(address);
782         }
783
784         CScript scriptPubKey;
785         scriptPubKey.SetAddress(address);
786         auto nAmount = AmountFromValue(s.value_);
787
788         if (nAmount < nMinimumInputValue)
789             throw JSONRPCError(-101, "Send amount too small");
790
791         totalAmount += nAmount;
792
793         vecSend.push_back({ scriptPubKey, nAmount });
794     }
795
796     EnsureWalletIsUnlocked();
797
798     // Check funds
799     auto nBalance = GetAccountBalance(strAccount, nMinDepth, MINE_SPENDABLE);
800     if (totalAmount > nBalance)
801         throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
802
803     // Send
804     CReserveKey keyChange(pwalletMain);
805     int64_t nFeeRequired = 0;
806     bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
807     if (!fCreated)
808     {
809         auto nTotal = pwalletMain->GetBalance(), nWatchOnly = pwalletMain->GetWatchOnlyBalance();
810         if (totalAmount + nFeeRequired > nTotal - nWatchOnly)
811             throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds");
812         throw JSONRPCError(RPC_WALLET_ERROR, "Transaction creation failed");
813     }
814     if (!pwalletMain->CommitTransaction(wtx, keyChange))
815         throw JSONRPCError(RPC_WALLET_ERROR, "Transaction commit failed");
816
817     return wtx.GetHash().GetHex();
818 }
819
820 Value addmultisigaddress(const Array& params, bool fHelp)
821 {
822     if (fHelp || params.size() < 2 || params.size() > 3)
823     {
824         string msg = "addmultisigaddress <nrequired> <'[\"key\",\"key\"]'> [account]\n"
825             "Add a nrequired-to-sign multisignature address to the wallet\"\n"
826             "each key is a NovaCoin address or hex-encoded public key\n"
827             "If [account] is specified, assign address to [account].";
828         throw runtime_error(msg);
829     }
830
831     int nRequired = params[0].get_int();
832     const Array& keys = params[1].get_array();
833     string strAccount;
834     if (params.size() > 2)
835         strAccount = AccountFromValue(params[2]);
836
837     // Gather public keys
838     if (nRequired < 1)
839         throw runtime_error("a multisignature address must require at least one key to redeem");
840     if ((int)keys.size() < nRequired)
841         throw runtime_error(
842             strprintf("not enough keys supplied "
843                       "(got %" PRIszu " keys, but need at least %d to redeem)", keys.size(), nRequired));
844     if (keys.size() > 16)
845         throw runtime_error("Number of addresses involved in the multisignature address creation > 16\nReduce the number");
846     vector<CPubKey> pubkeys;
847     pubkeys.resize(keys.size());
848     for (unsigned int i = 0; i < keys.size(); i++)
849     {
850         const auto& ks = keys[i].get_str();
851
852         // Case 1: Bitcoin address and we have full public key:
853         CBitcoinAddress address(ks);
854         if (address.IsValid())
855         {
856             CKeyID keyID;
857             if (!address.GetKeyID(keyID))
858                 throw runtime_error(
859                     strprintf("%s does not refer to a key",ks.c_str()));
860             CPubKey vchPubKey;
861             if (!pwalletMain->GetPubKey(keyID, vchPubKey))
862                 throw runtime_error(
863                     strprintf("no full public key for address %s",ks.c_str()));
864             if (!vchPubKey.IsValid())
865                 throw runtime_error(" Invalid public key: "+ks);
866             pubkeys[i] = vchPubKey;
867         }
868
869         // Case 2: hex public key
870         else if (IsHex(ks))
871         {
872             CPubKey vchPubKey(ParseHex(ks));
873             if (!vchPubKey.IsValid())
874                 throw runtime_error(" Invalid public key: "+ks);
875              pubkeys[i] = vchPubKey;
876         }
877         else
878         {
879             throw runtime_error(" Invalid public key: "+ks);
880         }
881     }
882
883     // Construct using pay-to-script-hash:
884     CScript inner;
885     inner.SetMultisig(nRequired, pubkeys);
886
887     if (inner.size() > MAX_SCRIPT_ELEMENT_SIZE)
888     throw runtime_error(
889         strprintf("redeemScript exceeds size limit: %" PRIszu " > %d", inner.size(), MAX_SCRIPT_ELEMENT_SIZE));
890
891     pwalletMain->AddCScript(inner);
892     CBitcoinAddress address{ CScriptID(inner) }; // "most vexing parse"
893
894     pwalletMain->SetAddressBookName(address, strAccount);
895     return address.ToString();
896 }
897
898 Value addredeemscript(const Array& params, bool fHelp)
899 {
900     if (fHelp || params.size() < 1 || params.size() > 2)
901     {
902         string msg = "addredeemscript <redeemScript> [account]\n"
903             "Add a P2SH address with a specified redeemScript to the wallet.\n"
904             "If [account] is specified, assign address to [account].";
905         throw runtime_error(msg);
906     }
907
908     string strAccount;
909     if (params.size() > 1)
910         strAccount = AccountFromValue(params[1]);
911
912     // Construct using pay-to-script-hash:
913     auto innerData = ParseHexV(params[0], "redeemScript");
914     CScript inner(innerData.begin(), innerData.end());
915     pwalletMain->AddCScript(inner);
916     CBitcoinAddress address{ CScriptID(inner) }; // "most vexing parse"
917
918     pwalletMain->SetAddressBookName(address, strAccount);
919     return address.ToString();
920 }
921
922 struct tallyitem
923 {
924     int64_t nAmount;
925     int nConf;
926     tallyitem()
927     {
928         nAmount = 0;
929         nConf = numeric_limits<int>::max();
930     }
931 };
932
933 Value ListReceived(const Array& params, bool fByAccounts)
934 {
935     // Minimum confirmations
936     int nMinDepth = 1;
937     if (params.size() > 0)
938         nMinDepth = params[0].get_int();
939
940     // Whether to include empty accounts
941     bool fIncludeEmpty = false;
942     if (params.size() > 1)
943         fIncludeEmpty = params[1].get_bool();
944
945     // Tally
946     map<CBitcoinAddress, tallyitem> mapTally;
947     for (const auto &wit : pwalletMain->mapWallet)
948     {
949         const auto& wtx = wit.second;
950
951         if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
952             continue;
953
954         int nDepth = wtx.GetDepthInMainChain();
955         if (nDepth < nMinDepth)
956             continue;
957
958         for(const auto& txout :  wtx.vout)
959         {
960             CTxDestination address;
961             if (!ExtractDestination(txout.scriptPubKey, address) || !IsMine(*pwalletMain, address))
962                 continue;
963
964             auto& item = mapTally[address];
965             item.nAmount += txout.nValue;
966             item.nConf = min(item.nConf, nDepth);
967         }
968     }
969
970     // Reply
971     Array ret;
972     map<string, tallyitem> mapAccountTally;
973     for(const auto& item : pwalletMain->mapAddressBook)
974     {
975         const auto& address = item.first;
976         const auto& strAccount = item.second;
977         auto it = mapTally.find(address);
978         if (it == mapTally.end() && !fIncludeEmpty)
979             continue;
980
981         int64_t nAmount = 0;
982         int nConf = numeric_limits<int>::max();
983         if (it != mapTally.end())
984         {
985             nAmount = (*it).second.nAmount;
986             nConf = (*it).second.nConf;
987         }
988
989         if (fByAccounts)
990         {
991             auto& item = mapAccountTally[strAccount];
992             item.nAmount += nAmount;
993             item.nConf = min(item.nConf, nConf);
994         }
995         else
996         {
997             Object obj;
998             obj.push_back(Pair("address",       address.ToString()));
999             obj.push_back(Pair("account",       strAccount));
1000             obj.push_back(Pair("amount",        ValueFromAmount(nAmount)));
1001             obj.push_back(Pair("confirmations", (nConf == numeric_limits<int>::max() ? 0 : nConf)));
1002             ret.push_back(obj);
1003         }
1004     }
1005
1006     if (fByAccounts)
1007     {
1008         for (const auto &acc : mapAccountTally)
1009         {
1010             auto nAmount = acc.second.nAmount;
1011             int nConf = acc.second.nConf;
1012             Object obj;
1013             obj.push_back(Pair("account",       acc.first));
1014             obj.push_back(Pair("amount",        ValueFromAmount(nAmount)));
1015             obj.push_back(Pair("confirmations", (nConf == numeric_limits<int>::max() ? 0 : nConf)));
1016             ret.push_back(obj);
1017         }
1018     }
1019
1020     return ret;
1021 }
1022
1023 Value listreceivedbyaddress(const Array& params, bool fHelp)
1024 {
1025     if (fHelp || params.size() > 2)
1026         throw runtime_error(
1027             "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
1028             "[minconf] is the minimum number of confirmations before payments are included.\n"
1029             "[includeempty] whether to include addresses that haven't received any payments.\n"
1030             "Returns an array of objects containing:\n"
1031             "  \"address\" : receiving address\n"
1032             "  \"account\" : the account of the receiving address\n"
1033             "  \"amount\" : total amount received by the address\n"
1034             "  \"confirmations\" : number of confirmations of the most recent transaction included");
1035
1036     return ListReceived(params, false);
1037 }
1038
1039 Value listreceivedbyaccount(const Array& params, bool fHelp)
1040 {
1041     if (fHelp || params.size() > 2)
1042         throw runtime_error(
1043             "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
1044             "[minconf] is the minimum number of confirmations before payments are included.\n"
1045             "[includeempty] whether to include accounts that haven't received any payments.\n"
1046             "Returns an array of objects containing:\n"
1047             "  \"account\" : the account of the receiving addresses\n"
1048             "  \"amount\" : total amount received by addresses with this account\n"
1049             "  \"confirmations\" : number of confirmations of the most recent transaction included");
1050
1051     return ListReceived(params, true);
1052 }
1053
1054 static void MaybePushAddress(Object & entry, const CBitcoinAddress &dest)
1055 {
1056     entry.push_back(Pair("address", dest.ToString()));
1057 }
1058
1059 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret, const isminefilter& filter)
1060 {
1061     int64_t nGeneratedImmature, nGeneratedMature, nFee;
1062     string strSentAccount;
1063     list<pair<CBitcoinAddress, int64_t> > listReceived;
1064     list<pair<CBitcoinAddress, int64_t> > listSent;
1065
1066     wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount, filter);
1067
1068     bool fAllAccounts = (strAccount == string("*"));
1069     bool involvesWatchonly = wtx.IsFromMe(MINE_WATCH_ONLY);
1070
1071     // Generated blocks assigned to account ""
1072     if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount.empty()))
1073     {
1074         Object entry;
1075         entry.push_back(Pair("account", string("")));
1076         if (nGeneratedImmature)
1077         {
1078             entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
1079             entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
1080         }
1081         else
1082         {
1083             entry.push_back(Pair("category", "generate"));
1084             entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
1085         }
1086         if (fLong)
1087             WalletTxToJSON(wtx, entry);
1088         ret.push_back(entry);
1089     }
1090
1091     // Sent
1092     if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1093     {
1094         for(const auto& s : listSent)
1095         {
1096             Object entry;
1097             entry.push_back(Pair("account", strSentAccount));
1098             if(involvesWatchonly || (::IsMine(*pwalletMain, s.first) & MINE_WATCH_ONLY))
1099                 entry.push_back(Pair("involvesWatchonly", true));
1100             MaybePushAddress(entry, s.first);
1101
1102             if (wtx.GetDepthInMainChain() < 0) {
1103                 entry.push_back(Pair("category", "conflicted"));
1104             } else {
1105                 entry.push_back(Pair("category", "send"));
1106             }
1107
1108             entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1109             entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1110             if (fLong)
1111                 WalletTxToJSON(wtx, entry);
1112             ret.push_back(entry);
1113         }
1114     }
1115
1116     // Received
1117     if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1118     {
1119         for(const auto& r : listReceived)
1120         {
1121             string account;
1122             if (pwalletMain->mapAddressBook.count(r.first))
1123                 account = pwalletMain->mapAddressBook[r.first];
1124             if (fAllAccounts || (account == strAccount))
1125             {
1126                 Object entry;
1127                 entry.push_back(Pair("account", account));
1128                 if(involvesWatchonly || (::IsMine(*pwalletMain, r.first) & MINE_WATCH_ONLY))
1129                     entry.push_back(Pair("involvesWatchonly", true));
1130                 MaybePushAddress(entry, r.first);
1131                 if (wtx.IsCoinBase())
1132                 {
1133                     if (wtx.GetDepthInMainChain() < 1)
1134                         entry.push_back(Pair("category", "orphan"));
1135                     else if (wtx.GetBlocksToMaturity() > 0)
1136                         entry.push_back(Pair("category", "immature"));
1137                     else
1138                         entry.push_back(Pair("category", "generate"));
1139                 }
1140                 else
1141                     entry.push_back(Pair("category", "receive"));
1142                 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1143                 if (fLong)
1144                     WalletTxToJSON(wtx, entry);
1145                 ret.push_back(entry);
1146             }
1147         }
1148     }
1149 }
1150
1151 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1152 {
1153     bool fAllAccounts = (strAccount == string("*"));
1154
1155     if (fAllAccounts || acentry.strAccount == strAccount)
1156     {
1157         Object entry;
1158         entry.push_back(Pair("account", acentry.strAccount));
1159         entry.push_back(Pair("category", "move"));
1160         entry.push_back(Pair("time", (int64_t)acentry.nTime));
1161         entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1162         entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1163         entry.push_back(Pair("comment", acentry.strComment));
1164         ret.push_back(entry);
1165     }
1166 }
1167
1168 Value listtransactions(const Array& params, bool fHelp)
1169 {
1170     if (fHelp || params.size() > 3)
1171         throw runtime_error(
1172             "listtransactions [account] [count=10] [from=0]\n"
1173             "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1174
1175     string strAccount = "*";
1176     if (params.size() > 0)
1177         strAccount = params[0].get_str();
1178     int nCount = 10;
1179     if (params.size() > 1)
1180         nCount = params[1].get_int();
1181     int nFrom = 0;
1182     if (params.size() > 2)
1183         nFrom = params[2].get_int();
1184
1185     isminefilter filter = MINE_SPENDABLE;
1186     if(params.size() > 3)
1187         if(params[3].get_bool())
1188             filter = filter | MINE_WATCH_ONLY;
1189
1190     if (nCount < 0)
1191         throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count");
1192     if (nFrom < 0)
1193         throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative from");
1194
1195     Array ret;
1196
1197     list<CAccountingEntry> acentries;
1198     auto txOrdered = pwalletMain->OrderedTxItems(acentries, strAccount);
1199
1200     // iterate backwards until we have nCount items to return:
1201     for (auto it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
1202     {
1203         CWalletTx *const pwtx = (*it).second.first;
1204         if (pwtx != 0)
1205             ListTransactions(*pwtx, strAccount, 0, true, ret, filter);
1206         CAccountingEntry *const pacentry = (*it).second.second;
1207         if (pacentry != 0)
1208             AcentryToJSON(*pacentry, strAccount, ret);
1209
1210         if ((int)ret.size() >= (nCount+nFrom)) break;
1211     }
1212     // ret is newest to oldest
1213
1214     if (nFrom > (int)ret.size())
1215         nFrom = ret.size();
1216     if ((nFrom + nCount) > (int)ret.size())
1217         nCount = ret.size() - nFrom;
1218     auto first = ret.begin();
1219     advance(first, nFrom);
1220     auto last = ret.begin();
1221     advance(last, nFrom+nCount);
1222
1223     if (last != ret.end()) ret.erase(last, ret.end());
1224     if (first != ret.begin()) ret.erase(ret.begin(), first);
1225
1226     reverse(ret.begin(), ret.end()); // Return oldest to newest
1227
1228     return ret;
1229 }
1230
1231 Value listaccounts(const Array& params, bool fHelp)
1232 {
1233     if (fHelp || params.size() > 1)
1234         throw runtime_error(
1235             "listaccounts [minconf=1]\n"
1236             "Returns Object that has account names as keys, account balances as values.");
1237
1238     int nMinDepth = 1;
1239     if (params.size() > 0)
1240         nMinDepth = params[0].get_int();
1241
1242     isminefilter includeWatchonly = MINE_SPENDABLE;
1243     if(params.size() > 1)
1244         if(params[1].get_bool())
1245             includeWatchonly = includeWatchonly | MINE_WATCH_ONLY;
1246
1247
1248     map<string, int64_t> mapAccountBalances;
1249     for(const auto& entry : pwalletMain->mapAddressBook) {
1250         if (IsMine(*pwalletMain, entry.first)) // This address belongs to me
1251             mapAccountBalances[entry.second] = 0;
1252     }
1253
1254     for (auto it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1255     {
1256         const CWalletTx& wtx = (*it).second;
1257         int64_t nGeneratedImmature, nGeneratedMature, nFee;
1258         string strSentAccount;
1259         list<pair<CBitcoinAddress, int64_t> > listReceived;
1260         list<pair<CBitcoinAddress, int64_t> > listSent;
1261         wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount, includeWatchonly);
1262         mapAccountBalances[strSentAccount] -= nFee;
1263         for(const auto& s : listSent)
1264             mapAccountBalances[strSentAccount] -= s.second;
1265         if (wtx.GetDepthInMainChain() >= nMinDepth)
1266         {
1267             mapAccountBalances[""] += nGeneratedMature;
1268             for(const auto& r : listReceived)
1269                 if (pwalletMain->mapAddressBook.count(r.first))
1270                     mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1271                 else
1272                     mapAccountBalances[""] += r.second;
1273         }
1274     }
1275
1276     list<CAccountingEntry> acentries;
1277     CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1278     for(const auto& entry : acentries)
1279         mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1280
1281     Object ret;
1282     for(const auto& accountBalance : mapAccountBalances) {
1283         ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1284     }
1285     return ret;
1286 }
1287
1288 Value listsinceblock(const Array& params, bool fHelp)
1289 {
1290     if (fHelp)
1291         throw runtime_error(
1292             "listsinceblock [blockhash] [target-confirmations]\n"
1293             "Get all transactions in blocks since block [blockhash], or all transactions if omitted");
1294
1295     CBlockIndex *pindex = NULL;
1296     int target_confirms = 1;
1297     isminefilter filter = MINE_SPENDABLE;
1298
1299     if (params.size() > 0)
1300     {
1301         uint256 blockId = 0;
1302
1303         blockId.SetHex(params[0].get_str());
1304         pindex = CBlockLocator(blockId).GetBlockIndex();
1305     }
1306
1307     if (params.size() > 1)
1308     {
1309         target_confirms = params[1].get_int();
1310
1311         if (target_confirms < 1)
1312             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter");
1313     }
1314
1315     if(params.size() > 2)
1316         if(params[2].get_bool())
1317             filter = filter | MINE_WATCH_ONLY;
1318
1319     int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
1320
1321     Array transactions;
1322
1323     for (auto it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1324     {
1325         auto tx = (*it).second;
1326
1327         if (depth == -1 || tx.GetDepthInMainChain() < depth)
1328             ListTransactions(tx, "*", 0, true, transactions, filter);
1329     }
1330
1331     uint256 lastblock;
1332
1333     if (target_confirms == 1)
1334     {
1335         lastblock = hashBestChain;
1336     }
1337     else
1338     {
1339         int target_height = pindexBest->nHeight + 1 - target_confirms;
1340
1341         CBlockIndex *block;
1342         for (block = pindexBest;
1343              block && block->nHeight > target_height;
1344              block = block->pprev)  { }
1345
1346         lastblock = block ? block->GetBlockHash() : 0;
1347     }
1348
1349     Object ret;
1350     ret.push_back(Pair("transactions", transactions));
1351     ret.push_back(Pair("lastblock", lastblock.GetHex()));
1352
1353     return ret;
1354 }
1355
1356 Value gettransaction(const Array& params, bool fHelp)
1357 {
1358     if (fHelp || params.size() != 1)
1359         throw runtime_error(
1360             "gettransaction <txid>\n"
1361             "Get detailed information about <txid>");
1362
1363     uint256 hash;
1364     hash.SetHex(params[0].get_str());
1365
1366     isminefilter filter = MINE_SPENDABLE;
1367     if(params.size() > 1)
1368         if(params[1].get_bool())
1369             filter = filter | MINE_WATCH_ONLY;
1370
1371     Object entry;
1372
1373     if (pwalletMain->mapWallet.count(hash))
1374     {
1375         const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1376
1377         TxToJSON(wtx, 0, entry);
1378
1379         auto nCredit = wtx.GetCredit(filter);
1380         auto nDebit = wtx.GetDebit(filter);
1381         auto nNet = nCredit - nDebit;
1382         auto nFee = (wtx.IsFromMe(filter) ? wtx.GetValueOut() - nDebit : 0);
1383
1384         entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1385         if (wtx.IsFromMe(filter))
1386             entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1387
1388         WalletTxToJSON(wtx, entry);
1389
1390         Array details;
1391         ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details, filter);
1392         entry.push_back(Pair("details", details));
1393     }
1394     else
1395     {
1396         CTransaction tx;
1397         uint256 hashBlock = 0;
1398         if (GetTransaction(hash, tx, hashBlock))
1399         {
1400             TxToJSON(tx, 0, entry);
1401             if (hashBlock == 0)
1402                 entry.push_back(Pair("confirmations", 0));
1403             else
1404             {
1405                 entry.push_back(Pair("blockhash", hashBlock.GetHex()));
1406                 auto mi = mapBlockIndex.find(hashBlock);
1407                 if (mi != mapBlockIndex.end() && (*mi).second)
1408                 {
1409                     auto pindex = (*mi).second;
1410                     if (pindex->IsInMainChain())
1411                         entry.push_back(Pair("confirmations", 1 + nBestHeight - pindex->nHeight));
1412                     else
1413                         entry.push_back(Pair("confirmations", 0));
1414                 }
1415             }
1416         }
1417         else
1418             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction");
1419     }
1420
1421     return entry;
1422 }
1423
1424
1425 Value backupwallet(const Array& params, bool fHelp)
1426 {
1427     if (fHelp || params.size() != 1)
1428         throw runtime_error(
1429             "backupwallet <destination>\n"
1430             "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1431
1432     auto strDest = params[0].get_str();
1433     if (!BackupWallet(*pwalletMain, strDest))
1434         throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!");
1435
1436     return Value::null;
1437 }
1438
1439
1440 Value keypoolrefill(const Array& params, bool fHelp)
1441 {
1442     if (fHelp || params.size() > 1)
1443         throw runtime_error(
1444             "keypoolrefill [new-size]\n"
1445             "Fills the keypool.\n"
1446             "IMPORTANT: Any previous backups you have made of your wallet file "
1447             "should be replaced with the newly generated one."
1448             + HelpRequiringPassphrase());
1449
1450     unsigned int nSize = max<unsigned int>(GetArgUInt("-keypool", 100), 0);
1451     if (params.size() > 0) {
1452         if (params[0].get_int() < 0)
1453             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size");
1454         nSize = (unsigned int) params[0].get_int();
1455     }
1456
1457     EnsureWalletIsUnlocked();
1458
1459     pwalletMain->TopUpKeyPool(nSize);
1460
1461     if (pwalletMain->GetKeyPoolSize() < nSize)
1462         throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool.");
1463
1464     return Value::null;
1465 }
1466
1467 Value keypoolreset(const Array& params, bool fHelp)
1468 {
1469     if (fHelp || params.size() > 1)
1470         throw runtime_error(
1471             "keypoolreset [new-size]\n"
1472             "Resets the keypool.\n"
1473             "IMPORTANT: Any previous backups you have made of your wallet file "
1474             "should be replaced with the newly generated one."
1475             + HelpRequiringPassphrase());
1476
1477     unsigned int nSize = max<unsigned int>(GetArgUInt("-keypool", 100), 0);
1478     if (params.size() > 0) {
1479         if (params[0].get_int() < 0)
1480             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size");
1481         nSize = (unsigned int) params[0].get_int();
1482     }
1483
1484     EnsureWalletIsUnlocked();
1485
1486     pwalletMain->NewKeyPool(nSize);
1487
1488     if (pwalletMain->GetKeyPoolSize() < nSize)
1489         throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool.");
1490
1491     return Value::null;
1492 }
1493
1494
1495 void ThreadTopUpKeyPool(void* parg)
1496 {
1497     // Make this thread recognisable as the key-topping-up thread
1498     RenameThread("novacoin-key-top");
1499
1500     pwalletMain->TopUpKeyPool();
1501 }
1502
1503 void ThreadCleanWalletPassphrase(void* parg)
1504 {
1505     // Make this thread recognisable as the wallet relocking thread
1506     RenameThread("novacoin-lock-wa");
1507
1508     auto nMyWakeTime = GetTimeMillis() + *((int64_t*)parg) * 1000;
1509
1510     ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1511
1512     if (nWalletUnlockTime == 0)
1513     {
1514         nWalletUnlockTime = nMyWakeTime;
1515
1516         for ( ; ; )
1517         {
1518             if (nWalletUnlockTime==0)
1519                 break;
1520             auto nToSleep = nWalletUnlockTime - GetTimeMillis();
1521             if (nToSleep <= 0)
1522                 break;
1523
1524             LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1525             Sleep(nToSleep);
1526             ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1527
1528         };
1529
1530         if (nWalletUnlockTime)
1531         {
1532             nWalletUnlockTime = 0;
1533             pwalletMain->Lock();
1534         }
1535     }
1536     else
1537     {
1538         if (nWalletUnlockTime < nMyWakeTime)
1539             nWalletUnlockTime = nMyWakeTime;
1540     }
1541
1542     LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1543
1544     delete (int64_t*)parg;
1545 }
1546
1547 Value walletpassphrase(const Array& params, bool fHelp)
1548 {
1549     if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 3))
1550         throw runtime_error(
1551             "walletpassphrase <passphrase> <timeout> [mintonly]\n"
1552             "Stores the wallet decryption key in memory for <timeout> seconds.\n"
1553             "mintonly is optional true/false allowing only block minting.");
1554     if (fHelp)
1555         return true;
1556     if (!pwalletMain->IsCrypted())
1557         throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1558
1559     if (!pwalletMain->IsLocked())
1560         throw JSONRPCError(RPC_WALLET_ALREADY_UNLOCKED, "Error: Wallet is already unlocked, use walletlock first if need to change unlock settings.");
1561     // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1562     SecureString strWalletPass;
1563     strWalletPass.reserve(100);
1564     // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1565     // Alternately, find a way to make params[0] mlock()'d to begin with.
1566     strWalletPass = params[0].get_str().c_str();
1567
1568     if (strWalletPass.length() > 0)
1569     {
1570         if (!pwalletMain->Unlock(strWalletPass))
1571             throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
1572     }
1573     else
1574         throw runtime_error(
1575             "walletpassphrase <passphrase> <timeout>\n"
1576             "Stores the wallet decryption key in memory for <timeout> seconds.");
1577
1578     NewThread(ThreadTopUpKeyPool, NULL);
1579     int64_t* pnSleepTime = new int64_t(params[1].get_int64());
1580     NewThread(ThreadCleanWalletPassphrase, pnSleepTime);
1581
1582     // ppcoin: if user OS account compromised prevent trivial sendmoney commands
1583     if (params.size() > 2)
1584         fWalletUnlockMintOnly = params[2].get_bool();
1585     else
1586         fWalletUnlockMintOnly = false;
1587
1588     return Value::null;
1589 }
1590
1591
1592 Value walletpassphrasechange(const Array& params, bool fHelp)
1593 {
1594     if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1595         throw runtime_error(
1596             "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1597             "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1598     if (fHelp)
1599         return true;
1600     if (!pwalletMain->IsCrypted())
1601         throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1602
1603     // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1604     // Alternately, find a way to make params[0] mlock()'d to begin with.
1605     SecureString strOldWalletPass;
1606     strOldWalletPass.reserve(100);
1607     strOldWalletPass = params[0].get_str().c_str();
1608
1609     SecureString strNewWalletPass;
1610     strNewWalletPass.reserve(100);
1611     strNewWalletPass = params[1].get_str().c_str();
1612
1613     if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1614         throw runtime_error(
1615             "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1616             "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1617
1618     if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1619         throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
1620
1621     return Value::null;
1622 }
1623
1624
1625 Value walletlock(const Array& params, bool fHelp)
1626 {
1627     if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1628         throw runtime_error(
1629             "walletlock\n"
1630             "Removes the wallet encryption key from memory, locking the wallet.\n"
1631             "After calling this method, you will need to call walletpassphrase again\n"
1632             "before being able to call any methods which require the wallet to be unlocked.");
1633     if (fHelp)
1634         return true;
1635     if (!pwalletMain->IsCrypted())
1636         throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletlock was called.");
1637
1638     {
1639         LOCK(cs_nWalletUnlockTime);
1640         pwalletMain->Lock();
1641         nWalletUnlockTime = 0;
1642     }
1643
1644     return Value::null;
1645 }
1646
1647
1648 Value encryptwallet(const Array& params, bool fHelp)
1649 {
1650     if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1651         throw runtime_error(
1652             "encryptwallet <passphrase>\n"
1653             "Encrypts the wallet with <passphrase>.");
1654     if (fHelp)
1655         return true;
1656     if (pwalletMain->IsCrypted())
1657         throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an encrypted wallet, but encryptwallet was called.");
1658
1659     // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1660     // Alternately, find a way to make params[0] mlock()'d to begin with.
1661     SecureString strWalletPass;
1662     strWalletPass.reserve(100);
1663     strWalletPass = params[0].get_str().c_str();
1664
1665     if (strWalletPass.length() < 1)
1666         throw runtime_error(
1667             "encryptwallet <passphrase>\n"
1668             "Encrypts the wallet with <passphrase>.");
1669
1670     if (!pwalletMain->EncryptWallet(strWalletPass))
1671         throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: Failed to encrypt the wallet.");
1672
1673     // BDB seems to have a bad habit of writing old data into
1674     // slack space in .dat files; that is bad if the old data is
1675     // unencrypted private keys. So:
1676     StartShutdown();
1677     return "wallet encrypted; NovaCoin server stopping, restart to run with encrypted wallet.  The keypool has been flushed, you need to make a new backup.";
1678 }
1679
1680 class DescribeAddressVisitor : public boost::static_visitor<Object>
1681 {
1682 private:
1683     isminetype mine;
1684 public:
1685     DescribeAddressVisitor(isminetype mineIn) : mine(mineIn) {}
1686
1687     Object operator()(const CNoDestination &dest) const { return Object(); }
1688     Object operator()(const CKeyID &keyID) const {
1689         Object obj;
1690         CPubKey vchPubKey;
1691         pwalletMain->GetPubKey(keyID, vchPubKey);
1692         obj.push_back(Pair("isscript", false));
1693         if (mine == MINE_SPENDABLE) {
1694             pwalletMain->GetPubKey(keyID, vchPubKey);
1695             obj.push_back(Pair("pubkey", HexStr(vchPubKey.begin(), vchPubKey.end())));
1696             obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed()));
1697         }
1698         return obj;
1699     }
1700
1701     Object operator()(const CScriptID &scriptID) const {
1702         Object obj;
1703         obj.push_back(Pair("isscript", true));
1704         if (mine == MINE_SPENDABLE) {
1705             CScript subscript;
1706             pwalletMain->GetCScript(scriptID, subscript);
1707             vector<CTxDestination> addresses;
1708             txnouttype whichType;
1709             int nRequired;
1710             ExtractDestinations(subscript, whichType, addresses, nRequired);
1711             obj.push_back(Pair("script", GetTxnOutputType(whichType)));
1712             obj.push_back(Pair("hex", HexStr(subscript.begin(), subscript.end())));
1713             Array a;
1714             for(const auto& addr : addresses)
1715                 a.push_back(CBitcoinAddress(addr).ToString());
1716             obj.push_back(Pair("addresses", a));
1717             if (whichType == TX_MULTISIG)
1718                 obj.push_back(Pair("sigsrequired", nRequired));
1719         }
1720         return obj;
1721     }
1722 };
1723
1724 Value validateaddress(const Array& params, bool fHelp)
1725 {
1726     if (fHelp || params.size() != 1)
1727         throw runtime_error(
1728             "validateaddress <novacoinaddress>\n"
1729             "Return information about <novacoinaddress>.");
1730
1731     CBitcoinAddress address(params[0].get_str());
1732     bool isValid = address.IsValid();
1733
1734     Object ret;
1735     ret.push_back(Pair("isvalid", isValid));
1736     if (isValid)
1737     {
1738         if (address.IsPair())
1739         {
1740             CMalleablePubKey mpk;
1741             mpk.setvch(address.GetData());
1742             ret.push_back(Pair("ispair", true));
1743
1744             CMalleableKeyView view;
1745             bool isMine = pwalletMain->GetMalleableView(mpk, view);
1746             ret.push_back(Pair("ismine", isMine));
1747             ret.push_back(Pair("PubkeyPair", mpk.ToString()));
1748
1749             if (isMine)
1750                 ret.push_back(Pair("KeyView", view.ToString()));
1751         }
1752         else
1753         {
1754             auto currentAddress = address.ToString();
1755             auto dest = address.Get();
1756             ret.push_back(Pair("address", currentAddress));
1757             auto mine = IsMine(*pwalletMain, address);
1758             ret.push_back(Pair("ismine", mine != MINE_NO));
1759             if (mine != MINE_NO) {
1760                 ret.push_back(Pair("watchonly", mine == MINE_WATCH_ONLY));
1761                 Object detail = boost::apply_visitor(DescribeAddressVisitor(mine), dest);
1762                 ret.insert(ret.end(), detail.begin(), detail.end());
1763             }
1764             if (pwalletMain->mapAddressBook.count(address))
1765                 ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
1766         }
1767     }
1768     return ret;
1769 }
1770
1771 // ppcoin: reserve balance from being staked for network protection
1772 Value reservebalance(const Array& params, bool fHelp)
1773 {
1774     if (fHelp || params.size() > 2)
1775         throw runtime_error(
1776             "reservebalance [<reserve> [amount]]\n"
1777             "<reserve> is true or false to turn balance reserve on or off.\n"
1778             "<amount> is a real and rounded to cent.\n"
1779             "Set reserve amount not participating in network protection.\n"
1780             "If no parameters provided current setting is printed.\n");
1781
1782     if (params.size() > 0)
1783     {
1784         bool fReserve = params[0].get_bool();
1785         if (fReserve)
1786         {
1787             if (params.size() == 1)
1788                 throw runtime_error("must provide amount to reserve balance.\n");
1789             auto nAmount = AmountFromValue(params[1]);
1790             nAmount = (nAmount / CENT) * CENT;  // round to cent
1791             if (nAmount < 0)
1792                 throw runtime_error("amount cannot be negative.\n");
1793             mapArgs["-reservebalance"] = FormatMoney(nAmount);
1794         }
1795         else
1796         {
1797             if (params.size() > 1)
1798                 throw runtime_error("cannot specify amount to turn off reserve.\n");
1799             mapArgs["-reservebalance"] = "0";
1800         }
1801     }
1802
1803     Object result;
1804     if (mapArgs.count("-reservebalance") && !ParseMoney(mapArgs["-reservebalance"], nReserveBalance))
1805         throw runtime_error("invalid reserve balance amount\n");
1806     result.push_back(Pair("reserve", (nReserveBalance > 0)));
1807     result.push_back(Pair("amount", ValueFromAmount(nReserveBalance)));
1808     return result;
1809 }
1810
1811
1812 // ppcoin: check wallet integrity
1813 Value checkwallet(const Array& params, bool fHelp)
1814 {
1815     if (fHelp || params.size() > 0)
1816         throw runtime_error(
1817             "checkwallet\n"
1818             "Check wallet for integrity.\n");
1819
1820     int nMismatchSpent;
1821     int64_t nBalanceInQuestion;
1822     pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion, true);
1823     Object result;
1824     if (nMismatchSpent == 0)
1825         result.push_back(Pair("wallet check passed", true));
1826     else
1827     {
1828         result.push_back(Pair("mismatched spent coins", nMismatchSpent));
1829         result.push_back(Pair("amount in question", ValueFromAmount(nBalanceInQuestion)));
1830     }
1831     return result;
1832 }
1833
1834
1835 // ppcoin: repair wallet
1836 Value repairwallet(const Array& params, bool fHelp)
1837 {
1838     if (fHelp || params.size() > 0)
1839         throw runtime_error(
1840             "repairwallet\n"
1841             "Repair wallet if checkwallet reports any problem.\n");
1842
1843     int nMismatchSpent;
1844     int64_t nBalanceInQuestion;
1845     pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion);
1846     Object result;
1847     if (nMismatchSpent == 0)
1848         result.push_back(Pair("wallet check passed", true));
1849     else
1850     {
1851         result.push_back(Pair("mismatched spent coins", nMismatchSpent));
1852         result.push_back(Pair("amount affected by repair", ValueFromAmount(nBalanceInQuestion)));
1853     }
1854     return result;
1855 }
1856
1857 // NovaCoin: resend unconfirmed wallet transactions
1858 Value resendtx(const Array& params, bool fHelp)
1859 {
1860     if (fHelp || params.size() > 1)
1861         throw runtime_error(
1862             "resendtx\n"
1863             "Re-send unconfirmed transactions.\n"
1864         );
1865
1866     ResendWalletTransactions(true);
1867
1868     return Value::null;
1869 }
1870
1871 Value resendwallettransactions(const Array& params, bool fHelp)
1872 {
1873     if (fHelp || params.size() != 0)
1874         throw runtime_error(
1875             "resendwallettransactions\n"
1876             "Immediately re-broadcast unconfirmed wallet transactions to all peers.\n"
1877             "Intended only for testing; the wallet code periodically re-broadcasts\n"
1878             "automatically.\n"
1879             "Returns array of transaction ids that were re-broadcast.\n"
1880             );
1881
1882     LOCK2(cs_main, pwalletMain->cs_wallet);
1883
1884     auto txids = pwalletMain->ResendWalletTransactionsBefore(GetTime());
1885     Array result;
1886     for(const auto& txid :  txids)
1887     {
1888         result.push_back(txid.ToString());
1889     }
1890     return result;
1891 }
1892
1893
1894 // Make a public-private key pair
1895 Value makekeypair(const Array& params, bool fHelp)
1896 {
1897     if (fHelp || params.size() > 0)
1898         throw runtime_error(
1899             "makekeypair\n"
1900             "Make a public/private key pair.\n");
1901
1902     string strPrefix = "";
1903     if (params.size() > 0)
1904         strPrefix = params[0].get_str();
1905
1906     CKey key;
1907     key.MakeNewKey(true);
1908
1909     auto vchPrivKey = key.GetPrivKey();
1910     Object result;
1911     result.push_back(Pair("PrivateKey", HexStr<CPrivKey::iterator>(vchPrivKey.begin(), vchPrivKey.end())));
1912
1913     bool fCompressed;
1914     auto vchSecret = key.GetSecret(fCompressed);
1915     auto vchPubKey = key.GetPubKey();
1916     result.push_back(Pair("Secret", HexStr<CSecret::iterator>(vchSecret.begin(), vchSecret.end())));
1917     result.push_back(Pair("PublicKey", HexStr(vchPubKey.begin(), vchPubKey.end())));
1918     return result;
1919 }
1920
1921 Value newmalleablekey(const Array& params, bool fHelp)
1922 {
1923     if (fHelp || params.size() > 1)
1924         throw runtime_error(
1925             "newmalleablekey\n"
1926             "Make a malleable public/private key pair.\n");
1927
1928     // Parse the account first so we don't generate a key if there's an error
1929     string strAccount;
1930     if (params.size() > 0)
1931         strAccount = AccountFromValue(params[0]);
1932
1933     auto keyView = pwalletMain->GenerateNewMalleableKey();
1934
1935     CMalleableKey mKey;
1936     if (!pwalletMain->GetMalleableKey(keyView, mKey))
1937         throw runtime_error("Unable to generate new malleable key");
1938
1939     auto mPubKey = mKey.GetMalleablePubKey();
1940     CBitcoinAddress address(mPubKey);
1941
1942     pwalletMain->SetAddressBookName(address, strAccount);
1943
1944     Object result;
1945     result.push_back(Pair("PublicPair", mPubKey.ToString()));
1946     result.push_back(Pair("PublicBytes", HexStr(mPubKey.Raw())));
1947     result.push_back(Pair("Address", address.ToString()));
1948     result.push_back(Pair("KeyView", keyView.ToString()));
1949
1950     return result;
1951 }
1952
1953 Value adjustmalleablekey(const Array& params, bool fHelp)
1954 {
1955     if (fHelp || params.size() != 3)
1956         throw runtime_error(
1957             "adjustmalleablekey <Malleable key data> <Public key variant data> <R data>\n"
1958             "Calculate new private key using provided malleable key, public key and R data.\n");
1959
1960     CMalleableKey malleableKey;
1961     malleableKey.SetString(params[0].get_str());
1962
1963     CKey privKeyVariant;
1964     auto vchPubKeyVariant = CPubKey(ParseHex(params[1].get_str()));
1965
1966     CPubKey R(ParseHex(params[2].get_str()));
1967
1968     if (!malleableKey.CheckKeyVariant(R,vchPubKeyVariant, privKeyVariant)) {
1969         throw runtime_error("Unable to calculate the private key");
1970     }
1971
1972     Object result;
1973     bool fCompressed;
1974     auto vchPrivKeyVariant = privKeyVariant.GetSecret(fCompressed);
1975
1976     result.push_back(Pair("PrivateKey", CBitcoinSecret(vchPrivKeyVariant, fCompressed).ToString()));
1977
1978     return result;
1979 }
1980
1981 Value adjustmalleablepubkey(const Array& params, bool fHelp)
1982 {
1983     if (fHelp || params.size() > 2 || params.size() == 0)
1984         throw runtime_error(
1985             "adjustmalleablepubkey <Malleable address, key view or public key pair>\n"
1986             "Calculate new public key using provided data.\n");
1987
1988     auto strData = params[0].get_str();
1989     CMalleablePubKey malleablePubKey;
1990
1991     do
1992     {
1993         CBitcoinAddress addr(strData);
1994         if (addr.IsValid() && addr.IsPair())
1995         {
1996             // Initialize malleable pubkey with address data
1997             malleablePubKey = CMalleablePubKey(addr.GetData());
1998             break;
1999         }
2000         CMalleableKeyView viewTmp(strData);
2001         if (viewTmp.IsValid())
2002         {
2003             // Shazaam, we have a valid key view here.
2004             malleablePubKey = viewTmp.GetMalleablePubKey();
2005             break;
2006         }
2007         if (malleablePubKey.SetString(strData))
2008             break; // A valid public key pair
2009
2010         throw runtime_error("Though your data seems a valid Base58 string, we were unable to recognize it.");
2011     }
2012     while(false);
2013
2014     CPubKey R, vchPubKeyVariant;
2015     malleablePubKey.GetVariant(R, vchPubKeyVariant);
2016
2017     Object result;
2018     result.push_back(Pair("R", HexStr(R.begin(), R.end())));
2019     result.push_back(Pair("PubkeyVariant", HexStr(vchPubKeyVariant.begin(), vchPubKeyVariant.end())));
2020     result.push_back(Pair("KeyVariantID", CBitcoinAddress(vchPubKeyVariant.GetID()).ToString()));
2021
2022     return result;
2023 }
2024
2025 Value listmalleableviews(const Array& params, bool fHelp)
2026 {
2027     if (fHelp || params.size() != 0)
2028         throw runtime_error(
2029             "listmalleableviews\n"
2030             "Get list of views for generated malleable keys.\n");
2031
2032     list<CMalleableKeyView> keyViewList;
2033     pwalletMain->ListMalleableViews(keyViewList);
2034
2035     Array result;
2036     for(const auto &keyView : keyViewList)
2037         result.push_back(keyView.ToString());
2038
2039     return result;
2040 }
2041