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