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