Add redeemScript size sanity checkings.
[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_t 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_t nAmount = AmountFromValue(params[0]);
274
275     // Min input amount
276     int64_t nMinValue = AmountFromValue(params[1]);
277
278     // Output amount
279     int64_t 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_t 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_t> 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_t 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_t 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_t GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth, const isminefilter& filter)
531 {
532     int64_t 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_t 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_t 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_t 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_t allGeneratedImmature, allGeneratedMature, allFee;
594             allGeneratedImmature = allGeneratedMature = allFee = 0;
595
596             string strSentAccount;
597             list<pair<CTxDestination, int64_t> > listReceived;
598             list<pair<CTxDestination, int64_t> > listSent;
599             wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount, filter);
600             if (wtx.GetDepthInMainChain() >= nMinDepth)
601             {
602                 BOOST_FOREACH(const PAIRTYPE(CTxDestination,int64_t)& r, listReceived)
603                     nBalance += r.second;
604             }
605             BOOST_FOREACH(const PAIRTYPE(CTxDestination,int64_t)& 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_t 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_t 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_t 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_t 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_t 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_t> > vecSend;
740
741     int64_t 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_t 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_t 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_t nFeeRequired = 0;
774     bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
775     if (!fCreated)
776     {
777         int64_t 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
851     if (inner.size() > MAX_SCRIPT_ELEMENT_SIZE)
852     throw runtime_error(
853         strprintf("redeemScript exceeds size limit: %" PRIszu " > %d", inner.size(), MAX_SCRIPT_ELEMENT_SIZE));
854
855     CScriptID innerID = inner.GetID();
856     pwalletMain->AddCScript(inner);
857
858     pwalletMain->SetAddressBookName(innerID, strAccount);
859     return CBitcoinAddress(innerID).ToString();
860 }
861
862 Value addredeemscript(const Array& params, bool fHelp)
863 {
864     if (fHelp || params.size() < 1 || params.size() > 2)
865     {
866         string msg = "addredeemscript <redeemScript> [account]\n"
867             "Add a P2SH address with a specified redeemScript to the wallet.\n"
868             "If [account] is specified, assign address to [account].";
869         throw runtime_error(msg);
870     }
871
872     string strAccount;
873     if (params.size() > 1)
874         strAccount = AccountFromValue(params[1]);
875
876     // Construct using pay-to-script-hash:
877     vector<unsigned char> innerData = ParseHexV(params[0], "redeemScript");
878     CScript inner(innerData.begin(), innerData.end());
879     CScriptID innerID = inner.GetID();
880     pwalletMain->AddCScript(inner);
881
882     pwalletMain->SetAddressBookName(innerID, strAccount);
883     return CBitcoinAddress(innerID).ToString();
884 }
885
886 struct tallyitem
887 {
888     int64_t nAmount;
889     int nConf;
890     tallyitem()
891     {
892         nAmount = 0;
893         nConf = std::numeric_limits<int>::max();
894     }
895 };
896
897 Value ListReceived(const Array& params, bool fByAccounts)
898 {
899     // Minimum confirmations
900     int nMinDepth = 1;
901     if (params.size() > 0)
902         nMinDepth = params[0].get_int();
903
904     // Whether to include empty accounts
905     bool fIncludeEmpty = false;
906     if (params.size() > 1)
907         fIncludeEmpty = params[1].get_bool();
908
909     // Tally
910     map<CBitcoinAddress, tallyitem> mapTally;
911     for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
912     {
913         const CWalletTx& wtx = (*it).second;
914
915         if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
916             continue;
917
918         int nDepth = wtx.GetDepthInMainChain();
919         if (nDepth < nMinDepth)
920             continue;
921
922         BOOST_FOREACH(const CTxOut& txout, wtx.vout)
923         {
924             CTxDestination address;
925             if (!ExtractDestination(txout.scriptPubKey, address) || !IsMine(*pwalletMain, address))
926                 continue;
927
928             tallyitem& item = mapTally[address];
929             item.nAmount += txout.nValue;
930             item.nConf = min(item.nConf, nDepth);
931         }
932     }
933
934     // Reply
935     Array ret;
936     map<string, tallyitem> mapAccountTally;
937     BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
938     {
939         const CBitcoinAddress& address = item.first;
940         const string& strAccount = item.second;
941         map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
942         if (it == mapTally.end() && !fIncludeEmpty)
943             continue;
944
945         int64_t nAmount = 0;
946         int nConf = std::numeric_limits<int>::max();
947         if (it != mapTally.end())
948         {
949             nAmount = (*it).second.nAmount;
950             nConf = (*it).second.nConf;
951         }
952
953         if (fByAccounts)
954         {
955             tallyitem& item = mapAccountTally[strAccount];
956             item.nAmount += nAmount;
957             item.nConf = min(item.nConf, nConf);
958         }
959         else
960         {
961             Object obj;
962             obj.push_back(Pair("address",       address.ToString()));
963             obj.push_back(Pair("account",       strAccount));
964             obj.push_back(Pair("amount",        ValueFromAmount(nAmount)));
965             obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
966             ret.push_back(obj);
967         }
968     }
969
970     if (fByAccounts)
971     {
972         for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
973         {
974             int64_t nAmount = (*it).second.nAmount;
975             int nConf = (*it).second.nConf;
976             Object obj;
977             obj.push_back(Pair("account",       (*it).first));
978             obj.push_back(Pair("amount",        ValueFromAmount(nAmount)));
979             obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
980             ret.push_back(obj);
981         }
982     }
983
984     return ret;
985 }
986
987 Value listreceivedbyaddress(const Array& params, bool fHelp)
988 {
989     if (fHelp || params.size() > 2)
990         throw runtime_error(
991             "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
992             "[minconf] is the minimum number of confirmations before payments are included.\n"
993             "[includeempty] whether to include addresses that haven't received any payments.\n"
994             "Returns an array of objects containing:\n"
995             "  \"address\" : receiving address\n"
996             "  \"account\" : the account of the receiving address\n"
997             "  \"amount\" : total amount received by the address\n"
998             "  \"confirmations\" : number of confirmations of the most recent transaction included");
999
1000     return ListReceived(params, false);
1001 }
1002
1003 Value listreceivedbyaccount(const Array& params, bool fHelp)
1004 {
1005     if (fHelp || params.size() > 2)
1006         throw runtime_error(
1007             "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
1008             "[minconf] is the minimum number of confirmations before payments are included.\n"
1009             "[includeempty] whether to include accounts that haven't received any payments.\n"
1010             "Returns an array of objects containing:\n"
1011             "  \"account\" : the account of the receiving addresses\n"
1012             "  \"amount\" : total amount received by addresses with this account\n"
1013             "  \"confirmations\" : number of confirmations of the most recent transaction included");
1014
1015     return ListReceived(params, true);
1016 }
1017
1018 static void MaybePushAddress(Object & entry, const CTxDestination &dest)
1019 {
1020     CBitcoinAddress addr;
1021     if (addr.Set(dest))
1022         entry.push_back(Pair("address", addr.ToString()));
1023 }
1024
1025 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret, const isminefilter& filter)
1026 {
1027     int64_t nGeneratedImmature, nGeneratedMature, nFee;
1028     string strSentAccount;
1029     list<pair<CTxDestination, int64_t> > listReceived;
1030     list<pair<CTxDestination, int64_t> > listSent;
1031
1032     wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount, filter);
1033
1034     bool fAllAccounts = (strAccount == string("*"));
1035     bool involvesWatchonly = wtx.IsFromMe(MINE_WATCH_ONLY);
1036
1037     // Generated blocks assigned to account ""
1038     if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
1039     {
1040         Object entry;
1041         entry.push_back(Pair("account", string("")));
1042         if (nGeneratedImmature)
1043         {
1044             entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
1045             entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
1046         }
1047         else
1048         {
1049             entry.push_back(Pair("category", "generate"));
1050             entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
1051         }
1052         if (fLong)
1053             WalletTxToJSON(wtx, entry);
1054         ret.push_back(entry);
1055     }
1056
1057     // Sent
1058     if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1059     {
1060         BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64_t)& s, listSent)
1061         {
1062             Object entry;
1063             entry.push_back(Pair("account", strSentAccount));
1064             if(involvesWatchonly || (::IsMine(*pwalletMain, s.first) & MINE_WATCH_ONLY))
1065                 entry.push_back(Pair("involvesWatchonly", true));
1066             MaybePushAddress(entry, s.first);
1067
1068             if (wtx.GetDepthInMainChain() < 0) {
1069                 entry.push_back(Pair("category", "conflicted"));
1070             } else {
1071                 entry.push_back(Pair("category", "send"));
1072             }
1073
1074             entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1075             entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1076             if (fLong)
1077                 WalletTxToJSON(wtx, entry);
1078             ret.push_back(entry);
1079         }
1080     }
1081
1082     // Received
1083     if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1084     {
1085         BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64_t)& r, listReceived)
1086         {
1087             string account;
1088             if (pwalletMain->mapAddressBook.count(r.first))
1089                 account = pwalletMain->mapAddressBook[r.first];
1090             if (fAllAccounts || (account == strAccount))
1091             {
1092                 Object entry;
1093                 entry.push_back(Pair("account", account));
1094                 if(involvesWatchonly || (::IsMine(*pwalletMain, r.first) & MINE_WATCH_ONLY))
1095                     entry.push_back(Pair("involvesWatchonly", true));
1096                 MaybePushAddress(entry, r.first);
1097                 if (wtx.IsCoinBase())
1098                 {
1099                     if (wtx.GetDepthInMainChain() < 1)
1100                         entry.push_back(Pair("category", "orphan"));
1101                     else if (wtx.GetBlocksToMaturity() > 0)
1102                         entry.push_back(Pair("category", "immature"));
1103                     else
1104                         entry.push_back(Pair("category", "generate"));
1105                 }
1106                 else
1107                     entry.push_back(Pair("category", "receive"));
1108                 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1109                 if (fLong)
1110                     WalletTxToJSON(wtx, entry);
1111                 ret.push_back(entry);
1112             }
1113         }
1114     }
1115 }
1116
1117 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1118 {
1119     bool fAllAccounts = (strAccount == string("*"));
1120
1121     if (fAllAccounts || acentry.strAccount == strAccount)
1122     {
1123         Object entry;
1124         entry.push_back(Pair("account", acentry.strAccount));
1125         entry.push_back(Pair("category", "move"));
1126         entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
1127         entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1128         entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1129         entry.push_back(Pair("comment", acentry.strComment));
1130         ret.push_back(entry);
1131     }
1132 }
1133
1134 Value listtransactions(const Array& params, bool fHelp)
1135 {
1136     if (fHelp || params.size() > 3)
1137         throw runtime_error(
1138             "listtransactions [account] [count=10] [from=0]\n"
1139             "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1140
1141     string strAccount = "*";
1142     if (params.size() > 0)
1143         strAccount = params[0].get_str();
1144     int nCount = 10;
1145     if (params.size() > 1)
1146         nCount = params[1].get_int();
1147     int nFrom = 0;
1148     if (params.size() > 2)
1149         nFrom = params[2].get_int();
1150
1151     isminefilter filter = MINE_SPENDABLE;
1152     if(params.size() > 3)
1153         if(params[3].get_bool())
1154             filter = filter | MINE_WATCH_ONLY;
1155
1156     if (nCount < 0)
1157         throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count");
1158     if (nFrom < 0)
1159         throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative from");
1160
1161     Array ret;
1162
1163     std::list<CAccountingEntry> acentries;
1164     CWallet::TxItems txOrdered = pwalletMain->OrderedTxItems(acentries, strAccount);
1165
1166     // iterate backwards until we have nCount items to return:
1167     for (CWallet::TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
1168     {
1169         CWalletTx *const pwtx = (*it).second.first;
1170         if (pwtx != 0)
1171             ListTransactions(*pwtx, strAccount, 0, true, ret, filter);
1172         CAccountingEntry *const pacentry = (*it).second.second;
1173         if (pacentry != 0)
1174             AcentryToJSON(*pacentry, strAccount, ret);
1175
1176         if ((int)ret.size() >= (nCount+nFrom)) break;
1177     }
1178     // ret is newest to oldest
1179
1180     if (nFrom > (int)ret.size())
1181         nFrom = ret.size();
1182     if ((nFrom + nCount) > (int)ret.size())
1183         nCount = ret.size() - nFrom;
1184     Array::iterator first = ret.begin();
1185     std::advance(first, nFrom);
1186     Array::iterator last = ret.begin();
1187     std::advance(last, nFrom+nCount);
1188
1189     if (last != ret.end()) ret.erase(last, ret.end());
1190     if (first != ret.begin()) ret.erase(ret.begin(), first);
1191
1192     std::reverse(ret.begin(), ret.end()); // Return oldest to newest
1193
1194     return ret;
1195 }
1196
1197 Value listaccounts(const Array& params, bool fHelp)
1198 {
1199     if (fHelp || params.size() > 1)
1200         throw runtime_error(
1201             "listaccounts [minconf=1]\n"
1202             "Returns Object that has account names as keys, account balances as values.");
1203
1204     int nMinDepth = 1;
1205     if (params.size() > 0)
1206         nMinDepth = params[0].get_int();
1207
1208     isminefilter includeWatchonly = MINE_SPENDABLE;
1209     if(params.size() > 1)
1210         if(params[1].get_bool())
1211             includeWatchonly = includeWatchonly | MINE_WATCH_ONLY;
1212
1213
1214     map<string, int64_t> mapAccountBalances;
1215     BOOST_FOREACH(const PAIRTYPE(CTxDestination, string)& entry, pwalletMain->mapAddressBook) {
1216         if (IsMine(*pwalletMain, entry.first)) // This address belongs to me
1217             mapAccountBalances[entry.second] = 0;
1218     }
1219
1220     for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1221     {
1222         const CWalletTx& wtx = (*it).second;
1223         int64_t nGeneratedImmature, nGeneratedMature, nFee;
1224         string strSentAccount;
1225         list<pair<CTxDestination, int64_t> > listReceived;
1226         list<pair<CTxDestination, int64_t> > listSent;
1227         wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount, includeWatchonly);
1228         mapAccountBalances[strSentAccount] -= nFee;
1229         BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64_t)& s, listSent)
1230             mapAccountBalances[strSentAccount] -= s.second;
1231         if (wtx.GetDepthInMainChain() >= nMinDepth)
1232         {
1233             mapAccountBalances[""] += nGeneratedMature;
1234             BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64_t)& r, listReceived)
1235                 if (pwalletMain->mapAddressBook.count(r.first))
1236                     mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1237                 else
1238                     mapAccountBalances[""] += r.second;
1239         }
1240     }
1241
1242     list<CAccountingEntry> acentries;
1243     CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1244     BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1245         mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1246
1247     Object ret;
1248     BOOST_FOREACH(const PAIRTYPE(string, int64_t)& accountBalance, mapAccountBalances) {
1249         ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1250     }
1251     return ret;
1252 }
1253
1254 Value listsinceblock(const Array& params, bool fHelp)
1255 {
1256     if (fHelp)
1257         throw runtime_error(
1258             "listsinceblock [blockhash] [target-confirmations]\n"
1259             "Get all transactions in blocks since block [blockhash], or all transactions if omitted");
1260
1261     CBlockIndex *pindex = NULL;
1262     int target_confirms = 1;
1263     isminefilter filter = MINE_SPENDABLE;
1264
1265     if (params.size() > 0)
1266     {
1267         uint256 blockId = 0;
1268
1269         blockId.SetHex(params[0].get_str());
1270         pindex = CBlockLocator(blockId).GetBlockIndex();
1271     }
1272
1273     if (params.size() > 1)
1274     {
1275         target_confirms = params[1].get_int();
1276
1277         if (target_confirms < 1)
1278             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter");
1279     }
1280
1281     if(params.size() > 2)
1282         if(params[2].get_bool())
1283             filter = filter | MINE_WATCH_ONLY;
1284
1285     int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
1286
1287     Array transactions;
1288
1289     for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1290     {
1291         CWalletTx tx = (*it).second;
1292
1293         if (depth == -1 || tx.GetDepthInMainChain() < depth)
1294             ListTransactions(tx, "*", 0, true, transactions, filter);
1295     }
1296
1297     uint256 lastblock;
1298
1299     if (target_confirms == 1)
1300     {
1301         lastblock = hashBestChain;
1302     }
1303     else
1304     {
1305         int target_height = pindexBest->nHeight + 1 - target_confirms;
1306
1307         CBlockIndex *block;
1308         for (block = pindexBest;
1309              block && block->nHeight > target_height;
1310              block = block->pprev)  { }
1311
1312         lastblock = block ? block->GetBlockHash() : 0;
1313     }
1314
1315     Object ret;
1316     ret.push_back(Pair("transactions", transactions));
1317     ret.push_back(Pair("lastblock", lastblock.GetHex()));
1318
1319     return ret;
1320 }
1321
1322 Value gettransaction(const Array& params, bool fHelp)
1323 {
1324     if (fHelp || params.size() != 1)
1325         throw runtime_error(
1326             "gettransaction <txid>\n"
1327             "Get detailed information about <txid>");
1328
1329     uint256 hash;
1330     hash.SetHex(params[0].get_str());
1331
1332     isminefilter filter = MINE_SPENDABLE;
1333     if(params.size() > 1)
1334         if(params[1].get_bool())
1335             filter = filter | MINE_WATCH_ONLY;
1336
1337     Object entry;
1338
1339     if (pwalletMain->mapWallet.count(hash))
1340     {
1341         const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1342
1343         TxToJSON(wtx, 0, entry);
1344
1345         int64_t nCredit = wtx.GetCredit(filter);
1346         int64_t nDebit = wtx.GetDebit(filter);
1347         int64_t nNet = nCredit - nDebit;
1348         int64_t nFee = (wtx.IsFromMe(filter) ? wtx.GetValueOut() - nDebit : 0);
1349
1350         entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1351         if (wtx.IsFromMe(filter))
1352             entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1353
1354         WalletTxToJSON(wtx, entry);
1355
1356         Array details;
1357         ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details, filter);
1358         entry.push_back(Pair("details", details));
1359     }
1360     else
1361     {
1362         CTransaction tx;
1363         uint256 hashBlock = 0;
1364         if (GetTransaction(hash, tx, hashBlock))
1365         {
1366             TxToJSON(tx, 0, entry);
1367             if (hashBlock == 0)
1368                 entry.push_back(Pair("confirmations", 0));
1369             else
1370             {
1371                 entry.push_back(Pair("blockhash", hashBlock.GetHex()));
1372                 map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
1373                 if (mi != mapBlockIndex.end() && (*mi).second)
1374                 {
1375                     CBlockIndex* pindex = (*mi).second;
1376                     if (pindex->IsInMainChain())
1377                         entry.push_back(Pair("confirmations", 1 + nBestHeight - pindex->nHeight));
1378                     else
1379                         entry.push_back(Pair("confirmations", 0));
1380                 }
1381             }
1382         }
1383         else
1384             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction");
1385     }
1386
1387     return entry;
1388 }
1389
1390
1391 Value backupwallet(const Array& params, bool fHelp)
1392 {
1393     if (fHelp || params.size() != 1)
1394         throw runtime_error(
1395             "backupwallet <destination>\n"
1396             "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1397
1398     string strDest = params[0].get_str();
1399     if (!BackupWallet(*pwalletMain, strDest))
1400         throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!");
1401
1402     return Value::null;
1403 }
1404
1405
1406 Value keypoolrefill(const Array& params, bool fHelp)
1407 {
1408     if (fHelp || params.size() > 1)
1409         throw runtime_error(
1410             "keypoolrefill [new-size]\n"
1411             "Fills the keypool."
1412             + HelpRequiringPassphrase());
1413
1414     unsigned int nSize = max<unsigned int>(GetArg("-keypool", 100), 0);
1415     if (params.size() > 0) {
1416         if (params[0].get_int() < 0)
1417             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size");
1418         nSize = (unsigned int) params[0].get_int();
1419     }
1420
1421     EnsureWalletIsUnlocked();
1422
1423     pwalletMain->TopUpKeyPool(nSize);
1424
1425     if (pwalletMain->GetKeyPoolSize() < nSize)
1426         throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool.");
1427
1428     return Value::null;
1429 }
1430
1431
1432 void ThreadTopUpKeyPool(void* parg)
1433 {
1434     // Make this thread recognisable as the key-topping-up thread
1435     RenameThread("novacoin-key-top");
1436
1437     pwalletMain->TopUpKeyPool();
1438 }
1439
1440 void ThreadCleanWalletPassphrase(void* parg)
1441 {
1442     // Make this thread recognisable as the wallet relocking thread
1443     RenameThread("novacoin-lock-wa");
1444
1445     int64_t nMyWakeTime = GetTimeMillis() + *((int64_t*)parg) * 1000;
1446
1447     ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1448
1449     if (nWalletUnlockTime == 0)
1450     {
1451         nWalletUnlockTime = nMyWakeTime;
1452
1453         do
1454         {
1455             if (nWalletUnlockTime==0)
1456                 break;
1457             int64_t nToSleep = nWalletUnlockTime - GetTimeMillis();
1458             if (nToSleep <= 0)
1459                 break;
1460
1461             LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1462             Sleep(nToSleep);
1463             ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1464
1465         } while(1);
1466
1467         if (nWalletUnlockTime)
1468         {
1469             nWalletUnlockTime = 0;
1470             pwalletMain->Lock();
1471         }
1472     }
1473     else
1474     {
1475         if (nWalletUnlockTime < nMyWakeTime)
1476             nWalletUnlockTime = nMyWakeTime;
1477     }
1478
1479     LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1480
1481     delete (int64_t*)parg;
1482 }
1483
1484 Value walletpassphrase(const Array& params, bool fHelp)
1485 {
1486     if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 3))
1487         throw runtime_error(
1488             "walletpassphrase <passphrase> <timeout> [mintonly]\n"
1489             "Stores the wallet decryption key in memory for <timeout> seconds.\n"
1490             "mintonly is optional true/false allowing only block minting.");
1491     if (fHelp)
1492         return true;
1493     if (!pwalletMain->IsCrypted())
1494         throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1495
1496     if (!pwalletMain->IsLocked())
1497         throw JSONRPCError(RPC_WALLET_ALREADY_UNLOCKED, "Error: Wallet is already unlocked, use walletlock first if need to change unlock settings.");
1498     // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1499     SecureString strWalletPass;
1500     strWalletPass.reserve(100);
1501     // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1502     // Alternately, find a way to make params[0] mlock()'d to begin with.
1503     strWalletPass = params[0].get_str().c_str();
1504
1505     if (strWalletPass.length() > 0)
1506     {
1507         if (!pwalletMain->Unlock(strWalletPass))
1508             throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
1509     }
1510     else
1511         throw runtime_error(
1512             "walletpassphrase <passphrase> <timeout>\n"
1513             "Stores the wallet decryption key in memory for <timeout> seconds.");
1514
1515     NewThread(ThreadTopUpKeyPool, NULL);
1516     int64_t* pnSleepTime = new int64_t(params[1].get_int64());
1517     NewThread(ThreadCleanWalletPassphrase, pnSleepTime);
1518
1519     // ppcoin: if user OS account compromised prevent trivial sendmoney commands
1520     if (params.size() > 2)
1521         fWalletUnlockMintOnly = params[2].get_bool();
1522     else
1523         fWalletUnlockMintOnly = false;
1524
1525     return Value::null;
1526 }
1527
1528
1529 Value walletpassphrasechange(const Array& params, bool fHelp)
1530 {
1531     if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1532         throw runtime_error(
1533             "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1534             "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1535     if (fHelp)
1536         return true;
1537     if (!pwalletMain->IsCrypted())
1538         throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1539
1540     // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1541     // Alternately, find a way to make params[0] mlock()'d to begin with.
1542     SecureString strOldWalletPass;
1543     strOldWalletPass.reserve(100);
1544     strOldWalletPass = params[0].get_str().c_str();
1545
1546     SecureString strNewWalletPass;
1547     strNewWalletPass.reserve(100);
1548     strNewWalletPass = params[1].get_str().c_str();
1549
1550     if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1551         throw runtime_error(
1552             "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1553             "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1554
1555     if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1556         throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
1557
1558     return Value::null;
1559 }
1560
1561
1562 Value walletlock(const Array& params, bool fHelp)
1563 {
1564     if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1565         throw runtime_error(
1566             "walletlock\n"
1567             "Removes the wallet encryption key from memory, locking the wallet.\n"
1568             "After calling this method, you will need to call walletpassphrase again\n"
1569             "before being able to call any methods which require the wallet to be unlocked.");
1570     if (fHelp)
1571         return true;
1572     if (!pwalletMain->IsCrypted())
1573         throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletlock was called.");
1574
1575     {
1576         LOCK(cs_nWalletUnlockTime);
1577         pwalletMain->Lock();
1578         nWalletUnlockTime = 0;
1579     }
1580
1581     return Value::null;
1582 }
1583
1584
1585 Value encryptwallet(const Array& params, bool fHelp)
1586 {
1587     if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1588         throw runtime_error(
1589             "encryptwallet <passphrase>\n"
1590             "Encrypts the wallet with <passphrase>.");
1591     if (fHelp)
1592         return true;
1593     if (pwalletMain->IsCrypted())
1594         throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an encrypted wallet, but encryptwallet was called.");
1595
1596     // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1597     // Alternately, find a way to make params[0] mlock()'d to begin with.
1598     SecureString strWalletPass;
1599     strWalletPass.reserve(100);
1600     strWalletPass = params[0].get_str().c_str();
1601
1602     if (strWalletPass.length() < 1)
1603         throw runtime_error(
1604             "encryptwallet <passphrase>\n"
1605             "Encrypts the wallet with <passphrase>.");
1606
1607     if (!pwalletMain->EncryptWallet(strWalletPass))
1608         throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: Failed to encrypt the wallet.");
1609
1610     // BDB seems to have a bad habit of writing old data into
1611     // slack space in .dat files; that is bad if the old data is
1612     // unencrypted private keys. So:
1613     StartShutdown();
1614     return "wallet encrypted; NovaCoin server stopping, restart to run with encrypted wallet.  The keypool has been flushed, you need to make a new backup.";
1615 }
1616
1617 class DescribeAddressVisitor : public boost::static_visitor<Object>
1618 {
1619 private:
1620     isminetype mine;
1621 public:
1622     DescribeAddressVisitor(isminetype mineIn) : mine(mineIn) {}
1623
1624     Object operator()(const CNoDestination &dest) const { return Object(); }
1625     Object operator()(const CKeyID &keyID) const {
1626         Object obj;
1627         CPubKey vchPubKey;
1628         pwalletMain->GetPubKey(keyID, vchPubKey);
1629         obj.push_back(Pair("isscript", false));
1630         if (mine == MINE_SPENDABLE) {
1631             pwalletMain->GetPubKey(keyID, vchPubKey);
1632             obj.push_back(Pair("pubkey", HexStr(vchPubKey.Raw())));
1633             obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed()));
1634         }
1635         return obj;
1636     }
1637
1638     Object operator()(const CScriptID &scriptID) const {
1639         Object obj;
1640         obj.push_back(Pair("isscript", true));
1641         if (mine == MINE_SPENDABLE) {
1642             CScript subscript;
1643             pwalletMain->GetCScript(scriptID, subscript);
1644             std::vector<CTxDestination> addresses;
1645             txnouttype whichType;
1646             int nRequired;
1647             ExtractDestinations(subscript, whichType, addresses, nRequired);
1648             obj.push_back(Pair("script", GetTxnOutputType(whichType)));
1649             obj.push_back(Pair("hex", HexStr(subscript.begin(), subscript.end())));
1650             Array a;
1651             BOOST_FOREACH(const CTxDestination& addr, addresses)
1652                 a.push_back(CBitcoinAddress(addr).ToString());
1653             obj.push_back(Pair("addresses", a));
1654             if (whichType == TX_MULTISIG)
1655                 obj.push_back(Pair("sigsrequired", nRequired));
1656         }
1657         return obj;
1658     }
1659 };
1660
1661 Value validateaddress(const Array& params, bool fHelp)
1662 {
1663     if (fHelp || params.size() != 1)
1664         throw runtime_error(
1665             "validateaddress <novacoinaddress>\n"
1666             "Return information about <novacoinaddress>.");
1667
1668     CBitcoinAddress address(params[0].get_str());
1669     bool isValid = address.IsValid();
1670
1671     Object ret;
1672     ret.push_back(Pair("isvalid", isValid));
1673     if (isValid)
1674     {
1675         CTxDestination dest = address.Get();
1676         string currentAddress = address.ToString();
1677         ret.push_back(Pair("address", currentAddress));
1678         isminetype mine = pwalletMain ? IsMine(*pwalletMain, dest) : MINE_NO;
1679         ret.push_back(Pair("ismine", mine != MINE_NO));
1680         if (mine != MINE_NO) {
1681             ret.push_back(Pair("watchonly", mine == MINE_WATCH_ONLY));
1682             Object detail = boost::apply_visitor(DescribeAddressVisitor(mine), dest);
1683             ret.insert(ret.end(), detail.begin(), detail.end());
1684         }
1685         if (pwalletMain->mapAddressBook.count(dest))
1686             ret.push_back(Pair("account", pwalletMain->mapAddressBook[dest]));
1687     }
1688     return ret;
1689 }
1690
1691 // ppcoin: reserve balance from being staked for network protection
1692 Value reservebalance(const Array& params, bool fHelp)
1693 {
1694     if (fHelp || params.size() > 2)
1695         throw runtime_error(
1696             "reservebalance [<reserve> [amount]]\n"
1697             "<reserve> is true or false to turn balance reserve on or off.\n"
1698             "<amount> is a real and rounded to cent.\n"
1699             "Set reserve amount not participating in network protection.\n"
1700             "If no parameters provided current setting is printed.\n");
1701
1702     if (params.size() > 0)
1703     {
1704         bool fReserve = params[0].get_bool();
1705         if (fReserve)
1706         {
1707             if (params.size() == 1)
1708                 throw runtime_error("must provide amount to reserve balance.\n");
1709             int64_t nAmount = AmountFromValue(params[1]);
1710             nAmount = (nAmount / CENT) * CENT;  // round to cent
1711             if (nAmount < 0)
1712                 throw runtime_error("amount cannot be negative.\n");
1713             mapArgs["-reservebalance"] = FormatMoney(nAmount).c_str();
1714         }
1715         else
1716         {
1717             if (params.size() > 1)
1718                 throw runtime_error("cannot specify amount to turn off reserve.\n");
1719             mapArgs["-reservebalance"] = "0";
1720         }
1721     }
1722
1723     Object result;
1724     int64_t nReserveBalance = 0;
1725     if (mapArgs.count("-reservebalance") && !ParseMoney(mapArgs["-reservebalance"], nReserveBalance))
1726         throw runtime_error("invalid reserve balance amount\n");
1727     result.push_back(Pair("reserve", (nReserveBalance > 0)));
1728     result.push_back(Pair("amount", ValueFromAmount(nReserveBalance)));
1729     return result;
1730 }
1731
1732
1733 // ppcoin: check wallet integrity
1734 Value checkwallet(const Array& params, bool fHelp)
1735 {
1736     if (fHelp || params.size() > 0)
1737         throw runtime_error(
1738             "checkwallet\n"
1739             "Check wallet for integrity.\n");
1740
1741     int nMismatchSpent;
1742     int64_t nBalanceInQuestion;
1743     pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion, true);
1744     Object result;
1745     if (nMismatchSpent == 0)
1746         result.push_back(Pair("wallet check passed", true));
1747     else
1748     {
1749         result.push_back(Pair("mismatched spent coins", nMismatchSpent));
1750         result.push_back(Pair("amount in question", ValueFromAmount(nBalanceInQuestion)));
1751     }
1752     return result;
1753 }
1754
1755
1756 // ppcoin: repair wallet
1757 Value repairwallet(const Array& params, bool fHelp)
1758 {
1759     if (fHelp || params.size() > 0)
1760         throw runtime_error(
1761             "repairwallet\n"
1762             "Repair wallet if checkwallet reports any problem.\n");
1763
1764     int nMismatchSpent;
1765     int64_t nBalanceInQuestion;
1766     pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion);
1767     Object result;
1768     if (nMismatchSpent == 0)
1769         result.push_back(Pair("wallet check passed", true));
1770     else
1771     {
1772         result.push_back(Pair("mismatched spent coins", nMismatchSpent));
1773         result.push_back(Pair("amount affected by repair", ValueFromAmount(nBalanceInQuestion)));
1774     }
1775     return result;
1776 }
1777
1778 // NovaCoin: resend unconfirmed wallet transactions
1779 Value resendtx(const Array& params, bool fHelp)
1780 {
1781     if (fHelp || params.size() > 1)
1782         throw runtime_error(
1783             "resendtx\n"
1784             "Re-send unconfirmed transactions.\n"
1785         );
1786
1787     ResendWalletTransactions();
1788
1789     return Value::null;
1790 }
1791
1792 // ppcoin: make a public-private key pair
1793 Value makekeypair(const Array& params, bool fHelp)
1794 {
1795     if (fHelp || params.size() > 1)
1796         throw runtime_error(
1797             "makekeypair [prefix]\n"
1798             "Make a public/private key pair.\n"
1799             "[prefix] is optional preferred prefix for the public key.\n");
1800
1801     string strPrefix = "";
1802     if (params.size() > 0)
1803         strPrefix = params[0].get_str();
1804  
1805     CKey key;
1806     key.MakeNewKey(false);
1807
1808     CPrivKey vchPrivKey = key.GetPrivKey();
1809     Object result;
1810     result.push_back(Pair("PrivateKey", HexStr<CPrivKey::iterator>(vchPrivKey.begin(), vchPrivKey.end())));
1811     result.push_back(Pair("PublicKey", HexStr(key.GetPubKey().Raw())));
1812     return result;
1813 }