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("timeoffset", (boost::int64_t)GetTimeOffset()));
81 obj.push_back(Pair("moneysupply", ValueFromAmount(pindexBest->nMoneySupply)));
82 obj.push_back(Pair("connections", (int)vNodes.size()));
83 obj.push_back(Pair("proxy", (proxy.first.IsValid() ? proxy.first.ToStringIPPort() : string())));
84 obj.push_back(Pair("ip", addrSeenByPeer.ToStringIP()));
86 diff.push_back(Pair("proof-of-work", GetDifficulty()));
87 diff.push_back(Pair("proof-of-stake", GetDifficulty(GetLastBlockIndex(pindexBest, true))));
88 obj.push_back(Pair("difficulty", diff));
90 obj.push_back(Pair("testnet", fTestNet));
91 obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
92 obj.push_back(Pair("keypoolsize", (int)pwalletMain->GetKeyPoolSize()));
93 obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee)));
94 obj.push_back(Pair("mininput", ValueFromAmount(nMinimumInputValue)));
95 if (pwalletMain->IsCrypted())
96 obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime / 1000));
97 obj.push_back(Pair("errors", GetWarnings("statusbar")));
102 Value getnewpubkey(const Array& params, bool fHelp)
104 if (fHelp || params.size() > 1)
106 "getnewpubkey [account]\n"
107 "Returns new public key for coinbase generation.");
109 // Parse the account first so we don't generate a key if there's an error
111 if (params.size() > 0)
112 strAccount = AccountFromValue(params[0]);
114 if (!pwalletMain->IsLocked())
115 pwalletMain->TopUpKeyPool();
117 // Generate a new key that is added to wallet
119 if (!pwalletMain->GetKeyFromPool(newKey, false))
120 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
121 CKeyID keyID = newKey.GetID();
123 pwalletMain->SetAddressBookName(keyID, strAccount);
124 vector<unsigned char> vchPubKey = newKey.Raw();
126 return HexStr(vchPubKey.begin(), vchPubKey.end());
130 Value getnewaddress(const Array& params, bool fHelp)
132 if (fHelp || params.size() > 1)
134 "getnewaddress [account]\n"
135 "Returns a new NovaCoin address for receiving payments. "
136 "If [account] is specified (recommended), it is added to the address book "
137 "so payments received with the address will be credited to [account].");
139 // Parse the account first so we don't generate a key if there's an error
141 if (params.size() > 0)
142 strAccount = AccountFromValue(params[0]);
144 if (!pwalletMain->IsLocked())
145 pwalletMain->TopUpKeyPool();
147 // Generate a new key that is added to wallet
149 if (!pwalletMain->GetKeyFromPool(newKey, false))
150 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
151 CKeyID keyID = newKey.GetID();
153 pwalletMain->SetAddressBookName(keyID, strAccount);
155 return CBitcoinAddress(keyID).ToString();
159 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
161 CWalletDB walletdb(pwalletMain->strWalletFile);
164 walletdb.ReadAccount(strAccount, account);
166 bool bKeyUsed = false;
168 // Check if the current key has been used
169 if (account.vchPubKey.IsValid())
171 CScript scriptPubKey;
172 scriptPubKey.SetDestination(account.vchPubKey.GetID());
173 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
174 it != pwalletMain->mapWallet.end() && account.vchPubKey.IsValid();
177 const CWalletTx& wtx = (*it).second;
178 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
179 if (txout.scriptPubKey == scriptPubKey)
184 // Generate a new key
185 if (!account.vchPubKey.IsValid() || bForceNew || bKeyUsed)
187 if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false))
188 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
190 pwalletMain->SetAddressBookName(account.vchPubKey.GetID(), strAccount);
191 walletdb.WriteAccount(strAccount, account);
194 return CBitcoinAddress(account.vchPubKey.GetID());
197 Value getaccountaddress(const Array& params, bool fHelp)
199 if (fHelp || params.size() != 1)
201 "getaccountaddress <account>\n"
202 "Returns the current NovaCoin address for receiving payments to this account.");
204 // Parse the account first so we don't generate a key if there's an error
205 string strAccount = AccountFromValue(params[0]);
209 ret = GetAccountAddress(strAccount).ToString();
216 Value setaccount(const Array& params, bool fHelp)
218 if (fHelp || params.size() < 1 || params.size() > 2)
220 "setaccount <novacoinaddress> <account>\n"
221 "Sets the account associated with the given address.");
223 CBitcoinAddress address(params[0].get_str());
224 if (!address.IsValid())
225 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
229 if (params.size() > 1)
230 strAccount = AccountFromValue(params[1]);
232 // Detect when changing the account of an address that is the 'unused current key' of another account:
233 if (pwalletMain->mapAddressBook.count(address.Get()))
235 string strOldAccount = pwalletMain->mapAddressBook[address.Get()];
236 if (address == GetAccountAddress(strOldAccount))
237 GetAccountAddress(strOldAccount, true);
240 pwalletMain->SetAddressBookName(address.Get(), strAccount);
246 Value getaccount(const Array& params, bool fHelp)
248 if (fHelp || params.size() != 1)
250 "getaccount <novacoinaddress>\n"
251 "Returns the account associated with the given address.");
253 CBitcoinAddress address(params[0].get_str());
254 if (!address.IsValid())
255 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
258 map<CTxDestination, string>::iterator mi = pwalletMain->mapAddressBook.find(address.Get());
259 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
260 strAccount = (*mi).second;
265 Value getaddressesbyaccount(const Array& params, bool fHelp)
267 if (fHelp || params.size() != 1)
269 "getaddressesbyaccount <account>\n"
270 "Returns the list of addresses for the given account.");
272 string strAccount = AccountFromValue(params[0]);
274 // Find all addresses that have the given account
276 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
278 const CBitcoinAddress& address = item.first;
279 const string& strName = item.second;
280 if (strName == strAccount)
281 ret.push_back(address.ToString());
286 Value sendtoaddress(const Array& params, bool fHelp)
288 if (fHelp || params.size() < 2 || params.size() > 4)
290 "sendtoaddress <novacoinaddress> <amount> [comment] [comment-to]\n"
291 "<amount> is a real and is rounded to the nearest 0.000001"
292 + HelpRequiringPassphrase());
294 CBitcoinAddress address(params[0].get_str());
295 if (!address.IsValid())
296 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
299 int64 nAmount = AmountFromValue(params[1]);
301 if (nAmount < MIN_TXOUT_AMOUNT)
302 throw JSONRPCError(-101, "Send amount too small");
306 if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
307 wtx.mapValue["comment"] = params[2].get_str();
308 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
309 wtx.mapValue["to"] = params[3].get_str();
311 if (pwalletMain->IsLocked())
312 throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
314 string strError = pwalletMain->SendMoneyToDestination(address.Get(), nAmount, wtx);
316 throw JSONRPCError(RPC_WALLET_ERROR, strError);
318 return wtx.GetHash().GetHex();
321 Value listaddressgroupings(const Array& params, bool fHelp)
325 "listaddressgroupings\n"
326 "Lists groups of addresses which have had their common ownership\n"
327 "made public by common use as inputs or as the resulting change\n"
328 "in past transactions");
331 map<CTxDestination, int64> balances = pwalletMain->GetAddressBalances();
332 BOOST_FOREACH(set<CTxDestination> grouping, pwalletMain->GetAddressGroupings())
335 BOOST_FOREACH(CTxDestination address, grouping)
338 addressInfo.push_back(CBitcoinAddress(address).ToString());
339 addressInfo.push_back(ValueFromAmount(balances[address]));
341 LOCK(pwalletMain->cs_wallet);
342 if (pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get()) != pwalletMain->mapAddressBook.end())
343 addressInfo.push_back(pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get())->second);
345 jsonGrouping.push_back(addressInfo);
347 jsonGroupings.push_back(jsonGrouping);
349 return jsonGroupings;
352 Value signmessage(const Array& params, bool fHelp)
354 if (fHelp || params.size() != 2)
356 "signmessage <novacoinaddress> <message>\n"
357 "Sign a message with the private key of an address");
359 EnsureWalletIsUnlocked();
361 string strAddress = params[0].get_str();
362 string strMessage = params[1].get_str();
364 CBitcoinAddress addr(strAddress);
366 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
369 if (!addr.GetKeyID(keyID))
370 throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
373 if (!pwalletMain->GetKey(keyID, key))
374 throw JSONRPCError(RPC_WALLET_ERROR, "Private key not available");
376 CDataStream ss(SER_GETHASH, 0);
377 ss << strMessageMagic;
380 vector<unsigned char> vchSig;
381 if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
382 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed");
384 return EncodeBase64(&vchSig[0], vchSig.size());
387 Value verifymessage(const Array& params, bool fHelp)
389 if (fHelp || params.size() != 3)
391 "verifymessage <novacoinaddress> <signature> <message>\n"
392 "Verify a signed message");
394 string strAddress = params[0].get_str();
395 string strSign = params[1].get_str();
396 string strMessage = params[2].get_str();
398 CBitcoinAddress addr(strAddress);
400 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
403 if (!addr.GetKeyID(keyID))
404 throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
406 bool fInvalid = false;
407 vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
410 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Malformed base64 encoding");
412 CDataStream ss(SER_GETHASH, 0);
413 ss << strMessageMagic;
417 if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
420 return (key.GetPubKey().GetID() == keyID);
424 Value getreceivedbyaddress(const Array& params, bool fHelp)
426 if (fHelp || params.size() < 1 || params.size() > 2)
428 "getreceivedbyaddress <novacoinaddress> [minconf=1]\n"
429 "Returns the total amount received by <novacoinaddress> in transactions with at least [minconf] confirmations.");
432 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
433 CScript scriptPubKey;
434 if (!address.IsValid())
435 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
436 scriptPubKey.SetDestination(address.Get());
437 if (!IsMine(*pwalletMain,scriptPubKey))
440 // Minimum confirmations
442 if (params.size() > 1)
443 nMinDepth = params[1].get_int();
447 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
449 const CWalletTx& wtx = (*it).second;
450 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
453 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
454 if (txout.scriptPubKey == scriptPubKey)
455 if (wtx.GetDepthInMainChain() >= nMinDepth)
456 nAmount += txout.nValue;
459 return ValueFromAmount(nAmount);
463 void GetAccountAddresses(string strAccount, set<CTxDestination>& setAddress)
465 BOOST_FOREACH(const PAIRTYPE(CTxDestination, string)& item, pwalletMain->mapAddressBook)
467 const CTxDestination& address = item.first;
468 const string& strName = item.second;
469 if (strName == strAccount)
470 setAddress.insert(address);
474 Value getreceivedbyaccount(const Array& params, bool fHelp)
476 if (fHelp || params.size() < 1 || params.size() > 2)
478 "getreceivedbyaccount <account> [minconf=1]\n"
479 "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
481 // Minimum confirmations
483 if (params.size() > 1)
484 nMinDepth = params[1].get_int();
486 // Get the set of pub keys assigned to account
487 string strAccount = AccountFromValue(params[0]);
488 set<CTxDestination> setAddress;
489 GetAccountAddresses(strAccount, setAddress);
493 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
495 const CWalletTx& wtx = (*it).second;
496 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
499 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
501 CTxDestination address;
502 if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*pwalletMain, address) && setAddress.count(address))
503 if (wtx.GetDepthInMainChain() >= nMinDepth)
504 nAmount += txout.nValue;
508 return (double)nAmount / (double)COIN;
512 int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
516 // Tally wallet transactions
517 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
519 const CWalletTx& wtx = (*it).second;
523 int64 nGenerated, nReceived, nSent, nFee;
524 wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee);
526 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
527 nBalance += nReceived;
528 nBalance += nGenerated - nSent - nFee;
531 // Tally internal accounting entries
532 nBalance += walletdb.GetAccountCreditDebit(strAccount);
537 int64 GetAccountBalance(const string& strAccount, int nMinDepth)
539 CWalletDB walletdb(pwalletMain->strWalletFile);
540 return GetAccountBalance(walletdb, strAccount, nMinDepth);
544 Value getbalance(const Array& params, bool fHelp)
546 if (fHelp || params.size() > 2)
548 "getbalance [account] [minconf=1]\n"
549 "If [account] is not specified, returns the server's total available balance.\n"
550 "If [account] is specified, returns the balance in the account.");
552 if (params.size() == 0)
553 return ValueFromAmount(pwalletMain->GetBalance());
556 if (params.size() > 1)
557 nMinDepth = params[1].get_int();
559 if (params[0].get_str() == "*") {
560 // Calculate total balance a different way from GetBalance()
561 // (GetBalance() sums up all unspent TxOuts)
562 // getbalance and getbalance '*' 0 should return the same number.
564 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
566 const CWalletTx& wtx = (*it).second;
567 if (!wtx.IsTrusted())
570 int64 allGeneratedImmature, allGeneratedMature, allFee;
571 allGeneratedImmature = allGeneratedMature = allFee = 0;
573 string strSentAccount;
574 list<pair<CTxDestination, int64> > listReceived;
575 list<pair<CTxDestination, int64> > listSent;
576 wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
577 if (wtx.GetDepthInMainChain() >= nMinDepth)
579 BOOST_FOREACH(const PAIRTYPE(CTxDestination,int64)& r, listReceived)
580 nBalance += r.second;
582 BOOST_FOREACH(const PAIRTYPE(CTxDestination,int64)& r, listSent)
583 nBalance -= r.second;
585 nBalance += allGeneratedMature;
587 return ValueFromAmount(nBalance);
590 string strAccount = AccountFromValue(params[0]);
592 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
594 return ValueFromAmount(nBalance);
598 Value movecmd(const Array& params, bool fHelp)
600 if (fHelp || params.size() < 3 || params.size() > 5)
602 "move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
603 "Move from one account in your wallet to another.");
605 string strFrom = AccountFromValue(params[0]);
606 string strTo = AccountFromValue(params[1]);
607 int64 nAmount = AmountFromValue(params[2]);
609 if (nAmount < MIN_TXOUT_AMOUNT)
610 throw JSONRPCError(-101, "Send amount too small");
612 if (params.size() > 3)
613 // unused parameter, used to be nMinDepth, keep type-checking it though
614 (void)params[3].get_int();
616 if (params.size() > 4)
617 strComment = params[4].get_str();
619 CWalletDB walletdb(pwalletMain->strWalletFile);
620 if (!walletdb.TxnBegin())
621 throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
623 int64 nNow = GetAdjustedTime();
626 CAccountingEntry debit;
627 debit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
628 debit.strAccount = strFrom;
629 debit.nCreditDebit = -nAmount;
631 debit.strOtherAccount = strTo;
632 debit.strComment = strComment;
633 walletdb.WriteAccountingEntry(debit);
636 CAccountingEntry credit;
637 credit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
638 credit.strAccount = strTo;
639 credit.nCreditDebit = nAmount;
641 credit.strOtherAccount = strFrom;
642 credit.strComment = strComment;
643 walletdb.WriteAccountingEntry(credit);
645 if (!walletdb.TxnCommit())
646 throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
652 Value sendfrom(const Array& params, bool fHelp)
654 if (fHelp || params.size() < 3 || params.size() > 6)
656 "sendfrom <fromaccount> <tonovacoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
657 "<amount> is a real and is rounded to the nearest 0.000001"
658 + HelpRequiringPassphrase());
660 string strAccount = AccountFromValue(params[0]);
661 CBitcoinAddress address(params[1].get_str());
662 if (!address.IsValid())
663 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
664 int64 nAmount = AmountFromValue(params[2]);
666 if (nAmount < MIN_TXOUT_AMOUNT)
667 throw JSONRPCError(-101, "Send amount too small");
670 if (params.size() > 3)
671 nMinDepth = params[3].get_int();
674 wtx.strFromAccount = strAccount;
675 if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
676 wtx.mapValue["comment"] = params[4].get_str();
677 if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
678 wtx.mapValue["to"] = params[5].get_str();
680 EnsureWalletIsUnlocked();
683 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
684 if (nAmount > nBalance)
685 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
688 string strError = pwalletMain->SendMoneyToDestination(address.Get(), nAmount, wtx);
690 throw JSONRPCError(RPC_WALLET_ERROR, strError);
692 return wtx.GetHash().GetHex();
696 Value sendmany(const Array& params, bool fHelp)
698 if (fHelp || params.size() < 2 || params.size() > 4)
700 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
701 "amounts are double-precision floating point numbers"
702 + HelpRequiringPassphrase());
704 string strAccount = AccountFromValue(params[0]);
705 Object sendTo = params[1].get_obj();
707 if (params.size() > 2)
708 nMinDepth = params[2].get_int();
711 wtx.strFromAccount = strAccount;
712 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
713 wtx.mapValue["comment"] = params[3].get_str();
715 set<CBitcoinAddress> setAddress;
716 vector<pair<CScript, int64> > vecSend;
718 int64 totalAmount = 0;
719 BOOST_FOREACH(const Pair& s, sendTo)
721 CBitcoinAddress address(s.name_);
722 if (!address.IsValid())
723 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid NovaCoin address: ")+s.name_);
725 if (setAddress.count(address))
726 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+s.name_);
727 setAddress.insert(address);
729 CScript scriptPubKey;
730 scriptPubKey.SetDestination(address.Get());
731 int64 nAmount = AmountFromValue(s.value_);
733 if (nAmount < MIN_TXOUT_AMOUNT)
734 throw JSONRPCError(-101, "Send amount too small");
736 totalAmount += nAmount;
738 vecSend.push_back(make_pair(scriptPubKey, nAmount));
741 EnsureWalletIsUnlocked();
744 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
745 if (totalAmount > nBalance)
746 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
749 CReserveKey keyChange(pwalletMain);
750 int64 nFeeRequired = 0;
751 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
754 if (totalAmount + nFeeRequired > pwalletMain->GetBalance())
755 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds");
756 throw JSONRPCError(RPC_WALLET_ERROR, "Transaction creation failed");
758 if (!pwalletMain->CommitTransaction(wtx, keyChange))
759 throw JSONRPCError(RPC_WALLET_ERROR, "Transaction commit failed");
761 return wtx.GetHash().GetHex();
764 Value addmultisigaddress(const Array& params, bool fHelp)
766 if (fHelp || params.size() < 2 || params.size() > 3)
768 string msg = "addmultisigaddress <nrequired> <'[\"key\",\"key\"]'> [account]\n"
769 "Add a nrequired-to-sign multisignature address to the wallet\"\n"
770 "each key is a NovaCoin address or hex-encoded public key\n"
771 "If [account] is specified, assign address to [account].";
772 throw runtime_error(msg);
775 int nRequired = params[0].get_int();
776 const Array& keys = params[1].get_array();
778 if (params.size() > 2)
779 strAccount = AccountFromValue(params[2]);
781 // Gather public keys
783 throw runtime_error("a multisignature address must require at least one key to redeem");
784 if ((int)keys.size() < nRequired)
786 strprintf("not enough keys supplied "
787 "(got %"PRIszu" keys, but need at least %d to redeem)", keys.size(), nRequired));
788 std::vector<CKey> pubkeys;
789 pubkeys.resize(keys.size());
790 for (unsigned int i = 0; i < keys.size(); i++)
792 const std::string& ks = keys[i].get_str();
794 // Case 1: Bitcoin address and we have full public key:
795 CBitcoinAddress address(ks);
796 if (address.IsValid())
799 if (!address.GetKeyID(keyID))
801 strprintf("%s does not refer to a key",ks.c_str()));
803 if (!pwalletMain->GetPubKey(keyID, vchPubKey))
805 strprintf("no full public key for address %s",ks.c_str()));
806 if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey))
807 throw runtime_error(" Invalid public key: "+ks);
810 // Case 2: hex public key
813 CPubKey vchPubKey(ParseHex(ks));
814 if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey))
815 throw runtime_error(" Invalid public key: "+ks);
819 throw runtime_error(" Invalid public key: "+ks);
823 // Construct using pay-to-script-hash:
825 inner.SetMultisig(nRequired, pubkeys);
826 CScriptID innerID = inner.GetID();
827 pwalletMain->AddCScript(inner);
829 pwalletMain->SetAddressBookName(innerID, strAccount);
830 return CBitcoinAddress(innerID).ToString();
833 Value addredeemscript(const Array& params, bool fHelp)
835 if (fHelp || params.size() < 1 || params.size() > 2)
837 string msg = "addredeemscript <redeemScript> [account]\n"
838 "Add a P2SH address with a specified redeemScript to the wallet.\n"
839 "If [account] is specified, assign address to [account].";
840 throw runtime_error(msg);
844 if (params.size() > 1)
845 strAccount = AccountFromValue(params[1]);
847 // Construct using pay-to-script-hash:
848 vector<unsigned char> innerData = ParseHexV(params[0], "redeemScript");
849 CScript inner(innerData.begin(), innerData.end());
850 CScriptID innerID = inner.GetID();
851 pwalletMain->AddCScript(inner);
853 pwalletMain->SetAddressBookName(innerID, strAccount);
854 return CBitcoinAddress(innerID).ToString();
864 nConf = std::numeric_limits<int>::max();
868 Value ListReceived(const Array& params, bool fByAccounts)
870 // Minimum confirmations
872 if (params.size() > 0)
873 nMinDepth = params[0].get_int();
875 // Whether to include empty accounts
876 bool fIncludeEmpty = false;
877 if (params.size() > 1)
878 fIncludeEmpty = params[1].get_bool();
881 map<CBitcoinAddress, tallyitem> mapTally;
882 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
884 const CWalletTx& wtx = (*it).second;
886 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
889 int nDepth = wtx.GetDepthInMainChain();
890 if (nDepth < nMinDepth)
893 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
895 CTxDestination address;
896 if (!ExtractDestination(txout.scriptPubKey, address) || !IsMine(*pwalletMain, address))
899 tallyitem& item = mapTally[address];
900 item.nAmount += txout.nValue;
901 item.nConf = min(item.nConf, nDepth);
907 map<string, tallyitem> mapAccountTally;
908 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
910 const CBitcoinAddress& address = item.first;
911 const string& strAccount = item.second;
912 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
913 if (it == mapTally.end() && !fIncludeEmpty)
917 int nConf = std::numeric_limits<int>::max();
918 if (it != mapTally.end())
920 nAmount = (*it).second.nAmount;
921 nConf = (*it).second.nConf;
926 tallyitem& item = mapAccountTally[strAccount];
927 item.nAmount += nAmount;
928 item.nConf = min(item.nConf, nConf);
933 obj.push_back(Pair("address", address.ToString()));
934 obj.push_back(Pair("account", strAccount));
935 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
936 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
943 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
945 int64 nAmount = (*it).second.nAmount;
946 int nConf = (*it).second.nConf;
948 obj.push_back(Pair("account", (*it).first));
949 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
950 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
958 Value listreceivedbyaddress(const Array& params, bool fHelp)
960 if (fHelp || params.size() > 2)
962 "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
963 "[minconf] is the minimum number of confirmations before payments are included.\n"
964 "[includeempty] whether to include addresses that haven't received any payments.\n"
965 "Returns an array of objects containing:\n"
966 " \"address\" : receiving address\n"
967 " \"account\" : the account of the receiving address\n"
968 " \"amount\" : total amount received by the address\n"
969 " \"confirmations\" : number of confirmations of the most recent transaction included");
971 return ListReceived(params, false);
974 Value listreceivedbyaccount(const Array& params, bool fHelp)
976 if (fHelp || params.size() > 2)
978 "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
979 "[minconf] is the minimum number of confirmations before payments are included.\n"
980 "[includeempty] whether to include accounts that haven't received any payments.\n"
981 "Returns an array of objects containing:\n"
982 " \"account\" : the account of the receiving addresses\n"
983 " \"amount\" : total amount received by addresses with this account\n"
984 " \"confirmations\" : number of confirmations of the most recent transaction included");
986 return ListReceived(params, true);
989 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
991 int64 nGeneratedImmature, nGeneratedMature, nFee;
992 string strSentAccount;
993 list<pair<CTxDestination, int64> > listReceived;
994 list<pair<CTxDestination, int64> > listSent;
996 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
998 bool fAllAccounts = (strAccount == string("*"));
1000 // Generated blocks assigned to account ""
1001 if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
1004 entry.push_back(Pair("account", string("")));
1005 if (nGeneratedImmature)
1007 entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
1008 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
1012 entry.push_back(Pair("category", "generate"));
1013 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
1016 WalletTxToJSON(wtx, entry);
1017 ret.push_back(entry);
1021 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1023 BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& s, listSent)
1026 entry.push_back(Pair("account", strSentAccount));
1027 entry.push_back(Pair("address", CBitcoinAddress(s.first).ToString()));
1029 if (wtx.GetDepthInMainChain() < 0) {
1030 entry.push_back(Pair("category", "conflicted"));
1032 entry.push_back(Pair("category", "send"));
1035 entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1036 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1038 WalletTxToJSON(wtx, entry);
1039 ret.push_back(entry);
1044 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1046 BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& r, listReceived)
1049 if (pwalletMain->mapAddressBook.count(r.first))
1050 account = pwalletMain->mapAddressBook[r.first];
1051 if (fAllAccounts || (account == strAccount))
1054 entry.push_back(Pair("account", account));
1055 entry.push_back(Pair("address", CBitcoinAddress(r.first).ToString()));
1056 if (wtx.IsCoinBase())
1058 if (wtx.GetDepthInMainChain() < 1)
1059 entry.push_back(Pair("category", "orphan"));
1060 else if (wtx.GetBlocksToMaturity() > 0)
1061 entry.push_back(Pair("category", "immature"));
1063 entry.push_back(Pair("category", "generate"));
1066 if (wtx.GetDepthInMainChain() < 0) {
1067 entry.push_back(Pair("category", "conflicted"));
1069 entry.push_back(Pair("category", "receive"));
1072 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1074 WalletTxToJSON(wtx, entry);
1075 ret.push_back(entry);
1081 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1083 bool fAllAccounts = (strAccount == string("*"));
1085 if (fAllAccounts || acentry.strAccount == strAccount)
1088 entry.push_back(Pair("account", acentry.strAccount));
1089 entry.push_back(Pair("category", "move"));
1090 entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
1091 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1092 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1093 entry.push_back(Pair("comment", acentry.strComment));
1094 ret.push_back(entry);
1098 Value listtransactions(const Array& params, bool fHelp)
1100 if (fHelp || params.size() > 3)
1101 throw runtime_error(
1102 "listtransactions [account] [count=10] [from=0]\n"
1103 "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1105 string strAccount = "*";
1106 if (params.size() > 0)
1107 strAccount = params[0].get_str();
1109 if (params.size() > 1)
1110 nCount = params[1].get_int();
1112 if (params.size() > 2)
1113 nFrom = params[2].get_int();
1116 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count");
1118 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative from");
1122 std::list<CAccountingEntry> acentries;
1123 CWallet::TxItems txOrdered = pwalletMain->OrderedTxItems(acentries, strAccount);
1125 // iterate backwards until we have nCount items to return:
1126 for (CWallet::TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
1128 CWalletTx *const pwtx = (*it).second.first;
1130 ListTransactions(*pwtx, strAccount, 0, true, ret);
1131 CAccountingEntry *const pacentry = (*it).second.second;
1133 AcentryToJSON(*pacentry, strAccount, ret);
1135 if ((int)ret.size() >= (nCount+nFrom)) break;
1137 // ret is newest to oldest
1139 if (nFrom > (int)ret.size())
1141 if ((nFrom + nCount) > (int)ret.size())
1142 nCount = ret.size() - nFrom;
1143 Array::iterator first = ret.begin();
1144 std::advance(first, nFrom);
1145 Array::iterator last = ret.begin();
1146 std::advance(last, nFrom+nCount);
1148 if (last != ret.end()) ret.erase(last, ret.end());
1149 if (first != ret.begin()) ret.erase(ret.begin(), first);
1151 std::reverse(ret.begin(), ret.end()); // Return oldest to newest
1156 Value listaccounts(const Array& params, bool fHelp)
1158 if (fHelp || params.size() > 1)
1159 throw runtime_error(
1160 "listaccounts [minconf=1]\n"
1161 "Returns Object that has account names as keys, account balances as values.");
1164 if (params.size() > 0)
1165 nMinDepth = params[0].get_int();
1167 map<string, int64> mapAccountBalances;
1168 BOOST_FOREACH(const PAIRTYPE(CTxDestination, string)& entry, pwalletMain->mapAddressBook) {
1169 if (IsMine(*pwalletMain, entry.first)) // This address belongs to me
1170 mapAccountBalances[entry.second] = 0;
1173 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1175 const CWalletTx& wtx = (*it).second;
1176 int64 nGeneratedImmature, nGeneratedMature, nFee;
1177 string strSentAccount;
1178 list<pair<CTxDestination, int64> > listReceived;
1179 list<pair<CTxDestination, int64> > listSent;
1180 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1181 mapAccountBalances[strSentAccount] -= nFee;
1182 BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& s, listSent)
1183 mapAccountBalances[strSentAccount] -= s.second;
1184 if (wtx.GetDepthInMainChain() >= nMinDepth)
1186 mapAccountBalances[""] += nGeneratedMature;
1187 BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& r, listReceived)
1188 if (pwalletMain->mapAddressBook.count(r.first))
1189 mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1191 mapAccountBalances[""] += r.second;
1195 list<CAccountingEntry> acentries;
1196 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1197 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1198 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1201 BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) {
1202 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1207 Value listsinceblock(const Array& params, bool fHelp)
1210 throw runtime_error(
1211 "listsinceblock [blockhash] [target-confirmations]\n"
1212 "Get all transactions in blocks since block [blockhash], or all transactions if omitted");
1214 CBlockIndex *pindex = NULL;
1215 int target_confirms = 1;
1217 if (params.size() > 0)
1219 uint256 blockId = 0;
1221 blockId.SetHex(params[0].get_str());
1222 pindex = CBlockLocator(blockId).GetBlockIndex();
1225 if (params.size() > 1)
1227 target_confirms = params[1].get_int();
1229 if (target_confirms < 1)
1230 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter");
1233 int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
1237 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1239 CWalletTx tx = (*it).second;
1241 if (depth == -1 || tx.GetDepthInMainChain() < depth)
1242 ListTransactions(tx, "*", 0, true, transactions);
1247 if (target_confirms == 1)
1249 lastblock = hashBestChain;
1253 int target_height = pindexBest->nHeight + 1 - target_confirms;
1256 for (block = pindexBest;
1257 block && block->nHeight > target_height;
1258 block = block->pprev) { }
1260 lastblock = block ? block->GetBlockHash() : 0;
1264 ret.push_back(Pair("transactions", transactions));
1265 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1270 Value gettransaction(const Array& params, bool fHelp)
1272 if (fHelp || params.size() != 1)
1273 throw runtime_error(
1274 "gettransaction <txid>\n"
1275 "Get detailed information about <txid>");
1278 hash.SetHex(params[0].get_str());
1282 if (pwalletMain->mapWallet.count(hash))
1284 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1286 TxToJSON(wtx, 0, entry);
1288 int64 nCredit = wtx.GetCredit();
1289 int64 nDebit = wtx.GetDebit();
1290 int64 nNet = nCredit - nDebit;
1291 int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
1293 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1295 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1297 WalletTxToJSON(wtx, entry);
1300 ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
1301 entry.push_back(Pair("details", details));
1303 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
1305 string strHex = HexStr(ssTx.begin(), ssTx.end());
1306 entry.push_back(Pair("hex", strHex));
1311 uint256 hashBlock = 0;
1312 if (GetTransaction(hash, tx, hashBlock, true))
1314 TxToJSON(tx, 0, entry);
1316 entry.push_back(Pair("confirmations", 0));
1319 entry.push_back(Pair("blockhash", hashBlock.GetHex()));
1320 map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
1321 if (mi != mapBlockIndex.end() && (*mi).second)
1323 CBlockIndex* pindex = (*mi).second;
1324 if (pindex->IsInMainChain())
1325 entry.push_back(Pair("confirmations", 1 + nBestHeight - pindex->nHeight));
1327 entry.push_back(Pair("confirmations", 0));
1332 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction");
1339 Value backupwallet(const Array& params, bool fHelp)
1341 if (fHelp || params.size() != 1)
1342 throw runtime_error(
1343 "backupwallet <destination>\n"
1344 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1346 string strDest = params[0].get_str();
1347 if (!BackupWallet(*pwalletMain, strDest))
1348 throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!");
1354 Value keypoolrefill(const Array& params, bool fHelp)
1356 if (fHelp || params.size() > 1)
1357 throw runtime_error(
1358 "keypoolrefill [new-size]\n"
1359 "Fills the keypool."
1360 + HelpRequiringPassphrase());
1362 unsigned int nSize = max(GetArg("-keypool", 100), 0LL);
1363 if (params.size() > 0) {
1364 if (params[0].get_int() < 0)
1365 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size");
1366 nSize = (unsigned int) params[0].get_int();
1369 EnsureWalletIsUnlocked();
1371 pwalletMain->TopUpKeyPool(nSize);
1373 if (pwalletMain->GetKeyPoolSize() < nSize)
1374 throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool.");
1380 void ThreadTopUpKeyPool(void* parg)
1382 // Make this thread recognisable as the key-topping-up thread
1383 RenameThread("bitcoin-key-top");
1385 pwalletMain->TopUpKeyPool();
1388 void ThreadCleanWalletPassphrase(void* parg)
1390 // Make this thread recognisable as the wallet relocking thread
1391 RenameThread("bitcoin-lock-wa");
1393 int64 nMyWakeTime = GetTimeMillis() + *((int64*)parg) * 1000;
1395 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1397 if (nWalletUnlockTime == 0)
1399 nWalletUnlockTime = nMyWakeTime;
1403 if (nWalletUnlockTime==0)
1405 int64 nToSleep = nWalletUnlockTime - GetTimeMillis();
1409 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1411 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1415 if (nWalletUnlockTime)
1417 nWalletUnlockTime = 0;
1418 pwalletMain->Lock();
1423 if (nWalletUnlockTime < nMyWakeTime)
1424 nWalletUnlockTime = nMyWakeTime;
1427 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1429 delete (int64*)parg;
1432 Value walletpassphrase(const Array& params, bool fHelp)
1434 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 3))
1435 throw runtime_error(
1436 "walletpassphrase <passphrase> <timeout> [mintonly]\n"
1437 "Stores the wallet decryption key in memory for <timeout> seconds.\n"
1438 "mintonly is optional true/false allowing only block minting.");
1441 if (!pwalletMain->IsCrypted())
1442 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1444 if (!pwalletMain->IsLocked())
1445 throw JSONRPCError(RPC_WALLET_ALREADY_UNLOCKED, "Error: Wallet is already unlocked, use walletlock first if need to change unlock settings.");
1446 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1447 SecureString strWalletPass;
1448 strWalletPass.reserve(100);
1449 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1450 // Alternately, find a way to make params[0] mlock()'d to begin with.
1451 strWalletPass = params[0].get_str().c_str();
1453 if (strWalletPass.length() > 0)
1455 if (!pwalletMain->Unlock(strWalletPass))
1456 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
1459 throw runtime_error(
1460 "walletpassphrase <passphrase> <timeout>\n"
1461 "Stores the wallet decryption key in memory for <timeout> seconds.");
1463 NewThread(ThreadTopUpKeyPool, NULL);
1464 int64* pnSleepTime = new int64(params[1].get_int64());
1465 NewThread(ThreadCleanWalletPassphrase, pnSleepTime);
1467 // ppcoin: if user OS account compromised prevent trivial sendmoney commands
1468 if (params.size() > 2)
1469 fWalletUnlockMintOnly = params[2].get_bool();
1471 fWalletUnlockMintOnly = false;
1477 Value walletpassphrasechange(const Array& params, bool fHelp)
1479 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1480 throw runtime_error(
1481 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1482 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1485 if (!pwalletMain->IsCrypted())
1486 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1488 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1489 // Alternately, find a way to make params[0] mlock()'d to begin with.
1490 SecureString strOldWalletPass;
1491 strOldWalletPass.reserve(100);
1492 strOldWalletPass = params[0].get_str().c_str();
1494 SecureString strNewWalletPass;
1495 strNewWalletPass.reserve(100);
1496 strNewWalletPass = params[1].get_str().c_str();
1498 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1499 throw runtime_error(
1500 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1501 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1503 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1504 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
1510 Value walletlock(const Array& params, bool fHelp)
1512 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1513 throw runtime_error(
1515 "Removes the wallet encryption key from memory, locking the wallet.\n"
1516 "After calling this method, you will need to call walletpassphrase again\n"
1517 "before being able to call any methods which require the wallet to be unlocked.");
1520 if (!pwalletMain->IsCrypted())
1521 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletlock was called.");
1524 LOCK(cs_nWalletUnlockTime);
1525 pwalletMain->Lock();
1526 nWalletUnlockTime = 0;
1533 Value encryptwallet(const Array& params, bool fHelp)
1535 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1536 throw runtime_error(
1537 "encryptwallet <passphrase>\n"
1538 "Encrypts the wallet with <passphrase>.");
1541 if (pwalletMain->IsCrypted())
1542 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an encrypted wallet, but encryptwallet was called.");
1544 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1545 // Alternately, find a way to make params[0] mlock()'d to begin with.
1546 SecureString strWalletPass;
1547 strWalletPass.reserve(100);
1548 strWalletPass = params[0].get_str().c_str();
1550 if (strWalletPass.length() < 1)
1551 throw runtime_error(
1552 "encryptwallet <passphrase>\n"
1553 "Encrypts the wallet with <passphrase>.");
1555 if (!pwalletMain->EncryptWallet(strWalletPass))
1556 throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: Failed to encrypt the wallet.");
1558 // BDB seems to have a bad habit of writing old data into
1559 // slack space in .dat files; that is bad if the old data is
1560 // unencrypted private keys. So:
1562 return "wallet encrypted; NovaCoin server stopping, restart to run with encrypted wallet. The keypool has been flushed, you need to make a new backup.";
1565 class DescribeAddressVisitor : public boost::static_visitor<Object>
1568 Object operator()(const CNoDestination &dest) const { return Object(); }
1570 Object operator()(const CKeyID &keyID) const {
1573 pwalletMain->GetPubKey(keyID, vchPubKey);
1574 obj.push_back(Pair("isscript", false));
1575 obj.push_back(Pair("pubkey", HexStr(vchPubKey.Raw())));
1576 obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed()));
1580 Object operator()(const CScriptID &scriptID) const {
1582 obj.push_back(Pair("isscript", true));
1584 pwalletMain->GetCScript(scriptID, subscript);
1585 std::vector<CTxDestination> addresses;
1586 txnouttype whichType;
1588 ExtractDestinations(subscript, whichType, addresses, nRequired);
1589 obj.push_back(Pair("script", GetTxnOutputType(whichType)));
1590 obj.push_back(Pair("hex", HexStr(subscript.begin(), subscript.end())));
1592 BOOST_FOREACH(const CTxDestination& addr, addresses)
1593 a.push_back(CBitcoinAddress(addr).ToString());
1594 obj.push_back(Pair("addresses", a));
1595 if (whichType == TX_MULTISIG)
1596 obj.push_back(Pair("sigsrequired", nRequired));
1601 Value validateaddress(const Array& params, bool fHelp)
1603 if (fHelp || params.size() != 1)
1604 throw runtime_error(
1605 "validateaddress <novacoinaddress>\n"
1606 "Return information about <novacoinaddress>.");
1608 CBitcoinAddress address(params[0].get_str());
1609 bool isValid = address.IsValid();
1612 ret.push_back(Pair("isvalid", isValid));
1615 CTxDestination dest = address.Get();
1616 string currentAddress = address.ToString();
1617 ret.push_back(Pair("address", currentAddress));
1618 bool fMine = IsMine(*pwalletMain, dest);
1619 ret.push_back(Pair("ismine", fMine));
1621 Object detail = boost::apply_visitor(DescribeAddressVisitor(), dest);
1622 ret.insert(ret.end(), detail.begin(), detail.end());
1624 if (pwalletMain->mapAddressBook.count(dest))
1625 ret.push_back(Pair("account", pwalletMain->mapAddressBook[dest]));
1630 Value validatepubkey(const Array& params, bool fHelp)
1632 if (fHelp || !params.size() || params.size() > 2)
1633 throw runtime_error(
1634 "validatepubkey <novacoinpubkey>\n"
1635 "Return information about <novacoinpubkey>.");
1637 std::vector<unsigned char> vchPubKey = ParseHex(params[0].get_str());
1638 CPubKey pubKey(vchPubKey);
1640 bool isValid = pubKey.IsValid();
1641 bool isCompressed = pubKey.IsCompressed();
1642 CKeyID keyID = pubKey.GetID();
1644 CBitcoinAddress address;
1648 ret.push_back(Pair("isvalid", isValid));
1651 CTxDestination dest = address.Get();
1652 string currentAddress = address.ToString();
1653 ret.push_back(Pair("address", currentAddress));
1654 bool fMine = IsMine(*pwalletMain, dest);
1655 ret.push_back(Pair("ismine", fMine));
1656 ret.push_back(Pair("iscompressed", isCompressed));
1658 Object detail = boost::apply_visitor(DescribeAddressVisitor(), dest);
1659 ret.insert(ret.end(), detail.begin(), detail.end());
1661 if (pwalletMain->mapAddressBook.count(dest))
1662 ret.push_back(Pair("account", pwalletMain->mapAddressBook[dest]));
1667 // reserve balance from being staked for network protection
1668 Value reservebalance(const Array& params, bool fHelp)
1670 if (fHelp || params.size() > 2)
1671 throw runtime_error(
1672 "reservebalance [<reserve> [amount]]\n"
1673 "<reserve> is true or false to turn balance reserve on or off.\n"
1674 "<amount> is a real and rounded to cent.\n"
1675 "Set reserve amount not participating in network protection.\n"
1676 "If no parameters provided current setting is printed.\n");
1678 if (params.size() > 0)
1680 bool fReserve = params[0].get_bool();
1683 if (params.size() == 1)
1684 throw runtime_error("must provide amount to reserve balance.\n");
1685 int64 nAmount = AmountFromValue(params[1]);
1686 nAmount = (nAmount / CENT) * CENT; // round to cent
1688 throw runtime_error("amount cannot be negative.\n");
1689 mapArgs["-reservebalance"] = FormatMoney(nAmount).c_str();
1693 if (params.size() > 1)
1694 throw runtime_error("cannot specify amount to turn off reserve.\n");
1695 mapArgs["-reservebalance"] = "0";
1700 int64 nReserveBalance = 0;
1701 if (mapArgs.count("-reservebalance") && !ParseMoney(mapArgs["-reservebalance"], nReserveBalance))
1702 throw runtime_error("invalid reserve balance amount\n");
1703 result.push_back(Pair("reserve", (nReserveBalance > 0)));
1704 result.push_back(Pair("amount", ValueFromAmount(nReserveBalance)));
1709 // check wallet integrity
1710 Value checkwallet(const Array& params, bool fHelp)
1712 if (fHelp || params.size() > 0)
1713 throw runtime_error(
1715 "Check wallet for integrity.\n");
1718 int64 nBalanceInQuestion;
1719 pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion, true);
1721 if (nMismatchSpent == 0)
1722 result.push_back(Pair("wallet check passed", true));
1725 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
1726 result.push_back(Pair("amount in question", ValueFromAmount(nBalanceInQuestion)));
1733 Value repairwallet(const Array& params, bool fHelp)
1735 if (fHelp || params.size() > 0)
1736 throw runtime_error(
1738 "Repair wallet if checkwallet reports any problem.\n");
1741 int64 nBalanceInQuestion;
1742 pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion);
1744 if (nMismatchSpent == 0)
1745 result.push_back(Pair("wallet check passed", true));
1748 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
1749 result.push_back(Pair("amount affected by repair", ValueFromAmount(nBalanceInQuestion)));
1754 // resend unconfirmed wallet transactions
1755 Value resendtx(const Array& params, bool fHelp)
1757 if (fHelp || params.size() > 1)
1758 throw runtime_error(
1760 "Re-send unconfirmed transactions.\n"
1763 ResendWalletTransactions();
1768 // make a public-private key pair
1769 Value makekeypair(const Array& params, bool fHelp)
1771 if (fHelp || params.size() > 1)
1772 throw runtime_error(
1773 "makekeypair [prefix]\n"
1774 "Make a public/private key pair.\n"
1775 "[prefix] is optional preferred prefix for the public key.\n");
1777 string strPrefix = "";
1778 if (params.size() > 0)
1779 strPrefix = params[0].get_str();
1782 key.MakeNewKey(false);
1784 CPrivKey vchPrivKey = key.GetPrivKey();
1786 result.push_back(Pair("PrivateKey", HexStr<CPrivKey::iterator>(vchPrivKey.begin(), vchPrivKey.end())));
1787 result.push_back(Pair("PublicKey", HexStr(key.GetPubKey().Raw())));