]> Git Repo - VerusCoin.git/blame - src/rpcwallet.cpp
Merge pull request #1431 from luke-jr/opt_ipv6
[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));
bdbfd232 41 entry.push_back(Pair("blocktime", (boost::int64_t)(mapBlockIndex[wtx.hashBlock]->nTime)));
e3bc5698
JG
42 }
43 entry.push_back(Pair("txid", wtx.GetHash().GetHex()));
44 entry.push_back(Pair("time", (boost::int64_t)wtx.GetTxTime()));
bdbfd232 45 entry.push_back(Pair("timereceived", (boost::int64_t)wtx.nTimeReceived));
e3bc5698
JG
46 BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
47 entry.push_back(Pair(item.first, item.second));
48}
49
50string AccountFromValue(const Value& value)
51{
52 string strAccount = value.get_str();
53 if (strAccount == "*")
54 throw JSONRPCError(-11, "Invalid account name");
55 return strAccount;
56}
57
c625ae04
JG
58Value getinfo(const Array& params, bool fHelp)
59{
60 if (fHelp || params.size() != 0)
61 throw runtime_error(
62 "getinfo\n"
63 "Returns an object containing various state info.");
64
65 CService addrProxy;
66 GetProxy(NET_IPV4, addrProxy);
67
68 Object obj;
69 obj.push_back(Pair("version", (int)CLIENT_VERSION));
70 obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION));
71 obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
72 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
73 obj.push_back(Pair("blocks", (int)nBestHeight));
74 obj.push_back(Pair("connections", (int)vNodes.size()));
75 obj.push_back(Pair("proxy", (addrProxy.IsValid() ? addrProxy.ToStringIPPort() : string())));
76 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
77 obj.push_back(Pair("testnet", fTestNet));
78 obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
79 obj.push_back(Pair("keypoolsize", pwalletMain->GetKeyPoolSize()));
80 obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee)));
81 if (pwalletMain->IsCrypted())
82 obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime / 1000));
83 obj.push_back(Pair("errors", GetWarnings("statusbar")));
84 return obj;
85}
86
87
88
e3bc5698
JG
89Value getnewaddress(const Array& params, bool fHelp)
90{
91 if (fHelp || params.size() > 1)
92 throw runtime_error(
93 "getnewaddress [account]\n"
94 "Returns a new Bitcoin address for receiving payments. "
95 "If [account] is specified (recommended), it is added to the address book "
96 "so payments received with the address will be credited to [account].");
97
98 // Parse the account first so we don't generate a key if there's an error
99 string strAccount;
100 if (params.size() > 0)
101 strAccount = AccountFromValue(params[0]);
102
103 if (!pwalletMain->IsLocked())
104 pwalletMain->TopUpKeyPool();
105
106 // Generate a new key that is added to wallet
107 CPubKey newKey;
108 if (!pwalletMain->GetKeyFromPool(newKey, false))
109 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
110 CKeyID keyID = newKey.GetID();
111
112 pwalletMain->SetAddressBookName(keyID, strAccount);
113
114 return CBitcoinAddress(keyID).ToString();
115}
116
117
118CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
119{
120 CWalletDB walletdb(pwalletMain->strWalletFile);
121
122 CAccount account;
123 walletdb.ReadAccount(strAccount, account);
124
125 bool bKeyUsed = false;
126
127 // Check if the current key has been used
128 if (account.vchPubKey.IsValid())
129 {
130 CScript scriptPubKey;
131 scriptPubKey.SetDestination(account.vchPubKey.GetID());
132 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
133 it != pwalletMain->mapWallet.end() && account.vchPubKey.IsValid();
134 ++it)
135 {
136 const CWalletTx& wtx = (*it).second;
137 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
138 if (txout.scriptPubKey == scriptPubKey)
139 bKeyUsed = true;
140 }
141 }
142
143 // Generate a new key
144 if (!account.vchPubKey.IsValid() || bForceNew || bKeyUsed)
145 {
146 if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false))
147 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
148
149 pwalletMain->SetAddressBookName(account.vchPubKey.GetID(), strAccount);
150 walletdb.WriteAccount(strAccount, account);
151 }
152
153 return CBitcoinAddress(account.vchPubKey.GetID());
154}
155
156Value getaccountaddress(const Array& params, bool fHelp)
157{
158 if (fHelp || params.size() != 1)
159 throw runtime_error(
160 "getaccountaddress <account>\n"
161 "Returns the current Bitcoin address for receiving payments to this account.");
162
163 // Parse the account first so we don't generate a key if there's an error
164 string strAccount = AccountFromValue(params[0]);
165
166 Value ret;
167
168 ret = GetAccountAddress(strAccount).ToString();
169
170 return ret;
171}
172
173
174
175Value setaccount(const Array& params, bool fHelp)
176{
177 if (fHelp || params.size() < 1 || params.size() > 2)
178 throw runtime_error(
179 "setaccount <bitcoinaddress> <account>\n"
180 "Sets the account associated with the given address.");
181
182 CBitcoinAddress address(params[0].get_str());
183 if (!address.IsValid())
184 throw JSONRPCError(-5, "Invalid Bitcoin address");
185
186
187 string strAccount;
188 if (params.size() > 1)
189 strAccount = AccountFromValue(params[1]);
190
191 // Detect when changing the account of an address that is the 'unused current key' of another account:
192 if (pwalletMain->mapAddressBook.count(address.Get()))
193 {
194 string strOldAccount = pwalletMain->mapAddressBook[address.Get()];
195 if (address == GetAccountAddress(strOldAccount))
196 GetAccountAddress(strOldAccount, true);
197 }
198
199 pwalletMain->SetAddressBookName(address.Get(), strAccount);
200
201 return Value::null;
202}
203
204
205Value getaccount(const Array& params, bool fHelp)
206{
207 if (fHelp || params.size() != 1)
208 throw runtime_error(
209 "getaccount <bitcoinaddress>\n"
210 "Returns the account associated with the given address.");
211
212 CBitcoinAddress address(params[0].get_str());
213 if (!address.IsValid())
214 throw JSONRPCError(-5, "Invalid Bitcoin address");
215
216 string strAccount;
217 map<CTxDestination, string>::iterator mi = pwalletMain->mapAddressBook.find(address.Get());
218 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
219 strAccount = (*mi).second;
220 return strAccount;
221}
222
223
224Value getaddressesbyaccount(const Array& params, bool fHelp)
225{
226 if (fHelp || params.size() != 1)
227 throw runtime_error(
228 "getaddressesbyaccount <account>\n"
229 "Returns the list of addresses for the given account.");
230
231 string strAccount = AccountFromValue(params[0]);
232
233 // Find all addresses that have the given account
234 Array ret;
235 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
236 {
237 const CBitcoinAddress& address = item.first;
238 const string& strName = item.second;
239 if (strName == strAccount)
240 ret.push_back(address.ToString());
241 }
242 return ret;
243}
244
245Value sendtoaddress(const Array& params, bool fHelp)
246{
247 if (fHelp || params.size() < 2 || params.size() > 4)
248 throw runtime_error(
249 "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
250 "<amount> is a real and is rounded to the nearest 0.00000001"
251 + HelpRequiringPassphrase());
252
253 CBitcoinAddress address(params[0].get_str());
254 if (!address.IsValid())
255 throw JSONRPCError(-5, "Invalid Bitcoin address");
256
257 // Amount
258 int64 nAmount = AmountFromValue(params[1]);
259
260 // Wallet comments
261 CWalletTx wtx;
262 if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
263 wtx.mapValue["comment"] = params[2].get_str();
264 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
265 wtx.mapValue["to"] = params[3].get_str();
266
267 if (pwalletMain->IsLocked())
268 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
269
270 string strError = pwalletMain->SendMoneyToDestination(address.Get(), nAmount, wtx);
271 if (strError != "")
272 throw JSONRPCError(-4, strError);
273
274 return wtx.GetHash().GetHex();
275}
276
277Value signmessage(const Array& params, bool fHelp)
278{
279 if (fHelp || params.size() != 2)
280 throw runtime_error(
281 "signmessage <bitcoinaddress> <message>\n"
282 "Sign a message with the private key of an address");
283
284 EnsureWalletIsUnlocked();
285
286 string strAddress = params[0].get_str();
287 string strMessage = params[1].get_str();
288
289 CBitcoinAddress addr(strAddress);
290 if (!addr.IsValid())
291 throw JSONRPCError(-3, "Invalid address");
292
293 CKeyID keyID;
294 if (!addr.GetKeyID(keyID))
295 throw JSONRPCError(-3, "Address does not refer to key");
296
297 CKey key;
298 if (!pwalletMain->GetKey(keyID, key))
299 throw JSONRPCError(-4, "Private key not available");
300
301 CDataStream ss(SER_GETHASH, 0);
302 ss << strMessageMagic;
303 ss << strMessage;
304
305 vector<unsigned char> vchSig;
306 if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
307 throw JSONRPCError(-5, "Sign failed");
308
309 return EncodeBase64(&vchSig[0], vchSig.size());
310}
311
312Value verifymessage(const Array& params, bool fHelp)
313{
314 if (fHelp || params.size() != 3)
315 throw runtime_error(
316 "verifymessage <bitcoinaddress> <signature> <message>\n"
317 "Verify a signed message");
318
319 string strAddress = params[0].get_str();
320 string strSign = params[1].get_str();
321 string strMessage = params[2].get_str();
322
323 CBitcoinAddress addr(strAddress);
324 if (!addr.IsValid())
325 throw JSONRPCError(-3, "Invalid address");
326
327 CKeyID keyID;
328 if (!addr.GetKeyID(keyID))
329 throw JSONRPCError(-3, "Address does not refer to key");
330
331 bool fInvalid = false;
332 vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
333
334 if (fInvalid)
335 throw JSONRPCError(-5, "Malformed base64 encoding");
336
337 CDataStream ss(SER_GETHASH, 0);
338 ss << strMessageMagic;
339 ss << strMessage;
340
341 CKey key;
342 if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
343 return false;
344
345 return (key.GetPubKey().GetID() == keyID);
346}
347
348
349Value getreceivedbyaddress(const Array& params, bool fHelp)
350{
351 if (fHelp || params.size() < 1 || params.size() > 2)
352 throw runtime_error(
353 "getreceivedbyaddress <bitcoinaddress> [minconf=1]\n"
354 "Returns the total amount received by <bitcoinaddress> in transactions with at least [minconf] confirmations.");
355
356 // Bitcoin address
357 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
358 CScript scriptPubKey;
359 if (!address.IsValid())
360 throw JSONRPCError(-5, "Invalid Bitcoin address");
361 scriptPubKey.SetDestination(address.Get());
362 if (!IsMine(*pwalletMain,scriptPubKey))
363 return (double)0.0;
364
365 // Minimum confirmations
366 int nMinDepth = 1;
367 if (params.size() > 1)
368 nMinDepth = params[1].get_int();
369
370 // Tally
371 int64 nAmount = 0;
372 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
373 {
374 const CWalletTx& wtx = (*it).second;
375 if (wtx.IsCoinBase() || !wtx.IsFinal())
376 continue;
377
378 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
379 if (txout.scriptPubKey == scriptPubKey)
380 if (wtx.GetDepthInMainChain() >= nMinDepth)
381 nAmount += txout.nValue;
382 }
383
384 return ValueFromAmount(nAmount);
385}
386
387
388void GetAccountAddresses(string strAccount, set<CTxDestination>& setAddress)
389{
390 BOOST_FOREACH(const PAIRTYPE(CTxDestination, string)& item, pwalletMain->mapAddressBook)
391 {
392 const CTxDestination& address = item.first;
393 const string& strName = item.second;
394 if (strName == strAccount)
395 setAddress.insert(address);
396 }
397}
398
399Value getreceivedbyaccount(const Array& params, bool fHelp)
400{
401 if (fHelp || params.size() < 1 || params.size() > 2)
402 throw runtime_error(
403 "getreceivedbyaccount <account> [minconf=1]\n"
404 "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
405
406 // Minimum confirmations
407 int nMinDepth = 1;
408 if (params.size() > 1)
409 nMinDepth = params[1].get_int();
410
411 // Get the set of pub keys assigned to account
412 string strAccount = AccountFromValue(params[0]);
413 set<CTxDestination> setAddress;
414 GetAccountAddresses(strAccount, setAddress);
415
416 // Tally
417 int64 nAmount = 0;
418 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
419 {
420 const CWalletTx& wtx = (*it).second;
421 if (wtx.IsCoinBase() || !wtx.IsFinal())
422 continue;
423
424 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
425 {
426 CTxDestination address;
427 if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*pwalletMain, address) && setAddress.count(address))
428 if (wtx.GetDepthInMainChain() >= nMinDepth)
429 nAmount += txout.nValue;
430 }
431 }
432
433 return (double)nAmount / (double)COIN;
434}
435
436
437int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
438{
439 int64 nBalance = 0;
440
441 // Tally wallet transactions
442 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
443 {
444 const CWalletTx& wtx = (*it).second;
445 if (!wtx.IsFinal())
446 continue;
447
448 int64 nGenerated, nReceived, nSent, nFee;
449 wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee);
450
451 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
452 nBalance += nReceived;
453 nBalance += nGenerated - nSent - nFee;
454 }
455
456 // Tally internal accounting entries
457 nBalance += walletdb.GetAccountCreditDebit(strAccount);
458
459 return nBalance;
460}
461
462int64 GetAccountBalance(const string& strAccount, int nMinDepth)
463{
464 CWalletDB walletdb(pwalletMain->strWalletFile);
465 return GetAccountBalance(walletdb, strAccount, nMinDepth);
466}
467
468
469Value getbalance(const Array& params, bool fHelp)
470{
471 if (fHelp || params.size() > 2)
472 throw runtime_error(
473 "getbalance [account] [minconf=1]\n"
474 "If [account] is not specified, returns the server's total available balance.\n"
475 "If [account] is specified, returns the balance in the account.");
476
477 if (params.size() == 0)
478 return ValueFromAmount(pwalletMain->GetBalance());
479
480 int nMinDepth = 1;
481 if (params.size() > 1)
482 nMinDepth = params[1].get_int();
483
484 if (params[0].get_str() == "*") {
485 // Calculate total balance a different way from GetBalance()
486 // (GetBalance() sums up all unspent TxOuts)
487 // getbalance and getbalance '*' should always return the same number.
488 int64 nBalance = 0;
489 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
490 {
491 const CWalletTx& wtx = (*it).second;
492 if (!wtx.IsFinal())
493 continue;
494
495 int64 allGeneratedImmature, allGeneratedMature, allFee;
496 allGeneratedImmature = allGeneratedMature = allFee = 0;
497 string strSentAccount;
498 list<pair<CTxDestination, int64> > listReceived;
499 list<pair<CTxDestination, int64> > listSent;
500 wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
501 if (wtx.GetDepthInMainChain() >= nMinDepth)
502 {
503 BOOST_FOREACH(const PAIRTYPE(CTxDestination,int64)& r, listReceived)
504 nBalance += r.second;
505 }
506 BOOST_FOREACH(const PAIRTYPE(CTxDestination,int64)& r, listSent)
507 nBalance -= r.second;
508 nBalance -= allFee;
509 nBalance += allGeneratedMature;
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{
880 int64 nGeneratedImmature, nGeneratedMature, nFee;
881 string strSentAccount;
882 list<pair<CTxDestination, int64> > listReceived;
883 list<pair<CTxDestination, int64> > listSent;
884
885 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
886
887 bool fAllAccounts = (strAccount == string("*"));
888
889 // Generated blocks assigned to account ""
890 if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
891 {
892 Object entry;
893 entry.push_back(Pair("account", string("")));
894 if (nGeneratedImmature)
895 {
896 entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
897 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
898 }
899 else
900 {
901 entry.push_back(Pair("category", "generate"));
902 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
903 }
904 if (fLong)
905 WalletTxToJSON(wtx, entry);
906 ret.push_back(entry);
907 }
908
909 // Sent
910 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
911 {
912 BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& s, listSent)
913 {
914 Object entry;
915 entry.push_back(Pair("account", strSentAccount));
916 entry.push_back(Pair("address", CBitcoinAddress(s.first).ToString()));
917 entry.push_back(Pair("category", "send"));
918 entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
919 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
920 if (fLong)
921 WalletTxToJSON(wtx, entry);
922 ret.push_back(entry);
923 }
924 }
925
926 // Received
927 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
928 {
929 BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& r, listReceived)
930 {
931 string account;
932 if (pwalletMain->mapAddressBook.count(r.first))
933 account = pwalletMain->mapAddressBook[r.first];
934 if (fAllAccounts || (account == strAccount))
935 {
936 Object entry;
937 entry.push_back(Pair("account", account));
938 entry.push_back(Pair("address", CBitcoinAddress(r.first).ToString()));
939 entry.push_back(Pair("category", "receive"));
940 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
941 if (fLong)
942 WalletTxToJSON(wtx, entry);
943 ret.push_back(entry);
944 }
945 }
946 }
947}
948
949void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
950{
951 bool fAllAccounts = (strAccount == string("*"));
952
953 if (fAllAccounts || acentry.strAccount == strAccount)
954 {
955 Object entry;
956 entry.push_back(Pair("account", acentry.strAccount));
957 entry.push_back(Pair("category", "move"));
958 entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
959 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
960 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
961 entry.push_back(Pair("comment", acentry.strComment));
962 ret.push_back(entry);
963 }
964}
965
966Value listtransactions(const Array& params, bool fHelp)
967{
968 if (fHelp || params.size() > 3)
969 throw runtime_error(
970 "listtransactions [account] [count=10] [from=0]\n"
971 "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
972
973 string strAccount = "*";
974 if (params.size() > 0)
975 strAccount = params[0].get_str();
976 int nCount = 10;
977 if (params.size() > 1)
978 nCount = params[1].get_int();
979 int nFrom = 0;
980 if (params.size() > 2)
981 nFrom = params[2].get_int();
982
983 if (nCount < 0)
984 throw JSONRPCError(-8, "Negative count");
985 if (nFrom < 0)
986 throw JSONRPCError(-8, "Negative from");
987
988 Array ret;
e3bc5698 989
c3f95ef1 990 CWallet::TxItems txOrdered = pwalletMain->OrderedTxItems(strAccount);
e3bc5698
JG
991
992 // iterate backwards until we have nCount items to return:
c3f95ef1 993 for (CWallet::TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
e3bc5698
JG
994 {
995 CWalletTx *const pwtx = (*it).second.first;
996 if (pwtx != 0)
997 ListTransactions(*pwtx, strAccount, 0, true, ret);
998 CAccountingEntry *const pacentry = (*it).second.second;
999 if (pacentry != 0)
1000 AcentryToJSON(*pacentry, strAccount, ret);
1001
1002 if ((int)ret.size() >= (nCount+nFrom)) break;
1003 }
1004 // ret is newest to oldest
1005
1006 if (nFrom > (int)ret.size())
1007 nFrom = ret.size();
1008 if ((nFrom + nCount) > (int)ret.size())
1009 nCount = ret.size() - nFrom;
1010 Array::iterator first = ret.begin();
1011 std::advance(first, nFrom);
1012 Array::iterator last = ret.begin();
1013 std::advance(last, nFrom+nCount);
1014
1015 if (last != ret.end()) ret.erase(last, ret.end());
1016 if (first != ret.begin()) ret.erase(ret.begin(), first);
1017
1018 std::reverse(ret.begin(), ret.end()); // Return oldest to newest
1019
1020 return ret;
1021}
1022
1023Value listaccounts(const Array& params, bool fHelp)
1024{
1025 if (fHelp || params.size() > 1)
1026 throw runtime_error(
1027 "listaccounts [minconf=1]\n"
1028 "Returns Object that has account names as keys, account balances as values.");
1029
1030 int nMinDepth = 1;
1031 if (params.size() > 0)
1032 nMinDepth = params[0].get_int();
1033
1034 map<string, int64> mapAccountBalances;
1035 BOOST_FOREACH(const PAIRTYPE(CTxDestination, string)& entry, pwalletMain->mapAddressBook) {
1036 if (IsMine(*pwalletMain, entry.first)) // This address belongs to me
1037 mapAccountBalances[entry.second] = 0;
1038 }
1039
1040 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1041 {
1042 const CWalletTx& wtx = (*it).second;
1043 int64 nGeneratedImmature, nGeneratedMature, nFee;
1044 string strSentAccount;
1045 list<pair<CTxDestination, int64> > listReceived;
1046 list<pair<CTxDestination, int64> > listSent;
1047 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1048 mapAccountBalances[strSentAccount] -= nFee;
1049 BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& s, listSent)
1050 mapAccountBalances[strSentAccount] -= s.second;
1051 if (wtx.GetDepthInMainChain() >= nMinDepth)
1052 {
1053 mapAccountBalances[""] += nGeneratedMature;
1054 BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& r, listReceived)
1055 if (pwalletMain->mapAddressBook.count(r.first))
1056 mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1057 else
1058 mapAccountBalances[""] += r.second;
1059 }
1060 }
1061
1062 list<CAccountingEntry> acentries;
1063 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1064 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1065 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1066
1067 Object ret;
1068 BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) {
1069 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1070 }
1071 return ret;
1072}
1073
1074Value listsinceblock(const Array& params, bool fHelp)
1075{
1076 if (fHelp)
1077 throw runtime_error(
1078 "listsinceblock [blockhash] [target-confirmations]\n"
1079 "Get all transactions in blocks since block [blockhash], or all transactions if omitted");
1080
1081 CBlockIndex *pindex = NULL;
1082 int target_confirms = 1;
1083
1084 if (params.size() > 0)
1085 {
1086 uint256 blockId = 0;
1087
1088 blockId.SetHex(params[0].get_str());
1089 pindex = CBlockLocator(blockId).GetBlockIndex();
1090 }
1091
1092 if (params.size() > 1)
1093 {
1094 target_confirms = params[1].get_int();
1095
1096 if (target_confirms < 1)
1097 throw JSONRPCError(-8, "Invalid parameter");
1098 }
1099
1100 int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
1101
1102 Array transactions;
1103
1104 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1105 {
1106 CWalletTx tx = (*it).second;
1107
1108 if (depth == -1 || tx.GetDepthInMainChain() < depth)
1109 ListTransactions(tx, "*", 0, true, transactions);
1110 }
1111
1112 uint256 lastblock;
1113
1114 if (target_confirms == 1)
1115 {
1116 lastblock = hashBestChain;
1117 }
1118 else
1119 {
1120 int target_height = pindexBest->nHeight + 1 - target_confirms;
1121
1122 CBlockIndex *block;
1123 for (block = pindexBest;
1124 block && block->nHeight > target_height;
1125 block = block->pprev) { }
1126
1127 lastblock = block ? block->GetBlockHash() : 0;
1128 }
1129
1130 Object ret;
1131 ret.push_back(Pair("transactions", transactions));
1132 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1133
1134 return ret;
1135}
1136
1137Value gettransaction(const Array& params, bool fHelp)
1138{
1139 if (fHelp || params.size() != 1)
1140 throw runtime_error(
1141 "gettransaction <txid>\n"
1142 "Get detailed information about in-wallet transaction <txid>");
1143
1144 uint256 hash;
1145 hash.SetHex(params[0].get_str());
1146
1147 Object entry;
1148 if (!pwalletMain->mapWallet.count(hash))
1149 throw JSONRPCError(-5, "Invalid or non-wallet transaction id");
1150 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1151
1152 int64 nCredit = wtx.GetCredit();
1153 int64 nDebit = wtx.GetDebit();
1154 int64 nNet = nCredit - nDebit;
1155 int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
1156
1157 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1158 if (wtx.IsFromMe())
1159 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1160
1161 WalletTxToJSON(wtx, entry);
1162
1163 Array details;
1164 ListTransactions(wtx, "*", 0, false, details);
1165 entry.push_back(Pair("details", details));
1166
1167 return entry;
1168}
1169
1170
1171Value backupwallet(const Array& params, bool fHelp)
1172{
1173 if (fHelp || params.size() != 1)
1174 throw runtime_error(
1175 "backupwallet <destination>\n"
1176 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1177
1178 string strDest = params[0].get_str();
1179 BackupWallet(*pwalletMain, strDest);
1180
1181 return Value::null;
1182}
1183
1184
1185Value keypoolrefill(const Array& params, bool fHelp)
1186{
1187 if (fHelp || params.size() > 0)
1188 throw runtime_error(
1189 "keypoolrefill\n"
1190 "Fills the keypool."
1191 + HelpRequiringPassphrase());
1192
1193 EnsureWalletIsUnlocked();
1194
1195 pwalletMain->TopUpKeyPool();
1196
1197 if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100))
1198 throw JSONRPCError(-4, "Error refreshing keypool.");
1199
1200 return Value::null;
1201}
1202
1203
1204void ThreadTopUpKeyPool(void* parg)
1205{
1206 // Make this thread recognisable as the key-topping-up thread
1207 RenameThread("bitcoin-key-top");
1208
1209 pwalletMain->TopUpKeyPool();
1210}
1211
1212void ThreadCleanWalletPassphrase(void* parg)
1213{
1214 // Make this thread recognisable as the wallet relocking thread
1215 RenameThread("bitcoin-lock-wa");
1216
1217 int64 nMyWakeTime = GetTimeMillis() + *((int64*)parg) * 1000;
1218
1219 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1220
1221 if (nWalletUnlockTime == 0)
1222 {
1223 nWalletUnlockTime = nMyWakeTime;
1224
1225 do
1226 {
1227 if (nWalletUnlockTime==0)
1228 break;
1229 int64 nToSleep = nWalletUnlockTime - GetTimeMillis();
1230 if (nToSleep <= 0)
1231 break;
1232
1233 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1234 Sleep(nToSleep);
1235 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1236
1237 } while(1);
1238
1239 if (nWalletUnlockTime)
1240 {
1241 nWalletUnlockTime = 0;
1242 pwalletMain->Lock();
1243 }
1244 }
1245 else
1246 {
1247 if (nWalletUnlockTime < nMyWakeTime)
1248 nWalletUnlockTime = nMyWakeTime;
1249 }
1250
1251 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1252
1253 delete (int64*)parg;
1254}
1255
1256Value walletpassphrase(const Array& params, bool fHelp)
1257{
1258 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1259 throw runtime_error(
1260 "walletpassphrase <passphrase> <timeout>\n"
1261 "Stores the wallet decryption key in memory for <timeout> seconds.");
1262 if (fHelp)
1263 return true;
1264 if (!pwalletMain->IsCrypted())
1265 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1266
1267 if (!pwalletMain->IsLocked())
1268 throw JSONRPCError(-17, "Error: Wallet is already unlocked.");
1269
1270 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1271 SecureString strWalletPass;
1272 strWalletPass.reserve(100);
1273 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1274 // Alternately, find a way to make params[0] mlock()'d to begin with.
1275 strWalletPass = params[0].get_str().c_str();
1276
1277 if (strWalletPass.length() > 0)
1278 {
1279 if (!pwalletMain->Unlock(strWalletPass))
1280 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1281 }
1282 else
1283 throw runtime_error(
1284 "walletpassphrase <passphrase> <timeout>\n"
1285 "Stores the wallet decryption key in memory for <timeout> seconds.");
1286
1287 CreateThread(ThreadTopUpKeyPool, NULL);
1288 int64* pnSleepTime = new int64(params[1].get_int64());
1289 CreateThread(ThreadCleanWalletPassphrase, pnSleepTime);
1290
1291 return Value::null;
1292}
1293
1294
1295Value walletpassphrasechange(const Array& params, bool fHelp)
1296{
1297 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1298 throw runtime_error(
1299 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1300 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1301 if (fHelp)
1302 return true;
1303 if (!pwalletMain->IsCrypted())
1304 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1305
1306 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1307 // Alternately, find a way to make params[0] mlock()'d to begin with.
1308 SecureString strOldWalletPass;
1309 strOldWalletPass.reserve(100);
1310 strOldWalletPass = params[0].get_str().c_str();
1311
1312 SecureString strNewWalletPass;
1313 strNewWalletPass.reserve(100);
1314 strNewWalletPass = params[1].get_str().c_str();
1315
1316 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1317 throw runtime_error(
1318 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1319 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1320
1321 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1322 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1323
1324 return Value::null;
1325}
1326
1327
1328Value walletlock(const Array& params, bool fHelp)
1329{
1330 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1331 throw runtime_error(
1332 "walletlock\n"
1333 "Removes the wallet encryption key from memory, locking the wallet.\n"
1334 "After calling this method, you will need to call walletpassphrase again\n"
1335 "before being able to call any methods which require the wallet to be unlocked.");
1336 if (fHelp)
1337 return true;
1338 if (!pwalletMain->IsCrypted())
1339 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called.");
1340
1341 {
1342 LOCK(cs_nWalletUnlockTime);
1343 pwalletMain->Lock();
1344 nWalletUnlockTime = 0;
1345 }
1346
1347 return Value::null;
1348}
1349
1350
1351Value encryptwallet(const Array& params, bool fHelp)
1352{
1353 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1354 throw runtime_error(
1355 "encryptwallet <passphrase>\n"
1356 "Encrypts the wallet with <passphrase>.");
1357 if (fHelp)
1358 return true;
1359 if (pwalletMain->IsCrypted())
1360 throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
1361
1362 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1363 // Alternately, find a way to make params[0] mlock()'d to begin with.
1364 SecureString strWalletPass;
1365 strWalletPass.reserve(100);
1366 strWalletPass = params[0].get_str().c_str();
1367
1368 if (strWalletPass.length() < 1)
1369 throw runtime_error(
1370 "encryptwallet <passphrase>\n"
1371 "Encrypts the wallet with <passphrase>.");
1372
1373 if (!pwalletMain->EncryptWallet(strWalletPass))
1374 throw JSONRPCError(-16, "Error: Failed to encrypt the wallet.");
1375
1376 // BDB seems to have a bad habit of writing old data into
1377 // slack space in .dat files; that is bad if the old data is
331544bc 1378 // unencrypted private keys. So:
e3bc5698
JG
1379 StartShutdown();
1380 return "wallet encrypted; Bitcoin server stopping, restart to run with encrypted wallet";
1381}
1382
1383class DescribeAddressVisitor : public boost::static_visitor<Object>
1384{
1385public:
1386 Object operator()(const CNoDestination &dest) const { return Object(); }
1387
1388 Object operator()(const CKeyID &keyID) const {
1389 Object obj;
1390 CPubKey vchPubKey;
1391 pwalletMain->GetPubKey(keyID, vchPubKey);
1392 obj.push_back(Pair("isscript", false));
1393 obj.push_back(Pair("pubkey", HexStr(vchPubKey.Raw())));
1394 obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed()));
1395 return obj;
1396 }
1397
1398 Object operator()(const CScriptID &scriptID) const {
1399 Object obj;
1400 obj.push_back(Pair("isscript", true));
1401 CScript subscript;
1402 pwalletMain->GetCScript(scriptID, subscript);
1403 std::vector<CTxDestination> addresses;
1404 txnouttype whichType;
1405 int nRequired;
1406 ExtractDestinations(subscript, whichType, addresses, nRequired);
1407 obj.push_back(Pair("script", GetTxnOutputType(whichType)));
1408 Array a;
1409 BOOST_FOREACH(const CTxDestination& addr, addresses)
1410 a.push_back(CBitcoinAddress(addr).ToString());
1411 obj.push_back(Pair("addresses", a));
1412 if (whichType == TX_MULTISIG)
1413 obj.push_back(Pair("sigsrequired", nRequired));
1414 return obj;
1415 }
1416};
1417
1418Value validateaddress(const Array& params, bool fHelp)
1419{
1420 if (fHelp || params.size() != 1)
1421 throw runtime_error(
1422 "validateaddress <bitcoinaddress>\n"
1423 "Return information about <bitcoinaddress>.");
1424
1425 CBitcoinAddress address(params[0].get_str());
1426 bool isValid = address.IsValid();
1427
1428 Object ret;
1429 ret.push_back(Pair("isvalid", isValid));
1430 if (isValid)
1431 {
1432 CTxDestination dest = address.Get();
1433 string currentAddress = address.ToString();
1434 ret.push_back(Pair("address", currentAddress));
1435 bool fMine = IsMine(*pwalletMain, dest);
1436 ret.push_back(Pair("ismine", fMine));
1437 if (fMine) {
1438 Object detail = boost::apply_visitor(DescribeAddressVisitor(), dest);
1439 ret.insert(ret.end(), detail.begin(), detail.end());
1440 }
1441 if (pwalletMain->mapAddressBook.count(dest))
1442 ret.push_back(Pair("account", pwalletMain->mapAddressBook[dest]));
1443 }
1444 return ret;
1445}
1446
This page took 0.16446 seconds and 4 git commands to generate.