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