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 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", FormatFullVersion()));
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("newmint", ValueFromAmount(pwalletMain->GetNewMint())));
78 obj.push_back(Pair("stake", ValueFromAmount(pwalletMain->GetStake())));
79 obj.push_back(Pair("blocks", (int)nBestHeight));
80 obj.push_back(Pair("moneysupply", ValueFromAmount(pindexBest->nMoneySupply)));
81 obj.push_back(Pair("connections", (int)vNodes.size()));
82 obj.push_back(Pair("proxy", (proxy.first.IsValid() ? proxy.first.ToStringIPPort() : string())));
83 obj.push_back(Pair("ip", addrSeenByPeer.ToStringIP()));
84 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
85 obj.push_back(Pair("testnet", fTestNet));
86 obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
87 obj.push_back(Pair("keypoolsize", pwalletMain->GetKeyPoolSize()));
88 obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee)));
89 if (pwalletMain->IsCrypted())
90 obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime / 1000));
91 obj.push_back(Pair("errors", GetWarnings("statusbar")));
96 Value getnewpubkey(const Array& params, bool fHelp)
98 if (fHelp || params.size() > 1)
100 "getnewpubkey [account]\n"
101 "Returns new public key for coinbase generation.");
103 // Parse the account first so we don't generate a key if there's an error
105 if (params.size() > 0)
106 strAccount = AccountFromValue(params[0]);
108 if (!pwalletMain->IsLocked())
109 pwalletMain->TopUpKeyPool();
111 // Generate a new key that is added to wallet
113 if (!pwalletMain->GetKeyFromPool(newKey, false))
114 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
115 CKeyID keyID = newKey.GetID();
117 pwalletMain->SetAddressBookName(keyID, strAccount);
118 vector<unsigned char> vchPubKey = newKey.Raw();
120 return HexStr(vchPubKey.begin(), vchPubKey.end());
124 Value getnewaddress(const Array& params, bool fHelp)
126 if (fHelp || params.size() > 1)
128 "getnewaddress [account]\n"
129 "Returns a new NovaCoin address for receiving payments. "
130 "If [account] is specified (recommended), it is added to the address book "
131 "so payments received with the address will be credited to [account].");
133 // Parse the account first so we don't generate a key if there's an error
135 if (params.size() > 0)
136 strAccount = AccountFromValue(params[0]);
138 if (!pwalletMain->IsLocked())
139 pwalletMain->TopUpKeyPool();
141 // Generate a new key that is added to wallet
143 if (!pwalletMain->GetKeyFromPool(newKey, false))
144 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
145 CKeyID keyID = newKey.GetID();
147 pwalletMain->SetAddressBookName(keyID, strAccount);
149 return CBitcoinAddress(keyID).ToString();
153 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
155 CWalletDB walletdb(pwalletMain->strWalletFile);
158 walletdb.ReadAccount(strAccount, account);
160 bool bKeyUsed = false;
162 // Check if the current key has been used
163 if (account.vchPubKey.IsValid())
165 CScript scriptPubKey;
166 scriptPubKey.SetDestination(account.vchPubKey.GetID());
167 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
168 it != pwalletMain->mapWallet.end() && account.vchPubKey.IsValid();
171 const CWalletTx& wtx = (*it).second;
172 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
173 if (txout.scriptPubKey == scriptPubKey)
178 // Generate a new key
179 if (!account.vchPubKey.IsValid() || bForceNew || bKeyUsed)
181 if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false))
182 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
184 pwalletMain->SetAddressBookName(account.vchPubKey.GetID(), strAccount);
185 walletdb.WriteAccount(strAccount, account);
188 return CBitcoinAddress(account.vchPubKey.GetID());
191 Value getaccountaddress(const Array& params, bool fHelp)
193 if (fHelp || params.size() != 1)
195 "getaccountaddress <account>\n"
196 "Returns the current NovaCoin address for receiving payments to this account.");
198 // Parse the account first so we don't generate a key if there's an error
199 string strAccount = AccountFromValue(params[0]);
203 ret = GetAccountAddress(strAccount).ToString();
210 Value setaccount(const Array& params, bool fHelp)
212 if (fHelp || params.size() < 1 || params.size() > 2)
214 "setaccount <novacoinaddress> <account>\n"
215 "Sets the account associated with the given address.");
217 CBitcoinAddress address(params[0].get_str());
218 if (!address.IsValid())
219 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
223 if (params.size() > 1)
224 strAccount = AccountFromValue(params[1]);
226 // Detect when changing the account of an address that is the 'unused current key' of another account:
227 if (pwalletMain->mapAddressBook.count(address.Get()))
229 string strOldAccount = pwalletMain->mapAddressBook[address.Get()];
230 if (address == GetAccountAddress(strOldAccount))
231 GetAccountAddress(strOldAccount, true);
234 pwalletMain->SetAddressBookName(address.Get(), strAccount);
240 Value getaccount(const Array& params, bool fHelp)
242 if (fHelp || params.size() != 1)
244 "getaccount <novacoinaddress>\n"
245 "Returns the account associated with the given address.");
247 CBitcoinAddress address(params[0].get_str());
248 if (!address.IsValid())
249 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
252 map<CTxDestination, string>::iterator mi = pwalletMain->mapAddressBook.find(address.Get());
253 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
254 strAccount = (*mi).second;
259 Value getaddressesbyaccount(const Array& params, bool fHelp)
261 if (fHelp || params.size() != 1)
263 "getaddressesbyaccount <account>\n"
264 "Returns the list of addresses for the given account.");
266 string strAccount = AccountFromValue(params[0]);
268 // Find all addresses that have the given account
270 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
272 const CBitcoinAddress& address = item.first;
273 const string& strName = item.second;
274 if (strName == strAccount)
275 ret.push_back(address.ToString());
280 Value sendtoaddress(const Array& params, bool fHelp)
282 if (fHelp || params.size() < 2 || params.size() > 4)
284 "sendtoaddress <novacoinaddress> <amount> [comment] [comment-to]\n"
285 "<amount> is a real and is rounded to the nearest 0.000001"
286 + HelpRequiringPassphrase());
288 CBitcoinAddress address(params[0].get_str());
289 if (!address.IsValid())
290 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
293 int64 nAmount = AmountFromValue(params[1]);
295 if (nAmount < MIN_TXOUT_AMOUNT)
296 throw JSONRPCError(-101, "Send amount too small");
300 if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
301 wtx.mapValue["comment"] = params[2].get_str();
302 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
303 wtx.mapValue["to"] = params[3].get_str();
305 if (pwalletMain->IsLocked())
306 throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
308 string strError = pwalletMain->SendMoneyToDestination(address.Get(), nAmount, wtx);
310 throw JSONRPCError(RPC_WALLET_ERROR, strError);
312 return wtx.GetHash().GetHex();
315 Value listaddressgroupings(const Array& params, bool fHelp)
319 "listaddressgroupings\n"
320 "Lists groups of addresses which have had their common ownership\n"
321 "made public by common use as inputs or as the resulting change\n"
322 "in past transactions");
325 map<CTxDestination, int64> balances = pwalletMain->GetAddressBalances();
326 BOOST_FOREACH(set<CTxDestination> grouping, pwalletMain->GetAddressGroupings())
329 BOOST_FOREACH(CTxDestination address, grouping)
332 addressInfo.push_back(CBitcoinAddress(address).ToString());
333 addressInfo.push_back(ValueFromAmount(balances[address]));
335 LOCK(pwalletMain->cs_wallet);
336 if (pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get()) != pwalletMain->mapAddressBook.end())
337 addressInfo.push_back(pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get())->second);
339 jsonGrouping.push_back(addressInfo);
341 jsonGroupings.push_back(jsonGrouping);
343 return jsonGroupings;
346 Value signmessage(const Array& params, bool fHelp)
348 if (fHelp || params.size() != 2)
350 "signmessage <novacoinaddress> <message>\n"
351 "Sign a message with the private key of an address");
353 EnsureWalletIsUnlocked();
355 string strAddress = params[0].get_str();
356 string strMessage = params[1].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");
367 if (!pwalletMain->GetKey(keyID, key))
368 throw JSONRPCError(RPC_WALLET_ERROR, "Private key not available");
370 CDataStream ss(SER_GETHASH, 0);
371 ss << strMessageMagic;
374 vector<unsigned char> vchSig;
375 if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
376 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed");
378 return EncodeBase64(&vchSig[0], vchSig.size());
381 Value verifymessage(const Array& params, bool fHelp)
383 if (fHelp || params.size() != 3)
385 "verifymessage <novacoinaddress> <signature> <message>\n"
386 "Verify a signed message");
388 string strAddress = params[0].get_str();
389 string strSign = params[1].get_str();
390 string strMessage = params[2].get_str();
392 CBitcoinAddress addr(strAddress);
394 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
397 if (!addr.GetKeyID(keyID))
398 throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
400 bool fInvalid = false;
401 vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
404 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Malformed base64 encoding");
406 CDataStream ss(SER_GETHASH, 0);
407 ss << strMessageMagic;
411 if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
414 return (key.GetPubKey().GetID() == keyID);
418 Value getreceivedbyaddress(const Array& params, bool fHelp)
420 if (fHelp || params.size() < 1 || params.size() > 2)
422 "getreceivedbyaddress <novacoinaddress> [minconf=1]\n"
423 "Returns the total amount received by <novacoinaddress> in transactions with at least [minconf] confirmations.");
426 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
427 CScript scriptPubKey;
428 if (!address.IsValid())
429 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
430 scriptPubKey.SetDestination(address.Get());
431 if (!IsMine(*pwalletMain,scriptPubKey))
434 // Minimum confirmations
436 if (params.size() > 1)
437 nMinDepth = params[1].get_int();
441 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
443 const CWalletTx& wtx = (*it).second;
444 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
447 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
448 if (txout.scriptPubKey == scriptPubKey)
449 if (wtx.GetDepthInMainChain() >= nMinDepth)
450 nAmount += txout.nValue;
453 return ValueFromAmount(nAmount);
457 void GetAccountAddresses(string strAccount, set<CTxDestination>& setAddress)
459 BOOST_FOREACH(const PAIRTYPE(CTxDestination, string)& item, pwalletMain->mapAddressBook)
461 const CTxDestination& address = item.first;
462 const string& strName = item.second;
463 if (strName == strAccount)
464 setAddress.insert(address);
468 Value getreceivedbyaccount(const Array& params, bool fHelp)
470 if (fHelp || params.size() < 1 || params.size() > 2)
472 "getreceivedbyaccount <account> [minconf=1]\n"
473 "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
475 // Minimum confirmations
477 if (params.size() > 1)
478 nMinDepth = params[1].get_int();
480 // Get the set of pub keys assigned to account
481 string strAccount = AccountFromValue(params[0]);
482 set<CTxDestination> setAddress;
483 GetAccountAddresses(strAccount, setAddress);
487 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
489 const CWalletTx& wtx = (*it).second;
490 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
493 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
495 CTxDestination address;
496 if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*pwalletMain, address) && setAddress.count(address))
497 if (wtx.GetDepthInMainChain() >= nMinDepth)
498 nAmount += txout.nValue;
502 return (double)nAmount / (double)COIN;
506 int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
510 // Tally wallet transactions
511 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
513 const CWalletTx& wtx = (*it).second;
517 int64 nGenerated, nReceived, nSent, nFee;
518 wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee);
520 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
521 nBalance += nReceived;
522 nBalance += nGenerated - nSent - nFee;
525 // Tally internal accounting entries
526 nBalance += walletdb.GetAccountCreditDebit(strAccount);
531 int64 GetAccountBalance(const string& strAccount, int nMinDepth)
533 CWalletDB walletdb(pwalletMain->strWalletFile);
534 return GetAccountBalance(walletdb, strAccount, nMinDepth);
538 Value getbalance(const Array& params, bool fHelp)
540 if (fHelp || params.size() > 2)
542 "getbalance [account] [minconf=1]\n"
543 "If [account] is not specified, returns the server's total available balance.\n"
544 "If [account] is specified, returns the balance in the account.");
546 if (params.size() == 0)
547 return ValueFromAmount(pwalletMain->GetBalance());
550 if (params.size() > 1)
551 nMinDepth = params[1].get_int();
553 if (params[0].get_str() == "*") {
554 // Calculate total balance a different way from GetBalance()
555 // (GetBalance() sums up all unspent TxOuts)
556 // getbalance and getbalance '*' should always return the same number.
558 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
560 const CWalletTx& wtx = (*it).second;
564 int64 allGeneratedImmature, allGeneratedMature, allFee;
565 allGeneratedImmature = allGeneratedMature = allFee = 0;
567 string strSentAccount;
568 list<pair<CTxDestination, int64> > listReceived;
569 list<pair<CTxDestination, int64> > listSent;
570 wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
571 if (wtx.GetDepthInMainChain() >= nMinDepth)
573 BOOST_FOREACH(const PAIRTYPE(CTxDestination,int64)& r, listReceived)
574 nBalance += r.second;
576 BOOST_FOREACH(const PAIRTYPE(CTxDestination,int64)& r, listSent)
577 nBalance -= r.second;
579 nBalance += allGeneratedMature;
581 return ValueFromAmount(nBalance);
584 string strAccount = AccountFromValue(params[0]);
586 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
588 return ValueFromAmount(nBalance);
592 Value movecmd(const Array& params, bool fHelp)
594 if (fHelp || params.size() < 3 || params.size() > 5)
596 "move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
597 "Move from one account in your wallet to another.");
599 string strFrom = AccountFromValue(params[0]);
600 string strTo = AccountFromValue(params[1]);
601 int64 nAmount = AmountFromValue(params[2]);
603 if (nAmount < MIN_TXOUT_AMOUNT)
604 throw JSONRPCError(-101, "Send amount too small");
606 if (params.size() > 3)
607 // unused parameter, used to be nMinDepth, keep type-checking it though
608 (void)params[3].get_int();
610 if (params.size() > 4)
611 strComment = params[4].get_str();
613 CWalletDB walletdb(pwalletMain->strWalletFile);
614 if (!walletdb.TxnBegin())
615 throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
617 int64 nNow = GetAdjustedTime();
620 CAccountingEntry debit;
621 debit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
622 debit.strAccount = strFrom;
623 debit.nCreditDebit = -nAmount;
625 debit.strOtherAccount = strTo;
626 debit.strComment = strComment;
627 walletdb.WriteAccountingEntry(debit);
630 CAccountingEntry credit;
631 credit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
632 credit.strAccount = strTo;
633 credit.nCreditDebit = nAmount;
635 credit.strOtherAccount = strFrom;
636 credit.strComment = strComment;
637 walletdb.WriteAccountingEntry(credit);
639 if (!walletdb.TxnCommit())
640 throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
646 Value sendfrom(const Array& params, bool fHelp)
648 if (fHelp || params.size() < 3 || params.size() > 6)
650 "sendfrom <fromaccount> <tonovacoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
651 "<amount> is a real and is rounded to the nearest 0.000001"
652 + HelpRequiringPassphrase());
654 string strAccount = AccountFromValue(params[0]);
655 CBitcoinAddress address(params[1].get_str());
656 if (!address.IsValid())
657 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
658 int64 nAmount = AmountFromValue(params[2]);
660 if (nAmount < MIN_TXOUT_AMOUNT)
661 throw JSONRPCError(-101, "Send amount too small");
664 if (params.size() > 3)
665 nMinDepth = params[3].get_int();
668 wtx.strFromAccount = strAccount;
669 if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
670 wtx.mapValue["comment"] = params[4].get_str();
671 if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
672 wtx.mapValue["to"] = params[5].get_str();
674 EnsureWalletIsUnlocked();
677 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
678 if (nAmount > nBalance)
679 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
682 string strError = pwalletMain->SendMoneyToDestination(address.Get(), nAmount, wtx);
684 throw JSONRPCError(RPC_WALLET_ERROR, strError);
686 return wtx.GetHash().GetHex();
690 Value sendmany(const Array& params, bool fHelp)
692 if (fHelp || params.size() < 2 || params.size() > 4)
694 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
695 "amounts are double-precision floating point numbers"
696 + HelpRequiringPassphrase());
698 string strAccount = AccountFromValue(params[0]);
699 Object sendTo = params[1].get_obj();
701 if (params.size() > 2)
702 nMinDepth = params[2].get_int();
705 wtx.strFromAccount = strAccount;
706 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
707 wtx.mapValue["comment"] = params[3].get_str();
709 set<CBitcoinAddress> setAddress;
710 vector<pair<CScript, int64> > vecSend;
712 int64 totalAmount = 0;
713 BOOST_FOREACH(const Pair& s, sendTo)
715 CBitcoinAddress address(s.name_);
716 if (!address.IsValid())
717 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid NovaCoin address: ")+s.name_);
719 if (setAddress.count(address))
720 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+s.name_);
721 setAddress.insert(address);
723 CScript scriptPubKey;
724 scriptPubKey.SetDestination(address.Get());
725 int64 nAmount = AmountFromValue(s.value_);
727 if (nAmount < MIN_TXOUT_AMOUNT)
728 throw JSONRPCError(-101, "Send amount too small");
730 totalAmount += nAmount;
732 vecSend.push_back(make_pair(scriptPubKey, nAmount));
735 EnsureWalletIsUnlocked();
738 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
739 if (totalAmount > nBalance)
740 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
743 CReserveKey keyChange(pwalletMain);
744 int64 nFeeRequired = 0;
745 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
748 if (totalAmount + nFeeRequired > pwalletMain->GetBalance())
749 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds");
750 throw JSONRPCError(RPC_WALLET_ERROR, "Transaction creation failed");
752 if (!pwalletMain->CommitTransaction(wtx, keyChange))
753 throw JSONRPCError(RPC_WALLET_ERROR, "Transaction commit failed");
755 return wtx.GetHash().GetHex();
758 Value addmultisigaddress(const Array& params, bool fHelp)
760 if (fHelp || params.size() < 2 || params.size() > 3)
762 string msg = "addmultisigaddress <nrequired> <'[\"key\",\"key\"]'> [account]\n"
763 "Add a nrequired-to-sign multisignature address to the wallet\"\n"
764 "each key is a NovaCoin address or hex-encoded public key\n"
765 "If [account] is specified, assign address to [account].";
766 throw runtime_error(msg);
769 int nRequired = params[0].get_int();
770 const Array& keys = params[1].get_array();
772 if (params.size() > 2)
773 strAccount = AccountFromValue(params[2]);
775 // Gather public keys
777 throw runtime_error("a multisignature address must require at least one key to redeem");
778 if ((int)keys.size() < nRequired)
780 strprintf("not enough keys supplied "
781 "(got %"PRIszu" keys, but need at least %d to redeem)", keys.size(), nRequired));
782 std::vector<CKey> pubkeys;
783 pubkeys.resize(keys.size());
784 for (unsigned int i = 0; i < keys.size(); i++)
786 const std::string& ks = keys[i].get_str();
788 // Case 1: Bitcoin address and we have full public key:
789 CBitcoinAddress address(ks);
790 if (address.IsValid())
793 if (!address.GetKeyID(keyID))
795 strprintf("%s does not refer to a key",ks.c_str()));
797 if (!pwalletMain->GetPubKey(keyID, vchPubKey))
799 strprintf("no full public key for address %s",ks.c_str()));
800 if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey))
801 throw runtime_error(" Invalid public key: "+ks);
804 // Case 2: hex public key
807 CPubKey vchPubKey(ParseHex(ks));
808 if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey))
809 throw runtime_error(" Invalid public key: "+ks);
813 throw runtime_error(" Invalid public key: "+ks);
817 // Construct using pay-to-script-hash:
819 inner.SetMultisig(nRequired, pubkeys);
820 CScriptID innerID = inner.GetID();
821 pwalletMain->AddCScript(inner);
823 pwalletMain->SetAddressBookName(innerID, strAccount);
824 return CBitcoinAddress(innerID).ToString();
835 nConf = std::numeric_limits<int>::max();
839 Value ListReceived(const Array& params, bool fByAccounts)
841 // Minimum confirmations
843 if (params.size() > 0)
844 nMinDepth = params[0].get_int();
846 // Whether to include empty accounts
847 bool fIncludeEmpty = false;
848 if (params.size() > 1)
849 fIncludeEmpty = params[1].get_bool();
852 map<CBitcoinAddress, tallyitem> mapTally;
853 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
855 const CWalletTx& wtx = (*it).second;
857 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
860 int nDepth = wtx.GetDepthInMainChain();
861 if (nDepth < nMinDepth)
864 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
866 CTxDestination address;
867 if (!ExtractDestination(txout.scriptPubKey, address) || !IsMine(*pwalletMain, address))
870 tallyitem& item = mapTally[address];
871 item.nAmount += txout.nValue;
872 item.nConf = min(item.nConf, nDepth);
878 map<string, tallyitem> mapAccountTally;
879 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
881 const CBitcoinAddress& address = item.first;
882 const string& strAccount = item.second;
883 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
884 if (it == mapTally.end() && !fIncludeEmpty)
888 int nConf = std::numeric_limits<int>::max();
889 if (it != mapTally.end())
891 nAmount = (*it).second.nAmount;
892 nConf = (*it).second.nConf;
897 tallyitem& item = mapAccountTally[strAccount];
898 item.nAmount += nAmount;
899 item.nConf = min(item.nConf, nConf);
904 obj.push_back(Pair("address", address.ToString()));
905 obj.push_back(Pair("account", strAccount));
906 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
907 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
914 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
916 int64 nAmount = (*it).second.nAmount;
917 int nConf = (*it).second.nConf;
919 obj.push_back(Pair("account", (*it).first));
920 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
921 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
929 Value listreceivedbyaddress(const Array& params, bool fHelp)
931 if (fHelp || params.size() > 2)
933 "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
934 "[minconf] is the minimum number of confirmations before payments are included.\n"
935 "[includeempty] whether to include addresses that haven't received any payments.\n"
936 "Returns an array of objects containing:\n"
937 " \"address\" : receiving address\n"
938 " \"account\" : the account of the receiving address\n"
939 " \"amount\" : total amount received by the address\n"
940 " \"confirmations\" : number of confirmations of the most recent transaction included");
942 return ListReceived(params, false);
945 Value listreceivedbyaccount(const Array& params, bool fHelp)
947 if (fHelp || params.size() > 2)
949 "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
950 "[minconf] is the minimum number of confirmations before payments are included.\n"
951 "[includeempty] whether to include accounts that haven't received any payments.\n"
952 "Returns an array of objects containing:\n"
953 " \"account\" : the account of the receiving addresses\n"
954 " \"amount\" : total amount received by addresses with this account\n"
955 " \"confirmations\" : number of confirmations of the most recent transaction included");
957 return ListReceived(params, true);
960 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
962 int64 nGeneratedImmature, nGeneratedMature, nFee;
963 string strSentAccount;
964 list<pair<CTxDestination, int64> > listReceived;
965 list<pair<CTxDestination, int64> > listSent;
967 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
969 bool fAllAccounts = (strAccount == string("*"));
971 // Generated blocks assigned to account ""
972 if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
975 entry.push_back(Pair("account", string("")));
976 if (nGeneratedImmature)
978 entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
979 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
983 entry.push_back(Pair("category", "generate"));
984 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
987 WalletTxToJSON(wtx, entry);
988 ret.push_back(entry);
992 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
994 BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& s, listSent)
997 entry.push_back(Pair("account", strSentAccount));
998 entry.push_back(Pair("address", CBitcoinAddress(s.first).ToString()));
999 entry.push_back(Pair("category", "send"));
1000 entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1001 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1003 WalletTxToJSON(wtx, entry);
1004 ret.push_back(entry);
1009 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1011 BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& r, listReceived)
1014 if (pwalletMain->mapAddressBook.count(r.first))
1015 account = pwalletMain->mapAddressBook[r.first];
1016 if (fAllAccounts || (account == strAccount))
1019 entry.push_back(Pair("account", account));
1020 entry.push_back(Pair("address", CBitcoinAddress(r.first).ToString()));
1021 if (wtx.IsCoinBase())
1023 if (wtx.GetDepthInMainChain() < 1)
1024 entry.push_back(Pair("category", "orphan"));
1025 else if (wtx.GetBlocksToMaturity() > 0)
1026 entry.push_back(Pair("category", "immature"));
1028 entry.push_back(Pair("category", "generate"));
1031 entry.push_back(Pair("category", "receive"));
1032 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1034 WalletTxToJSON(wtx, entry);
1035 ret.push_back(entry);
1041 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1043 bool fAllAccounts = (strAccount == string("*"));
1045 if (fAllAccounts || acentry.strAccount == strAccount)
1048 entry.push_back(Pair("account", acentry.strAccount));
1049 entry.push_back(Pair("category", "move"));
1050 entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
1051 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1052 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1053 entry.push_back(Pair("comment", acentry.strComment));
1054 ret.push_back(entry);
1058 Value listtransactions(const Array& params, bool fHelp)
1060 if (fHelp || params.size() > 3)
1061 throw runtime_error(
1062 "listtransactions [account] [count=10] [from=0]\n"
1063 "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1065 string strAccount = "*";
1066 if (params.size() > 0)
1067 strAccount = params[0].get_str();
1069 if (params.size() > 1)
1070 nCount = params[1].get_int();
1072 if (params.size() > 2)
1073 nFrom = params[2].get_int();
1076 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count");
1078 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative from");
1082 std::list<CAccountingEntry> acentries;
1083 CWallet::TxItems txOrdered = pwalletMain->OrderedTxItems(acentries, strAccount);
1085 // iterate backwards until we have nCount items to return:
1086 for (CWallet::TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
1088 CWalletTx *const pwtx = (*it).second.first;
1090 ListTransactions(*pwtx, strAccount, 0, true, ret);
1091 CAccountingEntry *const pacentry = (*it).second.second;
1093 AcentryToJSON(*pacentry, strAccount, ret);
1095 if ((int)ret.size() >= (nCount+nFrom)) break;
1097 // ret is newest to oldest
1099 if (nFrom > (int)ret.size())
1101 if ((nFrom + nCount) > (int)ret.size())
1102 nCount = ret.size() - nFrom;
1103 Array::iterator first = ret.begin();
1104 std::advance(first, nFrom);
1105 Array::iterator last = ret.begin();
1106 std::advance(last, nFrom+nCount);
1108 if (last != ret.end()) ret.erase(last, ret.end());
1109 if (first != ret.begin()) ret.erase(ret.begin(), first);
1111 std::reverse(ret.begin(), ret.end()); // Return oldest to newest
1116 Value listaccounts(const Array& params, bool fHelp)
1118 if (fHelp || params.size() > 1)
1119 throw runtime_error(
1120 "listaccounts [minconf=1]\n"
1121 "Returns Object that has account names as keys, account balances as values.");
1124 if (params.size() > 0)
1125 nMinDepth = params[0].get_int();
1127 map<string, int64> mapAccountBalances;
1128 BOOST_FOREACH(const PAIRTYPE(CTxDestination, string)& entry, pwalletMain->mapAddressBook) {
1129 if (IsMine(*pwalletMain, entry.first)) // This address belongs to me
1130 mapAccountBalances[entry.second] = 0;
1133 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1135 const CWalletTx& wtx = (*it).second;
1136 int64 nGeneratedImmature, nGeneratedMature, nFee;
1137 string strSentAccount;
1138 list<pair<CTxDestination, int64> > listReceived;
1139 list<pair<CTxDestination, int64> > listSent;
1140 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1141 mapAccountBalances[strSentAccount] -= nFee;
1142 BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& s, listSent)
1143 mapAccountBalances[strSentAccount] -= s.second;
1144 if (wtx.GetDepthInMainChain() >= nMinDepth)
1146 mapAccountBalances[""] += nGeneratedMature;
1147 BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& r, listReceived)
1148 if (pwalletMain->mapAddressBook.count(r.first))
1149 mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1151 mapAccountBalances[""] += r.second;
1155 list<CAccountingEntry> acentries;
1156 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1157 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1158 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1161 BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) {
1162 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1167 Value listsinceblock(const Array& params, bool fHelp)
1170 throw runtime_error(
1171 "listsinceblock [blockhash] [target-confirmations]\n"
1172 "Get all transactions in blocks since block [blockhash], or all transactions if omitted");
1174 CBlockIndex *pindex = NULL;
1175 int target_confirms = 1;
1177 if (params.size() > 0)
1179 uint256 blockId = 0;
1181 blockId.SetHex(params[0].get_str());
1182 pindex = CBlockLocator(blockId).GetBlockIndex();
1185 if (params.size() > 1)
1187 target_confirms = params[1].get_int();
1189 if (target_confirms < 1)
1190 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter");
1193 int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
1197 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1199 CWalletTx tx = (*it).second;
1201 if (depth == -1 || tx.GetDepthInMainChain() < depth)
1202 ListTransactions(tx, "*", 0, true, transactions);
1207 if (target_confirms == 1)
1209 lastblock = hashBestChain;
1213 int target_height = pindexBest->nHeight + 1 - target_confirms;
1216 for (block = pindexBest;
1217 block && block->nHeight > target_height;
1218 block = block->pprev) { }
1220 lastblock = block ? block->GetBlockHash() : 0;
1224 ret.push_back(Pair("transactions", transactions));
1225 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1230 Value gettransaction(const Array& params, bool fHelp)
1232 if (fHelp || params.size() != 1)
1233 throw runtime_error(
1234 "gettransaction <txid>\n"
1235 "Get detailed information about <txid>");
1238 hash.SetHex(params[0].get_str());
1242 if (pwalletMain->mapWallet.count(hash))
1244 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1246 TxToJSON(wtx, 0, entry);
1248 int64 nCredit = wtx.GetCredit();
1249 int64 nDebit = wtx.GetDebit();
1250 int64 nNet = nCredit - nDebit;
1251 int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
1253 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1255 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1257 WalletTxToJSON(wtx, entry);
1260 ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
1261 entry.push_back(Pair("details", details));
1266 uint256 hashBlock = 0;
1267 if (GetTransaction(hash, tx, hashBlock))
1269 entry.push_back(Pair("txid", hash.GetHex()));
1270 TxToJSON(tx, 0, entry);
1272 entry.push_back(Pair("confirmations", 0));
1275 entry.push_back(Pair("blockhash", hashBlock.GetHex()));
1276 map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
1277 if (mi != mapBlockIndex.end() && (*mi).second)
1279 CBlockIndex* pindex = (*mi).second;
1280 if (pindex->IsInMainChain())
1282 entry.push_back(Pair("confirmations", 1 + nBestHeight - pindex->nHeight));
1283 entry.push_back(Pair("txntime", (boost::int64_t)tx.nTime));
1284 entry.push_back(Pair("time", (boost::int64_t)pindex->nTime));
1287 entry.push_back(Pair("confirmations", 0));
1292 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction");
1299 Value backupwallet(const Array& params, bool fHelp)
1301 if (fHelp || params.size() != 1)
1302 throw runtime_error(
1303 "backupwallet <destination>\n"
1304 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1306 string strDest = params[0].get_str();
1307 if (!BackupWallet(*pwalletMain, strDest))
1308 throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!");
1314 Value keypoolrefill(const Array& params, bool fHelp)
1316 if (fHelp || params.size() > 0)
1317 throw runtime_error(
1319 "Fills the keypool."
1320 + HelpRequiringPassphrase());
1322 EnsureWalletIsUnlocked();
1324 pwalletMain->TopUpKeyPool();
1326 if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100))
1327 throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool.");
1333 void ThreadTopUpKeyPool(void* parg)
1335 // Make this thread recognisable as the key-topping-up thread
1336 RenameThread("bitcoin-key-top");
1338 pwalletMain->TopUpKeyPool();
1341 void ThreadCleanWalletPassphrase(void* parg)
1343 // Make this thread recognisable as the wallet relocking thread
1344 RenameThread("bitcoin-lock-wa");
1346 int64 nMyWakeTime = GetTimeMillis() + *((int64*)parg) * 1000;
1348 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1350 if (nWalletUnlockTime == 0)
1352 nWalletUnlockTime = nMyWakeTime;
1356 if (nWalletUnlockTime==0)
1358 int64 nToSleep = nWalletUnlockTime - GetTimeMillis();
1362 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1364 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1368 if (nWalletUnlockTime)
1370 nWalletUnlockTime = 0;
1371 pwalletMain->Lock();
1376 if (nWalletUnlockTime < nMyWakeTime)
1377 nWalletUnlockTime = nMyWakeTime;
1380 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1382 delete (int64*)parg;
1385 Value walletpassphrase(const Array& params, bool fHelp)
1387 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 3))
1388 throw runtime_error(
1389 "walletpassphrase <passphrase> <timeout> [mintonly]\n"
1390 "Stores the wallet decryption key in memory for <timeout> seconds.\n"
1391 "mintonly is optional true/false allowing only block minting.");
1394 if (!pwalletMain->IsCrypted())
1395 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1397 if (!pwalletMain->IsLocked())
1398 throw JSONRPCError(RPC_WALLET_ALREADY_UNLOCKED, "Error: Wallet is already unlocked, use walletlock first if need to change unlock settings.");
1399 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1400 SecureString strWalletPass;
1401 strWalletPass.reserve(100);
1402 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1403 // Alternately, find a way to make params[0] mlock()'d to begin with.
1404 strWalletPass = params[0].get_str().c_str();
1406 if (strWalletPass.length() > 0)
1408 if (!pwalletMain->Unlock(strWalletPass))
1409 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
1412 throw runtime_error(
1413 "walletpassphrase <passphrase> <timeout>\n"
1414 "Stores the wallet decryption key in memory for <timeout> seconds.");
1416 NewThread(ThreadTopUpKeyPool, NULL);
1417 int64* pnSleepTime = new int64(params[1].get_int64());
1418 NewThread(ThreadCleanWalletPassphrase, pnSleepTime);
1420 // ppcoin: if user OS account compromised prevent trivial sendmoney commands
1421 if (params.size() > 2)
1422 fWalletUnlockMintOnly = params[2].get_bool();
1424 fWalletUnlockMintOnly = false;
1430 Value walletpassphrasechange(const Array& params, bool fHelp)
1432 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1433 throw runtime_error(
1434 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1435 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1438 if (!pwalletMain->IsCrypted())
1439 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1441 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1442 // Alternately, find a way to make params[0] mlock()'d to begin with.
1443 SecureString strOldWalletPass;
1444 strOldWalletPass.reserve(100);
1445 strOldWalletPass = params[0].get_str().c_str();
1447 SecureString strNewWalletPass;
1448 strNewWalletPass.reserve(100);
1449 strNewWalletPass = params[1].get_str().c_str();
1451 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1452 throw runtime_error(
1453 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1454 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1456 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1457 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
1463 Value walletlock(const Array& params, bool fHelp)
1465 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1466 throw runtime_error(
1468 "Removes the wallet encryption key from memory, locking the wallet.\n"
1469 "After calling this method, you will need to call walletpassphrase again\n"
1470 "before being able to call any methods which require the wallet to be unlocked.");
1473 if (!pwalletMain->IsCrypted())
1474 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletlock was called.");
1477 LOCK(cs_nWalletUnlockTime);
1478 pwalletMain->Lock();
1479 nWalletUnlockTime = 0;
1486 Value encryptwallet(const Array& params, bool fHelp)
1488 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1489 throw runtime_error(
1490 "encryptwallet <passphrase>\n"
1491 "Encrypts the wallet with <passphrase>.");
1494 if (pwalletMain->IsCrypted())
1495 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an encrypted wallet, but encryptwallet was called.");
1497 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1498 // Alternately, find a way to make params[0] mlock()'d to begin with.
1499 SecureString strWalletPass;
1500 strWalletPass.reserve(100);
1501 strWalletPass = params[0].get_str().c_str();
1503 if (strWalletPass.length() < 1)
1504 throw runtime_error(
1505 "encryptwallet <passphrase>\n"
1506 "Encrypts the wallet with <passphrase>.");
1508 if (!pwalletMain->EncryptWallet(strWalletPass))
1509 throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: Failed to encrypt the wallet.");
1511 // BDB seems to have a bad habit of writing old data into
1512 // slack space in .dat files; that is bad if the old data is
1513 // unencrypted private keys. So:
1515 return "wallet encrypted; NovaCoin server stopping, restart to run with encrypted wallet. The keypool has been flushed, you need to make a new backup.";
1518 class DescribeAddressVisitor : public boost::static_visitor<Object>
1521 Object operator()(const CNoDestination &dest) const { return Object(); }
1523 Object operator()(const CKeyID &keyID) const {
1526 pwalletMain->GetPubKey(keyID, vchPubKey);
1527 obj.push_back(Pair("isscript", false));
1528 obj.push_back(Pair("pubkey", HexStr(vchPubKey.Raw())));
1529 obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed()));
1533 Object operator()(const CScriptID &scriptID) const {
1535 obj.push_back(Pair("isscript", true));
1537 pwalletMain->GetCScript(scriptID, subscript);
1538 std::vector<CTxDestination> addresses;
1539 txnouttype whichType;
1541 ExtractDestinations(subscript, whichType, addresses, nRequired);
1542 obj.push_back(Pair("script", GetTxnOutputType(whichType)));
1544 BOOST_FOREACH(const CTxDestination& addr, addresses)
1545 a.push_back(CBitcoinAddress(addr).ToString());
1546 obj.push_back(Pair("addresses", a));
1547 if (whichType == TX_MULTISIG)
1548 obj.push_back(Pair("sigsrequired", nRequired));
1553 Value validateaddress(const Array& params, bool fHelp)
1555 if (fHelp || params.size() != 1)
1556 throw runtime_error(
1557 "validateaddress <novacoinaddress>\n"
1558 "Return information about <novacoinaddress>.");
1560 CBitcoinAddress address(params[0].get_str());
1561 bool isValid = address.IsValid();
1564 ret.push_back(Pair("isvalid", isValid));
1567 CTxDestination dest = address.Get();
1568 string currentAddress = address.ToString();
1569 ret.push_back(Pair("address", currentAddress));
1570 bool fMine = IsMine(*pwalletMain, dest);
1571 ret.push_back(Pair("ismine", fMine));
1573 Object detail = boost::apply_visitor(DescribeAddressVisitor(), dest);
1574 ret.insert(ret.end(), detail.begin(), detail.end());
1576 if (pwalletMain->mapAddressBook.count(dest))
1577 ret.push_back(Pair("account", pwalletMain->mapAddressBook[dest]));
1582 Value validatepubkey(const Array& params, bool fHelp)
1584 if (fHelp || !params.size() || params.size() > 2)
1585 throw runtime_error(
1586 "validatepubkey <novacoinpubkey>\n"
1587 "Return information about <novacoinpubkey>.");
1589 std::vector<unsigned char> vchPubKey = ParseHex(params[0].get_str());
1590 CPubKey pubKey(vchPubKey);
1592 bool isValid = pubKey.IsValid();
1593 bool isCompressed = pubKey.IsCompressed();
1594 CKeyID keyID = pubKey.GetID();
1596 CBitcoinAddress address;
1600 ret.push_back(Pair("isvalid", isValid));
1603 CTxDestination dest = address.Get();
1604 string currentAddress = address.ToString();
1605 ret.push_back(Pair("address", currentAddress));
1606 bool fMine = IsMine(*pwalletMain, dest);
1607 ret.push_back(Pair("ismine", fMine));
1608 ret.push_back(Pair("iscompressed", isCompressed));
1610 Object detail = boost::apply_visitor(DescribeAddressVisitor(), dest);
1611 ret.insert(ret.end(), detail.begin(), detail.end());
1613 if (pwalletMain->mapAddressBook.count(dest))
1614 ret.push_back(Pair("account", pwalletMain->mapAddressBook[dest]));
1619 // ppcoin: reserve balance from being staked for network protection
1620 Value reservebalance(const Array& params, bool fHelp)
1622 if (fHelp || params.size() > 2)
1623 throw runtime_error(
1624 "reservebalance [<reserve> [amount]]\n"
1625 "<reserve> is true or false to turn balance reserve on or off.\n"
1626 "<amount> is a real and rounded to cent.\n"
1627 "Set reserve amount not participating in network protection.\n"
1628 "If no parameters provided current setting is printed.\n");
1630 if (params.size() > 0)
1632 bool fReserve = params[0].get_bool();
1635 if (params.size() == 1)
1636 throw runtime_error("must provide amount to reserve balance.\n");
1637 int64 nAmount = AmountFromValue(params[1]);
1638 nAmount = (nAmount / CENT) * CENT; // round to cent
1640 throw runtime_error("amount cannot be negative.\n");
1641 mapArgs["-reservebalance"] = FormatMoney(nAmount).c_str();
1645 if (params.size() > 1)
1646 throw runtime_error("cannot specify amount to turn off reserve.\n");
1647 mapArgs["-reservebalance"] = "0";
1652 int64 nReserveBalance = 0;
1653 if (mapArgs.count("-reservebalance") && !ParseMoney(mapArgs["-reservebalance"], nReserveBalance))
1654 throw runtime_error("invalid reserve balance amount\n");
1655 result.push_back(Pair("reserve", (nReserveBalance > 0)));
1656 result.push_back(Pair("amount", ValueFromAmount(nReserveBalance)));
1661 // ppcoin: check wallet integrity
1662 Value checkwallet(const Array& params, bool fHelp)
1664 if (fHelp || params.size() > 0)
1665 throw runtime_error(
1667 "Check wallet for integrity.\n");
1670 int64 nBalanceInQuestion;
1671 pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion, true);
1673 if (nMismatchSpent == 0)
1674 result.push_back(Pair("wallet check passed", true));
1677 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
1678 result.push_back(Pair("amount in question", ValueFromAmount(nBalanceInQuestion)));
1684 // ppcoin: repair wallet
1685 Value repairwallet(const Array& params, bool fHelp)
1687 if (fHelp || params.size() > 0)
1688 throw runtime_error(
1690 "Repair wallet if checkwallet reports any problem.\n");
1693 int64 nBalanceInQuestion;
1694 pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion);
1696 if (nMismatchSpent == 0)
1697 result.push_back(Pair("wallet check passed", true));
1700 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
1701 result.push_back(Pair("amount affected by repair", ValueFromAmount(nBalanceInQuestion)));
1706 // NovaCoin: resend unconfirmed wallet transactions
1707 Value resendtx(const Array& params, bool fHelp)
1709 if (fHelp || params.size() > 1)
1710 throw runtime_error(
1712 "Re-send unconfirmed transactions.\n"
1715 ResendWalletTransactions();
1720 // ppcoin: make a public-private key pair
1721 Value makekeypair(const Array& params, bool fHelp)
1723 if (fHelp || params.size() > 1)
1724 throw runtime_error(
1725 "makekeypair [prefix]\n"
1726 "Make a public/private key pair.\n"
1727 "[prefix] is optional preferred prefix for the public key.\n");
1729 string strPrefix = "";
1730 if (params.size() > 0)
1731 strPrefix = params[0].get_str();
1734 key.MakeNewKey(false);
1736 CPrivKey vchPrivKey = key.GetPrivKey();
1738 result.push_back(Pair("PrivateKey", HexStr<CPrivKey::iterator>(vchPrivKey.begin(), vchPrivKey.end())));
1739 result.push_back(Pair("PublicKey", HexStr(key.GetPubKey().Raw())));