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.
8 #include "bitcoinrpc.h"
12 using namespace json_spirit;
15 int64 nWalletUnlockTime;
16 static CCriticalSection cs_nWalletUnlockTime;
18 std::string HelpRequiringPassphrase()
20 return pwalletMain->IsCrypted()
21 ? "\nrequires wallet passphrase to be set with walletpassphrase first"
25 void EnsureWalletIsUnlocked()
27 if (pwalletMain->IsLocked())
28 throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
31 void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
33 int confirms = wtx.GetDepthInMainChain();
34 entry.push_back(Pair("confirmations", confirms));
36 entry.push_back(Pair("generated", true));
39 entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex()));
40 entry.push_back(Pair("blockindex", wtx.nIndex));
41 entry.push_back(Pair("blocktime", (boost::int64_t)(mapBlockIndex[wtx.hashBlock]->nTime)));
43 entry.push_back(Pair("txid", wtx.GetHash().GetHex()));
44 entry.push_back(Pair("time", (boost::int64_t)wtx.GetTxTime()));
45 entry.push_back(Pair("timereceived", (boost::int64_t)wtx.nTimeReceived));
46 BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
47 entry.push_back(Pair(item.first, item.second));
50 string AccountFromValue(const Value& value)
52 string strAccount = value.get_str();
53 if (strAccount == "*")
54 throw JSONRPCError(RPC_WALLET_INVALID_ACCOUNT_NAME, "Invalid account name");
58 Value getinfo(const Array& params, bool fHelp)
60 if (fHelp || params.size() != 0)
63 "Returns an object containing various state info.");
66 GetProxy(NET_IPV4, proxy);
69 obj.push_back(Pair("version", (int)CLIENT_VERSION));
70 obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION));
71 obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
72 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
73 obj.push_back(Pair("blocks", (int)nBestHeight));
74 obj.push_back(Pair("connections", (int)vNodes.size()));
75 obj.push_back(Pair("proxy", (proxy.first.IsValid() ? proxy.first.ToStringIPPort() : string())));
76 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
77 obj.push_back(Pair("testnet", fTestNet));
78 obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
79 obj.push_back(Pair("keypoolsize", pwalletMain->GetKeyPoolSize()));
80 obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee)));
81 if (pwalletMain->IsCrypted())
82 obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime / 1000));
83 obj.push_back(Pair("errors", GetWarnings("statusbar")));
89 Value getnewaddress(const Array& params, bool fHelp)
91 if (fHelp || params.size() > 1)
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].");
98 // Parse the account first so we don't generate a key if there's an error
100 if (params.size() > 0)
101 strAccount = AccountFromValue(params[0]);
103 if (!pwalletMain->IsLocked())
104 pwalletMain->TopUpKeyPool();
106 // Generate a new key that is added to wallet
108 if (!pwalletMain->GetKeyFromPool(newKey, false))
109 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
110 CKeyID keyID = newKey.GetID();
112 pwalletMain->SetAddressBookName(keyID, strAccount);
114 return CBitcoinAddress(keyID).ToString();
118 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
120 CWalletDB walletdb(pwalletMain->strWalletFile);
123 walletdb.ReadAccount(strAccount, account);
125 bool bKeyUsed = false;
127 // Check if the current key has been used
128 if (account.vchPubKey.IsValid())
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();
136 const CWalletTx& wtx = (*it).second;
137 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
138 if (txout.scriptPubKey == scriptPubKey)
143 // Generate a new key
144 if (!account.vchPubKey.IsValid() || bForceNew || bKeyUsed)
146 if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false))
147 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
149 pwalletMain->SetAddressBookName(account.vchPubKey.GetID(), strAccount);
150 walletdb.WriteAccount(strAccount, account);
153 return CBitcoinAddress(account.vchPubKey.GetID());
156 Value getaccountaddress(const Array& params, bool fHelp)
158 if (fHelp || params.size() != 1)
160 "getaccountaddress <account>\n"
161 "Returns the current Bitcoin address for receiving payments to this account.");
163 // Parse the account first so we don't generate a key if there's an error
164 string strAccount = AccountFromValue(params[0]);
168 ret = GetAccountAddress(strAccount).ToString();
175 Value setaccount(const Array& params, bool fHelp)
177 if (fHelp || params.size() < 1 || params.size() > 2)
179 "setaccount <bitcoinaddress> <account>\n"
180 "Sets the account associated with the given address.");
182 CBitcoinAddress address(params[0].get_str());
183 if (!address.IsValid())
184 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
188 if (params.size() > 1)
189 strAccount = AccountFromValue(params[1]);
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()))
194 string strOldAccount = pwalletMain->mapAddressBook[address.Get()];
195 if (address == GetAccountAddress(strOldAccount))
196 GetAccountAddress(strOldAccount, true);
199 pwalletMain->SetAddressBookName(address.Get(), strAccount);
205 Value getaccount(const Array& params, bool fHelp)
207 if (fHelp || params.size() != 1)
209 "getaccount <bitcoinaddress>\n"
210 "Returns the account associated with the given address.");
212 CBitcoinAddress address(params[0].get_str());
213 if (!address.IsValid())
214 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
217 map<CTxDestination, string>::iterator mi = pwalletMain->mapAddressBook.find(address.Get());
218 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
219 strAccount = (*mi).second;
224 Value getaddressesbyaccount(const Array& params, bool fHelp)
226 if (fHelp || params.size() != 1)
228 "getaddressesbyaccount <account>\n"
229 "Returns the list of addresses for the given account.");
231 string strAccount = AccountFromValue(params[0]);
233 // Find all addresses that have the given account
235 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
237 const CBitcoinAddress& address = item.first;
238 const string& strName = item.second;
239 if (strName == strAccount)
240 ret.push_back(address.ToString());
245 Value sendtoaddress(const Array& params, bool fHelp)
247 if (fHelp || params.size() < 2 || params.size() > 4)
249 "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
250 "<amount> is a real and is rounded to the nearest 0.00000001"
251 + HelpRequiringPassphrase());
253 CBitcoinAddress address(params[0].get_str());
254 if (!address.IsValid())
255 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
258 int64 nAmount = AmountFromValue(params[1]);
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();
267 if (pwalletMain->IsLocked())
268 throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
270 string strError = pwalletMain->SendMoneyToDestination(address.Get(), nAmount, wtx);
272 throw JSONRPCError(RPC_WALLET_ERROR, strError);
274 return wtx.GetHash().GetHex();
277 Value listaddressgroupings(const Array& params, bool fHelp)
281 "listaddressgroupings\n"
282 "Lists groups of addresses which have had their common ownership\n"
283 "made public by common use as inputs or as the resulting change\n"
284 "in past transactions");
287 map<CTxDestination, int64> balances = pwalletMain->GetAddressBalances();
288 BOOST_FOREACH(set<CTxDestination> grouping, pwalletMain->GetAddressGroupings())
291 BOOST_FOREACH(CTxDestination address, grouping)
294 addressInfo.push_back(CBitcoinAddress(address).ToString());
295 addressInfo.push_back(ValueFromAmount(balances[address]));
297 LOCK(pwalletMain->cs_wallet);
298 if (pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get()) != pwalletMain->mapAddressBook.end())
299 addressInfo.push_back(pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get())->second);
301 jsonGrouping.push_back(addressInfo);
303 jsonGroupings.push_back(jsonGrouping);
305 return jsonGroupings;
308 Value signmessage(const Array& params, bool fHelp)
310 if (fHelp || params.size() != 2)
312 "signmessage <bitcoinaddress> <message>\n"
313 "Sign a message with the private key of an address");
315 EnsureWalletIsUnlocked();
317 string strAddress = params[0].get_str();
318 string strMessage = params[1].get_str();
320 CBitcoinAddress addr(strAddress);
322 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
325 if (!addr.GetKeyID(keyID))
326 throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
329 if (!pwalletMain->GetKey(keyID, key))
330 throw JSONRPCError(RPC_WALLET_ERROR, "Private key not available");
332 CHashWriter ss(SER_GETHASH, 0);
333 ss << strMessageMagic;
336 vector<unsigned char> vchSig;
337 if (!key.SignCompact(ss.GetHash(), vchSig))
338 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed");
340 return EncodeBase64(&vchSig[0], vchSig.size());
343 Value verifymessage(const Array& params, bool fHelp)
345 if (fHelp || params.size() != 3)
347 "verifymessage <bitcoinaddress> <signature> <message>\n"
348 "Verify a signed message");
350 string strAddress = params[0].get_str();
351 string strSign = params[1].get_str();
352 string strMessage = params[2].get_str();
354 CBitcoinAddress addr(strAddress);
356 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
359 if (!addr.GetKeyID(keyID))
360 throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
362 bool fInvalid = false;
363 vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
366 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Malformed base64 encoding");
368 CHashWriter ss(SER_GETHASH, 0);
369 ss << strMessageMagic;
373 if (!key.SetCompactSignature(ss.GetHash(), vchSig))
376 return (key.GetPubKey().GetID() == keyID);
380 Value getreceivedbyaddress(const Array& params, bool fHelp)
382 if (fHelp || params.size() < 1 || params.size() > 2)
384 "getreceivedbyaddress <bitcoinaddress> [minconf=1]\n"
385 "Returns the total amount received by <bitcoinaddress> in transactions with at least [minconf] confirmations.");
388 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
389 CScript scriptPubKey;
390 if (!address.IsValid())
391 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
392 scriptPubKey.SetDestination(address.Get());
393 if (!IsMine(*pwalletMain,scriptPubKey))
396 // Minimum confirmations
398 if (params.size() > 1)
399 nMinDepth = params[1].get_int();
403 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
405 const CWalletTx& wtx = (*it).second;
406 if (wtx.IsCoinBase() || !wtx.IsFinal())
409 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
410 if (txout.scriptPubKey == scriptPubKey)
411 if (wtx.GetDepthInMainChain() >= nMinDepth)
412 nAmount += txout.nValue;
415 return ValueFromAmount(nAmount);
419 void GetAccountAddresses(string strAccount, set<CTxDestination>& setAddress)
421 BOOST_FOREACH(const PAIRTYPE(CTxDestination, string)& item, pwalletMain->mapAddressBook)
423 const CTxDestination& address = item.first;
424 const string& strName = item.second;
425 if (strName == strAccount)
426 setAddress.insert(address);
430 Value getreceivedbyaccount(const Array& params, bool fHelp)
432 if (fHelp || params.size() < 1 || params.size() > 2)
434 "getreceivedbyaccount <account> [minconf=1]\n"
435 "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
437 // Minimum confirmations
439 if (params.size() > 1)
440 nMinDepth = params[1].get_int();
442 // Get the set of pub keys assigned to account
443 string strAccount = AccountFromValue(params[0]);
444 set<CTxDestination> setAddress;
445 GetAccountAddresses(strAccount, setAddress);
449 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
451 const CWalletTx& wtx = (*it).second;
452 if (wtx.IsCoinBase() || !wtx.IsFinal())
455 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
457 CTxDestination address;
458 if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*pwalletMain, address) && setAddress.count(address))
459 if (wtx.GetDepthInMainChain() >= nMinDepth)
460 nAmount += txout.nValue;
464 return (double)nAmount / (double)COIN;
468 int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
472 // Tally wallet transactions
473 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
475 const CWalletTx& wtx = (*it).second;
479 int64 nReceived, nSent, nFee;
480 wtx.GetAccountAmounts(strAccount, nReceived, nSent, nFee);
482 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
483 nBalance += nReceived;
484 nBalance -= nSent + nFee;
487 // Tally internal accounting entries
488 nBalance += walletdb.GetAccountCreditDebit(strAccount);
493 int64 GetAccountBalance(const string& strAccount, int nMinDepth)
495 CWalletDB walletdb(pwalletMain->strWalletFile);
496 return GetAccountBalance(walletdb, strAccount, nMinDepth);
500 Value getbalance(const Array& params, bool fHelp)
502 if (fHelp || params.size() > 2)
504 "getbalance [account] [minconf=1]\n"
505 "If [account] is not specified, returns the server's total available balance.\n"
506 "If [account] is specified, returns the balance in the account.");
508 if (params.size() == 0)
509 return ValueFromAmount(pwalletMain->GetBalance());
512 if (params.size() > 1)
513 nMinDepth = params[1].get_int();
515 if (params[0].get_str() == "*") {
516 // Calculate total balance a different way from GetBalance()
517 // (GetBalance() sums up all unspent TxOuts)
518 // getbalance and getbalance '*' should always return the same number.
520 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
522 const CWalletTx& wtx = (*it).second;
527 string strSentAccount;
528 list<pair<CTxDestination, int64> > listReceived;
529 list<pair<CTxDestination, int64> > listSent;
530 wtx.GetAmounts(listReceived, listSent, allFee, strSentAccount);
531 if (wtx.GetDepthInMainChain() >= nMinDepth)
533 BOOST_FOREACH(const PAIRTYPE(CTxDestination,int64)& r, listReceived)
534 nBalance += r.second;
536 BOOST_FOREACH(const PAIRTYPE(CTxDestination,int64)& r, listSent)
537 nBalance -= r.second;
540 return ValueFromAmount(nBalance);
543 string strAccount = AccountFromValue(params[0]);
545 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
547 return ValueFromAmount(nBalance);
551 Value movecmd(const Array& params, bool fHelp)
553 if (fHelp || params.size() < 3 || params.size() > 5)
555 "move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
556 "Move from one account in your wallet to another.");
558 string strFrom = AccountFromValue(params[0]);
559 string strTo = AccountFromValue(params[1]);
560 int64 nAmount = AmountFromValue(params[2]);
561 if (params.size() > 3)
562 // unused parameter, used to be nMinDepth, keep type-checking it though
563 (void)params[3].get_int();
565 if (params.size() > 4)
566 strComment = params[4].get_str();
568 CWalletDB walletdb(pwalletMain->strWalletFile);
569 if (!walletdb.TxnBegin())
570 throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
572 int64 nNow = GetAdjustedTime();
575 CAccountingEntry debit;
576 debit.nOrderPos = pwalletMain->IncOrderPosNext();
577 debit.strAccount = strFrom;
578 debit.nCreditDebit = -nAmount;
580 debit.strOtherAccount = strTo;
581 debit.strComment = strComment;
582 walletdb.WriteAccountingEntry(debit);
585 CAccountingEntry credit;
586 credit.nOrderPos = pwalletMain->IncOrderPosNext();
587 credit.strAccount = strTo;
588 credit.nCreditDebit = nAmount;
590 credit.strOtherAccount = strFrom;
591 credit.strComment = strComment;
592 walletdb.WriteAccountingEntry(credit);
594 if (!walletdb.TxnCommit())
595 throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
601 Value sendfrom(const Array& params, bool fHelp)
603 if (fHelp || params.size() < 3 || params.size() > 6)
605 "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
606 "<amount> is a real and is rounded to the nearest 0.00000001"
607 + HelpRequiringPassphrase());
609 string strAccount = AccountFromValue(params[0]);
610 CBitcoinAddress address(params[1].get_str());
611 if (!address.IsValid())
612 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
613 int64 nAmount = AmountFromValue(params[2]);
615 if (params.size() > 3)
616 nMinDepth = params[3].get_int();
619 wtx.strFromAccount = strAccount;
620 if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
621 wtx.mapValue["comment"] = params[4].get_str();
622 if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
623 wtx.mapValue["to"] = params[5].get_str();
625 EnsureWalletIsUnlocked();
628 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
629 if (nAmount > nBalance)
630 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
633 string strError = pwalletMain->SendMoneyToDestination(address.Get(), nAmount, wtx);
635 throw JSONRPCError(RPC_WALLET_ERROR, strError);
637 return wtx.GetHash().GetHex();
641 Value sendmany(const Array& params, bool fHelp)
643 if (fHelp || params.size() < 2 || params.size() > 4)
645 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
646 "amounts are double-precision floating point numbers"
647 + HelpRequiringPassphrase());
649 string strAccount = AccountFromValue(params[0]);
650 Object sendTo = params[1].get_obj();
652 if (params.size() > 2)
653 nMinDepth = params[2].get_int();
656 wtx.strFromAccount = strAccount;
657 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
658 wtx.mapValue["comment"] = params[3].get_str();
660 set<CBitcoinAddress> setAddress;
661 vector<pair<CScript, int64> > vecSend;
663 int64 totalAmount = 0;
664 BOOST_FOREACH(const Pair& s, sendTo)
666 CBitcoinAddress address(s.name_);
667 if (!address.IsValid())
668 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bitcoin address: ")+s.name_);
670 if (setAddress.count(address))
671 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+s.name_);
672 setAddress.insert(address);
674 CScript scriptPubKey;
675 scriptPubKey.SetDestination(address.Get());
676 int64 nAmount = AmountFromValue(s.value_);
677 totalAmount += nAmount;
679 vecSend.push_back(make_pair(scriptPubKey, nAmount));
682 EnsureWalletIsUnlocked();
685 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
686 if (totalAmount > nBalance)
687 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
690 CReserveKey keyChange(pwalletMain);
691 int64 nFeeRequired = 0;
692 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
695 if (totalAmount + nFeeRequired > pwalletMain->GetBalance())
696 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds");
697 throw JSONRPCError(RPC_WALLET_ERROR, "Transaction creation failed");
699 if (!pwalletMain->CommitTransaction(wtx, keyChange))
700 throw JSONRPCError(RPC_WALLET_ERROR, "Transaction commit failed");
702 return wtx.GetHash().GetHex();
705 Value addmultisigaddress(const Array& params, bool fHelp)
707 if (fHelp || params.size() < 2 || params.size() > 3)
709 string msg = "addmultisigaddress <nrequired> <'[\"key\",\"key\"]'> [account]\n"
710 "Add a nrequired-to-sign multisignature address to the wallet\"\n"
711 "each key is a Bitcoin address or hex-encoded public key\n"
712 "If [account] is specified, assign address to [account].";
713 throw runtime_error(msg);
716 int nRequired = params[0].get_int();
717 const Array& keys = params[1].get_array();
719 if (params.size() > 2)
720 strAccount = AccountFromValue(params[2]);
722 // Gather public keys
724 throw runtime_error("a multisignature address must require at least one key to redeem");
725 if ((int)keys.size() < nRequired)
727 strprintf("not enough keys supplied "
728 "(got %"PRIszu" keys, but need at least %d to redeem)", keys.size(), nRequired));
729 std::vector<CKey> pubkeys;
730 pubkeys.resize(keys.size());
731 for (unsigned int i = 0; i < keys.size(); i++)
733 const std::string& ks = keys[i].get_str();
735 // Case 1: Bitcoin address and we have full public key:
736 CBitcoinAddress address(ks);
737 if (address.IsValid())
740 if (!address.GetKeyID(keyID))
742 strprintf("%s does not refer to a key",ks.c_str()));
744 if (!pwalletMain->GetPubKey(keyID, vchPubKey))
746 strprintf("no full public key for address %s",ks.c_str()));
747 if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey))
748 throw runtime_error(" Invalid public key: "+ks);
751 // Case 2: hex public key
754 CPubKey vchPubKey(ParseHex(ks));
755 if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey))
756 throw runtime_error(" Invalid public key: "+ks);
760 throw runtime_error(" Invalid public key: "+ks);
764 // Construct using pay-to-script-hash:
766 inner.SetMultisig(nRequired, pubkeys);
767 CScriptID innerID = inner.GetID();
768 pwalletMain->AddCScript(inner);
770 pwalletMain->SetAddressBookName(innerID, strAccount);
771 return CBitcoinAddress(innerID).ToString();
782 nConf = std::numeric_limits<int>::max();
786 Value ListReceived(const Array& params, bool fByAccounts)
788 // Minimum confirmations
790 if (params.size() > 0)
791 nMinDepth = params[0].get_int();
793 // Whether to include empty accounts
794 bool fIncludeEmpty = false;
795 if (params.size() > 1)
796 fIncludeEmpty = params[1].get_bool();
799 map<CBitcoinAddress, tallyitem> mapTally;
800 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
802 const CWalletTx& wtx = (*it).second;
804 if (wtx.IsCoinBase() || !wtx.IsFinal())
807 int nDepth = wtx.GetDepthInMainChain();
808 if (nDepth < nMinDepth)
811 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
813 CTxDestination address;
814 if (!ExtractDestination(txout.scriptPubKey, address) || !IsMine(*pwalletMain, address))
817 tallyitem& item = mapTally[address];
818 item.nAmount += txout.nValue;
819 item.nConf = min(item.nConf, nDepth);
825 map<string, tallyitem> mapAccountTally;
826 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
828 const CBitcoinAddress& address = item.first;
829 const string& strAccount = item.second;
830 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
831 if (it == mapTally.end() && !fIncludeEmpty)
835 int nConf = std::numeric_limits<int>::max();
836 if (it != mapTally.end())
838 nAmount = (*it).second.nAmount;
839 nConf = (*it).second.nConf;
844 tallyitem& item = mapAccountTally[strAccount];
845 item.nAmount += nAmount;
846 item.nConf = min(item.nConf, nConf);
851 obj.push_back(Pair("address", address.ToString()));
852 obj.push_back(Pair("account", strAccount));
853 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
854 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
861 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
863 int64 nAmount = (*it).second.nAmount;
864 int nConf = (*it).second.nConf;
866 obj.push_back(Pair("account", (*it).first));
867 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
868 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
876 Value listreceivedbyaddress(const Array& params, bool fHelp)
878 if (fHelp || params.size() > 2)
880 "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
881 "[minconf] is the minimum number of confirmations before payments are included.\n"
882 "[includeempty] whether to include addresses that haven't received any payments.\n"
883 "Returns an array of objects containing:\n"
884 " \"address\" : receiving address\n"
885 " \"account\" : the account of the receiving address\n"
886 " \"amount\" : total amount received by the address\n"
887 " \"confirmations\" : number of confirmations of the most recent transaction included");
889 return ListReceived(params, false);
892 Value listreceivedbyaccount(const Array& params, bool fHelp)
894 if (fHelp || params.size() > 2)
896 "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
897 "[minconf] is the minimum number of confirmations before payments are included.\n"
898 "[includeempty] whether to include accounts that haven't received any payments.\n"
899 "Returns an array of objects containing:\n"
900 " \"account\" : the account of the receiving addresses\n"
901 " \"amount\" : total amount received by addresses with this account\n"
902 " \"confirmations\" : number of confirmations of the most recent transaction included");
904 return ListReceived(params, true);
907 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
910 string strSentAccount;
911 list<pair<CTxDestination, int64> > listReceived;
912 list<pair<CTxDestination, int64> > listSent;
914 wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount);
916 bool fAllAccounts = (strAccount == string("*"));
919 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
921 BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& s, listSent)
924 entry.push_back(Pair("account", strSentAccount));
925 entry.push_back(Pair("address", CBitcoinAddress(s.first).ToString()));
926 entry.push_back(Pair("category", "send"));
927 entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
928 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
930 WalletTxToJSON(wtx, entry);
931 ret.push_back(entry);
936 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
938 BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& r, listReceived)
941 if (pwalletMain->mapAddressBook.count(r.first))
942 account = pwalletMain->mapAddressBook[r.first];
943 if (fAllAccounts || (account == strAccount))
946 entry.push_back(Pair("account", account));
947 entry.push_back(Pair("address", CBitcoinAddress(r.first).ToString()));
948 if (wtx.IsCoinBase())
950 if (wtx.GetDepthInMainChain() < 1)
951 entry.push_back(Pair("category", "orphan"));
952 else if (wtx.GetBlocksToMaturity() > 0)
953 entry.push_back(Pair("category", "immature"));
955 entry.push_back(Pair("category", "generate"));
958 entry.push_back(Pair("category", "receive"));
959 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
961 WalletTxToJSON(wtx, entry);
962 ret.push_back(entry);
968 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
970 bool fAllAccounts = (strAccount == string("*"));
972 if (fAllAccounts || acentry.strAccount == strAccount)
975 entry.push_back(Pair("account", acentry.strAccount));
976 entry.push_back(Pair("category", "move"));
977 entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
978 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
979 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
980 entry.push_back(Pair("comment", acentry.strComment));
981 ret.push_back(entry);
985 Value listtransactions(const Array& params, bool fHelp)
987 if (fHelp || params.size() > 3)
989 "listtransactions [account] [count=10] [from=0]\n"
990 "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
992 string strAccount = "*";
993 if (params.size() > 0)
994 strAccount = params[0].get_str();
996 if (params.size() > 1)
997 nCount = params[1].get_int();
999 if (params.size() > 2)
1000 nFrom = params[2].get_int();
1003 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count");
1005 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative from");
1009 std::list<CAccountingEntry> acentries;
1010 CWallet::TxItems txOrdered = pwalletMain->OrderedTxItems(acentries, strAccount);
1012 // iterate backwards until we have nCount items to return:
1013 for (CWallet::TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
1015 CWalletTx *const pwtx = (*it).second.first;
1017 ListTransactions(*pwtx, strAccount, 0, true, ret);
1018 CAccountingEntry *const pacentry = (*it).second.second;
1020 AcentryToJSON(*pacentry, strAccount, ret);
1022 if ((int)ret.size() >= (nCount+nFrom)) break;
1024 // ret is newest to oldest
1026 if (nFrom > (int)ret.size())
1028 if ((nFrom + nCount) > (int)ret.size())
1029 nCount = ret.size() - nFrom;
1030 Array::iterator first = ret.begin();
1031 std::advance(first, nFrom);
1032 Array::iterator last = ret.begin();
1033 std::advance(last, nFrom+nCount);
1035 if (last != ret.end()) ret.erase(last, ret.end());
1036 if (first != ret.begin()) ret.erase(ret.begin(), first);
1038 std::reverse(ret.begin(), ret.end()); // Return oldest to newest
1043 Value listaccounts(const Array& params, bool fHelp)
1045 if (fHelp || params.size() > 1)
1046 throw runtime_error(
1047 "listaccounts [minconf=1]\n"
1048 "Returns Object that has account names as keys, account balances as values.");
1051 if (params.size() > 0)
1052 nMinDepth = params[0].get_int();
1054 map<string, int64> mapAccountBalances;
1055 BOOST_FOREACH(const PAIRTYPE(CTxDestination, string)& entry, pwalletMain->mapAddressBook) {
1056 if (IsMine(*pwalletMain, entry.first)) // This address belongs to me
1057 mapAccountBalances[entry.second] = 0;
1060 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1062 const CWalletTx& wtx = (*it).second;
1064 string strSentAccount;
1065 list<pair<CTxDestination, int64> > listReceived;
1066 list<pair<CTxDestination, int64> > listSent;
1067 wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount);
1068 mapAccountBalances[strSentAccount] -= nFee;
1069 BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& s, listSent)
1070 mapAccountBalances[strSentAccount] -= s.second;
1071 if (wtx.GetDepthInMainChain() >= nMinDepth)
1073 BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& r, listReceived)
1074 if (pwalletMain->mapAddressBook.count(r.first))
1075 mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1077 mapAccountBalances[""] += r.second;
1081 list<CAccountingEntry> acentries;
1082 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1083 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1084 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1087 BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) {
1088 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1093 Value listsinceblock(const Array& params, bool fHelp)
1096 throw runtime_error(
1097 "listsinceblock [blockhash] [target-confirmations]\n"
1098 "Get all transactions in blocks since block [blockhash], or all transactions if omitted");
1100 CBlockIndex *pindex = NULL;
1101 int target_confirms = 1;
1103 if (params.size() > 0)
1105 uint256 blockId = 0;
1107 blockId.SetHex(params[0].get_str());
1108 pindex = CBlockLocator(blockId).GetBlockIndex();
1111 if (params.size() > 1)
1113 target_confirms = params[1].get_int();
1115 if (target_confirms < 1)
1116 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter");
1119 int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
1123 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1125 CWalletTx tx = (*it).second;
1127 if (depth == -1 || tx.GetDepthInMainChain() < depth)
1128 ListTransactions(tx, "*", 0, true, transactions);
1133 if (target_confirms == 1)
1135 lastblock = hashBestChain;
1139 int target_height = pindexBest->nHeight + 1 - target_confirms;
1142 for (block = pindexBest;
1143 block && block->nHeight > target_height;
1144 block = block->pprev) { }
1146 lastblock = block ? block->GetBlockHash() : 0;
1150 ret.push_back(Pair("transactions", transactions));
1151 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1156 Value gettransaction(const Array& params, bool fHelp)
1158 if (fHelp || params.size() != 1)
1159 throw runtime_error(
1160 "gettransaction <txid>\n"
1161 "Get detailed information about in-wallet transaction <txid>");
1164 hash.SetHex(params[0].get_str());
1167 if (!pwalletMain->mapWallet.count(hash))
1168 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id");
1169 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1171 int64 nCredit = wtx.GetCredit();
1172 int64 nDebit = wtx.GetDebit();
1173 int64 nNet = nCredit - nDebit;
1174 int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
1176 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1178 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1180 WalletTxToJSON(wtx, entry);
1183 ListTransactions(wtx, "*", 0, false, details);
1184 entry.push_back(Pair("details", details));
1190 Value backupwallet(const Array& params, bool fHelp)
1192 if (fHelp || params.size() != 1)
1193 throw runtime_error(
1194 "backupwallet <destination>\n"
1195 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1197 string strDest = params[0].get_str();
1198 BackupWallet(*pwalletMain, strDest);
1204 Value keypoolrefill(const Array& params, bool fHelp)
1206 if (fHelp || params.size() > 0)
1207 throw runtime_error(
1209 "Fills the keypool."
1210 + HelpRequiringPassphrase());
1212 EnsureWalletIsUnlocked();
1214 pwalletMain->TopUpKeyPool();
1216 if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100))
1217 throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool.");
1223 void ThreadTopUpKeyPool(void* parg)
1225 // Make this thread recognisable as the key-topping-up thread
1226 RenameThread("bitcoin-key-top");
1228 pwalletMain->TopUpKeyPool();
1231 void ThreadCleanWalletPassphrase(void* parg)
1233 // Make this thread recognisable as the wallet relocking thread
1234 RenameThread("bitcoin-lock-wa");
1236 int64 nMyWakeTime = GetTimeMillis() + *((int64*)parg) * 1000;
1238 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1240 if (nWalletUnlockTime == 0)
1242 nWalletUnlockTime = nMyWakeTime;
1246 if (nWalletUnlockTime==0)
1248 int64 nToSleep = nWalletUnlockTime - GetTimeMillis();
1252 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1254 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1258 if (nWalletUnlockTime)
1260 nWalletUnlockTime = 0;
1261 pwalletMain->Lock();
1266 if (nWalletUnlockTime < nMyWakeTime)
1267 nWalletUnlockTime = nMyWakeTime;
1270 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1272 delete (int64*)parg;
1275 Value walletpassphrase(const Array& params, bool fHelp)
1277 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1278 throw runtime_error(
1279 "walletpassphrase <passphrase> <timeout>\n"
1280 "Stores the wallet decryption key in memory for <timeout> seconds.");
1283 if (!pwalletMain->IsCrypted())
1284 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1286 if (!pwalletMain->IsLocked())
1287 throw JSONRPCError(RPC_WALLET_ALREADY_UNLOCKED, "Error: Wallet is already unlocked.");
1289 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1290 SecureString strWalletPass;
1291 strWalletPass.reserve(100);
1292 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1293 // Alternately, find a way to make params[0] mlock()'d to begin with.
1294 strWalletPass = params[0].get_str().c_str();
1296 if (strWalletPass.length() > 0)
1298 if (!pwalletMain->Unlock(strWalletPass))
1299 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
1302 throw runtime_error(
1303 "walletpassphrase <passphrase> <timeout>\n"
1304 "Stores the wallet decryption key in memory for <timeout> seconds.");
1306 NewThread(ThreadTopUpKeyPool, NULL);
1307 int64* pnSleepTime = new int64(params[1].get_int64());
1308 NewThread(ThreadCleanWalletPassphrase, pnSleepTime);
1314 Value walletpassphrasechange(const Array& params, bool fHelp)
1316 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1317 throw runtime_error(
1318 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1319 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1322 if (!pwalletMain->IsCrypted())
1323 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1325 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1326 // Alternately, find a way to make params[0] mlock()'d to begin with.
1327 SecureString strOldWalletPass;
1328 strOldWalletPass.reserve(100);
1329 strOldWalletPass = params[0].get_str().c_str();
1331 SecureString strNewWalletPass;
1332 strNewWalletPass.reserve(100);
1333 strNewWalletPass = params[1].get_str().c_str();
1335 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1336 throw runtime_error(
1337 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1338 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1340 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1341 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
1347 Value walletlock(const Array& params, bool fHelp)
1349 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1350 throw runtime_error(
1352 "Removes the wallet encryption key from memory, locking the wallet.\n"
1353 "After calling this method, you will need to call walletpassphrase again\n"
1354 "before being able to call any methods which require the wallet to be unlocked.");
1357 if (!pwalletMain->IsCrypted())
1358 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletlock was called.");
1361 LOCK(cs_nWalletUnlockTime);
1362 pwalletMain->Lock();
1363 nWalletUnlockTime = 0;
1370 Value encryptwallet(const Array& params, bool fHelp)
1372 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1373 throw runtime_error(
1374 "encryptwallet <passphrase>\n"
1375 "Encrypts the wallet with <passphrase>.");
1378 if (pwalletMain->IsCrypted())
1379 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an encrypted wallet, but encryptwallet was called.");
1381 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1382 // Alternately, find a way to make params[0] mlock()'d to begin with.
1383 SecureString strWalletPass;
1384 strWalletPass.reserve(100);
1385 strWalletPass = params[0].get_str().c_str();
1387 if (strWalletPass.length() < 1)
1388 throw runtime_error(
1389 "encryptwallet <passphrase>\n"
1390 "Encrypts the wallet with <passphrase>.");
1392 if (!pwalletMain->EncryptWallet(strWalletPass))
1393 throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: Failed to encrypt the wallet.");
1395 // BDB seems to have a bad habit of writing old data into
1396 // slack space in .dat files; that is bad if the old data is
1397 // unencrypted private keys. So:
1399 return "wallet encrypted; Bitcoin server stopping, restart to run with encrypted wallet. The keypool has been flushed, you need to make a new backup.";
1402 class DescribeAddressVisitor : public boost::static_visitor<Object>
1405 Object operator()(const CNoDestination &dest) const { return Object(); }
1407 Object operator()(const CKeyID &keyID) const {
1410 pwalletMain->GetPubKey(keyID, vchPubKey);
1411 obj.push_back(Pair("isscript", false));
1412 obj.push_back(Pair("pubkey", HexStr(vchPubKey.Raw())));
1413 obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed()));
1417 Object operator()(const CScriptID &scriptID) const {
1419 obj.push_back(Pair("isscript", true));
1421 pwalletMain->GetCScript(scriptID, subscript);
1422 std::vector<CTxDestination> addresses;
1423 txnouttype whichType;
1425 ExtractDestinations(subscript, whichType, addresses, nRequired);
1426 obj.push_back(Pair("script", GetTxnOutputType(whichType)));
1428 BOOST_FOREACH(const CTxDestination& addr, addresses)
1429 a.push_back(CBitcoinAddress(addr).ToString());
1430 obj.push_back(Pair("addresses", a));
1431 if (whichType == TX_MULTISIG)
1432 obj.push_back(Pair("sigsrequired", nRequired));
1437 Value validateaddress(const Array& params, bool fHelp)
1439 if (fHelp || params.size() != 1)
1440 throw runtime_error(
1441 "validateaddress <bitcoinaddress>\n"
1442 "Return information about <bitcoinaddress>.");
1444 CBitcoinAddress address(params[0].get_str());
1445 bool isValid = address.IsValid();
1448 ret.push_back(Pair("isvalid", isValid));
1451 CTxDestination dest = address.Get();
1452 string currentAddress = address.ToString();
1453 ret.push_back(Pair("address", currentAddress));
1454 bool fMine = IsMine(*pwalletMain, dest);
1455 ret.push_back(Pair("ismine", fMine));
1457 Object detail = boost::apply_visitor(DescribeAddressVisitor(), dest);
1458 ret.insert(ret.end(), detail.begin(), detail.end());
1460 if (pwalletMain->mapAddressBook.count(dest))
1461 ret.push_back(Pair("account", pwalletMain->mapAddressBook[dest]));