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 extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, json_spirit::Object& entry);
20 std::string HelpRequiringPassphrase()
22 return pwalletMain->IsCrypted()
23 ? "\nrequires wallet passphrase to be set with walletpassphrase first"
27 void EnsureWalletIsUnlocked()
29 if (pwalletMain->IsLocked())
30 throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
31 if (fWalletUnlockMintOnly)
32 throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Wallet unlocked for block minting only.");
35 void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
37 int confirms = wtx.GetDepthInMainChain();
38 entry.push_back(Pair("confirmations", confirms));
39 if (wtx.IsCoinBase() || wtx.IsCoinStake())
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 uint256 hash = wtx.GetHash();
48 uint256 metahash = wtx.GetMetaHash();
49 entry.push_back(Pair("txid", hash.GetHex()));
50 entry.push_back(Pair("metahash", metahash.GetHex()));
52 BOOST_FOREACH(const uint256& conflict, wtx.GetConflicts())
53 conflicts.push_back(conflict.GetHex());
54 entry.push_back(Pair("walletconflicts", conflicts));
55 entry.push_back(Pair("time", (boost::int64_t)wtx.GetTxTime()));
56 entry.push_back(Pair("timereceived", (boost::int64_t)wtx.nTimeReceived));
57 BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
58 entry.push_back(Pair(item.first, item.second));
61 string AccountFromValue(const Value& value)
63 string strAccount = value.get_str();
64 if (strAccount == "*")
65 throw JSONRPCError(RPC_WALLET_INVALID_ACCOUNT_NAME, "Invalid account name");
69 Value getinfo(const Array& params, bool fHelp)
71 if (fHelp || params.size() != 0)
74 "Returns an object containing various state info.");
77 GetProxy(NET_IPV4, proxy);
80 obj.push_back(Pair("version", FormatFullVersion()));
81 obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION));
82 obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
83 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
84 obj.push_back(Pair("newmint", ValueFromAmount(pwalletMain->GetNewMint())));
85 obj.push_back(Pair("stake", ValueFromAmount(pwalletMain->GetStake())));
86 obj.push_back(Pair("blocks", (int)nBestHeight));
87 obj.push_back(Pair("timeoffset", (boost::int64_t)GetTimeOffset()));
88 obj.push_back(Pair("moneysupply", ValueFromAmount(pindexBest->nMoneySupply)));
89 obj.push_back(Pair("connections", (int)vNodes.size()));
90 obj.push_back(Pair("proxy", (proxy.first.IsValid() ? proxy.first.ToStringIPPort() : string())));
91 obj.push_back(Pair("ip", addrSeenByPeer.ToStringIP()));
93 diff.push_back(Pair("proof-of-work", GetDifficulty()));
94 diff.push_back(Pair("proof-of-stake", GetDifficulty(GetLastBlockIndex(pindexBest, true))));
95 obj.push_back(Pair("difficulty", diff));
97 obj.push_back(Pair("testnet", fTestNet));
98 obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
99 obj.push_back(Pair("keypoolsize", (int)pwalletMain->GetKeyPoolSize()));
100 obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee)));
101 obj.push_back(Pair("mininput", ValueFromAmount(nMinimumInputValue)));
102 if (pwalletMain->IsCrypted())
103 obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime / 1000));
104 obj.push_back(Pair("errors", GetWarnings("statusbar")));
109 Value getnewpubkey(const Array& params, bool fHelp)
111 if (fHelp || params.size() > 1)
113 "getnewpubkey [account]\n"
114 "Returns new public key for coinbase generation.");
116 // Parse the account first so we don't generate a key if there's an error
118 if (params.size() > 0)
119 strAccount = AccountFromValue(params[0]);
121 if (!pwalletMain->IsLocked())
122 pwalletMain->TopUpKeyPool();
124 // Generate a new key that is added to wallet
126 if (!pwalletMain->GetKeyFromPool(newKey, false))
127 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
128 CKeyID keyID = newKey.GetID();
130 pwalletMain->SetAddressBookName(keyID, strAccount);
131 vector<unsigned char> vchPubKey = newKey.Raw();
133 return HexStr(vchPubKey.begin(), vchPubKey.end());
137 Value getnewaddress(const Array& params, bool fHelp)
139 if (fHelp || params.size() > 1)
141 "getnewaddress [account]\n"
142 "Returns a new NovaCoin address for receiving payments. "
143 "If [account] is specified (recommended), it is added to the address book "
144 "so payments received with the address will be credited to [account].");
146 // Parse the account first so we don't generate a key if there's an error
148 if (params.size() > 0)
149 strAccount = AccountFromValue(params[0]);
151 if (!pwalletMain->IsLocked())
152 pwalletMain->TopUpKeyPool();
154 // Generate a new key that is added to wallet
156 if (!pwalletMain->GetKeyFromPool(newKey, false))
157 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
158 CKeyID keyID = newKey.GetID();
160 pwalletMain->SetAddressBookName(keyID, strAccount);
162 return CBitcoinAddress(keyID).ToString();
166 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
168 CWalletDB walletdb(pwalletMain->strWalletFile);
171 walletdb.ReadAccount(strAccount, account);
173 bool bKeyUsed = false;
175 // Check if the current key has been used
176 if (account.vchPubKey.IsValid())
178 CScript scriptPubKey;
179 scriptPubKey.SetDestination(account.vchPubKey.GetID());
180 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
181 it != pwalletMain->mapWallet.end() && account.vchPubKey.IsValid();
184 const CWalletTx& wtx = (*it).second;
185 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
186 if (txout.scriptPubKey == scriptPubKey)
191 // Generate a new key
192 if (!account.vchPubKey.IsValid() || bForceNew || bKeyUsed)
194 if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false))
195 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
197 pwalletMain->SetAddressBookName(account.vchPubKey.GetID(), strAccount);
198 walletdb.WriteAccount(strAccount, account);
201 return CBitcoinAddress(account.vchPubKey.GetID());
204 Value getaccountaddress(const Array& params, bool fHelp)
206 if (fHelp || params.size() != 1)
208 "getaccountaddress <account>\n"
209 "Returns the current NovaCoin address for receiving payments to this account.");
211 // Parse the account first so we don't generate a key if there's an error
212 string strAccount = AccountFromValue(params[0]);
216 ret = GetAccountAddress(strAccount).ToString();
223 Value setaccount(const Array& params, bool fHelp)
225 if (fHelp || params.size() < 1 || params.size() > 2)
227 "setaccount <novacoinaddress> <account>\n"
228 "Sets the account associated with the given address.");
230 CBitcoinAddress address(params[0].get_str());
231 if (!address.IsValid())
232 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
236 if (params.size() > 1)
237 strAccount = AccountFromValue(params[1]);
239 // Detect when changing the account of an address that is the 'unused current key' of another account:
240 if (pwalletMain->mapAddressBook.count(address.Get()))
242 string strOldAccount = pwalletMain->mapAddressBook[address.Get()];
243 if (address == GetAccountAddress(strOldAccount))
244 GetAccountAddress(strOldAccount, true);
247 pwalletMain->SetAddressBookName(address.Get(), strAccount);
253 Value getaccount(const Array& params, bool fHelp)
255 if (fHelp || params.size() != 1)
257 "getaccount <novacoinaddress>\n"
258 "Returns the account associated with the given address.");
260 CBitcoinAddress address(params[0].get_str());
261 if (!address.IsValid())
262 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
265 map<CTxDestination, string>::iterator mi = pwalletMain->mapAddressBook.find(address.Get());
266 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
267 strAccount = (*mi).second;
272 Value getaddressesbyaccount(const Array& params, bool fHelp)
274 if (fHelp || params.size() != 1)
276 "getaddressesbyaccount <account>\n"
277 "Returns the list of addresses for the given account.");
279 string strAccount = AccountFromValue(params[0]);
281 // Find all addresses that have the given account
283 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
285 const CBitcoinAddress& address = item.first;
286 const string& strName = item.second;
287 if (strName == strAccount)
288 ret.push_back(address.ToString());
293 Value sendtoaddress(const Array& params, bool fHelp)
295 if (fHelp || params.size() < 2 || params.size() > 4)
297 "sendtoaddress <novacoinaddress> <amount> [comment] [comment-to]\n"
298 "<amount> is a real and is rounded to the nearest " + FormatMoney(MIN_TXOUT_AMOUNT)
299 + HelpRequiringPassphrase());
301 CBitcoinAddress address(params[0].get_str());
302 if (!address.IsValid())
303 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
306 int64 nAmount = AmountFromValue(params[1]);
308 if (nAmount < MIN_TXOUT_AMOUNT)
309 throw JSONRPCError(-101, "Send amount too small");
313 if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
314 wtx.mapValue["comment"] = params[2].get_str();
315 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
316 wtx.mapValue["to"] = params[3].get_str();
318 if (pwalletMain->IsLocked())
319 throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
321 string strError = pwalletMain->SendMoneyToDestination(address.Get(), nAmount, wtx);
323 throw JSONRPCError(RPC_WALLET_ERROR, strError);
325 return wtx.GetHash().GetHex();
328 Value listaddressgroupings(const Array& params, bool fHelp)
332 "listaddressgroupings\n"
333 "Lists groups of addresses which have had their common ownership\n"
334 "made public by common use as inputs or as the resulting change\n"
335 "in past transactions");
338 map<CTxDestination, int64> balances = pwalletMain->GetAddressBalances();
339 BOOST_FOREACH(set<CTxDestination> grouping, pwalletMain->GetAddressGroupings())
342 BOOST_FOREACH(CTxDestination address, grouping)
345 addressInfo.push_back(CBitcoinAddress(address).ToString());
346 addressInfo.push_back(ValueFromAmount(balances[address]));
348 LOCK(pwalletMain->cs_wallet);
349 if (pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get()) != pwalletMain->mapAddressBook.end())
350 addressInfo.push_back(pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get())->second);
352 jsonGrouping.push_back(addressInfo);
354 jsonGroupings.push_back(jsonGrouping);
356 return jsonGroupings;
359 Value signmessage(const Array& params, bool fHelp)
361 if (fHelp || params.size() != 2)
363 "signmessage <novacoinaddress> <message>\n"
364 "Sign a message with the private key of an address");
366 EnsureWalletIsUnlocked();
368 string strAddress = params[0].get_str();
369 string strMessage = params[1].get_str();
371 CBitcoinAddress addr(strAddress);
373 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
376 if (!addr.GetKeyID(keyID))
377 throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
380 if (!pwalletMain->GetKey(keyID, key))
381 throw JSONRPCError(RPC_WALLET_ERROR, "Private key not available");
383 CDataStream ss(SER_GETHASH, 0);
384 ss << strMessageMagic;
387 vector<unsigned char> vchSig;
388 if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
389 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed");
391 return EncodeBase64(&vchSig[0], vchSig.size());
394 Value verifymessage(const Array& params, bool fHelp)
396 if (fHelp || params.size() != 3)
398 "verifymessage <novacoinaddress> <signature> <message>\n"
399 "Verify a signed message");
401 string strAddress = params[0].get_str();
402 string strSign = params[1].get_str();
403 string strMessage = params[2].get_str();
405 CBitcoinAddress addr(strAddress);
407 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
410 if (!addr.GetKeyID(keyID))
411 throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
413 bool fInvalid = false;
414 vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
417 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Malformed base64 encoding");
419 CDataStream ss(SER_GETHASH, 0);
420 ss << strMessageMagic;
424 if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
427 return (key.GetPubKey().GetID() == keyID);
431 Value getreceivedbyaddress(const Array& params, bool fHelp)
433 if (fHelp || params.size() < 1 || params.size() > 2)
435 "getreceivedbyaddress <novacoinaddress> [minconf=1]\n"
436 "Returns the total amount received by <novacoinaddress> in transactions with at least [minconf] confirmations.");
439 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
440 CScript scriptPubKey;
441 if (!address.IsValid())
442 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
443 scriptPubKey.SetDestination(address.Get());
444 if (!IsMine(*pwalletMain,scriptPubKey))
447 // Minimum confirmations
449 if (params.size() > 1)
450 nMinDepth = params[1].get_int();
454 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
456 const CWalletTx& wtx = (*it).second;
457 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
460 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
461 if (txout.scriptPubKey == scriptPubKey)
462 if (wtx.GetDepthInMainChain() >= nMinDepth)
463 nAmount += txout.nValue;
466 return ValueFromAmount(nAmount);
470 void GetAccountAddresses(string strAccount, set<CTxDestination>& setAddress)
472 BOOST_FOREACH(const PAIRTYPE(CTxDestination, string)& item, pwalletMain->mapAddressBook)
474 const CTxDestination& address = item.first;
475 const string& strName = item.second;
476 if (strName == strAccount)
477 setAddress.insert(address);
481 Value getreceivedbyaccount(const Array& params, bool fHelp)
483 if (fHelp || params.size() < 1 || params.size() > 2)
485 "getreceivedbyaccount <account> [minconf=1]\n"
486 "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
488 // Minimum confirmations
490 if (params.size() > 1)
491 nMinDepth = params[1].get_int();
493 // Get the set of pub keys assigned to account
494 string strAccount = AccountFromValue(params[0]);
495 set<CTxDestination> setAddress;
496 GetAccountAddresses(strAccount, setAddress);
500 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
502 const CWalletTx& wtx = (*it).second;
503 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
506 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
508 CTxDestination address;
509 if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*pwalletMain, address) && setAddress.count(address))
510 if (wtx.GetDepthInMainChain() >= nMinDepth)
511 nAmount += txout.nValue;
515 return (double)nAmount / (double)COIN;
519 int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
523 // Tally wallet transactions
524 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
526 const CWalletTx& wtx = (*it).second;
530 int64 nGenerated, nReceived, nSent, nFee;
531 wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee);
533 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
534 nBalance += nReceived;
535 nBalance += nGenerated - nSent - nFee;
538 // Tally internal accounting entries
539 nBalance += walletdb.GetAccountCreditDebit(strAccount);
544 int64 GetAccountBalance(const string& strAccount, int nMinDepth)
546 CWalletDB walletdb(pwalletMain->strWalletFile);
547 return GetAccountBalance(walletdb, strAccount, nMinDepth);
551 Value getbalance(const Array& params, bool fHelp)
553 if (fHelp || params.size() > 2)
555 "getbalance [account] [minconf=1]\n"
556 "If [account] is not specified, returns the server's total available balance.\n"
557 "If [account] is specified, returns the balance in the account.");
559 if (params.size() == 0)
560 return ValueFromAmount(pwalletMain->GetBalance());
563 if (params.size() > 1)
564 nMinDepth = params[1].get_int();
566 if (params[0].get_str() == "*") {
567 // Calculate total balance a different way from GetBalance()
568 // (GetBalance() sums up all unspent TxOuts)
569 // getbalance and getbalance '*' 0 should return the same number.
571 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
573 const CWalletTx& wtx = (*it).second;
574 if (!wtx.IsTrusted() || wtx.GetBlocksToMaturity() > 0)
577 int64 allGeneratedImmature, allGeneratedMature, allFee;
578 allGeneratedImmature = allGeneratedMature = allFee = 0;
580 string strSentAccount;
581 list<pair<CTxDestination, int64> > listReceived;
582 list<pair<CTxDestination, int64> > listSent;
583 wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
584 if (wtx.GetDepthInMainChain() >= nMinDepth)
586 BOOST_FOREACH(const PAIRTYPE(CTxDestination,int64)& r, listReceived)
587 nBalance += r.second;
589 BOOST_FOREACH(const PAIRTYPE(CTxDestination,int64)& r, listSent)
590 nBalance -= r.second;
592 nBalance += allGeneratedMature;
594 return ValueFromAmount(nBalance);
597 string strAccount = AccountFromValue(params[0]);
599 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
601 return ValueFromAmount(nBalance);
604 Value getunconfirmedbalance(const Array ¶ms, bool fHelp)
606 if (fHelp || params.size() > 0)
608 "getunconfirmedbalance\n"
609 "Returns the server's total unconfirmed balance\n");
610 return ValueFromAmount(pwalletMain->GetUnconfirmedBalance());
613 Value movecmd(const Array& params, bool fHelp)
615 if (fHelp || params.size() < 3 || params.size() > 5)
617 "move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
618 "Move from one account in your wallet to another.");
620 string strFrom = AccountFromValue(params[0]);
621 string strTo = AccountFromValue(params[1]);
622 int64 nAmount = AmountFromValue(params[2]);
624 if (nAmount < MIN_TXOUT_AMOUNT)
625 throw JSONRPCError(-101, "Send amount too small");
627 if (params.size() > 3)
628 // unused parameter, used to be nMinDepth, keep type-checking it though
629 (void)params[3].get_int();
631 if (params.size() > 4)
632 strComment = params[4].get_str();
634 CWalletDB walletdb(pwalletMain->strWalletFile);
635 if (!walletdb.TxnBegin())
636 throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
638 int64 nNow = GetAdjustedTime();
641 CAccountingEntry debit;
642 debit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
643 debit.strAccount = strFrom;
644 debit.nCreditDebit = -nAmount;
646 debit.strOtherAccount = strTo;
647 debit.strComment = strComment;
648 walletdb.WriteAccountingEntry(debit);
651 CAccountingEntry credit;
652 credit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
653 credit.strAccount = strTo;
654 credit.nCreditDebit = nAmount;
656 credit.strOtherAccount = strFrom;
657 credit.strComment = strComment;
658 walletdb.WriteAccountingEntry(credit);
660 if (!walletdb.TxnCommit())
661 throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
667 Value sendfrom(const Array& params, bool fHelp)
669 if (fHelp || params.size() < 3 || params.size() > 6)
671 "sendfrom <fromaccount> <tonovacoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
672 "<amount> is a real and is rounded to the nearest " + FormatMoney(MIN_TXOUT_AMOUNT)
673 + HelpRequiringPassphrase());
675 string strAccount = AccountFromValue(params[0]);
676 CBitcoinAddress address(params[1].get_str());
677 if (!address.IsValid())
678 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
679 int64 nAmount = AmountFromValue(params[2]);
681 if (nAmount < MIN_TXOUT_AMOUNT)
682 throw JSONRPCError(-101, "Send amount too small");
685 if (params.size() > 3)
686 nMinDepth = params[3].get_int();
689 wtx.strFromAccount = strAccount;
690 if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
691 wtx.mapValue["comment"] = params[4].get_str();
692 if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
693 wtx.mapValue["to"] = params[5].get_str();
695 EnsureWalletIsUnlocked();
698 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
699 if (nAmount > nBalance)
700 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
703 string strError = pwalletMain->SendMoneyToDestination(address.Get(), nAmount, wtx);
705 throw JSONRPCError(RPC_WALLET_ERROR, strError);
707 return wtx.GetHash().GetHex();
711 Value sendmany(const Array& params, bool fHelp)
713 if (fHelp || params.size() < 2 || params.size() > 4)
715 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
716 "amounts are double-precision floating point numbers"
717 + HelpRequiringPassphrase());
719 string strAccount = AccountFromValue(params[0]);
720 Object sendTo = params[1].get_obj();
722 if (params.size() > 2)
723 nMinDepth = params[2].get_int();
726 wtx.strFromAccount = strAccount;
727 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
728 wtx.mapValue["comment"] = params[3].get_str();
730 set<CBitcoinAddress> setAddress;
731 vector<pair<CScript, int64> > vecSend;
733 int64 totalAmount = 0;
734 BOOST_FOREACH(const Pair& s, sendTo)
736 CBitcoinAddress address(s.name_);
737 if (!address.IsValid())
738 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid NovaCoin address: ")+s.name_);
740 if (setAddress.count(address))
741 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+s.name_);
742 setAddress.insert(address);
744 CScript scriptPubKey;
745 scriptPubKey.SetDestination(address.Get());
746 int64 nAmount = AmountFromValue(s.value_);
748 if (nAmount < MIN_TXOUT_AMOUNT)
749 throw JSONRPCError(-101, "Send amount too small");
751 totalAmount += nAmount;
753 vecSend.push_back(make_pair(scriptPubKey, nAmount));
756 EnsureWalletIsUnlocked();
759 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
760 if (totalAmount > nBalance)
761 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
764 CReserveKey keyChange(pwalletMain);
765 int64 nFeeRequired = 0;
766 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
769 if (totalAmount + nFeeRequired > pwalletMain->GetBalance())
770 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds");
771 throw JSONRPCError(RPC_WALLET_ERROR, "Transaction creation failed");
773 if (!pwalletMain->CommitTransaction(wtx, keyChange))
774 throw JSONRPCError(RPC_WALLET_ERROR, "Transaction commit failed");
776 return wtx.GetHash().GetHex();
779 Value addmultisigaddress(const Array& params, bool fHelp)
781 if (fHelp || params.size() < 2 || params.size() > 3)
783 string msg = "addmultisigaddress <nrequired> <'[\"key\",\"key\"]'> [account]\n"
784 "Add a nrequired-to-sign multisignature address to the wallet\"\n"
785 "each key is a NovaCoin address or hex-encoded public key\n"
786 "If [account] is specified, assign address to [account].";
787 throw runtime_error(msg);
790 int nRequired = params[0].get_int();
791 const Array& keys = params[1].get_array();
793 if (params.size() > 2)
794 strAccount = AccountFromValue(params[2]);
796 // Gather public keys
798 throw runtime_error("a multisignature address must require at least one key to redeem");
799 if ((int)keys.size() < nRequired)
801 strprintf("not enough keys supplied "
802 "(got %"PRIszu" keys, but need at least %d to redeem)", keys.size(), nRequired));
803 std::vector<CKey> pubkeys;
804 pubkeys.resize(keys.size());
805 for (unsigned int i = 0; i < keys.size(); i++)
807 const std::string& ks = keys[i].get_str();
809 // Case 1: Bitcoin address and we have full public key:
810 CBitcoinAddress address(ks);
811 if (address.IsValid())
814 if (!address.GetKeyID(keyID))
816 strprintf("%s does not refer to a key",ks.c_str()));
818 if (!pwalletMain->GetPubKey(keyID, vchPubKey))
820 strprintf("no full public key for address %s",ks.c_str()));
821 if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey))
822 throw runtime_error(" Invalid public key: "+ks);
825 // Case 2: hex public key
828 CPubKey vchPubKey(ParseHex(ks));
829 if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey))
830 throw runtime_error(" Invalid public key: "+ks);
834 throw runtime_error(" Invalid public key: "+ks);
838 // Construct using pay-to-script-hash:
840 inner.SetMultisig(nRequired, pubkeys);
841 CScriptID innerID = inner.GetID();
842 pwalletMain->AddCScript(inner);
844 pwalletMain->SetAddressBookName(innerID, strAccount);
845 return CBitcoinAddress(innerID).ToString();
848 Value addredeemscript(const Array& params, bool fHelp)
850 if (fHelp || params.size() < 1 || params.size() > 2)
852 string msg = "addredeemscript <redeemScript> [account]\n"
853 "Add a P2SH address with a specified redeemScript to the wallet.\n"
854 "If [account] is specified, assign address to [account].";
855 throw runtime_error(msg);
859 if (params.size() > 1)
860 strAccount = AccountFromValue(params[1]);
862 // Construct using pay-to-script-hash:
863 vector<unsigned char> innerData = ParseHexV(params[0], "redeemScript");
864 CScript inner(innerData.begin(), innerData.end());
865 CScriptID innerID = inner.GetID();
866 pwalletMain->AddCScript(inner);
868 pwalletMain->SetAddressBookName(innerID, strAccount);
869 return CBitcoinAddress(innerID).ToString();
879 nConf = std::numeric_limits<int>::max();
883 Value ListReceived(const Array& params, bool fByAccounts)
885 // Minimum confirmations
887 if (params.size() > 0)
888 nMinDepth = params[0].get_int();
890 // Whether to include empty accounts
891 bool fIncludeEmpty = false;
892 if (params.size() > 1)
893 fIncludeEmpty = params[1].get_bool();
896 map<CBitcoinAddress, tallyitem> mapTally;
897 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
899 const CWalletTx& wtx = (*it).second;
901 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
904 int nDepth = wtx.GetDepthInMainChain();
905 if (nDepth < nMinDepth)
908 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
910 CTxDestination address;
911 if (!ExtractDestination(txout.scriptPubKey, address) || !IsMine(*pwalletMain, address))
914 tallyitem& item = mapTally[address];
915 item.nAmount += txout.nValue;
916 item.nConf = min(item.nConf, nDepth);
922 map<string, tallyitem> mapAccountTally;
923 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
925 const CBitcoinAddress& address = item.first;
926 const string& strAccount = item.second;
927 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
928 if (it == mapTally.end() && !fIncludeEmpty)
932 int nConf = std::numeric_limits<int>::max();
933 if (it != mapTally.end())
935 nAmount = (*it).second.nAmount;
936 nConf = (*it).second.nConf;
941 tallyitem& item = mapAccountTally[strAccount];
942 item.nAmount += nAmount;
943 item.nConf = min(item.nConf, nConf);
948 obj.push_back(Pair("address", address.ToString()));
949 obj.push_back(Pair("account", strAccount));
950 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
951 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
958 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
960 int64 nAmount = (*it).second.nAmount;
961 int nConf = (*it).second.nConf;
963 obj.push_back(Pair("account", (*it).first));
964 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
965 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
973 Value listreceivedbyaddress(const Array& params, bool fHelp)
975 if (fHelp || params.size() > 2)
977 "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
978 "[minconf] is the minimum number of confirmations before payments are included.\n"
979 "[includeempty] whether to include addresses that haven't received any payments.\n"
980 "Returns an array of objects containing:\n"
981 " \"address\" : receiving address\n"
982 " \"account\" : the account of the receiving address\n"
983 " \"amount\" : total amount received by the address\n"
984 " \"confirmations\" : number of confirmations of the most recent transaction included");
986 return ListReceived(params, false);
989 Value listreceivedbyaccount(const Array& params, bool fHelp)
991 if (fHelp || params.size() > 2)
993 "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
994 "[minconf] is the minimum number of confirmations before payments are included.\n"
995 "[includeempty] whether to include accounts that haven't received any payments.\n"
996 "Returns an array of objects containing:\n"
997 " \"account\" : the account of the receiving addresses\n"
998 " \"amount\" : total amount received by addresses with this account\n"
999 " \"confirmations\" : number of confirmations of the most recent transaction included");
1001 return ListReceived(params, true);
1004 static void MaybePushAddress(Object & entry, const CTxDestination &dest)
1006 CBitcoinAddress addr;
1008 entry.push_back(Pair("address", addr.ToString()));
1011 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
1013 int64 nGeneratedImmature, nGeneratedMature, nFee;
1014 string strSentAccount;
1015 list<pair<CTxDestination, int64> > listReceived;
1016 list<pair<CTxDestination, int64> > listSent;
1018 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1020 bool fAllAccounts = (strAccount == string("*"));
1022 // Generated blocks assigned to account ""
1023 if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
1026 entry.push_back(Pair("account", string("")));
1027 if (nGeneratedImmature)
1029 entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
1030 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
1034 entry.push_back(Pair("category", "generate"));
1035 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
1038 WalletTxToJSON(wtx, entry);
1039 ret.push_back(entry);
1043 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1045 BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& s, listSent)
1048 entry.push_back(Pair("account", strSentAccount));
1049 MaybePushAddress(entry, s.first);
1051 if (wtx.GetDepthInMainChain() < 0) {
1052 entry.push_back(Pair("category", "conflicted"));
1054 entry.push_back(Pair("category", "send"));
1057 entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1058 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1060 WalletTxToJSON(wtx, entry);
1061 ret.push_back(entry);
1066 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1068 BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& r, listReceived)
1071 if (pwalletMain->mapAddressBook.count(r.first))
1072 account = pwalletMain->mapAddressBook[r.first];
1073 if (fAllAccounts || (account == strAccount))
1076 entry.push_back(Pair("account", account));
1077 MaybePushAddress(entry, r.first);
1078 if (wtx.IsCoinBase())
1080 if (wtx.GetDepthInMainChain() < 1)
1081 entry.push_back(Pair("category", "orphan"));
1082 else if (wtx.GetBlocksToMaturity() > 0)
1083 entry.push_back(Pair("category", "immature"));
1085 entry.push_back(Pair("category", "generate"));
1088 if (wtx.GetDepthInMainChain() < 0) {
1089 entry.push_back(Pair("category", "conflicted"));
1091 entry.push_back(Pair("category", "receive"));
1094 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1096 WalletTxToJSON(wtx, entry);
1097 ret.push_back(entry);
1103 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1105 bool fAllAccounts = (strAccount == string("*"));
1107 if (fAllAccounts || acentry.strAccount == strAccount)
1110 entry.push_back(Pair("account", acentry.strAccount));
1111 entry.push_back(Pair("category", "move"));
1112 entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
1113 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1114 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1115 entry.push_back(Pair("comment", acentry.strComment));
1116 ret.push_back(entry);
1120 Value listtransactions(const Array& params, bool fHelp)
1122 if (fHelp || params.size() > 3)
1123 throw runtime_error(
1124 "listtransactions [account] [count=10] [from=0]\n"
1125 "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1127 string strAccount = "*";
1128 if (params.size() > 0)
1129 strAccount = params[0].get_str();
1131 if (params.size() > 1)
1132 nCount = params[1].get_int();
1134 if (params.size() > 2)
1135 nFrom = params[2].get_int();
1138 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count");
1140 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative from");
1144 std::list<CAccountingEntry> acentries;
1145 CWallet::TxItems txOrdered = pwalletMain->OrderedTxItems(acentries, strAccount);
1147 // iterate backwards until we have nCount items to return:
1148 for (CWallet::TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
1150 CWalletTx *const pwtx = (*it).second.first;
1152 ListTransactions(*pwtx, strAccount, 0, true, ret);
1153 CAccountingEntry *const pacentry = (*it).second.second;
1155 AcentryToJSON(*pacentry, strAccount, ret);
1157 if ((int)ret.size() >= (nCount+nFrom)) break;
1159 // ret is newest to oldest
1161 if (nFrom > (int)ret.size())
1163 if ((nFrom + nCount) > (int)ret.size())
1164 nCount = ret.size() - nFrom;
1165 Array::iterator first = ret.begin();
1166 std::advance(first, nFrom);
1167 Array::iterator last = ret.begin();
1168 std::advance(last, nFrom+nCount);
1170 if (last != ret.end()) ret.erase(last, ret.end());
1171 if (first != ret.begin()) ret.erase(ret.begin(), first);
1173 std::reverse(ret.begin(), ret.end()); // Return oldest to newest
1178 Value listaccounts(const Array& params, bool fHelp)
1180 if (fHelp || params.size() > 1)
1181 throw runtime_error(
1182 "listaccounts [minconf=1]\n"
1183 "Returns Object that has account names as keys, account balances as values.");
1186 if (params.size() > 0)
1187 nMinDepth = params[0].get_int();
1189 map<string, int64> mapAccountBalances;
1190 BOOST_FOREACH(const PAIRTYPE(CTxDestination, string)& entry, pwalletMain->mapAddressBook) {
1191 if (IsMine(*pwalletMain, entry.first)) // This address belongs to me
1192 mapAccountBalances[entry.second] = 0;
1195 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1197 const CWalletTx& wtx = (*it).second;
1198 int64 nGeneratedImmature, nGeneratedMature, nFee;
1199 string strSentAccount;
1200 list<pair<CTxDestination, int64> > listReceived;
1201 list<pair<CTxDestination, int64> > listSent;
1202 if (wtx.GetBlocksToMaturity() > 0)
1204 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1205 mapAccountBalances[strSentAccount] -= nFee;
1206 BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& s, listSent)
1207 mapAccountBalances[strSentAccount] -= s.second;
1208 if (wtx.GetDepthInMainChain() >= nMinDepth)
1210 mapAccountBalances[""] += nGeneratedMature;
1211 BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& r, listReceived)
1212 if (pwalletMain->mapAddressBook.count(r.first))
1213 mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1215 mapAccountBalances[""] += r.second;
1219 list<CAccountingEntry> acentries;
1220 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1221 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1222 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1225 BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) {
1226 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1231 Value listsinceblock(const Array& params, bool fHelp)
1234 throw runtime_error(
1235 "listsinceblock [blockhash] [target-confirmations]\n"
1236 "Get all transactions in blocks since block [blockhash], or all transactions if omitted");
1238 CBlockIndex *pindex = NULL;
1239 int target_confirms = 1;
1241 if (params.size() > 0)
1243 uint256 blockId = 0;
1245 blockId.SetHex(params[0].get_str());
1246 pindex = CBlockLocator(blockId).GetBlockIndex();
1249 if (params.size() > 1)
1251 target_confirms = params[1].get_int();
1253 if (target_confirms < 1)
1254 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter");
1257 int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
1261 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1263 CWalletTx tx = (*it).second;
1265 if (depth == -1 || tx.GetDepthInMainChain() < depth)
1266 ListTransactions(tx, "*", 0, true, transactions);
1271 if (target_confirms == 1)
1273 lastblock = hashBestChain;
1277 int target_height = pindexBest->nHeight + 1 - target_confirms;
1280 for (block = pindexBest;
1281 block && block->nHeight > target_height;
1282 block = block->pprev) { }
1284 lastblock = block ? block->GetBlockHash() : 0;
1288 ret.push_back(Pair("transactions", transactions));
1289 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1294 Value gettransaction(const Array& params, bool fHelp)
1296 if (fHelp || params.size() != 1)
1297 throw runtime_error(
1298 "gettransaction <txid>\n"
1299 "Get detailed information about <txid>");
1302 hash.SetHex(params[0].get_str());
1306 if (pwalletMain->mapWallet.count(hash))
1308 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1310 TxToJSON(wtx, 0, entry);
1312 int64 nCredit = wtx.GetCredit();
1313 int64 nDebit = wtx.GetDebit();
1314 int64 nNet = nCredit - nDebit;
1315 int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
1317 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1319 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1321 WalletTxToJSON(wtx, entry);
1324 ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
1325 entry.push_back(Pair("details", details));
1327 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
1329 string strHex = HexStr(ssTx.begin(), ssTx.end());
1330 entry.push_back(Pair("hex", strHex));
1335 uint256 hashBlock = 0;
1336 if (GetTransaction(hash, tx, hashBlock, true))
1338 TxToJSON(tx, 0, entry);
1340 entry.push_back(Pair("confirmations", 0));
1343 entry.push_back(Pair("blockhash", hashBlock.GetHex()));
1344 map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
1345 if (mi != mapBlockIndex.end() && (*mi).second)
1347 CBlockIndex* pindex = (*mi).second;
1348 if (pindex->IsInMainChain())
1349 entry.push_back(Pair("confirmations", 1 + nBestHeight - pindex->nHeight));
1351 entry.push_back(Pair("confirmations", 0));
1356 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction");
1363 Value backupwallet(const Array& params, bool fHelp)
1365 if (fHelp || params.size() != 1)
1366 throw runtime_error(
1367 "backupwallet <destination>\n"
1368 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1370 string strDest = params[0].get_str();
1371 if (!BackupWallet(*pwalletMain, strDest))
1372 throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!");
1378 Value keypoolrefill(const Array& params, bool fHelp)
1380 if (fHelp || params.size() > 1)
1381 throw runtime_error(
1382 "keypoolrefill [new-size]\n"
1383 "Fills the keypool."
1384 + HelpRequiringPassphrase());
1386 unsigned int nSize = max(GetArg("-keypool", 100), 0LL);
1387 if (params.size() > 0) {
1388 if (params[0].get_int() < 0)
1389 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size");
1390 nSize = (unsigned int) params[0].get_int();
1393 EnsureWalletIsUnlocked();
1395 pwalletMain->TopUpKeyPool(nSize);
1397 if (pwalletMain->GetKeyPoolSize() < nSize)
1398 throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool.");
1404 void ThreadTopUpKeyPool(void* parg)
1406 // Make this thread recognisable as the key-topping-up thread
1407 RenameThread("bitcoin-key-top");
1409 pwalletMain->TopUpKeyPool();
1412 void ThreadCleanWalletPassphrase(void* parg)
1414 // Make this thread recognisable as the wallet relocking thread
1415 RenameThread("bitcoin-lock-wa");
1417 int64 nMyWakeTime = GetTimeMillis() + *((int64*)parg) * 1000;
1419 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1421 if (nWalletUnlockTime == 0)
1423 nWalletUnlockTime = nMyWakeTime;
1427 if (nWalletUnlockTime==0)
1429 int64 nToSleep = nWalletUnlockTime - GetTimeMillis();
1433 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1435 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1439 if (nWalletUnlockTime)
1441 nWalletUnlockTime = 0;
1442 pwalletMain->Lock();
1447 if (nWalletUnlockTime < nMyWakeTime)
1448 nWalletUnlockTime = nMyWakeTime;
1451 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1453 delete (int64*)parg;
1456 Value walletpassphrase(const Array& params, bool fHelp)
1458 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 3))
1459 throw runtime_error(
1460 "walletpassphrase <passphrase> <timeout> [mintonly]\n"
1461 "Stores the wallet decryption key in memory for <timeout> seconds.\n"
1462 "mintonly is optional true/false allowing only block minting.");
1465 if (!pwalletMain->IsCrypted())
1466 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1468 if (!pwalletMain->IsLocked())
1469 throw JSONRPCError(RPC_WALLET_ALREADY_UNLOCKED, "Error: Wallet is already unlocked, use walletlock first if need to change unlock settings.");
1470 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1471 SecureString strWalletPass;
1472 strWalletPass.reserve(100);
1473 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1474 // Alternately, find a way to make params[0] mlock()'d to begin with.
1475 strWalletPass = params[0].get_str().c_str();
1477 if (strWalletPass.length() > 0)
1479 if (!pwalletMain->Unlock(strWalletPass))
1480 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
1483 throw runtime_error(
1484 "walletpassphrase <passphrase> <timeout>\n"
1485 "Stores the wallet decryption key in memory for <timeout> seconds.");
1487 NewThread(ThreadTopUpKeyPool, NULL);
1488 int64* pnSleepTime = new int64(params[1].get_int64());
1489 NewThread(ThreadCleanWalletPassphrase, pnSleepTime);
1491 // ppcoin: if user OS account compromised prevent trivial sendmoney commands
1492 if (params.size() > 2)
1493 fWalletUnlockMintOnly = params[2].get_bool();
1495 fWalletUnlockMintOnly = false;
1501 Value walletpassphrasechange(const Array& params, bool fHelp)
1503 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1504 throw runtime_error(
1505 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1506 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1509 if (!pwalletMain->IsCrypted())
1510 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1512 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1513 // Alternately, find a way to make params[0] mlock()'d to begin with.
1514 SecureString strOldWalletPass;
1515 strOldWalletPass.reserve(100);
1516 strOldWalletPass = params[0].get_str().c_str();
1518 SecureString strNewWalletPass;
1519 strNewWalletPass.reserve(100);
1520 strNewWalletPass = params[1].get_str().c_str();
1522 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1523 throw runtime_error(
1524 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1525 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1527 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1528 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
1534 Value walletlock(const Array& params, bool fHelp)
1536 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1537 throw runtime_error(
1539 "Removes the wallet encryption key from memory, locking the wallet.\n"
1540 "After calling this method, you will need to call walletpassphrase again\n"
1541 "before being able to call any methods which require the wallet to be unlocked.");
1544 if (!pwalletMain->IsCrypted())
1545 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletlock was called.");
1548 LOCK(cs_nWalletUnlockTime);
1549 pwalletMain->Lock();
1550 nWalletUnlockTime = 0;
1557 Value encryptwallet(const Array& params, bool fHelp)
1559 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1560 throw runtime_error(
1561 "encryptwallet <passphrase>\n"
1562 "Encrypts the wallet with <passphrase>.");
1565 if (pwalletMain->IsCrypted())
1566 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an encrypted wallet, but encryptwallet was called.");
1568 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1569 // Alternately, find a way to make params[0] mlock()'d to begin with.
1570 SecureString strWalletPass;
1571 strWalletPass.reserve(100);
1572 strWalletPass = params[0].get_str().c_str();
1574 if (strWalletPass.length() < 1)
1575 throw runtime_error(
1576 "encryptwallet <passphrase>\n"
1577 "Encrypts the wallet with <passphrase>.");
1579 if (!pwalletMain->EncryptWallet(strWalletPass))
1580 throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: Failed to encrypt the wallet.");
1582 // BDB seems to have a bad habit of writing old data into
1583 // slack space in .dat files; that is bad if the old data is
1584 // unencrypted private keys. So:
1586 return "wallet encrypted; NovaCoin server stopping, restart to run with encrypted wallet. The keypool has been flushed, you need to make a new backup.";
1589 class DescribeAddressVisitor : public boost::static_visitor<Object>
1592 Object operator()(const CNoDestination &dest) const { return Object(); }
1594 Object operator()(const CKeyID &keyID) const {
1597 pwalletMain->GetPubKey(keyID, vchPubKey);
1598 obj.push_back(Pair("isscript", false));
1599 obj.push_back(Pair("pubkey", HexStr(vchPubKey.Raw())));
1600 obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed()));
1604 Object operator()(const CScriptID &scriptID) const {
1606 obj.push_back(Pair("isscript", true));
1608 pwalletMain->GetCScript(scriptID, subscript);
1609 std::vector<CTxDestination> addresses;
1610 txnouttype whichType;
1612 ExtractDestinations(subscript, whichType, addresses, nRequired);
1613 obj.push_back(Pair("script", GetTxnOutputType(whichType)));
1614 obj.push_back(Pair("hex", HexStr(subscript.begin(), subscript.end())));
1616 BOOST_FOREACH(const CTxDestination& addr, addresses)
1617 a.push_back(CBitcoinAddress(addr).ToString());
1618 obj.push_back(Pair("addresses", a));
1619 if (whichType == TX_MULTISIG)
1620 obj.push_back(Pair("sigsrequired", nRequired));
1625 Value validateaddress(const Array& params, bool fHelp)
1627 if (fHelp || params.size() != 1)
1628 throw runtime_error(
1629 "validateaddress <novacoinaddress>\n"
1630 "Return information about <novacoinaddress>.");
1632 CBitcoinAddress address(params[0].get_str());
1633 bool isValid = address.IsValid();
1636 ret.push_back(Pair("isvalid", isValid));
1639 CTxDestination dest = address.Get();
1640 string currentAddress = address.ToString();
1641 ret.push_back(Pair("address", currentAddress));
1642 bool fMine = IsMine(*pwalletMain, dest);
1643 ret.push_back(Pair("ismine", fMine));
1645 Object detail = boost::apply_visitor(DescribeAddressVisitor(), dest);
1646 ret.insert(ret.end(), detail.begin(), detail.end());
1648 if (pwalletMain->mapAddressBook.count(dest))
1649 ret.push_back(Pair("account", pwalletMain->mapAddressBook[dest]));
1654 Value validatepubkey(const Array& params, bool fHelp)
1656 if (fHelp || !params.size() || params.size() > 2)
1657 throw runtime_error(
1658 "validatepubkey <novacoinpubkey>\n"
1659 "Return information about <novacoinpubkey>.");
1661 std::vector<unsigned char> vchPubKey = ParseHex(params[0].get_str());
1662 CPubKey pubKey(vchPubKey);
1664 bool isValid = pubKey.IsValid();
1665 bool isCompressed = pubKey.IsCompressed();
1666 CKeyID keyID = pubKey.GetID();
1668 CBitcoinAddress address;
1672 ret.push_back(Pair("isvalid", isValid));
1675 CTxDestination dest = address.Get();
1676 string currentAddress = address.ToString();
1677 ret.push_back(Pair("address", currentAddress));
1678 bool fMine = IsMine(*pwalletMain, dest);
1679 ret.push_back(Pair("ismine", fMine));
1680 ret.push_back(Pair("iscompressed", isCompressed));
1682 Object detail = boost::apply_visitor(DescribeAddressVisitor(), dest);
1683 ret.insert(ret.end(), detail.begin(), detail.end());
1685 if (pwalletMain->mapAddressBook.count(dest))
1686 ret.push_back(Pair("account", pwalletMain->mapAddressBook[dest]));
1691 // reserve balance from being staked for network protection
1692 Value reservebalance(const Array& params, bool fHelp)
1694 if (fHelp || params.size() > 2)
1695 throw runtime_error(
1696 "reservebalance [<reserve> [amount]]\n"
1697 "<reserve> is true or false to turn balance reserve on or off.\n"
1698 "<amount> is a real and rounded to cent.\n"
1699 "Set reserve amount not participating in network protection.\n"
1700 "If no parameters provided current setting is printed.\n");
1702 if (params.size() > 0)
1704 bool fReserve = params[0].get_bool();
1707 if (params.size() == 1)
1708 throw runtime_error("must provide amount to reserve balance.\n");
1709 int64 nAmount = AmountFromValue(params[1]);
1710 nAmount = (nAmount / CENT) * CENT; // round to cent
1712 throw runtime_error("amount cannot be negative.\n");
1713 mapArgs["-reservebalance"] = FormatMoney(nAmount).c_str();
1717 if (params.size() > 1)
1718 throw runtime_error("cannot specify amount to turn off reserve.\n");
1719 mapArgs["-reservebalance"] = "0";
1724 int64 nReserveBalance = 0;
1725 if (mapArgs.count("-reservebalance") && !ParseMoney(mapArgs["-reservebalance"], nReserveBalance))
1726 throw runtime_error("invalid reserve balance amount\n");
1727 result.push_back(Pair("reserve", (nReserveBalance > 0)));
1728 result.push_back(Pair("amount", ValueFromAmount(nReserveBalance)));
1733 // check wallet integrity
1734 Value checkwallet(const Array& params, bool fHelp)
1736 if (fHelp || params.size() > 0)
1737 throw runtime_error(
1739 "Check wallet for integrity.\n");
1742 int64 nBalanceInQuestion;
1743 pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion, true);
1745 if (nMismatchSpent == 0)
1746 result.push_back(Pair("wallet check passed", true));
1749 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
1750 result.push_back(Pair("amount in question", ValueFromAmount(nBalanceInQuestion)));
1757 Value repairwallet(const Array& params, bool fHelp)
1759 if (fHelp || params.size() > 0)
1760 throw runtime_error(
1762 "Repair wallet if checkwallet reports any problem.\n");
1765 int64 nBalanceInQuestion;
1766 pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion);
1768 if (nMismatchSpent == 0)
1769 result.push_back(Pair("wallet check passed", true));
1772 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
1773 result.push_back(Pair("amount affected by repair", ValueFromAmount(nBalanceInQuestion)));
1778 // resend unconfirmed wallet transactions
1779 Value resendtx(const Array& params, bool fHelp)
1781 if (fHelp || params.size() > 1)
1782 throw runtime_error(
1784 "Re-send unconfirmed transactions.\n"
1787 ResendWalletTransactions();
1792 // make a public-private key pair
1793 Value makekeypair(const Array& params, bool fHelp)
1795 if (fHelp || params.size() > 1)
1796 throw runtime_error(
1797 "makekeypair [prefix]\n"
1798 "Make a public/private key pair.\n"
1799 "[prefix] is optional preferred prefix for the public key.\n");
1801 string strPrefix = "";
1802 if (params.size() > 0)
1803 strPrefix = params[0].get_str();
1806 key.MakeNewKey(false);
1808 CPrivKey vchPrivKey = key.GetPrivKey();
1810 result.push_back(Pair("PrivateKey", HexStr<CPrivKey::iterator>(vchPrivKey.begin(), vchPrivKey.end())));
1811 result.push_back(Pair("PublicKey", HexStr(key.GetPubKey().Raw())));