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