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