Remove netbase.h from util header: create timedata files.
[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() > 2)
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     auto strAddress = params[0].get_str();
709
710     CBitcoinAddress address(strAddress);
711     if (address.IsValid())
712         scriptPubKey.SetAddress(address);
713     else
714         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
715
716
717     auto nAmount = AmountFromValue(params[2]);
718
719     if (nAmount < nMinimumInputValue)
720         throw JSONRPCError(-101, "Send amount too small");
721
722     int nMinDepth = 1;
723     if (params.size() > 3)
724         nMinDepth = params[3].get_int();
725
726     CWalletTx wtx;
727     wtx.strFromAccount = strAccount;
728     if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
729         wtx.mapValue["comment"] = params[4].get_str();
730     if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
731         wtx.mapValue["to"]      = params[5].get_str();
732
733     EnsureWalletIsUnlocked();
734
735     // Check funds
736     auto nBalance = GetAccountBalance(strAccount, nMinDepth, MINE_SPENDABLE);
737     if (nAmount > nBalance)
738         throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
739
740     // Send
741     auto strError = pwalletMain->SendMoney(scriptPubKey, nAmount, wtx);
742     if (!strError.empty())
743         throw JSONRPCError(RPC_WALLET_ERROR, strError);
744
745     return wtx.GetHash().GetHex();
746 }
747
748
749 Value sendmany(const Array& params, bool fHelp)
750 {
751     if (fHelp || params.size() < 2 || params.size() > 4)
752         throw runtime_error(
753             "sendmany <fromaccount> '{address:amount,...}' [minconf=1] [comment]\n"
754             "amounts are double-precision floating point numbers"
755             + HelpRequiringPassphrase());
756
757     auto strAccount = AccountFromValue(params[0]);
758     auto sendTo = params[1].get_obj();
759     int nMinDepth = 1;
760     if (params.size() > 2)
761         nMinDepth = params[2].get_int();
762
763     CWalletTx wtx;
764     wtx.strFromAccount = strAccount;
765     if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
766         wtx.mapValue["comment"] = params[3].get_str();
767
768     set<CBitcoinAddress> setAddress;
769     vector<pair<CScript, int64_t> > vecSend;
770
771     int64_t totalAmount = 0;
772     for(const Pair& s :  sendTo)
773     {
774         CBitcoinAddress address(s.name_);
775         if (!address.IsValid())
776             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid NovaCoin address: ")+s.name_);
777
778         if (!address.IsPair())
779         {
780             if (setAddress.count(address))
781                 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+s.name_);
782             setAddress.insert(address);
783         }
784
785         CScript scriptPubKey;
786         scriptPubKey.SetAddress(address);
787         auto nAmount = AmountFromValue(s.value_);
788
789         if (nAmount < nMinimumInputValue)
790             throw JSONRPCError(-101, "Send amount too small");
791
792         totalAmount += nAmount;
793
794         vecSend.push_back({ scriptPubKey, nAmount });
795     }
796
797     EnsureWalletIsUnlocked();
798
799     // Check funds
800     auto nBalance = GetAccountBalance(strAccount, nMinDepth, MINE_SPENDABLE);
801     if (totalAmount > nBalance)
802         throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
803
804     // Send
805     CReserveKey keyChange(pwalletMain);
806     int64_t nFeeRequired = 0;
807     bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
808     if (!fCreated)
809     {
810         auto nTotal = pwalletMain->GetBalance(), nWatchOnly = pwalletMain->GetWatchOnlyBalance();
811         if (totalAmount + nFeeRequired > nTotal - nWatchOnly)
812             throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds");
813         throw JSONRPCError(RPC_WALLET_ERROR, "Transaction creation failed");
814     }
815     if (!pwalletMain->CommitTransaction(wtx, keyChange))
816         throw JSONRPCError(RPC_WALLET_ERROR, "Transaction commit failed");
817
818     return wtx.GetHash().GetHex();
819 }
820
821 Value addmultisigaddress(const Array& params, bool fHelp)
822 {
823     if (fHelp || params.size() < 2 || params.size() > 3)
824     {
825         string msg = "addmultisigaddress <nrequired> <'[\"key\",\"key\"]'> [account]\n"
826             "Add a nrequired-to-sign multisignature address to the wallet\"\n"
827             "each key is a NovaCoin address or hex-encoded public key\n"
828             "If [account] is specified, assign address to [account].";
829         throw runtime_error(msg);
830     }
831
832     int nRequired = params[0].get_int();
833     const Array& keys = params[1].get_array();
834     string strAccount;
835     if (params.size() > 2)
836         strAccount = AccountFromValue(params[2]);
837
838     // Gather public keys
839     if (nRequired < 1)
840         throw runtime_error("a multisignature address must require at least one key to redeem");
841     if ((int)keys.size() < nRequired)
842         throw runtime_error(
843             strprintf("not enough keys supplied "
844                       "(got %" PRIszu " keys, but need at least %d to redeem)", keys.size(), nRequired));
845     if (keys.size() > 16)
846         throw runtime_error("Number of addresses involved in the multisignature address creation > 16\nReduce the number");
847     vector<CPubKey> pubkeys;
848     pubkeys.resize(keys.size());
849     for (unsigned int i = 0; i < keys.size(); i++)
850     {
851         const auto& ks = keys[i].get_str();
852
853         // Case 1: Bitcoin address and we have full public key:
854         CBitcoinAddress address(ks);
855         if (address.IsValid())
856         {
857             CKeyID keyID;
858             if (!address.GetKeyID(keyID))
859                 throw runtime_error(
860                     strprintf("%s does not refer to a key",ks.c_str()));
861             CPubKey vchPubKey;
862             if (!pwalletMain->GetPubKey(keyID, vchPubKey))
863                 throw runtime_error(
864                     strprintf("no full public key for address %s",ks.c_str()));
865             if (!vchPubKey.IsValid())
866                 throw runtime_error(" Invalid public key: "+ks);
867             pubkeys[i] = vchPubKey;
868         }
869
870         // Case 2: hex public key
871         else if (IsHex(ks))
872         {
873             CPubKey vchPubKey(ParseHex(ks));
874             if (!vchPubKey.IsValid())
875                 throw runtime_error(" Invalid public key: "+ks);
876              pubkeys[i] = vchPubKey;
877         }
878         else
879         {
880             throw runtime_error(" Invalid public key: "+ks);
881         }
882     }
883
884     // Construct using pay-to-script-hash:
885     CScript inner;
886     inner.SetMultisig(nRequired, pubkeys);
887
888     if (inner.size() > MAX_SCRIPT_ELEMENT_SIZE)
889     throw runtime_error(
890         strprintf("redeemScript exceeds size limit: %" PRIszu " > %d", inner.size(), MAX_SCRIPT_ELEMENT_SIZE));
891
892     pwalletMain->AddCScript(inner);
893     CBitcoinAddress address{ CScriptID(inner) }; // "most vexing parse"
894
895     pwalletMain->SetAddressBookName(address, strAccount);
896     return address.ToString();
897 }
898
899 Value addredeemscript(const Array& params, bool fHelp)
900 {
901     if (fHelp || params.size() < 1 || params.size() > 2)
902     {
903         string msg = "addredeemscript <redeemScript> [account]\n"
904             "Add a P2SH address with a specified redeemScript to the wallet.\n"
905             "If [account] is specified, assign address to [account].";
906         throw runtime_error(msg);
907     }
908
909     string strAccount;
910     if (params.size() > 1)
911         strAccount = AccountFromValue(params[1]);
912
913     // Construct using pay-to-script-hash:
914     auto innerData = ParseHexV(params[0], "redeemScript");
915     CScript inner(innerData.begin(), innerData.end());
916     pwalletMain->AddCScript(inner);
917     CBitcoinAddress address{ CScriptID(inner) }; // "most vexing parse"
918
919     pwalletMain->SetAddressBookName(address, strAccount);
920     return address.ToString();
921 }
922
923 struct tallyitem
924 {
925     int64_t nAmount;
926     int nConf;
927     tallyitem()
928     {
929         nAmount = 0;
930         nConf = numeric_limits<int>::max();
931     }
932 };
933
934 Value ListReceived(const Array& params, bool fByAccounts)
935 {
936     // Minimum confirmations
937     int nMinDepth = 1;
938     if (params.size() > 0)
939         nMinDepth = params[0].get_int();
940
941     // Whether to include empty accounts
942     bool fIncludeEmpty = false;
943     if (params.size() > 1)
944         fIncludeEmpty = params[1].get_bool();
945
946     // Tally
947     map<CBitcoinAddress, tallyitem> mapTally;
948     for (const auto &wit : pwalletMain->mapWallet)
949     {
950         const auto& wtx = wit.second;
951
952         if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
953             continue;
954
955         int nDepth = wtx.GetDepthInMainChain();
956         if (nDepth < nMinDepth)
957             continue;
958
959         for(const auto& txout :  wtx.vout)
960         {
961             CTxDestination address;
962             if (!ExtractDestination(txout.scriptPubKey, address) || !IsMine(*pwalletMain, address))
963                 continue;
964
965             auto& item = mapTally[address];
966             item.nAmount += txout.nValue;
967             item.nConf = min(item.nConf, nDepth);
968         }
969     }
970
971     // Reply
972     Array ret;
973     map<string, tallyitem> mapAccountTally;
974     for(const auto& item : pwalletMain->mapAddressBook)
975     {
976         const auto& address = item.first;
977         const auto& strAccount = item.second;
978         auto it = mapTally.find(address);
979         if (it == mapTally.end() && !fIncludeEmpty)
980             continue;
981
982         int64_t nAmount = 0;
983         int nConf = numeric_limits<int>::max();
984         if (it != mapTally.end())
985         {
986             nAmount = (*it).second.nAmount;
987             nConf = (*it).second.nConf;
988         }
989
990         if (fByAccounts)
991         {
992             auto& item = mapAccountTally[strAccount];
993             item.nAmount += nAmount;
994             item.nConf = min(item.nConf, nConf);
995         }
996         else
997         {
998             Object obj;
999             obj.push_back(Pair("address",       address.ToString()));
1000             obj.push_back(Pair("account",       strAccount));
1001             obj.push_back(Pair("amount",        ValueFromAmount(nAmount)));
1002             obj.push_back(Pair("confirmations", (nConf == numeric_limits<int>::max() ? 0 : nConf)));
1003             ret.push_back(obj);
1004         }
1005     }
1006
1007     if (fByAccounts)
1008     {
1009         for (const auto &acc : mapAccountTally)
1010         {
1011             auto nAmount = acc.second.nAmount;
1012             int nConf = acc.second.nConf;
1013             Object obj;
1014             obj.push_back(Pair("account",       acc.first));
1015             obj.push_back(Pair("amount",        ValueFromAmount(nAmount)));
1016             obj.push_back(Pair("confirmations", (nConf == numeric_limits<int>::max() ? 0 : nConf)));
1017             ret.push_back(obj);
1018         }
1019     }
1020
1021     return ret;
1022 }
1023
1024 Value listreceivedbyaddress(const Array& params, bool fHelp)
1025 {
1026     if (fHelp || params.size() > 2)
1027         throw runtime_error(
1028             "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
1029             "[minconf] is the minimum number of confirmations before payments are included.\n"
1030             "[includeempty] whether to include addresses that haven't received any payments.\n"
1031             "Returns an array of objects containing:\n"
1032             "  \"address\" : receiving address\n"
1033             "  \"account\" : the account of the receiving address\n"
1034             "  \"amount\" : total amount received by the address\n"
1035             "  \"confirmations\" : number of confirmations of the most recent transaction included");
1036
1037     return ListReceived(params, false);
1038 }
1039
1040 Value listreceivedbyaccount(const Array& params, bool fHelp)
1041 {
1042     if (fHelp || params.size() > 2)
1043         throw runtime_error(
1044             "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
1045             "[minconf] is the minimum number of confirmations before payments are included.\n"
1046             "[includeempty] whether to include accounts that haven't received any payments.\n"
1047             "Returns an array of objects containing:\n"
1048             "  \"account\" : the account of the receiving addresses\n"
1049             "  \"amount\" : total amount received by addresses with this account\n"
1050             "  \"confirmations\" : number of confirmations of the most recent transaction included");
1051
1052     return ListReceived(params, true);
1053 }
1054
1055 static void MaybePushAddress(Object & entry, const CBitcoinAddress &dest)
1056 {
1057     entry.push_back(Pair("address", dest.ToString()));
1058 }
1059
1060 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret, const isminefilter& filter)
1061 {
1062     int64_t nGeneratedImmature, nGeneratedMature, nFee;
1063     string strSentAccount;
1064     list<pair<CBitcoinAddress, int64_t> > listReceived;
1065     list<pair<CBitcoinAddress, int64_t> > listSent;
1066
1067     wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount, filter);
1068
1069     bool fAllAccounts = (strAccount == string("*"));
1070     bool involvesWatchonly = wtx.IsFromMe(MINE_WATCH_ONLY);
1071
1072     // Generated blocks assigned to account ""
1073     if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount.empty()))
1074     {
1075         Object entry;
1076         entry.push_back(Pair("account", string("")));
1077         if (nGeneratedImmature)
1078         {
1079             entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
1080             entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
1081         }
1082         else
1083         {
1084             entry.push_back(Pair("category", "generate"));
1085             entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
1086         }
1087         if (fLong)
1088             WalletTxToJSON(wtx, entry);
1089         ret.push_back(entry);
1090     }
1091
1092     // Sent
1093     if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1094     {
1095         for(const auto& s : listSent)
1096         {
1097             Object entry;
1098             entry.push_back(Pair("account", strSentAccount));
1099             if(involvesWatchonly || (::IsMine(*pwalletMain, s.first) & MINE_WATCH_ONLY))
1100                 entry.push_back(Pair("involvesWatchonly", true));
1101             MaybePushAddress(entry, s.first);
1102
1103             if (wtx.GetDepthInMainChain() < 0) {
1104                 entry.push_back(Pair("category", "conflicted"));
1105             } else {
1106                 entry.push_back(Pair("category", "send"));
1107             }
1108
1109             entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1110             entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1111             if (fLong)
1112                 WalletTxToJSON(wtx, entry);
1113             ret.push_back(entry);
1114         }
1115     }
1116
1117     // Received
1118     if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1119     {
1120         for(const auto& r : listReceived)
1121         {
1122             string account;
1123             if (pwalletMain->mapAddressBook.count(r.first))
1124                 account = pwalletMain->mapAddressBook[r.first];
1125             if (fAllAccounts || (account == strAccount))
1126             {
1127                 Object entry;
1128                 entry.push_back(Pair("account", account));
1129                 if(involvesWatchonly || (::IsMine(*pwalletMain, r.first) & MINE_WATCH_ONLY))
1130                     entry.push_back(Pair("involvesWatchonly", true));
1131                 MaybePushAddress(entry, r.first);
1132                 if (wtx.IsCoinBase())
1133                 {
1134                     if (wtx.GetDepthInMainChain() < 1)
1135                         entry.push_back(Pair("category", "orphan"));
1136                     else if (wtx.GetBlocksToMaturity() > 0)
1137                         entry.push_back(Pair("category", "immature"));
1138                     else
1139                         entry.push_back(Pair("category", "generate"));
1140                 }
1141                 else
1142                     entry.push_back(Pair("category", "receive"));
1143                 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1144                 if (fLong)
1145                     WalletTxToJSON(wtx, entry);
1146                 ret.push_back(entry);
1147             }
1148         }
1149     }
1150 }
1151
1152 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1153 {
1154     bool fAllAccounts = (strAccount == string("*"));
1155
1156     if (fAllAccounts || acentry.strAccount == strAccount)
1157     {
1158         Object entry;
1159         entry.push_back(Pair("account", acentry.strAccount));
1160         entry.push_back(Pair("category", "move"));
1161         entry.push_back(Pair("time", (int64_t)acentry.nTime));
1162         entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1163         entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1164         entry.push_back(Pair("comment", acentry.strComment));
1165         ret.push_back(entry);
1166     }
1167 }
1168
1169 Value listtransactions(const Array& params, bool fHelp)
1170 {
1171     if (fHelp || params.size() > 3)
1172         throw runtime_error(
1173             "listtransactions [account] [count=10] [from=0]\n"
1174             "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1175
1176     string strAccount = "*";
1177     if (params.size() > 0)
1178         strAccount = params[0].get_str();
1179     int nCount = 10;
1180     if (params.size() > 1)
1181         nCount = params[1].get_int();
1182     int nFrom = 0;
1183     if (params.size() > 2)
1184         nFrom = params[2].get_int();
1185
1186     isminefilter filter = MINE_SPENDABLE;
1187     if(params.size() > 3)
1188         if(params[3].get_bool())
1189             filter = filter | MINE_WATCH_ONLY;
1190
1191     if (nCount < 0)
1192         throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count");
1193     if (nFrom < 0)
1194         throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative from");
1195
1196     Array ret;
1197
1198     list<CAccountingEntry> acentries;
1199     auto txOrdered = pwalletMain->OrderedTxItems(acentries, strAccount);
1200
1201     // iterate backwards until we have nCount items to return:
1202     for (auto it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
1203     {
1204         CWalletTx *const pwtx = (*it).second.first;
1205         if (pwtx != 0)
1206             ListTransactions(*pwtx, strAccount, 0, true, ret, filter);
1207         CAccountingEntry *const pacentry = (*it).second.second;
1208         if (pacentry != 0)
1209             AcentryToJSON(*pacentry, strAccount, ret);
1210
1211         if ((int)ret.size() >= (nCount+nFrom)) break;
1212     }
1213     // ret is newest to oldest
1214
1215     if (nFrom > (int)ret.size())
1216         nFrom = ret.size();
1217     if ((nFrom + nCount) > (int)ret.size())
1218         nCount = ret.size() - nFrom;
1219     auto first = ret.begin();
1220     advance(first, nFrom);
1221     auto last = ret.begin();
1222     advance(last, nFrom+nCount);
1223
1224     if (last != ret.end()) ret.erase(last, ret.end());
1225     if (first != ret.begin()) ret.erase(ret.begin(), first);
1226
1227     reverse(ret.begin(), ret.end()); // Return oldest to newest
1228
1229     return ret;
1230 }
1231
1232 Value listaccounts(const Array& params, bool fHelp)
1233 {
1234     if (fHelp || params.size() > 1)
1235         throw runtime_error(
1236             "listaccounts [minconf=1]\n"
1237             "Returns Object that has account names as keys, account balances as values.");
1238
1239     int nMinDepth = 1;
1240     if (params.size() > 0)
1241         nMinDepth = params[0].get_int();
1242
1243     isminefilter includeWatchonly = MINE_SPENDABLE;
1244     if(params.size() > 1)
1245         if(params[1].get_bool())
1246             includeWatchonly = includeWatchonly | MINE_WATCH_ONLY;
1247
1248
1249     map<string, int64_t> mapAccountBalances;
1250     for(const auto& entry : pwalletMain->mapAddressBook) {
1251         if (IsMine(*pwalletMain, entry.first)) // This address belongs to me
1252             mapAccountBalances[entry.second] = 0;
1253     }
1254
1255     for (auto it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1256     {
1257         const CWalletTx& wtx = (*it).second;
1258         int64_t nGeneratedImmature, nGeneratedMature, nFee;
1259         string strSentAccount;
1260         list<pair<CBitcoinAddress, int64_t> > listReceived;
1261         list<pair<CBitcoinAddress, int64_t> > listSent;
1262         wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount, includeWatchonly);
1263         mapAccountBalances[strSentAccount] -= nFee;
1264         for(const auto& s : listSent)
1265             mapAccountBalances[strSentAccount] -= s.second;
1266         if (wtx.GetDepthInMainChain() >= nMinDepth)
1267         {
1268             mapAccountBalances[""] += nGeneratedMature;
1269             for(const auto& r : listReceived)
1270                 if (pwalletMain->mapAddressBook.count(r.first))
1271                     mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1272                 else
1273                     mapAccountBalances[""] += r.second;
1274         }
1275     }
1276
1277     list<CAccountingEntry> acentries;
1278     CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1279     for(const auto& entry : acentries)
1280         mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1281
1282     Object ret;
1283     for(const auto& accountBalance : mapAccountBalances) {
1284         ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1285     }
1286     return ret;
1287 }
1288
1289 Value listsinceblock(const Array& params, bool fHelp)
1290 {
1291     if (fHelp)
1292         throw runtime_error(
1293             "listsinceblock [blockhash] [target-confirmations]\n"
1294             "Get all transactions in blocks since block [blockhash], or all transactions if omitted");
1295
1296     CBlockIndex *pindex = NULL;
1297     int target_confirms = 1;
1298     isminefilter filter = MINE_SPENDABLE;
1299
1300     if (params.size() > 0)
1301     {
1302         uint256 blockId = 0;
1303
1304         blockId.SetHex(params[0].get_str());
1305         pindex = CBlockLocator(blockId).GetBlockIndex();
1306     }
1307
1308     if (params.size() > 1)
1309     {
1310         target_confirms = params[1].get_int();
1311
1312         if (target_confirms < 1)
1313             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter");
1314     }
1315
1316     if(params.size() > 2)
1317         if(params[2].get_bool())
1318             filter = filter | MINE_WATCH_ONLY;
1319
1320     int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
1321
1322     Array transactions;
1323
1324     for (auto it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1325     {
1326         auto tx = (*it).second;
1327
1328         if (depth == -1 || tx.GetDepthInMainChain() < depth)
1329             ListTransactions(tx, "*", 0, true, transactions, filter);
1330     }
1331
1332     uint256 lastblock;
1333
1334     if (target_confirms == 1)
1335     {
1336         lastblock = hashBestChain;
1337     }
1338     else
1339     {
1340         int target_height = pindexBest->nHeight + 1 - target_confirms;
1341
1342         CBlockIndex *block;
1343         for (block = pindexBest;
1344              block && block->nHeight > target_height;
1345              block = block->pprev)  { }
1346
1347         lastblock = block ? block->GetBlockHash() : 0;
1348     }
1349
1350     Object ret;
1351     ret.push_back(Pair("transactions", transactions));
1352     ret.push_back(Pair("lastblock", lastblock.GetHex()));
1353
1354     return ret;
1355 }
1356
1357 Value gettransaction(const Array& params, bool fHelp)
1358 {
1359     if (fHelp || params.size() != 1)
1360         throw runtime_error(
1361             "gettransaction <txid>\n"
1362             "Get detailed information about <txid>");
1363
1364     uint256 hash;
1365     hash.SetHex(params[0].get_str());
1366
1367     isminefilter filter = MINE_SPENDABLE;
1368     if(params.size() > 1)
1369         if(params[1].get_bool())
1370             filter = filter | MINE_WATCH_ONLY;
1371
1372     Object entry;
1373
1374     if (pwalletMain->mapWallet.count(hash))
1375     {
1376         const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1377
1378         TxToJSON(wtx, 0, entry);
1379
1380         auto nCredit = wtx.GetCredit(filter);
1381         auto nDebit = wtx.GetDebit(filter);
1382         auto nNet = nCredit - nDebit;
1383         auto nFee = (wtx.IsFromMe(filter) ? wtx.GetValueOut() - nDebit : 0);
1384
1385         entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1386         if (wtx.IsFromMe(filter))
1387             entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1388
1389         WalletTxToJSON(wtx, entry);
1390
1391         Array details;
1392         ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details, filter);
1393         entry.push_back(Pair("details", details));
1394     }
1395     else
1396     {
1397         CTransaction tx;
1398         uint256 hashBlock = 0;
1399         if (GetTransaction(hash, tx, hashBlock))
1400         {
1401             TxToJSON(tx, 0, entry);
1402             if (hashBlock == 0)
1403                 entry.push_back(Pair("confirmations", 0));
1404             else
1405             {
1406                 entry.push_back(Pair("blockhash", hashBlock.GetHex()));
1407                 auto mi = mapBlockIndex.find(hashBlock);
1408                 if (mi != mapBlockIndex.end() && (*mi).second)
1409                 {
1410                     auto pindex = (*mi).second;
1411                     if (pindex->IsInMainChain())
1412                         entry.push_back(Pair("confirmations", 1 + nBestHeight - pindex->nHeight));
1413                     else
1414                         entry.push_back(Pair("confirmations", 0));
1415                 }
1416             }
1417         }
1418         else
1419             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction");
1420     }
1421
1422     return entry;
1423 }
1424
1425
1426 Value backupwallet(const Array& params, bool fHelp)
1427 {
1428     if (fHelp || params.size() != 1)
1429         throw runtime_error(
1430             "backupwallet <destination>\n"
1431             "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1432
1433     auto strDest = params[0].get_str();
1434     if (!BackupWallet(*pwalletMain, strDest))
1435         throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!");
1436
1437     return Value::null;
1438 }
1439
1440
1441 Value keypoolrefill(const Array& params, bool fHelp)
1442 {
1443     if (fHelp || params.size() > 1)
1444         throw runtime_error(
1445             "keypoolrefill [new-size]\n"
1446             "Fills the keypool.\n"
1447             "IMPORTANT: Any previous backups you have made of your wallet file "
1448             "should be replaced with the newly generated one."
1449             + HelpRequiringPassphrase());
1450
1451     unsigned int nSize = max<unsigned int>(GetArgUInt("-keypool", 100), 0);
1452     if (params.size() > 0) {
1453         if (params[0].get_int() < 0)
1454             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size");
1455         nSize = (unsigned int) params[0].get_int();
1456     }
1457
1458     EnsureWalletIsUnlocked();
1459
1460     pwalletMain->TopUpKeyPool(nSize);
1461
1462     if (pwalletMain->GetKeyPoolSize() < nSize)
1463         throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool.");
1464
1465     return Value::null;
1466 }
1467
1468 Value keypoolreset(const Array& params, bool fHelp)
1469 {
1470     if (fHelp || params.size() > 1)
1471         throw runtime_error(
1472             "keypoolreset [new-size]\n"
1473             "Resets the keypool.\n"
1474             "IMPORTANT: Any previous backups you have made of your wallet file "
1475             "should be replaced with the newly generated one."
1476             + HelpRequiringPassphrase());
1477
1478     unsigned int nSize = max<unsigned int>(GetArgUInt("-keypool", 100), 0);
1479     if (params.size() > 0) {
1480         if (params[0].get_int() < 0)
1481             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size");
1482         nSize = (unsigned int) params[0].get_int();
1483     }
1484
1485     EnsureWalletIsUnlocked();
1486
1487     pwalletMain->NewKeyPool(nSize);
1488
1489     if (pwalletMain->GetKeyPoolSize() < nSize)
1490         throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool.");
1491
1492     return Value::null;
1493 }
1494
1495
1496 void ThreadTopUpKeyPool(void* parg)
1497 {
1498     // Make this thread recognisable as the key-topping-up thread
1499     RenameThread("novacoin-key-top");
1500
1501     pwalletMain->TopUpKeyPool();
1502 }
1503
1504 void ThreadCleanWalletPassphrase(void* parg)
1505 {
1506     // Make this thread recognisable as the wallet relocking thread
1507     RenameThread("novacoin-lock-wa");
1508
1509     auto nMyWakeTime = GetTimeMillis() + *((int64_t*)parg) * 1000;
1510
1511     ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1512
1513     if (nWalletUnlockTime == 0)
1514     {
1515         nWalletUnlockTime = nMyWakeTime;
1516
1517         for ( ; ; )
1518         {
1519             if (nWalletUnlockTime==0)
1520                 break;
1521             auto nToSleep = nWalletUnlockTime - GetTimeMillis();
1522             if (nToSleep <= 0)
1523                 break;
1524
1525             LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1526             Sleep(nToSleep);
1527             ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1528
1529         };
1530
1531         if (nWalletUnlockTime)
1532         {
1533             nWalletUnlockTime = 0;
1534             pwalletMain->Lock();
1535         }
1536     }
1537     else
1538     {
1539         if (nWalletUnlockTime < nMyWakeTime)
1540             nWalletUnlockTime = nMyWakeTime;
1541     }
1542
1543     LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1544
1545     delete (int64_t*)parg;
1546 }
1547
1548 Value walletpassphrase(const Array& params, bool fHelp)
1549 {
1550     if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 3))
1551         throw runtime_error(
1552             "walletpassphrase <passphrase> <timeout> [mintonly]\n"
1553             "Stores the wallet decryption key in memory for <timeout> seconds.\n"
1554             "mintonly is optional true/false allowing only block minting.");
1555     if (fHelp)
1556         return true;
1557     if (!pwalletMain->IsCrypted())
1558         throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1559
1560     if (!pwalletMain->IsLocked())
1561         throw JSONRPCError(RPC_WALLET_ALREADY_UNLOCKED, "Error: Wallet is already unlocked, use walletlock first if need to change unlock settings.");
1562     // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1563     SecureString strWalletPass;
1564     strWalletPass.reserve(100);
1565     // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1566     // Alternately, find a way to make params[0] mlock()'d to begin with.
1567     strWalletPass = params[0].get_str().c_str();
1568
1569     if (strWalletPass.length() > 0)
1570     {
1571         if (!pwalletMain->Unlock(strWalletPass))
1572             throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
1573     }
1574     else
1575         throw runtime_error(
1576             "walletpassphrase <passphrase> <timeout>\n"
1577             "Stores the wallet decryption key in memory for <timeout> seconds.");
1578
1579     NewThread(ThreadTopUpKeyPool, NULL);
1580     int64_t* pnSleepTime = new int64_t(params[1].get_int64());
1581     NewThread(ThreadCleanWalletPassphrase, pnSleepTime);
1582
1583     // ppcoin: if user OS account compromised prevent trivial sendmoney commands
1584     if (params.size() > 2)
1585         fWalletUnlockMintOnly = params[2].get_bool();
1586     else
1587         fWalletUnlockMintOnly = false;
1588
1589     return Value::null;
1590 }
1591
1592
1593 Value walletpassphrasechange(const Array& params, bool fHelp)
1594 {
1595     if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1596         throw runtime_error(
1597             "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1598             "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1599     if (fHelp)
1600         return true;
1601     if (!pwalletMain->IsCrypted())
1602         throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1603
1604     // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1605     // Alternately, find a way to make params[0] mlock()'d to begin with.
1606     SecureString strOldWalletPass;
1607     strOldWalletPass.reserve(100);
1608     strOldWalletPass = params[0].get_str().c_str();
1609
1610     SecureString strNewWalletPass;
1611     strNewWalletPass.reserve(100);
1612     strNewWalletPass = params[1].get_str().c_str();
1613
1614     if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1615         throw runtime_error(
1616             "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1617             "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1618
1619     if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1620         throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
1621
1622     return Value::null;
1623 }
1624
1625
1626 Value walletlock(const Array& params, bool fHelp)
1627 {
1628     if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1629         throw runtime_error(
1630             "walletlock\n"
1631             "Removes the wallet encryption key from memory, locking the wallet.\n"
1632             "After calling this method, you will need to call walletpassphrase again\n"
1633             "before being able to call any methods which require the wallet to be unlocked.");
1634     if (fHelp)
1635         return true;
1636     if (!pwalletMain->IsCrypted())
1637         throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletlock was called.");
1638
1639     {
1640         LOCK(cs_nWalletUnlockTime);
1641         pwalletMain->Lock();
1642         nWalletUnlockTime = 0;
1643     }
1644
1645     return Value::null;
1646 }
1647
1648
1649 Value encryptwallet(const Array& params, bool fHelp)
1650 {
1651     if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1652         throw runtime_error(
1653             "encryptwallet <passphrase>\n"
1654             "Encrypts the wallet with <passphrase>.");
1655     if (fHelp)
1656         return true;
1657     if (pwalletMain->IsCrypted())
1658         throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an encrypted wallet, but encryptwallet was called.");
1659
1660     // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1661     // Alternately, find a way to make params[0] mlock()'d to begin with.
1662     SecureString strWalletPass;
1663     strWalletPass.reserve(100);
1664     strWalletPass = params[0].get_str().c_str();
1665
1666     if (strWalletPass.length() < 1)
1667         throw runtime_error(
1668             "encryptwallet <passphrase>\n"
1669             "Encrypts the wallet with <passphrase>.");
1670
1671     if (!pwalletMain->EncryptWallet(strWalletPass))
1672         throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: Failed to encrypt the wallet.");
1673
1674     // BDB seems to have a bad habit of writing old data into
1675     // slack space in .dat files; that is bad if the old data is
1676     // unencrypted private keys. So:
1677     StartShutdown();
1678     return "wallet encrypted; NovaCoin server stopping, restart to run with encrypted wallet.  The keypool has been flushed, you need to make a new backup.";
1679 }
1680
1681 class DescribeAddressVisitor : public boost::static_visitor<Object>
1682 {
1683 private:
1684     isminetype mine;
1685 public:
1686     DescribeAddressVisitor(isminetype mineIn) : mine(mineIn) {}
1687
1688     Object operator()(const CNoDestination &dest) const { return Object(); }
1689     Object operator()(const CKeyID &keyID) const {
1690         Object obj;
1691         CPubKey vchPubKey;
1692         pwalletMain->GetPubKey(keyID, vchPubKey);
1693         obj.push_back(Pair("isscript", false));
1694         if (mine == MINE_SPENDABLE) {
1695             pwalletMain->GetPubKey(keyID, vchPubKey);
1696             obj.push_back(Pair("pubkey", HexStr(vchPubKey.begin(), vchPubKey.end())));
1697             obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed()));
1698         }
1699         return obj;
1700     }
1701
1702     Object operator()(const CScriptID &scriptID) const {
1703         Object obj;
1704         obj.push_back(Pair("isscript", true));
1705         if (mine == MINE_SPENDABLE) {
1706             CScript subscript;
1707             pwalletMain->GetCScript(scriptID, subscript);
1708             vector<CTxDestination> addresses;
1709             txnouttype whichType;
1710             int nRequired;
1711             ExtractDestinations(subscript, whichType, addresses, nRequired);
1712             obj.push_back(Pair("script", GetTxnOutputType(whichType)));
1713             obj.push_back(Pair("hex", HexStr(subscript.begin(), subscript.end())));
1714             Array a;
1715             for(const auto& addr : addresses)
1716                 a.push_back(CBitcoinAddress(addr).ToString());
1717             obj.push_back(Pair("addresses", a));
1718             if (whichType == TX_MULTISIG)
1719                 obj.push_back(Pair("sigsrequired", nRequired));
1720         }
1721         return obj;
1722     }
1723 };
1724
1725 Value validateaddress(const Array& params, bool fHelp)
1726 {
1727     if (fHelp || params.size() != 1)
1728         throw runtime_error(
1729             "validateaddress <novacoinaddress>\n"
1730             "Return information about <novacoinaddress>.");
1731
1732     CBitcoinAddress address(params[0].get_str());
1733     bool isValid = address.IsValid();
1734
1735     Object ret;
1736     ret.push_back(Pair("isvalid", isValid));
1737     if (isValid)
1738     {
1739         if (address.IsPair())
1740         {
1741             CMalleablePubKey mpk;
1742             mpk.setvch(address.GetData());
1743             ret.push_back(Pair("ispair", true));
1744
1745             CMalleableKeyView view;
1746             bool isMine = pwalletMain->GetMalleableView(mpk, view);
1747             ret.push_back(Pair("ismine", isMine));
1748             ret.push_back(Pair("PubkeyPair", mpk.ToString()));
1749
1750             if (isMine)
1751                 ret.push_back(Pair("KeyView", view.ToString()));
1752         }
1753         else
1754         {
1755             auto currentAddress = address.ToString();
1756             auto dest = address.Get();
1757             ret.push_back(Pair("address", currentAddress));
1758             auto mine = IsMine(*pwalletMain, address);
1759             ret.push_back(Pair("ismine", mine != MINE_NO));
1760             if (mine != MINE_NO) {
1761                 ret.push_back(Pair("watchonly", mine == MINE_WATCH_ONLY));
1762                 Object detail = boost::apply_visitor(DescribeAddressVisitor(mine), dest);
1763                 ret.insert(ret.end(), detail.begin(), detail.end());
1764             }
1765             if (pwalletMain->mapAddressBook.count(address))
1766                 ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
1767         }
1768     }
1769     return ret;
1770 }
1771
1772 // ppcoin: reserve balance from being staked for network protection
1773 Value reservebalance(const Array& params, bool fHelp)
1774 {
1775     if (fHelp || params.size() > 2)
1776         throw runtime_error(
1777             "reservebalance [<reserve> [amount]]\n"
1778             "<reserve> is true or false to turn balance reserve on or off.\n"
1779             "<amount> is a real and rounded to cent.\n"
1780             "Set reserve amount not participating in network protection.\n"
1781             "If no parameters provided current setting is printed.\n");
1782
1783     if (params.size() > 0)
1784     {
1785         bool fReserve = params[0].get_bool();
1786         if (fReserve)
1787         {
1788             if (params.size() == 1)
1789                 throw runtime_error("must provide amount to reserve balance.\n");
1790             auto nAmount = AmountFromValue(params[1]);
1791             nAmount = (nAmount / CENT) * CENT;  // round to cent
1792             if (nAmount < 0)
1793                 throw runtime_error("amount cannot be negative.\n");
1794             mapArgs["-reservebalance"] = FormatMoney(nAmount);
1795         }
1796         else
1797         {
1798             if (params.size() > 1)
1799                 throw runtime_error("cannot specify amount to turn off reserve.\n");
1800             mapArgs["-reservebalance"] = "0";
1801         }
1802     }
1803
1804     Object result;
1805     if (mapArgs.count("-reservebalance") && !ParseMoney(mapArgs["-reservebalance"], nReserveBalance))
1806         throw runtime_error("invalid reserve balance amount\n");
1807     result.push_back(Pair("reserve", (nReserveBalance > 0)));
1808     result.push_back(Pair("amount", ValueFromAmount(nReserveBalance)));
1809     return result;
1810 }
1811
1812
1813 // ppcoin: check wallet integrity
1814 Value checkwallet(const Array& params, bool fHelp)
1815 {
1816     if (fHelp || params.size() > 0)
1817         throw runtime_error(
1818             "checkwallet\n"
1819             "Check wallet for integrity.\n");
1820
1821     int nMismatchSpent;
1822     int64_t nBalanceInQuestion;
1823     pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion, true);
1824     Object result;
1825     if (nMismatchSpent == 0)
1826         result.push_back(Pair("wallet check passed", true));
1827     else
1828     {
1829         result.push_back(Pair("mismatched spent coins", nMismatchSpent));
1830         result.push_back(Pair("amount in question", ValueFromAmount(nBalanceInQuestion)));
1831     }
1832     return result;
1833 }
1834
1835
1836 // ppcoin: repair wallet
1837 Value repairwallet(const Array& params, bool fHelp)
1838 {
1839     if (fHelp || params.size() > 0)
1840         throw runtime_error(
1841             "repairwallet\n"
1842             "Repair wallet if checkwallet reports any problem.\n");
1843
1844     int nMismatchSpent;
1845     int64_t nBalanceInQuestion;
1846     pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion);
1847     Object result;
1848     if (nMismatchSpent == 0)
1849         result.push_back(Pair("wallet check passed", true));
1850     else
1851     {
1852         result.push_back(Pair("mismatched spent coins", nMismatchSpent));
1853         result.push_back(Pair("amount affected by repair", ValueFromAmount(nBalanceInQuestion)));
1854     }
1855     return result;
1856 }
1857
1858 // NovaCoin: resend unconfirmed wallet transactions
1859 Value resendtx(const Array& params, bool fHelp)
1860 {
1861     if (fHelp || params.size() > 1)
1862         throw runtime_error(
1863             "resendtx\n"
1864             "Re-send unconfirmed transactions.\n"
1865         );
1866
1867     ResendWalletTransactions(true);
1868
1869     return Value::null;
1870 }
1871
1872 Value resendwallettransactions(const Array& params, bool fHelp)
1873 {
1874     if (fHelp || params.size() != 0)
1875         throw runtime_error(
1876             "resendwallettransactions\n"
1877             "Immediately re-broadcast unconfirmed wallet transactions to all peers.\n"
1878             "Intended only for testing; the wallet code periodically re-broadcasts\n"
1879             "automatically.\n"
1880             "Returns array of transaction ids that were re-broadcast.\n"
1881             );
1882
1883     LOCK2(cs_main, pwalletMain->cs_wallet);
1884
1885     auto txids = pwalletMain->ResendWalletTransactionsBefore(GetTime());
1886     Array result;
1887     for(const auto& txid :  txids)
1888     {
1889         result.push_back(txid.ToString());
1890     }
1891     return result;
1892 }
1893
1894
1895 // Make a public-private key pair
1896 Value makekeypair(const Array& params, bool fHelp)
1897 {
1898     if (fHelp || params.size() > 0)
1899         throw runtime_error(
1900             "makekeypair\n"
1901             "Make a public/private key pair.\n");
1902
1903     string strPrefix = "";
1904     if (params.size() > 0)
1905         strPrefix = params[0].get_str();
1906
1907     CKey key;
1908     key.MakeNewKey(true);
1909
1910     auto vchPrivKey = key.GetPrivKey();
1911     Object result;
1912     result.push_back(Pair("PrivateKey", HexStr<CPrivKey::iterator>(vchPrivKey.begin(), vchPrivKey.end())));
1913
1914     bool fCompressed;
1915     auto vchSecret = key.GetSecret(fCompressed);
1916     auto vchPubKey = key.GetPubKey();
1917     result.push_back(Pair("Secret", HexStr<CSecret::iterator>(vchSecret.begin(), vchSecret.end())));
1918     result.push_back(Pair("PublicKey", HexStr(vchPubKey.begin(), vchPubKey.end())));
1919     return result;
1920 }
1921
1922 Value newmalleablekey(const Array& params, bool fHelp)
1923 {
1924     if (fHelp || params.size() > 1)
1925         throw runtime_error(
1926             "newmalleablekey\n"
1927             "Make a malleable public/private key pair.\n");
1928
1929     // Parse the account first so we don't generate a key if there's an error
1930     string strAccount;
1931     if (params.size() > 0)
1932         strAccount = AccountFromValue(params[0]);
1933
1934     auto keyView = pwalletMain->GenerateNewMalleableKey();
1935
1936     CMalleableKey mKey;
1937     if (!pwalletMain->GetMalleableKey(keyView, mKey))
1938         throw runtime_error("Unable to generate new malleable key");
1939
1940     auto mPubKey = mKey.GetMalleablePubKey();
1941     CBitcoinAddress address(mPubKey);
1942
1943     pwalletMain->SetAddressBookName(address, strAccount);
1944
1945     Object result;
1946     result.push_back(Pair("PublicPair", mPubKey.ToString()));
1947     result.push_back(Pair("PublicBytes", HexStr(mPubKey.Raw())));
1948     result.push_back(Pair("Address", address.ToString()));
1949     result.push_back(Pair("KeyView", keyView.ToString()));
1950
1951     return result;
1952 }
1953
1954 Value adjustmalleablekey(const Array& params, bool fHelp)
1955 {
1956     if (fHelp || params.size() != 3)
1957         throw runtime_error(
1958             "adjustmalleablekey <Malleable key data> <Public key variant data> <R data>\n"
1959             "Calculate new private key using provided malleable key, public key and R data.\n");
1960
1961     CMalleableKey malleableKey;
1962     malleableKey.SetString(params[0].get_str());
1963
1964     CKey privKeyVariant;
1965     auto vchPubKeyVariant = CPubKey(ParseHex(params[1].get_str()));
1966
1967     CPubKey R(ParseHex(params[2].get_str()));
1968
1969     if (!malleableKey.CheckKeyVariant(R,vchPubKeyVariant, privKeyVariant)) {
1970         throw runtime_error("Unable to calculate the private key");
1971     }
1972
1973     Object result;
1974     bool fCompressed;
1975     auto vchPrivKeyVariant = privKeyVariant.GetSecret(fCompressed);
1976
1977     result.push_back(Pair("PrivateKey", CBitcoinSecret(vchPrivKeyVariant, fCompressed).ToString()));
1978
1979     return result;
1980 }
1981
1982 Value adjustmalleablepubkey(const Array& params, bool fHelp)
1983 {
1984     if (fHelp || params.size() > 2 || params.size() == 0)
1985         throw runtime_error(
1986             "adjustmalleablepubkey <Malleable address, key view or public key pair>\n"
1987             "Calculate new public key using provided data.\n");
1988
1989     auto strData = params[0].get_str();
1990     CMalleablePubKey malleablePubKey;
1991
1992     do
1993     {
1994         CBitcoinAddress addr(strData);
1995         if (addr.IsValid() && addr.IsPair())
1996         {
1997             // Initialize malleable pubkey with address data
1998             malleablePubKey = CMalleablePubKey(addr.GetData());
1999             break;
2000         }
2001         CMalleableKeyView viewTmp(strData);
2002         if (viewTmp.IsValid())
2003         {
2004             // Shazaam, we have a valid key view here.
2005             malleablePubKey = viewTmp.GetMalleablePubKey();
2006             break;
2007         }
2008         if (malleablePubKey.SetString(strData))
2009             break; // A valid public key pair
2010
2011         throw runtime_error("Though your data seems a valid Base58 string, we were unable to recognize it.");
2012     }
2013     while(false);
2014
2015     CPubKey R, vchPubKeyVariant;
2016     malleablePubKey.GetVariant(R, vchPubKeyVariant);
2017
2018     Object result;
2019     result.push_back(Pair("R", HexStr(R.begin(), R.end())));
2020     result.push_back(Pair("PubkeyVariant", HexStr(vchPubKeyVariant.begin(), vchPubKeyVariant.end())));
2021     result.push_back(Pair("KeyVariantID", CBitcoinAddress(vchPubKeyVariant.GetID()).ToString()));
2022
2023     return result;
2024 }
2025
2026 Value listmalleableviews(const Array& params, bool fHelp)
2027 {
2028     if (fHelp || params.size() != 0)
2029         throw runtime_error(
2030             "listmalleableviews\n"
2031             "Get list of views for generated malleable keys.\n");
2032
2033     list<CMalleableKeyView> keyViewList;
2034     pwalletMain->ListMalleableViews(keyViewList);
2035
2036     Array result;
2037     for(const auto &keyView : keyViewList)
2038         result.push_back(keyView.ToString());
2039
2040     return result;
2041 }
2042