]> Git Repo - VerusCoin.git/blame - src/rpcwallet.cpp
Merge branch '2012_09_fixwformat' of github.com:laanwj/bitcoin
[VerusCoin.git] / src / rpcwallet.cpp
CommitLineData
e3bc5698
JG
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
12using namespace json_spirit;
13using namespace std;
14
15int64 nWalletUnlockTime;
16static CCriticalSection cs_nWalletUnlockTime;
17
bdab0cf5 18std::string HelpRequiringPassphrase()
e3bc5698
JG
19{
20 return pwalletMain->IsCrypted()
21 ? "\nrequires wallet passphrase to be set with walletpassphrase first"
22 : "";
23}
24
bdab0cf5 25void EnsureWalletIsUnlocked()
e3bc5698
JG
26{
27 if (pwalletMain->IsLocked())
28 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
29}
30
31void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
32{
33 int confirms = wtx.GetDepthInMainChain();
34 entry.push_back(Pair("confirmations", confirms));
e07c8e91
LD
35 if (wtx.IsCoinBase())
36 entry.push_back(Pair("generated", true));
e3bc5698
JG
37 if (confirms)
38 {
39 entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex()));
40 entry.push_back(Pair("blockindex", wtx.nIndex));
bdbfd232 41 entry.push_back(Pair("blocktime", (boost::int64_t)(mapBlockIndex[wtx.hashBlock]->nTime)));
e3bc5698
JG
42 }
43 entry.push_back(Pair("txid", wtx.GetHash().GetHex()));
44 entry.push_back(Pair("time", (boost::int64_t)wtx.GetTxTime()));
bdbfd232 45 entry.push_back(Pair("timereceived", (boost::int64_t)wtx.nTimeReceived));
e3bc5698
JG
46 BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
47 entry.push_back(Pair(item.first, item.second));
48}
49
50string AccountFromValue(const Value& value)
51{
52 string strAccount = value.get_str();
53 if (strAccount == "*")
54 throw JSONRPCError(-11, "Invalid account name");
55 return strAccount;
56}
57
c625ae04
JG
58Value 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 CService addrProxy;
66 GetProxy(NET_IPV4, addrProxy);
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", (addrProxy.IsValid() ? addrProxy.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
e3bc5698
JG
89Value 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(-12, "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
118CBitcoinAddress 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(-12, "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
156Value 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
175Value 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(-5, "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
205Value 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(-5, "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
224Value 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
245Value 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(-5, "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(-13, "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(-4, strError);
273
274 return wtx.GetHash().GetHex();
275}
276
22dfd735 277Value listaddressgroupings(const Array& params, bool fHelp)
278{
279 if (fHelp)
b1093efa
GM
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");
22dfd735 285
286 Array jsonGroupings;
b1093efa
GM
287 map<CTxDestination, int64> balances = pwalletMain->GetAddressBalances();
288 BOOST_FOREACH(set<CTxDestination> grouping, pwalletMain->GetAddressGroupings())
22dfd735 289 {
290 Array jsonGrouping;
b1093efa 291 BOOST_FOREACH(CTxDestination address, grouping)
22dfd735 292 {
293 Array addressInfo;
b1093efa 294 addressInfo.push_back(CBitcoinAddress(address).ToString());
22dfd735 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
e3bc5698
JG
308Value 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(-3, "Invalid address");
323
324 CKeyID keyID;
325 if (!addr.GetKeyID(keyID))
326 throw JSONRPCError(-3, "Address does not refer to key");
327
328 CKey key;
329 if (!pwalletMain->GetKey(keyID, key))
330 throw JSONRPCError(-4, "Private key not available");
331
332 CDataStream ss(SER_GETHASH, 0);
333 ss << strMessageMagic;
334 ss << strMessage;
335
336 vector<unsigned char> vchSig;
337 if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
338 throw JSONRPCError(-5, "Sign failed");
339
340 return EncodeBase64(&vchSig[0], vchSig.size());
341}
342
343Value 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(-3, "Invalid address");
357
358 CKeyID keyID;
359 if (!addr.GetKeyID(keyID))
360 throw JSONRPCError(-3, "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(-5, "Malformed base64 encoding");
367
368 CDataStream ss(SER_GETHASH, 0);
369 ss << strMessageMagic;
370 ss << strMessage;
371
372 CKey key;
373 if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
374 return false;
375
376 return (key.GetPubKey().GetID() == keyID);
377}
378
379
380Value 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(-5, "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
419void 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
430Value 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
468int64 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
e07c8e91
LD
479 int64 nReceived, nSent, nFee;
480 wtx.GetAccountAmounts(strAccount, nReceived, nSent, nFee);
e3bc5698
JG
481
482 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
483 nBalance += nReceived;
e07c8e91 484 nBalance -= nSent + nFee;
e3bc5698
JG
485 }
486
487 // Tally internal accounting entries
488 nBalance += walletdb.GetAccountCreditDebit(strAccount);
489
490 return nBalance;
491}
492
493int64 GetAccountBalance(const string& strAccount, int nMinDepth)
494{
495 CWalletDB walletdb(pwalletMain->strWalletFile);
496 return GetAccountBalance(walletdb, strAccount, nMinDepth);
497}
498
499
500Value 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
e07c8e91 526 int64 allFee;
e3bc5698
JG
527 string strSentAccount;
528 list<pair<CTxDestination, int64> > listReceived;
529 list<pair<CTxDestination, int64> > listSent;
e07c8e91 530 wtx.GetAmounts(listReceived, listSent, allFee, strSentAccount);
e3bc5698
JG
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;
e3bc5698
JG
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
551Value 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(-20, "database error");
571
572 int64 nNow = GetAdjustedTime();
573
574 // Debit
575 CAccountingEntry debit;
da7b8c12 576 debit.nOrderPos = pwalletMain->IncOrderPosNext();
e3bc5698
JG
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;
da7b8c12 586 credit.nOrderPos = pwalletMain->IncOrderPosNext();
e3bc5698
JG
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(-20, "database error");
596
597 return true;
598}
599
600
601Value 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(-5, "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(-6, "Account has insufficient funds");
631
632 // Send
633 string strError = pwalletMain->SendMoneyToDestination(address.Get(), nAmount, wtx);
634 if (strError != "")
635 throw JSONRPCError(-4, strError);
636
637 return wtx.GetHash().GetHex();
638}
639
640
641Value 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())
331544bc 668 throw JSONRPCError(-5, string("Invalid Bitcoin address: ")+s.name_);
e3bc5698
JG
669
670 if (setAddress.count(address))
671 throw JSONRPCError(-8, 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(-6, "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(-6, "Insufficient funds");
697 throw JSONRPCError(-4, "Transaction creation failed");
698 }
699 if (!pwalletMain->CommitTransaction(wtx, keyChange))
700 throw JSONRPCError(-4, "Transaction commit failed");
701
702 return wtx.GetHash().GetHex();
703}
704
705Value 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 "
d210f4f5 728 "(got %"PRIszu" keys, but need at least %d to redeem)", keys.size(), nRequired));
e3bc5698
JG
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
775struct tallyitem
776{
777 int64 nAmount;
778 int nConf;
779 tallyitem()
780 {
781 nAmount = 0;
782 nConf = std::numeric_limits<int>::max();
783 }
784};
785
786Value 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
876Value 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
892Value 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
907void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
908{
e07c8e91 909 int64 nFee;
e3bc5698
JG
910 string strSentAccount;
911 list<pair<CTxDestination, int64> > listReceived;
912 list<pair<CTxDestination, int64> > listSent;
913
e07c8e91 914 wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount);
e3bc5698
JG
915
916 bool fAllAccounts = (strAccount == string("*"));
917
e3bc5698
JG
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()));
e07c8e91
LD
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"));
e3bc5698
JG
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
968void 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
985Value 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(-8, "Negative count");
1004 if (nFrom < 0)
1005 throw JSONRPCError(-8, "Negative from");
1006
1007 Array ret;
e3bc5698 1008
ddb709e9
LD
1009 std::list<CAccountingEntry> acentries;
1010 CWallet::TxItems txOrdered = pwalletMain->OrderedTxItems(acentries, strAccount);
e3bc5698
JG
1011
1012 // iterate backwards until we have nCount items to return:
c3f95ef1 1013 for (CWallet::TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
e3bc5698
JG
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
1043Value 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;
e07c8e91 1063 int64 nFee;
e3bc5698
JG
1064 string strSentAccount;
1065 list<pair<CTxDestination, int64> > listReceived;
1066 list<pair<CTxDestination, int64> > listSent;
e07c8e91 1067 wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount);
e3bc5698
JG
1068 mapAccountBalances[strSentAccount] -= nFee;
1069 BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& s, listSent)
1070 mapAccountBalances[strSentAccount] -= s.second;
1071 if (wtx.GetDepthInMainChain() >= nMinDepth)
1072 {
e3bc5698
JG
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
1093Value 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(-8, "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
1156Value 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(-5, "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
1190Value 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
1204Value 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(-4, "Error refreshing keypool.");
1218
1219 return Value::null;
1220}
1221
1222
1223void 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
1231void 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
1275Value 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(-15, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1285
1286 if (!pwalletMain->IsLocked())
1287 throw JSONRPCError(-17, "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(-14, "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
4d1d94c5 1306 NewThread(ThreadTopUpKeyPool, NULL);
e3bc5698 1307 int64* pnSleepTime = new int64(params[1].get_int64());
4d1d94c5 1308 NewThread(ThreadCleanWalletPassphrase, pnSleepTime);
e3bc5698
JG
1309
1310 return Value::null;
1311}
1312
1313
1314Value 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(-15, "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(-14, "Error: The wallet passphrase entered was incorrect.");
1342
1343 return Value::null;
1344}
1345
1346
1347Value 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(-15, "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
1370Value 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(-15, "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(-16, "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
331544bc 1397 // unencrypted private keys. So:
e3bc5698 1398 StartShutdown();
31a8b70e 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.";
e3bc5698
JG
1400}
1401
1402class DescribeAddressVisitor : public boost::static_visitor<Object>
1403{
1404public:
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
1437Value 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.182914 seconds and 4 git commands to generate.