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.
6 #include <boost/assign/list_of.hpp>
10 #include "bitcoinrpc.h"
15 using namespace boost;
16 using namespace boost::assign;
17 using namespace json_spirit;
19 int64 nWalletUnlockTime;
20 static CCriticalSection cs_nWalletUnlockTime;
22 std::string HelpRequiringPassphrase()
24 return pwalletMain->IsCrypted()
25 ? "\nrequires wallet passphrase to be set with walletpassphrase first"
29 void EnsureWalletIsUnlocked()
31 if (pwalletMain->IsLocked())
32 throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
35 void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
37 int confirms = wtx.GetDepthInMainChain();
38 entry.push_back(Pair("confirmations", confirms));
40 entry.push_back(Pair("generated", true));
43 entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex()));
44 entry.push_back(Pair("blockindex", wtx.nIndex));
45 entry.push_back(Pair("blocktime", (boost::int64_t)(mapBlockIndex[wtx.hashBlock]->nTime)));
47 entry.push_back(Pair("txid", wtx.GetHash().GetHex()));
48 entry.push_back(Pair("time", (boost::int64_t)wtx.GetTxTime()));
49 entry.push_back(Pair("timereceived", (boost::int64_t)wtx.nTimeReceived));
50 BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
51 entry.push_back(Pair(item.first, item.second));
54 string AccountFromValue(const Value& value)
56 string strAccount = value.get_str();
57 if (strAccount == "*")
58 throw JSONRPCError(RPC_WALLET_INVALID_ACCOUNT_NAME, "Invalid account name");
62 Value getinfo(const Array& params, bool fHelp)
64 if (fHelp || params.size() != 0)
67 "Returns an object containing various state info.");
70 GetProxy(NET_IPV4, proxy);
73 obj.push_back(Pair("version", (int)CLIENT_VERSION));
74 obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION));
75 obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
76 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
77 obj.push_back(Pair("blocks", (int)nBestHeight));
78 obj.push_back(Pair("connections", (int)vNodes.size()));
79 obj.push_back(Pair("proxy", (proxy.first.IsValid() ? proxy.first.ToStringIPPort() : string())));
80 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
81 obj.push_back(Pair("testnet", fTestNet));
82 obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
83 obj.push_back(Pair("keypoolsize", pwalletMain->GetKeyPoolSize()));
84 obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee)));
85 if (pwalletMain->IsCrypted())
86 obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime / 1000));
87 obj.push_back(Pair("errors", GetWarnings("statusbar")));
93 Value getnewaddress(const Array& params, bool fHelp)
95 if (fHelp || params.size() > 1)
97 "getnewaddress [account]\n"
98 "Returns a new Bitcoin address for receiving payments. "
99 "If [account] is specified (recommended), it is added to the address book "
100 "so payments received with the address will be credited to [account].");
102 // Parse the account first so we don't generate a key if there's an error
104 if (params.size() > 0)
105 strAccount = AccountFromValue(params[0]);
107 if (!pwalletMain->IsLocked())
108 pwalletMain->TopUpKeyPool();
110 // Generate a new key that is added to wallet
112 if (!pwalletMain->GetKeyFromPool(newKey, false))
113 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
114 CKeyID keyID = newKey.GetID();
116 pwalletMain->SetAddressBookName(keyID, strAccount);
118 return CBitcoinAddress(keyID).ToString();
122 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
124 CWalletDB walletdb(pwalletMain->strWalletFile);
127 walletdb.ReadAccount(strAccount, account);
129 bool bKeyUsed = false;
131 // Check if the current key has been used
132 if (account.vchPubKey.IsValid())
134 CScript scriptPubKey;
135 scriptPubKey.SetDestination(account.vchPubKey.GetID());
136 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
137 it != pwalletMain->mapWallet.end() && account.vchPubKey.IsValid();
140 const CWalletTx& wtx = (*it).second;
141 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
142 if (txout.scriptPubKey == scriptPubKey)
147 // Generate a new key
148 if (!account.vchPubKey.IsValid() || bForceNew || bKeyUsed)
150 if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false))
151 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
153 pwalletMain->SetAddressBookName(account.vchPubKey.GetID(), strAccount);
154 walletdb.WriteAccount(strAccount, account);
157 return CBitcoinAddress(account.vchPubKey.GetID());
160 Value getaccountaddress(const Array& params, bool fHelp)
162 if (fHelp || params.size() != 1)
164 "getaccountaddress <account>\n"
165 "Returns the current Bitcoin address for receiving payments to this account.");
167 // Parse the account first so we don't generate a key if there's an error
168 string strAccount = AccountFromValue(params[0]);
172 ret = GetAccountAddress(strAccount).ToString();
179 Value setaccount(const Array& params, bool fHelp)
181 if (fHelp || params.size() < 1 || params.size() > 2)
183 "setaccount <bitcoinaddress> <account>\n"
184 "Sets the account associated with the given address.");
186 CBitcoinAddress address(params[0].get_str());
187 if (!address.IsValid())
188 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
192 if (params.size() > 1)
193 strAccount = AccountFromValue(params[1]);
195 // Detect when changing the account of an address that is the 'unused current key' of another account:
196 if (pwalletMain->mapAddressBook.count(address.Get()))
198 string strOldAccount = pwalletMain->mapAddressBook[address.Get()];
199 if (address == GetAccountAddress(strOldAccount))
200 GetAccountAddress(strOldAccount, true);
203 pwalletMain->SetAddressBookName(address.Get(), strAccount);
209 Value getaccount(const Array& params, bool fHelp)
211 if (fHelp || params.size() != 1)
213 "getaccount <bitcoinaddress>\n"
214 "Returns the account associated with the given address.");
216 CBitcoinAddress address(params[0].get_str());
217 if (!address.IsValid())
218 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
221 map<CTxDestination, string>::iterator mi = pwalletMain->mapAddressBook.find(address.Get());
222 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
223 strAccount = (*mi).second;
228 Value getaddressesbyaccount(const Array& params, bool fHelp)
230 if (fHelp || params.size() != 1)
232 "getaddressesbyaccount <account>\n"
233 "Returns the list of addresses for the given account.");
235 string strAccount = AccountFromValue(params[0]);
237 // Find all addresses that have the given account
239 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
241 const CBitcoinAddress& address = item.first;
242 const string& strName = item.second;
243 if (strName == strAccount)
244 ret.push_back(address.ToString());
249 Value sendtoaddress(const Array& params, bool fHelp)
251 if (fHelp || params.size() < 2 || params.size() > 4)
253 "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
254 "<amount> is a real and is rounded to the nearest 0.00000001"
255 + HelpRequiringPassphrase());
257 CBitcoinAddress address(params[0].get_str());
258 if (!address.IsValid())
259 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
262 int64 nAmount = AmountFromValue(params[1]);
266 if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
267 wtx.mapValue["comment"] = params[2].get_str();
268 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
269 wtx.mapValue["to"] = params[3].get_str();
271 if (pwalletMain->IsLocked())
272 throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
274 string strError = pwalletMain->SendMoneyToDestination(address.Get(), nAmount, wtx);
276 throw JSONRPCError(RPC_WALLET_ERROR, strError);
278 return wtx.GetHash().GetHex();
281 Value listaddressgroupings(const Array& params, bool fHelp)
285 "listaddressgroupings\n"
286 "Lists groups of addresses which have had their common ownership\n"
287 "made public by common use as inputs or as the resulting change\n"
288 "in past transactions");
291 map<CTxDestination, int64> balances = pwalletMain->GetAddressBalances();
292 BOOST_FOREACH(set<CTxDestination> grouping, pwalletMain->GetAddressGroupings())
295 BOOST_FOREACH(CTxDestination address, grouping)
298 addressInfo.push_back(CBitcoinAddress(address).ToString());
299 addressInfo.push_back(ValueFromAmount(balances[address]));
301 LOCK(pwalletMain->cs_wallet);
302 if (pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get()) != pwalletMain->mapAddressBook.end())
303 addressInfo.push_back(pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get())->second);
305 jsonGrouping.push_back(addressInfo);
307 jsonGroupings.push_back(jsonGrouping);
309 return jsonGroupings;
312 Value signmessage(const Array& params, bool fHelp)
314 if (fHelp || params.size() != 2)
316 "signmessage <bitcoinaddress> <message>\n"
317 "Sign a message with the private key of an address");
319 EnsureWalletIsUnlocked();
321 string strAddress = params[0].get_str();
322 string strMessage = params[1].get_str();
324 CBitcoinAddress addr(strAddress);
326 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
329 if (!addr.GetKeyID(keyID))
330 throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
333 if (!pwalletMain->GetKey(keyID, key))
334 throw JSONRPCError(RPC_WALLET_ERROR, "Private key not available");
336 CHashWriter ss(SER_GETHASH, 0);
337 ss << strMessageMagic;
340 vector<unsigned char> vchSig;
341 if (!key.SignCompact(ss.GetHash(), vchSig))
342 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed");
344 return EncodeBase64(&vchSig[0], vchSig.size());
347 Value verifymessage(const Array& params, bool fHelp)
349 if (fHelp || params.size() != 3)
351 "verifymessage <bitcoinaddress> <signature> <message>\n"
352 "Verify a signed message");
354 string strAddress = params[0].get_str();
355 string strSign = params[1].get_str();
356 string strMessage = params[2].get_str();
358 CBitcoinAddress addr(strAddress);
360 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
363 if (!addr.GetKeyID(keyID))
364 throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
366 bool fInvalid = false;
367 vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
370 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Malformed base64 encoding");
372 CHashWriter ss(SER_GETHASH, 0);
373 ss << strMessageMagic;
377 if (!key.SetCompactSignature(ss.GetHash(), vchSig))
380 return (key.GetPubKey().GetID() == keyID);
384 Value getreceivedbyaddress(const Array& params, bool fHelp)
386 if (fHelp || params.size() < 1 || params.size() > 2)
388 "getreceivedbyaddress <bitcoinaddress> [minconf=1]\n"
389 "Returns the total amount received by <bitcoinaddress> in transactions with at least [minconf] confirmations.");
392 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
393 CScript scriptPubKey;
394 if (!address.IsValid())
395 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
396 scriptPubKey.SetDestination(address.Get());
397 if (!IsMine(*pwalletMain,scriptPubKey))
400 // Minimum confirmations
402 if (params.size() > 1)
403 nMinDepth = params[1].get_int();
407 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
409 const CWalletTx& wtx = (*it).second;
410 if (wtx.IsCoinBase() || !wtx.IsFinal())
413 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
414 if (txout.scriptPubKey == scriptPubKey)
415 if (wtx.GetDepthInMainChain() >= nMinDepth)
416 nAmount += txout.nValue;
419 return ValueFromAmount(nAmount);
423 void GetAccountAddresses(string strAccount, set<CTxDestination>& setAddress)
425 BOOST_FOREACH(const PAIRTYPE(CTxDestination, string)& item, pwalletMain->mapAddressBook)
427 const CTxDestination& address = item.first;
428 const string& strName = item.second;
429 if (strName == strAccount)
430 setAddress.insert(address);
434 Value getreceivedbyaccount(const Array& params, bool fHelp)
436 if (fHelp || params.size() < 1 || params.size() > 2)
438 "getreceivedbyaccount <account> [minconf=1]\n"
439 "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
441 // Minimum confirmations
443 if (params.size() > 1)
444 nMinDepth = params[1].get_int();
446 // Get the set of pub keys assigned to account
447 string strAccount = AccountFromValue(params[0]);
448 set<CTxDestination> setAddress;
449 GetAccountAddresses(strAccount, setAddress);
453 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
455 const CWalletTx& wtx = (*it).second;
456 if (wtx.IsCoinBase() || !wtx.IsFinal())
459 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
461 CTxDestination address;
462 if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*pwalletMain, address) && setAddress.count(address))
463 if (wtx.GetDepthInMainChain() >= nMinDepth)
464 nAmount += txout.nValue;
468 return (double)nAmount / (double)COIN;
472 int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
476 // Tally wallet transactions
477 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
479 const CWalletTx& wtx = (*it).second;
483 int64 nReceived, nSent, nFee;
484 wtx.GetAccountAmounts(strAccount, nReceived, nSent, nFee);
486 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
487 nBalance += nReceived;
488 nBalance -= nSent + nFee;
491 // Tally internal accounting entries
492 nBalance += walletdb.GetAccountCreditDebit(strAccount);
497 int64 GetAccountBalance(const string& strAccount, int nMinDepth)
499 CWalletDB walletdb(pwalletMain->strWalletFile);
500 return GetAccountBalance(walletdb, strAccount, nMinDepth);
504 Value getbalance(const Array& params, bool fHelp)
506 if (fHelp || params.size() > 2)
508 "getbalance [account] [minconf=1]\n"
509 "If [account] is not specified, returns the server's total available balance.\n"
510 "If [account] is specified, returns the balance in the account.");
512 if (params.size() == 0)
513 return ValueFromAmount(pwalletMain->GetBalance());
516 if (params.size() > 1)
517 nMinDepth = params[1].get_int();
519 if (params[0].get_str() == "*") {
520 // Calculate total balance a different way from GetBalance()
521 // (GetBalance() sums up all unspent TxOuts)
522 // getbalance and getbalance '*' should always return the same number.
524 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
526 const CWalletTx& wtx = (*it).second;
531 string strSentAccount;
532 list<pair<CTxDestination, int64> > listReceived;
533 list<pair<CTxDestination, int64> > listSent;
534 wtx.GetAmounts(listReceived, listSent, allFee, strSentAccount);
535 if (wtx.GetDepthInMainChain() >= nMinDepth)
537 BOOST_FOREACH(const PAIRTYPE(CTxDestination,int64)& r, listReceived)
538 nBalance += r.second;
540 BOOST_FOREACH(const PAIRTYPE(CTxDestination,int64)& r, listSent)
541 nBalance -= r.second;
544 return ValueFromAmount(nBalance);
547 string strAccount = AccountFromValue(params[0]);
549 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
551 return ValueFromAmount(nBalance);
555 Value movecmd(const Array& params, bool fHelp)
557 if (fHelp || params.size() < 3 || params.size() > 5)
559 "move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
560 "Move from one account in your wallet to another.");
562 string strFrom = AccountFromValue(params[0]);
563 string strTo = AccountFromValue(params[1]);
564 int64 nAmount = AmountFromValue(params[2]);
565 if (params.size() > 3)
566 // unused parameter, used to be nMinDepth, keep type-checking it though
567 (void)params[3].get_int();
569 if (params.size() > 4)
570 strComment = params[4].get_str();
572 CWalletDB walletdb(pwalletMain->strWalletFile);
573 if (!walletdb.TxnBegin())
574 throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
576 int64 nNow = GetAdjustedTime();
579 CAccountingEntry debit;
580 debit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
581 debit.strAccount = strFrom;
582 debit.nCreditDebit = -nAmount;
584 debit.strOtherAccount = strTo;
585 debit.strComment = strComment;
586 walletdb.WriteAccountingEntry(debit);
589 CAccountingEntry credit;
590 credit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
591 credit.strAccount = strTo;
592 credit.nCreditDebit = nAmount;
594 credit.strOtherAccount = strFrom;
595 credit.strComment = strComment;
596 walletdb.WriteAccountingEntry(credit);
598 if (!walletdb.TxnCommit())
599 throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
605 Value sendfrom(const Array& params, bool fHelp)
607 if (fHelp || params.size() < 3 || params.size() > 6)
609 "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
610 "<amount> is a real and is rounded to the nearest 0.00000001"
611 + HelpRequiringPassphrase());
613 string strAccount = AccountFromValue(params[0]);
614 CBitcoinAddress address(params[1].get_str());
615 if (!address.IsValid())
616 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
617 int64 nAmount = AmountFromValue(params[2]);
619 if (params.size() > 3)
620 nMinDepth = params[3].get_int();
623 wtx.strFromAccount = strAccount;
624 if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
625 wtx.mapValue["comment"] = params[4].get_str();
626 if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
627 wtx.mapValue["to"] = params[5].get_str();
629 EnsureWalletIsUnlocked();
632 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
633 if (nAmount > nBalance)
634 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
637 string strError = pwalletMain->SendMoneyToDestination(address.Get(), nAmount, wtx);
639 throw JSONRPCError(RPC_WALLET_ERROR, strError);
641 return wtx.GetHash().GetHex();
645 Value sendmany(const Array& params, bool fHelp)
647 if (fHelp || params.size() < 2 || params.size() > 4)
649 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
650 "amounts are double-precision floating point numbers"
651 + HelpRequiringPassphrase());
653 string strAccount = AccountFromValue(params[0]);
654 Object sendTo = params[1].get_obj();
656 if (params.size() > 2)
657 nMinDepth = params[2].get_int();
660 wtx.strFromAccount = strAccount;
661 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
662 wtx.mapValue["comment"] = params[3].get_str();
664 set<CBitcoinAddress> setAddress;
665 vector<pair<CScript, int64> > vecSend;
667 int64 totalAmount = 0;
668 BOOST_FOREACH(const Pair& s, sendTo)
670 CBitcoinAddress address(s.name_);
671 if (!address.IsValid())
672 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bitcoin address: ")+s.name_);
674 if (setAddress.count(address))
675 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+s.name_);
676 setAddress.insert(address);
678 CScript scriptPubKey;
679 scriptPubKey.SetDestination(address.Get());
680 int64 nAmount = AmountFromValue(s.value_);
681 totalAmount += nAmount;
683 vecSend.push_back(make_pair(scriptPubKey, nAmount));
686 EnsureWalletIsUnlocked();
689 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
690 if (totalAmount > nBalance)
691 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
694 CReserveKey keyChange(pwalletMain);
695 int64 nFeeRequired = 0;
696 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
699 if (totalAmount + nFeeRequired > pwalletMain->GetBalance())
700 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds");
701 throw JSONRPCError(RPC_WALLET_ERROR, "Transaction creation failed");
703 if (!pwalletMain->CommitTransaction(wtx, keyChange))
704 throw JSONRPCError(RPC_WALLET_ERROR, "Transaction commit failed");
706 return wtx.GetHash().GetHex();
710 // Used by addmultisigaddress / createmultisig:
712 static CScript _createmultisig(const Array& params)
714 int nRequired = params[0].get_int();
715 const Array& keys = params[1].get_array();
717 // Gather public keys
719 throw runtime_error("a multisignature address must require at least one key to redeem");
720 if ((int)keys.size() < nRequired)
722 strprintf("not enough keys supplied "
723 "(got %"PRIszu" keys, but need at least %d to redeem)", keys.size(), nRequired));
724 std::vector<CKey> pubkeys;
725 pubkeys.resize(keys.size());
726 for (unsigned int i = 0; i < keys.size(); i++)
728 const std::string& ks = keys[i].get_str();
730 // Case 1: Bitcoin address and we have full public key:
731 CBitcoinAddress address(ks);
732 if (address.IsValid())
735 if (!address.GetKeyID(keyID))
737 strprintf("%s does not refer to a key",ks.c_str()));
739 if (!pwalletMain->GetPubKey(keyID, vchPubKey))
741 strprintf("no full public key for address %s",ks.c_str()));
742 if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey))
743 throw runtime_error(" Invalid public key: "+ks);
746 // Case 2: hex public key
749 CPubKey vchPubKey(ParseHex(ks));
750 if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey))
751 throw runtime_error(" Invalid public key: "+ks);
755 throw runtime_error(" Invalid public key: "+ks);
759 result.SetMultisig(nRequired, pubkeys);
763 Value addmultisigaddress(const Array& params, bool fHelp)
765 if (fHelp || params.size() < 2 || params.size() > 3)
767 string msg = "addmultisigaddress <nrequired> <'[\"key\",\"key\"]'> [account]\n"
768 "Add a nrequired-to-sign multisignature address to the wallet\"\n"
769 "each key is a Bitcoin address or hex-encoded public key\n"
770 "If [account] is specified, assign address to [account].";
771 throw runtime_error(msg);
775 if (params.size() > 2)
776 strAccount = AccountFromValue(params[2]);
778 // Construct using pay-to-script-hash:
779 CScript inner = _createmultisig(params);
780 CScriptID innerID = inner.GetID();
781 pwalletMain->AddCScript(inner);
783 pwalletMain->SetAddressBookName(innerID, strAccount);
784 return CBitcoinAddress(innerID).ToString();
787 Value createmultisig(const Array& params, bool fHelp)
789 if (fHelp || params.size() < 2 || params.size() > 2)
791 string msg = "createmultisig <nrequired> <'[\"key\",\"key\"]'>\n"
792 "Creates a multi-signature address and returns a json object\n"
794 "address : bitcoin address\n"
795 "redeemScript : hex-encoded redemption script";
796 throw runtime_error(msg);
799 // Construct using pay-to-script-hash:
800 CScript inner = _createmultisig(params);
801 CScriptID innerID = inner.GetID();
802 CBitcoinAddress address(innerID);
805 result.push_back(Pair("address", address.ToString()));
806 result.push_back(Pair("redeemScript", HexStr(inner.begin(), inner.end())));
819 nConf = std::numeric_limits<int>::max();
823 Value ListReceived(const Array& params, bool fByAccounts)
825 // Minimum confirmations
827 if (params.size() > 0)
828 nMinDepth = params[0].get_int();
830 // Whether to include empty accounts
831 bool fIncludeEmpty = false;
832 if (params.size() > 1)
833 fIncludeEmpty = params[1].get_bool();
836 map<CBitcoinAddress, tallyitem> mapTally;
837 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
839 const CWalletTx& wtx = (*it).second;
841 if (wtx.IsCoinBase() || !wtx.IsFinal())
844 int nDepth = wtx.GetDepthInMainChain();
845 if (nDepth < nMinDepth)
848 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
850 CTxDestination address;
851 if (!ExtractDestination(txout.scriptPubKey, address) || !IsMine(*pwalletMain, address))
854 tallyitem& item = mapTally[address];
855 item.nAmount += txout.nValue;
856 item.nConf = min(item.nConf, nDepth);
862 map<string, tallyitem> mapAccountTally;
863 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
865 const CBitcoinAddress& address = item.first;
866 const string& strAccount = item.second;
867 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
868 if (it == mapTally.end() && !fIncludeEmpty)
872 int nConf = std::numeric_limits<int>::max();
873 if (it != mapTally.end())
875 nAmount = (*it).second.nAmount;
876 nConf = (*it).second.nConf;
881 tallyitem& item = mapAccountTally[strAccount];
882 item.nAmount += nAmount;
883 item.nConf = min(item.nConf, nConf);
888 obj.push_back(Pair("address", address.ToString()));
889 obj.push_back(Pair("account", strAccount));
890 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
891 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
898 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
900 int64 nAmount = (*it).second.nAmount;
901 int nConf = (*it).second.nConf;
903 obj.push_back(Pair("account", (*it).first));
904 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
905 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
913 Value listreceivedbyaddress(const Array& params, bool fHelp)
915 if (fHelp || params.size() > 2)
917 "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
918 "[minconf] is the minimum number of confirmations before payments are included.\n"
919 "[includeempty] whether to include addresses that haven't received any payments.\n"
920 "Returns an array of objects containing:\n"
921 " \"address\" : receiving address\n"
922 " \"account\" : the account of the receiving address\n"
923 " \"amount\" : total amount received by the address\n"
924 " \"confirmations\" : number of confirmations of the most recent transaction included");
926 return ListReceived(params, false);
929 Value listreceivedbyaccount(const Array& params, bool fHelp)
931 if (fHelp || params.size() > 2)
933 "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
934 "[minconf] is the minimum number of confirmations before payments are included.\n"
935 "[includeempty] whether to include accounts that haven't received any payments.\n"
936 "Returns an array of objects containing:\n"
937 " \"account\" : the account of the receiving addresses\n"
938 " \"amount\" : total amount received by addresses with this account\n"
939 " \"confirmations\" : number of confirmations of the most recent transaction included");
941 return ListReceived(params, true);
944 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
947 string strSentAccount;
948 list<pair<CTxDestination, int64> > listReceived;
949 list<pair<CTxDestination, int64> > listSent;
951 wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount);
953 bool fAllAccounts = (strAccount == string("*"));
956 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
958 BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& s, listSent)
961 entry.push_back(Pair("account", strSentAccount));
962 entry.push_back(Pair("address", CBitcoinAddress(s.first).ToString()));
963 entry.push_back(Pair("category", "send"));
964 entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
965 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
967 WalletTxToJSON(wtx, entry);
968 ret.push_back(entry);
973 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
975 BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& r, listReceived)
978 if (pwalletMain->mapAddressBook.count(r.first))
979 account = pwalletMain->mapAddressBook[r.first];
980 if (fAllAccounts || (account == strAccount))
983 entry.push_back(Pair("account", account));
984 entry.push_back(Pair("address", CBitcoinAddress(r.first).ToString()));
985 if (wtx.IsCoinBase())
987 if (wtx.GetDepthInMainChain() < 1)
988 entry.push_back(Pair("category", "orphan"));
989 else if (wtx.GetBlocksToMaturity() > 0)
990 entry.push_back(Pair("category", "immature"));
992 entry.push_back(Pair("category", "generate"));
995 entry.push_back(Pair("category", "receive"));
996 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
998 WalletTxToJSON(wtx, entry);
999 ret.push_back(entry);
1005 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1007 bool fAllAccounts = (strAccount == string("*"));
1009 if (fAllAccounts || acentry.strAccount == strAccount)
1012 entry.push_back(Pair("account", acentry.strAccount));
1013 entry.push_back(Pair("category", "move"));
1014 entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
1015 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1016 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1017 entry.push_back(Pair("comment", acentry.strComment));
1018 ret.push_back(entry);
1022 Value listtransactions(const Array& params, bool fHelp)
1024 if (fHelp || params.size() > 3)
1025 throw runtime_error(
1026 "listtransactions [account] [count=10] [from=0]\n"
1027 "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1029 string strAccount = "*";
1030 if (params.size() > 0)
1031 strAccount = params[0].get_str();
1033 if (params.size() > 1)
1034 nCount = params[1].get_int();
1036 if (params.size() > 2)
1037 nFrom = params[2].get_int();
1040 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count");
1042 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative from");
1046 std::list<CAccountingEntry> acentries;
1047 CWallet::TxItems txOrdered = pwalletMain->OrderedTxItems(acentries, strAccount);
1049 // iterate backwards until we have nCount items to return:
1050 for (CWallet::TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
1052 CWalletTx *const pwtx = (*it).second.first;
1054 ListTransactions(*pwtx, strAccount, 0, true, ret);
1055 CAccountingEntry *const pacentry = (*it).second.second;
1057 AcentryToJSON(*pacentry, strAccount, ret);
1059 if ((int)ret.size() >= (nCount+nFrom)) break;
1061 // ret is newest to oldest
1063 if (nFrom > (int)ret.size())
1065 if ((nFrom + nCount) > (int)ret.size())
1066 nCount = ret.size() - nFrom;
1067 Array::iterator first = ret.begin();
1068 std::advance(first, nFrom);
1069 Array::iterator last = ret.begin();
1070 std::advance(last, nFrom+nCount);
1072 if (last != ret.end()) ret.erase(last, ret.end());
1073 if (first != ret.begin()) ret.erase(ret.begin(), first);
1075 std::reverse(ret.begin(), ret.end()); // Return oldest to newest
1080 Value listaccounts(const Array& params, bool fHelp)
1082 if (fHelp || params.size() > 1)
1083 throw runtime_error(
1084 "listaccounts [minconf=1]\n"
1085 "Returns Object that has account names as keys, account balances as values.");
1088 if (params.size() > 0)
1089 nMinDepth = params[0].get_int();
1091 map<string, int64> mapAccountBalances;
1092 BOOST_FOREACH(const PAIRTYPE(CTxDestination, string)& entry, pwalletMain->mapAddressBook) {
1093 if (IsMine(*pwalletMain, entry.first)) // This address belongs to me
1094 mapAccountBalances[entry.second] = 0;
1097 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1099 const CWalletTx& wtx = (*it).second;
1101 string strSentAccount;
1102 list<pair<CTxDestination, int64> > listReceived;
1103 list<pair<CTxDestination, int64> > listSent;
1104 wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount);
1105 mapAccountBalances[strSentAccount] -= nFee;
1106 BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& s, listSent)
1107 mapAccountBalances[strSentAccount] -= s.second;
1108 if (wtx.GetDepthInMainChain() >= nMinDepth)
1110 BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& r, listReceived)
1111 if (pwalletMain->mapAddressBook.count(r.first))
1112 mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1114 mapAccountBalances[""] += r.second;
1118 list<CAccountingEntry> acentries;
1119 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1120 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1121 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1124 BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) {
1125 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1130 Value listsinceblock(const Array& params, bool fHelp)
1133 throw runtime_error(
1134 "listsinceblock [blockhash] [target-confirmations]\n"
1135 "Get all transactions in blocks since block [blockhash], or all transactions if omitted");
1137 CBlockIndex *pindex = NULL;
1138 int target_confirms = 1;
1140 if (params.size() > 0)
1142 uint256 blockId = 0;
1144 blockId.SetHex(params[0].get_str());
1145 pindex = CBlockLocator(blockId).GetBlockIndex();
1148 if (params.size() > 1)
1150 target_confirms = params[1].get_int();
1152 if (target_confirms < 1)
1153 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter");
1156 int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
1160 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1162 CWalletTx tx = (*it).second;
1164 if (depth == -1 || tx.GetDepthInMainChain() < depth)
1165 ListTransactions(tx, "*", 0, true, transactions);
1170 if (target_confirms == 1)
1172 lastblock = hashBestChain;
1176 int target_height = pindexBest->nHeight + 1 - target_confirms;
1179 for (block = pindexBest;
1180 block && block->nHeight > target_height;
1181 block = block->pprev) { }
1183 lastblock = block ? block->GetBlockHash() : 0;
1187 ret.push_back(Pair("transactions", transactions));
1188 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1193 Value gettransaction(const Array& params, bool fHelp)
1195 if (fHelp || params.size() != 1)
1196 throw runtime_error(
1197 "gettransaction <txid>\n"
1198 "Get detailed information about in-wallet transaction <txid>");
1201 hash.SetHex(params[0].get_str());
1204 if (!pwalletMain->mapWallet.count(hash))
1205 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id");
1206 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1208 int64 nCredit = wtx.GetCredit();
1209 int64 nDebit = wtx.GetDebit();
1210 int64 nNet = nCredit - nDebit;
1211 int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
1213 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1215 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1217 WalletTxToJSON(wtx, entry);
1220 ListTransactions(wtx, "*", 0, false, details);
1221 entry.push_back(Pair("details", details));
1227 Value backupwallet(const Array& params, bool fHelp)
1229 if (fHelp || params.size() != 1)
1230 throw runtime_error(
1231 "backupwallet <destination>\n"
1232 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1234 string strDest = params[0].get_str();
1235 if (!BackupWallet(*pwalletMain, strDest))
1236 throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!");
1242 Value keypoolrefill(const Array& params, bool fHelp)
1244 if (fHelp || params.size() > 0)
1245 throw runtime_error(
1247 "Fills the keypool."
1248 + HelpRequiringPassphrase());
1250 EnsureWalletIsUnlocked();
1252 pwalletMain->TopUpKeyPool();
1254 if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100))
1255 throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool.");
1261 void ThreadTopUpKeyPool(void* parg)
1263 // Make this thread recognisable as the key-topping-up thread
1264 RenameThread("bitcoin-key-top");
1266 pwalletMain->TopUpKeyPool();
1269 void ThreadCleanWalletPassphrase(void* parg)
1271 // Make this thread recognisable as the wallet relocking thread
1272 RenameThread("bitcoin-lock-wa");
1274 int64 nMyWakeTime = GetTimeMillis() + *((int64*)parg) * 1000;
1276 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1278 if (nWalletUnlockTime == 0)
1280 nWalletUnlockTime = nMyWakeTime;
1284 if (nWalletUnlockTime==0)
1286 int64 nToSleep = nWalletUnlockTime - GetTimeMillis();
1290 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1292 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1296 if (nWalletUnlockTime)
1298 nWalletUnlockTime = 0;
1299 pwalletMain->Lock();
1304 if (nWalletUnlockTime < nMyWakeTime)
1305 nWalletUnlockTime = nMyWakeTime;
1308 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1310 delete (int64*)parg;
1313 Value walletpassphrase(const Array& params, bool fHelp)
1315 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1316 throw runtime_error(
1317 "walletpassphrase <passphrase> <timeout>\n"
1318 "Stores the wallet decryption key in memory for <timeout> seconds.");
1321 if (!pwalletMain->IsCrypted())
1322 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1324 if (!pwalletMain->IsLocked())
1325 throw JSONRPCError(RPC_WALLET_ALREADY_UNLOCKED, "Error: Wallet is already unlocked.");
1327 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1328 SecureString strWalletPass;
1329 strWalletPass.reserve(100);
1330 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1331 // Alternately, find a way to make params[0] mlock()'d to begin with.
1332 strWalletPass = params[0].get_str().c_str();
1334 if (strWalletPass.length() > 0)
1336 if (!pwalletMain->Unlock(strWalletPass))
1337 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
1340 throw runtime_error(
1341 "walletpassphrase <passphrase> <timeout>\n"
1342 "Stores the wallet decryption key in memory for <timeout> seconds.");
1344 NewThread(ThreadTopUpKeyPool, NULL);
1345 int64* pnSleepTime = new int64(params[1].get_int64());
1346 NewThread(ThreadCleanWalletPassphrase, pnSleepTime);
1352 Value walletpassphrasechange(const Array& params, bool fHelp)
1354 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1355 throw runtime_error(
1356 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1357 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1360 if (!pwalletMain->IsCrypted())
1361 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1363 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1364 // Alternately, find a way to make params[0] mlock()'d to begin with.
1365 SecureString strOldWalletPass;
1366 strOldWalletPass.reserve(100);
1367 strOldWalletPass = params[0].get_str().c_str();
1369 SecureString strNewWalletPass;
1370 strNewWalletPass.reserve(100);
1371 strNewWalletPass = params[1].get_str().c_str();
1373 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1374 throw runtime_error(
1375 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1376 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1378 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1379 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
1385 Value walletlock(const Array& params, bool fHelp)
1387 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1388 throw runtime_error(
1390 "Removes the wallet encryption key from memory, locking the wallet.\n"
1391 "After calling this method, you will need to call walletpassphrase again\n"
1392 "before being able to call any methods which require the wallet to be unlocked.");
1395 if (!pwalletMain->IsCrypted())
1396 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletlock was called.");
1399 LOCK(cs_nWalletUnlockTime);
1400 pwalletMain->Lock();
1401 nWalletUnlockTime = 0;
1408 Value encryptwallet(const Array& params, bool fHelp)
1410 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1411 throw runtime_error(
1412 "encryptwallet <passphrase>\n"
1413 "Encrypts the wallet with <passphrase>.");
1416 if (pwalletMain->IsCrypted())
1417 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an encrypted wallet, but encryptwallet was called.");
1419 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1420 // Alternately, find a way to make params[0] mlock()'d to begin with.
1421 SecureString strWalletPass;
1422 strWalletPass.reserve(100);
1423 strWalletPass = params[0].get_str().c_str();
1425 if (strWalletPass.length() < 1)
1426 throw runtime_error(
1427 "encryptwallet <passphrase>\n"
1428 "Encrypts the wallet with <passphrase>.");
1430 if (!pwalletMain->EncryptWallet(strWalletPass))
1431 throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: Failed to encrypt the wallet.");
1433 // BDB seems to have a bad habit of writing old data into
1434 // slack space in .dat files; that is bad if the old data is
1435 // unencrypted private keys. So:
1437 return "wallet encrypted; Bitcoin server stopping, restart to run with encrypted wallet. The keypool has been flushed, you need to make a new backup.";
1440 class DescribeAddressVisitor : public boost::static_visitor<Object>
1443 Object operator()(const CNoDestination &dest) const { return Object(); }
1445 Object operator()(const CKeyID &keyID) const {
1448 pwalletMain->GetPubKey(keyID, vchPubKey);
1449 obj.push_back(Pair("isscript", false));
1450 obj.push_back(Pair("pubkey", HexStr(vchPubKey.Raw())));
1451 obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed()));
1455 Object operator()(const CScriptID &scriptID) const {
1457 obj.push_back(Pair("isscript", true));
1459 pwalletMain->GetCScript(scriptID, subscript);
1460 std::vector<CTxDestination> addresses;
1461 txnouttype whichType;
1463 ExtractDestinations(subscript, whichType, addresses, nRequired);
1464 obj.push_back(Pair("script", GetTxnOutputType(whichType)));
1466 BOOST_FOREACH(const CTxDestination& addr, addresses)
1467 a.push_back(CBitcoinAddress(addr).ToString());
1468 obj.push_back(Pair("addresses", a));
1469 if (whichType == TX_MULTISIG)
1470 obj.push_back(Pair("sigsrequired", nRequired));
1475 Value validateaddress(const Array& params, bool fHelp)
1477 if (fHelp || params.size() != 1)
1478 throw runtime_error(
1479 "validateaddress <bitcoinaddress>\n"
1480 "Return information about <bitcoinaddress>.");
1482 CBitcoinAddress address(params[0].get_str());
1483 bool isValid = address.IsValid();
1486 ret.push_back(Pair("isvalid", isValid));
1489 CTxDestination dest = address.Get();
1490 string currentAddress = address.ToString();
1491 ret.push_back(Pair("address", currentAddress));
1492 bool fMine = IsMine(*pwalletMain, dest);
1493 ret.push_back(Pair("ismine", fMine));
1495 Object detail = boost::apply_visitor(DescribeAddressVisitor(), dest);
1496 ret.insert(ret.end(), detail.begin(), detail.end());
1498 if (pwalletMain->mapAddressBook.count(dest))
1499 ret.push_back(Pair("account", pwalletMain->mapAddressBook[dest]));
1504 Value lockunspent(const Array& params, bool fHelp)
1506 if (fHelp || params.size() < 1 || params.size() > 2)
1507 throw runtime_error(
1508 "lockunspent unlock? [array-of-Objects]\n"
1509 "Updates list of temporarily unspendable outputs.");
1511 if (params.size() == 1)
1512 RPCTypeCheck(params, list_of(bool_type));
1514 RPCTypeCheck(params, list_of(bool_type)(array_type));
1516 bool fUnlock = params[0].get_bool();
1518 if (params.size() == 1) {
1520 pwalletMain->UnlockAllCoins();
1524 Array outputs = params[1].get_array();
1525 BOOST_FOREACH(Value& output, outputs)
1527 if (output.type() != obj_type)
1528 throw JSONRPCError(-8, "Invalid parameter, expected object");
1529 const Object& o = output.get_obj();
1531 RPCTypeCheck(o, map_list_of("txid", str_type)("vout", int_type));
1533 string txid = find_value(o, "txid").get_str();
1535 throw JSONRPCError(-8, "Invalid parameter, expected hex txid");
1537 int nOutput = find_value(o, "vout").get_int();
1539 throw JSONRPCError(-8, "Invalid parameter, vout must be positive");
1541 COutPoint outpt(uint256(txid), nOutput);
1544 pwalletMain->UnlockCoin(outpt);
1546 pwalletMain->LockCoin(outpt);
1552 Value listlockunspent(const Array& params, bool fHelp)
1554 if (fHelp || params.size() > 0)
1555 throw runtime_error(
1557 "Returns list of temporarily unspendable outputs.");
1559 vector<COutPoint> vOutpts;
1560 pwalletMain->ListLockedCoins(vOutpts);
1564 BOOST_FOREACH(COutPoint &outpt, vOutpts) {
1567 o.push_back(Pair("txid", outpt.hash.GetHex()));
1568 o.push_back(Pair("vout", (int)outpt.n));