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