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("unspendable", ValueFromAmount(pwalletMain->GetWatchOnlyBalance())));
78 obj.push_back(Pair("newmint", ValueFromAmount(pwalletMain->GetNewMint())));
79 obj.push_back(Pair("stake", ValueFromAmount(pwalletMain->GetStake())));
80 obj.push_back(Pair("blocks", (int)nBestHeight));
81 obj.push_back(Pair("timeoffset", (boost::int64_t)GetTimeOffset()));
82 obj.push_back(Pair("moneysupply", ValueFromAmount(pindexBest->nMoneySupply)));
83 obj.push_back(Pair("connections", (int)vNodes.size()));
84 obj.push_back(Pair("proxy", (proxy.first.IsValid() ? proxy.first.ToStringIPPort() : string())));
85 obj.push_back(Pair("ip", addrSeenByPeer.ToStringIP()));
87 diff.push_back(Pair("proof-of-work", GetDifficulty()));
88 diff.push_back(Pair("proof-of-stake", GetDifficulty(GetLastBlockIndex(pindexBest, true))));
89 obj.push_back(Pair("difficulty", diff));
91 obj.push_back(Pair("testnet", fTestNet));
92 obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
93 obj.push_back(Pair("keypoolsize", (int)pwalletMain->GetKeyPoolSize()));
94 obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee)));
95 obj.push_back(Pair("mininput", ValueFromAmount(nMinimumInputValue)));
96 if (pwalletMain->IsCrypted())
97 obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime / 1000));
98 obj.push_back(Pair("errors", GetWarnings("statusbar")));
102 Value getnewaddress(const Array& params, bool fHelp)
104 if (fHelp || params.size() > 1)
106 "getnewaddress [account]\n"
107 "Returns a new NovaCoin address for receiving payments. "
108 "If [account] is specified (recommended), it is added to the address book "
109 "so payments received with the address will be credited to [account].");
111 // Parse the account first so we don't generate a key if there's an error
113 if (params.size() > 0)
114 strAccount = AccountFromValue(params[0]);
116 if (!pwalletMain->IsLocked())
117 pwalletMain->TopUpKeyPool();
119 // Generate a new key that is added to wallet
121 if (!pwalletMain->GetKeyFromPool(newKey, false))
122 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
123 CKeyID keyID = newKey.GetID();
125 pwalletMain->SetAddressBookName(keyID, strAccount);
127 return CBitcoinAddress(keyID).ToString();
131 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
133 CWalletDB walletdb(pwalletMain->strWalletFile);
136 walletdb.ReadAccount(strAccount, account);
138 bool bKeyUsed = false;
140 // Check if the current key has been used
141 if (account.vchPubKey.IsValid())
143 CScript scriptPubKey;
144 scriptPubKey.SetDestination(account.vchPubKey.GetID());
145 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
146 it != pwalletMain->mapWallet.end() && account.vchPubKey.IsValid();
149 const CWalletTx& wtx = (*it).second;
150 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
151 if (txout.scriptPubKey == scriptPubKey)
156 // Generate a new key
157 if (!account.vchPubKey.IsValid() || bForceNew || bKeyUsed)
159 if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false))
160 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
162 pwalletMain->SetAddressBookName(account.vchPubKey.GetID(), strAccount);
163 walletdb.WriteAccount(strAccount, account);
166 return CBitcoinAddress(account.vchPubKey.GetID());
169 Value getaccountaddress(const Array& params, bool fHelp)
171 if (fHelp || params.size() != 1)
173 "getaccountaddress <account>\n"
174 "Returns the current NovaCoin address for receiving payments to this account.");
176 // Parse the account first so we don't generate a key if there's an error
177 string strAccount = AccountFromValue(params[0]);
181 ret = GetAccountAddress(strAccount).ToString();
188 Value setaccount(const Array& params, bool fHelp)
190 if (fHelp || params.size() < 1 || params.size() > 2)
192 "setaccount <novacoinaddress> <account>\n"
193 "Sets the account associated with the given address.");
195 CBitcoinAddress address(params[0].get_str());
196 if (!address.IsValid())
197 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
201 if (params.size() > 1)
202 strAccount = AccountFromValue(params[1]);
204 // Detect when changing the account of an address that is the 'unused current key' of another account:
205 if (pwalletMain->mapAddressBook.count(address.Get()))
207 string strOldAccount = pwalletMain->mapAddressBook[address.Get()];
208 if (address == GetAccountAddress(strOldAccount))
209 GetAccountAddress(strOldAccount, true);
212 pwalletMain->SetAddressBookName(address.Get(), strAccount);
218 Value getaccount(const Array& params, bool fHelp)
220 if (fHelp || params.size() != 1)
222 "getaccount <novacoinaddress>\n"
223 "Returns the account associated with the given address.");
225 CBitcoinAddress address(params[0].get_str());
226 if (!address.IsValid())
227 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
230 map<CTxDestination, string>::iterator mi = pwalletMain->mapAddressBook.find(address.Get());
231 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
232 strAccount = (*mi).second;
237 Value getaddressesbyaccount(const Array& params, bool fHelp)
239 if (fHelp || params.size() != 1)
241 "getaddressesbyaccount <account>\n"
242 "Returns the list of addresses for the given account.");
244 string strAccount = AccountFromValue(params[0]);
246 // Find all addresses that have the given account
248 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
250 const CBitcoinAddress& address = item.first;
251 const string& strName = item.second;
252 if (strName == strAccount)
253 ret.push_back(address.ToString());
258 Value sendtoaddress(const Array& params, bool fHelp)
260 if (fHelp || params.size() < 2 || params.size() > 4)
262 "sendtoaddress <novacoinaddress> <amount> [comment] [comment-to]\n"
263 "<amount> is a real and is rounded to the nearest " + FormatMoney(MIN_TXOUT_AMOUNT)
264 + HelpRequiringPassphrase());
266 CBitcoinAddress address(params[0].get_str());
267 if (!address.IsValid())
268 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
271 int64 nAmount = AmountFromValue(params[1]);
273 if (nAmount < MIN_TXOUT_AMOUNT)
274 throw JSONRPCError(-101, "Send amount too small");
278 if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
279 wtx.mapValue["comment"] = params[2].get_str();
280 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
281 wtx.mapValue["to"] = params[3].get_str();
283 if (pwalletMain->IsLocked())
284 throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
286 string strError = pwalletMain->SendMoneyToDestination(address.Get(), nAmount, wtx);
288 throw JSONRPCError(RPC_WALLET_ERROR, strError);
290 return wtx.GetHash().GetHex();
293 Value listaddressgroupings(const Array& params, bool fHelp)
297 "listaddressgroupings\n"
298 "Lists groups of addresses which have had their common ownership\n"
299 "made public by common use as inputs or as the resulting change\n"
300 "in past transactions");
303 map<CTxDestination, int64> balances = pwalletMain->GetAddressBalances();
304 BOOST_FOREACH(set<CTxDestination> grouping, pwalletMain->GetAddressGroupings())
307 BOOST_FOREACH(CTxDestination address, grouping)
310 addressInfo.push_back(CBitcoinAddress(address).ToString());
311 addressInfo.push_back(ValueFromAmount(balances[address]));
313 LOCK(pwalletMain->cs_wallet);
314 if (pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get()) != pwalletMain->mapAddressBook.end())
315 addressInfo.push_back(pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get())->second);
317 jsonGrouping.push_back(addressInfo);
319 jsonGroupings.push_back(jsonGrouping);
321 return jsonGroupings;
324 Value signmessage(const Array& params, bool fHelp)
326 if (fHelp || params.size() != 2)
328 "signmessage <novacoinaddress> <message>\n"
329 "Sign a message with the private key of an address");
331 EnsureWalletIsUnlocked();
333 string strAddress = params[0].get_str();
334 string strMessage = params[1].get_str();
336 CBitcoinAddress addr(strAddress);
338 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
341 if (!addr.GetKeyID(keyID))
342 throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
345 if (!pwalletMain->GetKey(keyID, key))
346 throw JSONRPCError(RPC_WALLET_ERROR, "Private key not available");
348 CDataStream ss(SER_GETHASH, 0);
349 ss << strMessageMagic;
352 vector<unsigned char> vchSig;
353 if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
354 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed");
356 return EncodeBase64(&vchSig[0], vchSig.size());
359 Value verifymessage(const Array& params, bool fHelp)
361 if (fHelp || params.size() != 3)
363 "verifymessage <novacoinaddress> <signature> <message>\n"
364 "Verify a signed message");
366 string strAddress = params[0].get_str();
367 string strSign = params[1].get_str();
368 string strMessage = params[2].get_str();
370 CBitcoinAddress addr(strAddress);
372 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
375 if (!addr.GetKeyID(keyID))
376 throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
378 bool fInvalid = false;
379 vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
382 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Malformed base64 encoding");
384 CDataStream ss(SER_GETHASH, 0);
385 ss << strMessageMagic;
389 if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
392 return (key.GetPubKey().GetID() == keyID);
396 Value getreceivedbyaddress(const Array& params, bool fHelp)
398 if (fHelp || params.size() < 1 || params.size() > 2)
400 "getreceivedbyaddress <novacoinaddress> [minconf=1]\n"
401 "Returns the total amount received by <novacoinaddress> in transactions with at least [minconf] confirmations.");
404 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
405 CScript scriptPubKey;
406 if (!address.IsValid())
407 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
408 scriptPubKey.SetDestination(address.Get());
409 if (!IsMine(*pwalletMain,scriptPubKey))
412 // Minimum confirmations
414 if (params.size() > 1)
415 nMinDepth = params[1].get_int();
419 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
421 const CWalletTx& wtx = (*it).second;
422 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
425 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
426 if (txout.scriptPubKey == scriptPubKey)
427 if (wtx.GetDepthInMainChain() >= nMinDepth)
428 nAmount += txout.nValue;
431 return ValueFromAmount(nAmount);
435 void GetAccountAddresses(string strAccount, set<CTxDestination>& setAddress)
437 BOOST_FOREACH(const PAIRTYPE(CTxDestination, string)& item, pwalletMain->mapAddressBook)
439 const CTxDestination& address = item.first;
440 const string& strName = item.second;
441 if (strName == strAccount)
442 setAddress.insert(address);
446 Value getreceivedbyaccount(const Array& params, bool fHelp)
448 if (fHelp || params.size() < 1 || params.size() > 2)
450 "getreceivedbyaccount <account> [minconf=1]\n"
451 "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
453 // Minimum confirmations
455 if (params.size() > 1)
456 nMinDepth = params[1].get_int();
458 // Get the set of pub keys assigned to account
459 string strAccount = AccountFromValue(params[0]);
460 set<CTxDestination> setAddress;
461 GetAccountAddresses(strAccount, setAddress);
465 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
467 const CWalletTx& wtx = (*it).second;
468 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
471 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
473 CTxDestination address;
474 if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*pwalletMain, address) && setAddress.count(address))
475 if (wtx.GetDepthInMainChain() >= nMinDepth)
476 nAmount += txout.nValue;
480 return (double)nAmount / (double)COIN;
484 int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth, const isminefilter& filter)
488 // Tally wallet transactions
489 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
491 const CWalletTx& wtx = (*it).second;
495 int64 nGenerated, nReceived, nSent, nFee;
496 wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee, filter);
498 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
499 nBalance += nReceived;
500 nBalance += nGenerated - nSent - nFee;
503 // Tally internal accounting entries
504 nBalance += walletdb.GetAccountCreditDebit(strAccount);
509 int64 GetAccountBalance(const string& strAccount, int nMinDepth, const isminefilter& filter)
511 CWalletDB walletdb(pwalletMain->strWalletFile);
512 return GetAccountBalance(walletdb, strAccount, nMinDepth, filter);
516 Value getbalance(const Array& params, bool fHelp)
518 if (fHelp || params.size() > 2)
520 "getbalance [account] [minconf=1] [watchonly=0]\n"
521 "If [account] is not specified, returns the server's total available balance.\n"
522 "If [account] is specified, returns the balance in the account.\n"
523 "if [includeWatchonly] is specified, include balance in watchonly addresses (see 'importaddress').");
525 if (params.size() == 0)
526 return ValueFromAmount(pwalletMain->GetBalance());
529 if (params.size() > 1)
530 nMinDepth = params[1].get_int();
531 isminefilter filter = MINE_SPENDABLE;
532 if(params.size() > 2)
533 if(params[2].get_bool())
534 filter = filter | MINE_WATCH_ONLY;
536 if (params[0].get_str() == "*") {
537 // Calculate total balance a different way from GetBalance()
538 // (GetBalance() sums up all unspent TxOuts)
539 // getbalance and getbalance '*' 0 should return the same number.
541 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
543 const CWalletTx& wtx = (*it).second;
544 if (!wtx.IsTrusted())
547 int64 allGeneratedImmature, allGeneratedMature, allFee;
548 allGeneratedImmature = allGeneratedMature = allFee = 0;
550 string strSentAccount;
551 list<pair<CTxDestination, int64> > listReceived;
552 list<pair<CTxDestination, int64> > listSent;
553 wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount, filter);
554 if (wtx.GetDepthInMainChain() >= nMinDepth)
556 BOOST_FOREACH(const PAIRTYPE(CTxDestination,int64)& r, listReceived)
557 nBalance += r.second;
559 BOOST_FOREACH(const PAIRTYPE(CTxDestination,int64)& r, listSent)
560 nBalance -= r.second;
562 nBalance += allGeneratedMature;
564 return ValueFromAmount(nBalance);
567 string strAccount = AccountFromValue(params[0]);
569 int64 nBalance = GetAccountBalance(strAccount, nMinDepth, filter);
571 return ValueFromAmount(nBalance);
575 Value movecmd(const Array& params, bool fHelp)
577 if (fHelp || params.size() < 3 || params.size() > 5)
579 "move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
580 "Move from one account in your wallet to another.");
582 string strFrom = AccountFromValue(params[0]);
583 string strTo = AccountFromValue(params[1]);
584 int64 nAmount = AmountFromValue(params[2]);
586 if (nAmount < MIN_TXOUT_AMOUNT)
587 throw JSONRPCError(-101, "Send amount too small");
589 if (params.size() > 3)
590 // unused parameter, used to be nMinDepth, keep type-checking it though
591 (void)params[3].get_int();
593 if (params.size() > 4)
594 strComment = params[4].get_str();
596 CWalletDB walletdb(pwalletMain->strWalletFile);
597 if (!walletdb.TxnBegin())
598 throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
600 int64 nNow = GetAdjustedTime();
603 CAccountingEntry debit;
604 debit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
605 debit.strAccount = strFrom;
606 debit.nCreditDebit = -nAmount;
608 debit.strOtherAccount = strTo;
609 debit.strComment = strComment;
610 walletdb.WriteAccountingEntry(debit);
613 CAccountingEntry credit;
614 credit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
615 credit.strAccount = strTo;
616 credit.nCreditDebit = nAmount;
618 credit.strOtherAccount = strFrom;
619 credit.strComment = strComment;
620 walletdb.WriteAccountingEntry(credit);
622 if (!walletdb.TxnCommit())
623 throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
629 Value sendfrom(const Array& params, bool fHelp)
631 if (fHelp || params.size() < 3 || params.size() > 6)
633 "sendfrom <fromaccount> <tonovacoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
634 "<amount> is a real and is rounded to the nearest " + FormatMoney(MIN_TXOUT_AMOUNT)
635 + HelpRequiringPassphrase());
637 string strAccount = AccountFromValue(params[0]);
638 CBitcoinAddress address(params[1].get_str());
639 if (!address.IsValid())
640 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
641 int64 nAmount = AmountFromValue(params[2]);
643 if (nAmount < MIN_TXOUT_AMOUNT)
644 throw JSONRPCError(-101, "Send amount too small");
647 if (params.size() > 3)
648 nMinDepth = params[3].get_int();
651 wtx.strFromAccount = strAccount;
652 if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
653 wtx.mapValue["comment"] = params[4].get_str();
654 if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
655 wtx.mapValue["to"] = params[5].get_str();
657 EnsureWalletIsUnlocked();
660 int64 nBalance = GetAccountBalance(strAccount, nMinDepth, MINE_SPENDABLE);
661 if (nAmount > nBalance)
662 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
665 string strError = pwalletMain->SendMoneyToDestination(address.Get(), nAmount, wtx);
667 throw JSONRPCError(RPC_WALLET_ERROR, strError);
669 return wtx.GetHash().GetHex();
673 Value sendmany(const Array& params, bool fHelp)
675 if (fHelp || params.size() < 2 || params.size() > 4)
677 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
678 "amounts are double-precision floating point numbers"
679 + HelpRequiringPassphrase());
681 string strAccount = AccountFromValue(params[0]);
682 Object sendTo = params[1].get_obj();
684 if (params.size() > 2)
685 nMinDepth = params[2].get_int();
688 wtx.strFromAccount = strAccount;
689 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
690 wtx.mapValue["comment"] = params[3].get_str();
692 set<CBitcoinAddress> setAddress;
693 vector<pair<CScript, int64> > vecSend;
695 int64 totalAmount = 0;
696 BOOST_FOREACH(const Pair& s, sendTo)
698 CBitcoinAddress address(s.name_);
699 if (!address.IsValid())
700 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid NovaCoin address: ")+s.name_);
702 if (setAddress.count(address))
703 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+s.name_);
704 setAddress.insert(address);
706 CScript scriptPubKey;
707 scriptPubKey.SetDestination(address.Get());
708 int64 nAmount = AmountFromValue(s.value_);
710 if (nAmount < MIN_TXOUT_AMOUNT)
711 throw JSONRPCError(-101, "Send amount too small");
713 totalAmount += nAmount;
715 vecSend.push_back(make_pair(scriptPubKey, nAmount));
718 EnsureWalletIsUnlocked();
721 int64 nBalance = GetAccountBalance(strAccount, nMinDepth, MINE_SPENDABLE);
722 if (totalAmount > nBalance)
723 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
726 CReserveKey keyChange(pwalletMain);
727 int64 nFeeRequired = 0;
728 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
731 int64 nTotal = pwalletMain->GetBalance(), nWatchOnly = pwalletMain->GetWatchOnlyBalance();
732 if (totalAmount + nFeeRequired > nTotal - nWatchOnly)
733 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds");
734 throw JSONRPCError(RPC_WALLET_ERROR, "Transaction creation failed");
736 if (!pwalletMain->CommitTransaction(wtx, keyChange))
737 throw JSONRPCError(RPC_WALLET_ERROR, "Transaction commit failed");
739 return wtx.GetHash().GetHex();
742 Value addmultisigaddress(const Array& params, bool fHelp)
744 if (fHelp || params.size() < 2 || params.size() > 3)
746 string msg = "addmultisigaddress <nrequired> <'[\"key\",\"key\"]'> [account]\n"
747 "Add a nrequired-to-sign multisignature address to the wallet\"\n"
748 "each key is a NovaCoin address or hex-encoded public key\n"
749 "If [account] is specified, assign address to [account].";
750 throw runtime_error(msg);
753 int nRequired = params[0].get_int();
754 const Array& keys = params[1].get_array();
756 if (params.size() > 2)
757 strAccount = AccountFromValue(params[2]);
759 // Gather public keys
761 throw runtime_error("a multisignature address must require at least one key to redeem");
762 if ((int)keys.size() < nRequired)
764 strprintf("not enough keys supplied "
765 "(got %"PRIszu" keys, but need at least %d to redeem)", keys.size(), nRequired));
766 std::vector<CKey> pubkeys;
767 pubkeys.resize(keys.size());
768 for (unsigned int i = 0; i < keys.size(); i++)
770 const std::string& ks = keys[i].get_str();
772 // Case 1: Bitcoin address and we have full public key:
773 CBitcoinAddress address(ks);
774 if (address.IsValid())
777 if (!address.GetKeyID(keyID))
779 strprintf("%s does not refer to a key",ks.c_str()));
781 if (!pwalletMain->GetPubKey(keyID, vchPubKey))
783 strprintf("no full public key for address %s",ks.c_str()));
784 if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey))
785 throw runtime_error(" Invalid public key: "+ks);
788 // Case 2: hex public key
791 CPubKey vchPubKey(ParseHex(ks));
792 if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey))
793 throw runtime_error(" Invalid public key: "+ks);
797 throw runtime_error(" Invalid public key: "+ks);
801 // Construct using pay-to-script-hash:
803 inner.SetMultisig(nRequired, pubkeys);
804 CScriptID innerID = inner.GetID();
805 pwalletMain->AddCScript(inner);
807 pwalletMain->SetAddressBookName(innerID, strAccount);
808 return CBitcoinAddress(innerID).ToString();
811 Value addredeemscript(const Array& params, bool fHelp)
813 if (fHelp || params.size() < 1 || params.size() > 2)
815 string msg = "addredeemscript <redeemScript> [account]\n"
816 "Add a P2SH address with a specified redeemScript to the wallet.\n"
817 "If [account] is specified, assign address to [account].";
818 throw runtime_error(msg);
822 if (params.size() > 1)
823 strAccount = AccountFromValue(params[1]);
825 // Construct using pay-to-script-hash:
826 vector<unsigned char> innerData = ParseHexV(params[0], "redeemScript");
827 CScript inner(innerData.begin(), innerData.end());
828 CScriptID innerID = inner.GetID();
829 pwalletMain->AddCScript(inner);
831 pwalletMain->SetAddressBookName(innerID, strAccount);
832 return CBitcoinAddress(innerID).ToString();
842 nConf = std::numeric_limits<int>::max();
846 Value ListReceived(const Array& params, bool fByAccounts)
848 // Minimum confirmations
850 if (params.size() > 0)
851 nMinDepth = params[0].get_int();
853 // Whether to include empty accounts
854 bool fIncludeEmpty = false;
855 if (params.size() > 1)
856 fIncludeEmpty = params[1].get_bool();
859 map<CBitcoinAddress, tallyitem> mapTally;
860 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
862 const CWalletTx& wtx = (*it).second;
864 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
867 int nDepth = wtx.GetDepthInMainChain();
868 if (nDepth < nMinDepth)
871 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
873 CTxDestination address;
874 if (!ExtractDestination(txout.scriptPubKey, address) || !IsMine(*pwalletMain, address))
877 tallyitem& item = mapTally[address];
878 item.nAmount += txout.nValue;
879 item.nConf = min(item.nConf, nDepth);
885 map<string, tallyitem> mapAccountTally;
886 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
888 const CBitcoinAddress& address = item.first;
889 const string& strAccount = item.second;
890 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
891 if (it == mapTally.end() && !fIncludeEmpty)
895 int nConf = std::numeric_limits<int>::max();
896 if (it != mapTally.end())
898 nAmount = (*it).second.nAmount;
899 nConf = (*it).second.nConf;
904 tallyitem& item = mapAccountTally[strAccount];
905 item.nAmount += nAmount;
906 item.nConf = min(item.nConf, nConf);
911 obj.push_back(Pair("address", address.ToString()));
912 obj.push_back(Pair("account", strAccount));
913 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
914 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
921 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
923 int64 nAmount = (*it).second.nAmount;
924 int nConf = (*it).second.nConf;
926 obj.push_back(Pair("account", (*it).first));
927 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
928 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
936 Value listreceivedbyaddress(const Array& params, bool fHelp)
938 if (fHelp || params.size() > 2)
940 "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
941 "[minconf] is the minimum number of confirmations before payments are included.\n"
942 "[includeempty] whether to include addresses that haven't received any payments.\n"
943 "Returns an array of objects containing:\n"
944 " \"address\" : receiving address\n"
945 " \"account\" : the account of the receiving address\n"
946 " \"amount\" : total amount received by the address\n"
947 " \"confirmations\" : number of confirmations of the most recent transaction included");
949 return ListReceived(params, false);
952 Value listreceivedbyaccount(const Array& params, bool fHelp)
954 if (fHelp || params.size() > 2)
956 "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
957 "[minconf] is the minimum number of confirmations before payments are included.\n"
958 "[includeempty] whether to include accounts that haven't received any payments.\n"
959 "Returns an array of objects containing:\n"
960 " \"account\" : the account of the receiving addresses\n"
961 " \"amount\" : total amount received by addresses with this account\n"
962 " \"confirmations\" : number of confirmations of the most recent transaction included");
964 return ListReceived(params, true);
967 static void MaybePushAddress(Object & entry, const CTxDestination &dest)
969 CBitcoinAddress addr;
971 entry.push_back(Pair("address", addr.ToString()));
974 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret, const isminefilter& filter)
976 int64 nGeneratedImmature, nGeneratedMature, nFee;
977 string strSentAccount;
978 list<pair<CTxDestination, int64> > listReceived;
979 list<pair<CTxDestination, int64> > listSent;
981 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount, filter);
983 bool fAllAccounts = (strAccount == string("*"));
984 bool involvesWatchonly = wtx.IsFromMe(MINE_WATCH_ONLY);
986 // Generated blocks assigned to account ""
987 if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
990 entry.push_back(Pair("account", string("")));
991 if (nGeneratedImmature)
993 entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
994 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
998 entry.push_back(Pair("category", "generate"));
999 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
1002 WalletTxToJSON(wtx, entry);
1003 ret.push_back(entry);
1007 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1009 BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& s, listSent)
1012 entry.push_back(Pair("account", strSentAccount));
1013 if(involvesWatchonly || (::IsMine(*pwalletMain, s.first) & MINE_WATCH_ONLY))
1014 entry.push_back(Pair("involvesWatchonly", true));
1015 MaybePushAddress(entry, s.first);
1017 if (wtx.GetDepthInMainChain() < 0) {
1018 entry.push_back(Pair("category", "conflicted"));
1020 entry.push_back(Pair("category", "send"));
1023 entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1024 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1026 WalletTxToJSON(wtx, entry);
1027 ret.push_back(entry);
1032 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1034 BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& r, listReceived)
1037 if (pwalletMain->mapAddressBook.count(r.first))
1038 account = pwalletMain->mapAddressBook[r.first];
1039 if (fAllAccounts || (account == strAccount))
1042 entry.push_back(Pair("account", account));
1043 if(involvesWatchonly || (::IsMine(*pwalletMain, r.first) & MINE_WATCH_ONLY))
1044 entry.push_back(Pair("involvesWatchonly", true));
1045 MaybePushAddress(entry, r.first);
1046 if (wtx.IsCoinBase())
1048 if (wtx.GetDepthInMainChain() < 1)
1049 entry.push_back(Pair("category", "orphan"));
1050 else if (wtx.GetBlocksToMaturity() > 0)
1051 entry.push_back(Pair("category", "immature"));
1053 entry.push_back(Pair("category", "generate"));
1056 entry.push_back(Pair("category", "receive"));
1057 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1059 WalletTxToJSON(wtx, entry);
1060 ret.push_back(entry);
1066 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1068 bool fAllAccounts = (strAccount == string("*"));
1070 if (fAllAccounts || acentry.strAccount == strAccount)
1073 entry.push_back(Pair("account", acentry.strAccount));
1074 entry.push_back(Pair("category", "move"));
1075 entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
1076 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1077 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1078 entry.push_back(Pair("comment", acentry.strComment));
1079 ret.push_back(entry);
1083 Value listtransactions(const Array& params, bool fHelp)
1085 if (fHelp || params.size() > 3)
1086 throw runtime_error(
1087 "listtransactions [account] [count=10] [from=0]\n"
1088 "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1090 string strAccount = "*";
1091 if (params.size() > 0)
1092 strAccount = params[0].get_str();
1094 if (params.size() > 1)
1095 nCount = params[1].get_int();
1097 if (params.size() > 2)
1098 nFrom = params[2].get_int();
1100 isminefilter filter = MINE_SPENDABLE;
1101 if(params.size() > 3)
1102 if(params[3].get_bool())
1103 filter = filter | MINE_WATCH_ONLY;
1106 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count");
1108 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative from");
1112 std::list<CAccountingEntry> acentries;
1113 CWallet::TxItems txOrdered = pwalletMain->OrderedTxItems(acentries, strAccount);
1115 // iterate backwards until we have nCount items to return:
1116 for (CWallet::TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
1118 CWalletTx *const pwtx = (*it).second.first;
1120 ListTransactions(*pwtx, strAccount, 0, true, ret, filter);
1121 CAccountingEntry *const pacentry = (*it).second.second;
1123 AcentryToJSON(*pacentry, strAccount, ret);
1125 if ((int)ret.size() >= (nCount+nFrom)) break;
1127 // ret is newest to oldest
1129 if (nFrom > (int)ret.size())
1131 if ((nFrom + nCount) > (int)ret.size())
1132 nCount = ret.size() - nFrom;
1133 Array::iterator first = ret.begin();
1134 std::advance(first, nFrom);
1135 Array::iterator last = ret.begin();
1136 std::advance(last, nFrom+nCount);
1138 if (last != ret.end()) ret.erase(last, ret.end());
1139 if (first != ret.begin()) ret.erase(ret.begin(), first);
1141 std::reverse(ret.begin(), ret.end()); // Return oldest to newest
1146 Value listaccounts(const Array& params, bool fHelp)
1148 if (fHelp || params.size() > 1)
1149 throw runtime_error(
1150 "listaccounts [minconf=1]\n"
1151 "Returns Object that has account names as keys, account balances as values.");
1154 if (params.size() > 0)
1155 nMinDepth = params[0].get_int();
1157 isminefilter includeWatchonly = MINE_SPENDABLE;
1158 if(params.size() > 1)
1159 if(params[1].get_bool())
1160 includeWatchonly = includeWatchonly | MINE_WATCH_ONLY;
1163 map<string, int64> mapAccountBalances;
1164 BOOST_FOREACH(const PAIRTYPE(CTxDestination, string)& entry, pwalletMain->mapAddressBook) {
1165 if (IsMine(*pwalletMain, entry.first)) // This address belongs to me
1166 mapAccountBalances[entry.second] = 0;
1169 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1171 const CWalletTx& wtx = (*it).second;
1172 int64 nGeneratedImmature, nGeneratedMature, nFee;
1173 string strSentAccount;
1174 list<pair<CTxDestination, int64> > listReceived;
1175 list<pair<CTxDestination, int64> > listSent;
1176 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount, includeWatchonly);
1177 mapAccountBalances[strSentAccount] -= nFee;
1178 BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& s, listSent)
1179 mapAccountBalances[strSentAccount] -= s.second;
1180 if (wtx.GetDepthInMainChain() >= nMinDepth)
1182 mapAccountBalances[""] += nGeneratedMature;
1183 BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& r, listReceived)
1184 if (pwalletMain->mapAddressBook.count(r.first))
1185 mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1187 mapAccountBalances[""] += r.second;
1191 list<CAccountingEntry> acentries;
1192 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1193 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1194 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1197 BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) {
1198 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1203 Value listsinceblock(const Array& params, bool fHelp)
1206 throw runtime_error(
1207 "listsinceblock [blockhash] [target-confirmations]\n"
1208 "Get all transactions in blocks since block [blockhash], or all transactions if omitted");
1210 CBlockIndex *pindex = NULL;
1211 int target_confirms = 1;
1212 isminefilter filter = MINE_SPENDABLE;
1214 if (params.size() > 0)
1216 uint256 blockId = 0;
1218 blockId.SetHex(params[0].get_str());
1219 pindex = CBlockLocator(blockId).GetBlockIndex();
1222 if (params.size() > 1)
1224 target_confirms = params[1].get_int();
1226 if (target_confirms < 1)
1227 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter");
1230 if(params.size() > 2)
1231 if(params[2].get_bool())
1232 filter = filter | MINE_WATCH_ONLY;
1234 int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
1238 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1240 CWalletTx tx = (*it).second;
1242 if (depth == -1 || tx.GetDepthInMainChain() < depth)
1243 ListTransactions(tx, "*", 0, true, transactions, filter);
1248 if (target_confirms == 1)
1250 lastblock = hashBestChain;
1254 int target_height = pindexBest->nHeight + 1 - target_confirms;
1257 for (block = pindexBest;
1258 block && block->nHeight > target_height;
1259 block = block->pprev) { }
1261 lastblock = block ? block->GetBlockHash() : 0;
1265 ret.push_back(Pair("transactions", transactions));
1266 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1271 Value gettransaction(const Array& params, bool fHelp)
1273 if (fHelp || params.size() != 1)
1274 throw runtime_error(
1275 "gettransaction <txid>\n"
1276 "Get detailed information about <txid>");
1279 hash.SetHex(params[0].get_str());
1281 isminefilter filter = MINE_SPENDABLE;
1282 if(params.size() > 1)
1283 if(params[1].get_bool())
1284 filter = filter | MINE_WATCH_ONLY;
1288 if (pwalletMain->mapWallet.count(hash))
1290 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1292 TxToJSON(wtx, 0, entry);
1294 int64 nCredit = wtx.GetCredit(filter);
1295 int64 nDebit = wtx.GetDebit(filter);
1296 int64 nNet = nCredit - nDebit;
1297 int64 nFee = (wtx.IsFromMe(filter) ? wtx.GetValueOut() - nDebit : 0);
1299 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1300 if (wtx.IsFromMe(filter))
1301 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1303 WalletTxToJSON(wtx, entry);
1306 ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details, filter);
1307 entry.push_back(Pair("details", details));
1312 uint256 hashBlock = 0;
1313 if (GetTransaction(hash, tx, hashBlock))
1315 TxToJSON(tx, 0, entry);
1317 entry.push_back(Pair("confirmations", 0));
1320 entry.push_back(Pair("blockhash", hashBlock.GetHex()));
1321 map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
1322 if (mi != mapBlockIndex.end() && (*mi).second)
1324 CBlockIndex* pindex = (*mi).second;
1325 if (pindex->IsInMainChain())
1326 entry.push_back(Pair("confirmations", 1 + nBestHeight - pindex->nHeight));
1328 entry.push_back(Pair("confirmations", 0));
1333 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction");
1340 Value backupwallet(const Array& params, bool fHelp)
1342 if (fHelp || params.size() != 1)
1343 throw runtime_error(
1344 "backupwallet <destination>\n"
1345 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1347 string strDest = params[0].get_str();
1348 if (!BackupWallet(*pwalletMain, strDest))
1349 throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!");
1355 Value keypoolrefill(const Array& params, bool fHelp)
1357 if (fHelp || params.size() > 1)
1358 throw runtime_error(
1359 "keypoolrefill [new-size]\n"
1360 "Fills the keypool."
1361 + HelpRequiringPassphrase());
1363 unsigned int nSize = max(GetArg("-keypool", 100), 0LL);
1364 if (params.size() > 0) {
1365 if (params[0].get_int() < 0)
1366 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size");
1367 nSize = (unsigned int) params[0].get_int();
1370 EnsureWalletIsUnlocked();
1372 pwalletMain->TopUpKeyPool(nSize);
1374 if (pwalletMain->GetKeyPoolSize() < nSize)
1375 throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool.");
1381 void ThreadTopUpKeyPool(void* parg)
1383 // Make this thread recognisable as the key-topping-up thread
1384 RenameThread("novacoin-key-top");
1386 pwalletMain->TopUpKeyPool();
1389 void ThreadCleanWalletPassphrase(void* parg)
1391 // Make this thread recognisable as the wallet relocking thread
1392 RenameThread("novacoin-lock-wa");
1394 int64 nMyWakeTime = GetTimeMillis() + *((int64*)parg) * 1000;
1396 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1398 if (nWalletUnlockTime == 0)
1400 nWalletUnlockTime = nMyWakeTime;
1404 if (nWalletUnlockTime==0)
1406 int64 nToSleep = nWalletUnlockTime - GetTimeMillis();
1410 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1412 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1416 if (nWalletUnlockTime)
1418 nWalletUnlockTime = 0;
1419 pwalletMain->Lock();
1424 if (nWalletUnlockTime < nMyWakeTime)
1425 nWalletUnlockTime = nMyWakeTime;
1428 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1430 delete (int64*)parg;
1433 Value walletpassphrase(const Array& params, bool fHelp)
1435 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 3))
1436 throw runtime_error(
1437 "walletpassphrase <passphrase> <timeout> [mintonly]\n"
1438 "Stores the wallet decryption key in memory for <timeout> seconds.\n"
1439 "mintonly is optional true/false allowing only block minting.");
1442 if (!pwalletMain->IsCrypted())
1443 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1445 if (!pwalletMain->IsLocked())
1446 throw JSONRPCError(RPC_WALLET_ALREADY_UNLOCKED, "Error: Wallet is already unlocked, use walletlock first if need to change unlock settings.");
1447 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1448 SecureString strWalletPass;
1449 strWalletPass.reserve(100);
1450 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1451 // Alternately, find a way to make params[0] mlock()'d to begin with.
1452 strWalletPass = params[0].get_str().c_str();
1454 if (strWalletPass.length() > 0)
1456 if (!pwalletMain->Unlock(strWalletPass))
1457 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
1460 throw runtime_error(
1461 "walletpassphrase <passphrase> <timeout>\n"
1462 "Stores the wallet decryption key in memory for <timeout> seconds.");
1464 NewThread(ThreadTopUpKeyPool, NULL);
1465 int64* pnSleepTime = new int64(params[1].get_int64());
1466 NewThread(ThreadCleanWalletPassphrase, pnSleepTime);
1468 // ppcoin: if user OS account compromised prevent trivial sendmoney commands
1469 if (params.size() > 2)
1470 fWalletUnlockMintOnly = params[2].get_bool();
1472 fWalletUnlockMintOnly = false;
1478 Value walletpassphrasechange(const Array& params, bool fHelp)
1480 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1481 throw runtime_error(
1482 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1483 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1486 if (!pwalletMain->IsCrypted())
1487 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1489 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1490 // Alternately, find a way to make params[0] mlock()'d to begin with.
1491 SecureString strOldWalletPass;
1492 strOldWalletPass.reserve(100);
1493 strOldWalletPass = params[0].get_str().c_str();
1495 SecureString strNewWalletPass;
1496 strNewWalletPass.reserve(100);
1497 strNewWalletPass = params[1].get_str().c_str();
1499 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1500 throw runtime_error(
1501 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1502 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1504 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1505 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
1511 Value walletlock(const Array& params, bool fHelp)
1513 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1514 throw runtime_error(
1516 "Removes the wallet encryption key from memory, locking the wallet.\n"
1517 "After calling this method, you will need to call walletpassphrase again\n"
1518 "before being able to call any methods which require the wallet to be unlocked.");
1521 if (!pwalletMain->IsCrypted())
1522 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletlock was called.");
1525 LOCK(cs_nWalletUnlockTime);
1526 pwalletMain->Lock();
1527 nWalletUnlockTime = 0;
1534 Value encryptwallet(const Array& params, bool fHelp)
1536 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1537 throw runtime_error(
1538 "encryptwallet <passphrase>\n"
1539 "Encrypts the wallet with <passphrase>.");
1542 if (pwalletMain->IsCrypted())
1543 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an encrypted wallet, but encryptwallet was called.");
1545 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1546 // Alternately, find a way to make params[0] mlock()'d to begin with.
1547 SecureString strWalletPass;
1548 strWalletPass.reserve(100);
1549 strWalletPass = params[0].get_str().c_str();
1551 if (strWalletPass.length() < 1)
1552 throw runtime_error(
1553 "encryptwallet <passphrase>\n"
1554 "Encrypts the wallet with <passphrase>.");
1556 if (!pwalletMain->EncryptWallet(strWalletPass))
1557 throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: Failed to encrypt the wallet.");
1559 // BDB seems to have a bad habit of writing old data into
1560 // slack space in .dat files; that is bad if the old data is
1561 // unencrypted private keys. So:
1563 return "wallet encrypted; NovaCoin server stopping, restart to run with encrypted wallet. The keypool has been flushed, you need to make a new backup.";
1566 class DescribeAddressVisitor : public boost::static_visitor<Object>
1571 DescribeAddressVisitor(isminetype mineIn) : mine(mineIn) {}
1573 Object operator()(const CNoDestination &dest) const { return Object(); }
1574 Object operator()(const CKeyID &keyID) const {
1577 pwalletMain->GetPubKey(keyID, vchPubKey);
1578 obj.push_back(Pair("isscript", false));
1579 if (mine == MINE_SPENDABLE) {
1580 pwalletMain->GetPubKey(keyID, vchPubKey);
1581 obj.push_back(Pair("pubkey", HexStr(vchPubKey.Raw())));
1582 obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed()));
1587 Object operator()(const CScriptID &scriptID) const {
1589 obj.push_back(Pair("isscript", true));
1590 if (mine == MINE_SPENDABLE) {
1592 pwalletMain->GetCScript(scriptID, subscript);
1593 std::vector<CTxDestination> addresses;
1594 txnouttype whichType;
1596 ExtractDestinations(subscript, whichType, addresses, nRequired);
1597 obj.push_back(Pair("script", GetTxnOutputType(whichType)));
1598 obj.push_back(Pair("hex", HexStr(subscript.begin(), subscript.end())));
1600 BOOST_FOREACH(const CTxDestination& addr, addresses)
1601 a.push_back(CBitcoinAddress(addr).ToString());
1602 obj.push_back(Pair("addresses", a));
1603 if (whichType == TX_MULTISIG)
1604 obj.push_back(Pair("sigsrequired", nRequired));
1610 Value validateaddress(const Array& params, bool fHelp)
1612 if (fHelp || params.size() != 1)
1613 throw runtime_error(
1614 "validateaddress <novacoinaddress>\n"
1615 "Return information about <novacoinaddress>.");
1617 CBitcoinAddress address(params[0].get_str());
1618 bool isValid = address.IsValid();
1621 ret.push_back(Pair("isvalid", isValid));
1624 CTxDestination dest = address.Get();
1625 string currentAddress = address.ToString();
1626 ret.push_back(Pair("address", currentAddress));
1627 isminetype mine = pwalletMain ? IsMine(*pwalletMain, dest) : MINE_NO;
1628 ret.push_back(Pair("ismine", mine != MINE_NO));
1629 if (mine != MINE_NO) {
1630 ret.push_back(Pair("watchonly", mine == MINE_WATCH_ONLY));
1631 Object detail = boost::apply_visitor(DescribeAddressVisitor(mine), dest);
1632 ret.insert(ret.end(), detail.begin(), detail.end());
1634 if (pwalletMain->mapAddressBook.count(dest))
1635 ret.push_back(Pair("account", pwalletMain->mapAddressBook[dest]));
1640 // ppcoin: reserve balance from being staked for network protection
1641 Value reservebalance(const Array& params, bool fHelp)
1643 if (fHelp || params.size() > 2)
1644 throw runtime_error(
1645 "reservebalance [<reserve> [amount]]\n"
1646 "<reserve> is true or false to turn balance reserve on or off.\n"
1647 "<amount> is a real and rounded to cent.\n"
1648 "Set reserve amount not participating in network protection.\n"
1649 "If no parameters provided current setting is printed.\n");
1651 if (params.size() > 0)
1653 bool fReserve = params[0].get_bool();
1656 if (params.size() == 1)
1657 throw runtime_error("must provide amount to reserve balance.\n");
1658 int64 nAmount = AmountFromValue(params[1]);
1659 nAmount = (nAmount / CENT) * CENT; // round to cent
1661 throw runtime_error("amount cannot be negative.\n");
1662 mapArgs["-reservebalance"] = FormatMoney(nAmount).c_str();
1666 if (params.size() > 1)
1667 throw runtime_error("cannot specify amount to turn off reserve.\n");
1668 mapArgs["-reservebalance"] = "0";
1673 int64 nReserveBalance = 0;
1674 if (mapArgs.count("-reservebalance") && !ParseMoney(mapArgs["-reservebalance"], nReserveBalance))
1675 throw runtime_error("invalid reserve balance amount\n");
1676 result.push_back(Pair("reserve", (nReserveBalance > 0)));
1677 result.push_back(Pair("amount", ValueFromAmount(nReserveBalance)));
1682 // ppcoin: check wallet integrity
1683 Value checkwallet(const Array& params, bool fHelp)
1685 if (fHelp || params.size() > 0)
1686 throw runtime_error(
1688 "Check wallet for integrity.\n");
1691 int64 nBalanceInQuestion;
1692 pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion, true);
1694 if (nMismatchSpent == 0)
1695 result.push_back(Pair("wallet check passed", true));
1698 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
1699 result.push_back(Pair("amount in question", ValueFromAmount(nBalanceInQuestion)));
1705 // ppcoin: repair wallet
1706 Value repairwallet(const Array& params, bool fHelp)
1708 if (fHelp || params.size() > 0)
1709 throw runtime_error(
1711 "Repair wallet if checkwallet reports any problem.\n");
1714 int64 nBalanceInQuestion;
1715 pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion);
1717 if (nMismatchSpent == 0)
1718 result.push_back(Pair("wallet check passed", true));
1721 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
1722 result.push_back(Pair("amount affected by repair", ValueFromAmount(nBalanceInQuestion)));
1727 // NovaCoin: resend unconfirmed wallet transactions
1728 Value resendtx(const Array& params, bool fHelp)
1730 if (fHelp || params.size() > 1)
1731 throw runtime_error(
1733 "Re-send unconfirmed transactions.\n"
1736 ResendWalletTransactions();
1741 // ppcoin: make a public-private key pair
1742 Value makekeypair(const Array& params, bool fHelp)
1744 if (fHelp || params.size() > 1)
1745 throw runtime_error(
1746 "makekeypair [prefix]\n"
1747 "Make a public/private key pair.\n"
1748 "[prefix] is optional preferred prefix for the public key.\n");
1750 string strPrefix = "";
1751 if (params.size() > 0)
1752 strPrefix = params[0].get_str();
1755 key.MakeNewKey(false);
1757 CPrivKey vchPrivKey = key.GetPrivKey();
1759 result.push_back(Pair("PrivateKey", HexStr<CPrivKey::iterator>(vchPrivKey.begin(), vchPrivKey.end())));
1760 result.push_back(Pair("PublicKey", HexStr(key.GetPubKey().Raw())));