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")));
101 Value getnewaddress(const Array& params, bool fHelp)
103 if (fHelp || params.size() > 1)
105 "getnewaddress [account]\n"
106 "Returns a new NovaCoin address for receiving payments. "
107 "If [account] is specified (recommended), it is added to the address book "
108 "so payments received with the address will be credited to [account].");
110 // Parse the account first so we don't generate a key if there's an error
112 if (params.size() > 0)
113 strAccount = AccountFromValue(params[0]);
115 if (!pwalletMain->IsLocked())
116 pwalletMain->TopUpKeyPool();
118 // Generate a new key that is added to wallet
120 if (!pwalletMain->GetKeyFromPool(newKey, false))
121 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
122 CKeyID keyID = newKey.GetID();
124 pwalletMain->SetAddressBookName(keyID, strAccount);
126 return CBitcoinAddress(keyID).ToString();
130 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
132 CWalletDB walletdb(pwalletMain->strWalletFile);
135 walletdb.ReadAccount(strAccount, account);
137 bool bKeyUsed = false;
139 // Check if the current key has been used
140 if (account.vchPubKey.IsValid())
142 CScript scriptPubKey;
143 scriptPubKey.SetDestination(account.vchPubKey.GetID());
144 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
145 it != pwalletMain->mapWallet.end() && account.vchPubKey.IsValid();
148 const CWalletTx& wtx = (*it).second;
149 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
150 if (txout.scriptPubKey == scriptPubKey)
155 // Generate a new key
156 if (!account.vchPubKey.IsValid() || bForceNew || bKeyUsed)
158 if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false))
159 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
161 pwalletMain->SetAddressBookName(account.vchPubKey.GetID(), strAccount);
162 walletdb.WriteAccount(strAccount, account);
165 return CBitcoinAddress(account.vchPubKey.GetID());
168 Value getaccountaddress(const Array& params, bool fHelp)
170 if (fHelp || params.size() != 1)
172 "getaccountaddress <account>\n"
173 "Returns the current NovaCoin address for receiving payments to this account.");
175 // Parse the account first so we don't generate a key if there's an error
176 string strAccount = AccountFromValue(params[0]);
180 ret = GetAccountAddress(strAccount).ToString();
187 Value setaccount(const Array& params, bool fHelp)
189 if (fHelp || params.size() < 1 || params.size() > 2)
191 "setaccount <novacoinaddress> <account>\n"
192 "Sets the account associated with the given address.");
194 CBitcoinAddress address(params[0].get_str());
195 if (!address.IsValid())
196 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
200 if (params.size() > 1)
201 strAccount = AccountFromValue(params[1]);
203 // Detect when changing the account of an address that is the 'unused current key' of another account:
204 if (pwalletMain->mapAddressBook.count(address.Get()))
206 string strOldAccount = pwalletMain->mapAddressBook[address.Get()];
207 if (address == GetAccountAddress(strOldAccount))
208 GetAccountAddress(strOldAccount, true);
211 pwalletMain->SetAddressBookName(address.Get(), strAccount);
217 Value getaccount(const Array& params, bool fHelp)
219 if (fHelp || params.size() != 1)
221 "getaccount <novacoinaddress>\n"
222 "Returns the account associated with the given address.");
224 CBitcoinAddress address(params[0].get_str());
225 if (!address.IsValid())
226 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
229 map<CTxDestination, string>::iterator mi = pwalletMain->mapAddressBook.find(address.Get());
230 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
231 strAccount = (*mi).second;
236 Value getaddressesbyaccount(const Array& params, bool fHelp)
238 if (fHelp || params.size() != 1)
240 "getaddressesbyaccount <account>\n"
241 "Returns the list of addresses for the given account.");
243 string strAccount = AccountFromValue(params[0]);
245 // Find all addresses that have the given account
247 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
249 const CBitcoinAddress& address = item.first;
250 const string& strName = item.second;
251 if (strName == strAccount)
252 ret.push_back(address.ToString());
257 Value sendtoaddress(const Array& params, bool fHelp)
259 if (fHelp || params.size() < 2 || params.size() > 4)
261 "sendtoaddress <novacoinaddress> <amount> [comment] [comment-to]\n"
262 "<amount> is a real and is rounded to the nearest " + FormatMoney(MIN_TXOUT_AMOUNT)
263 + HelpRequiringPassphrase());
265 CBitcoinAddress address(params[0].get_str());
266 if (!address.IsValid())
267 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
270 int64 nAmount = AmountFromValue(params[1]);
272 if (nAmount < MIN_TXOUT_AMOUNT)
273 throw JSONRPCError(-101, "Send amount too small");
277 if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
278 wtx.mapValue["comment"] = params[2].get_str();
279 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
280 wtx.mapValue["to"] = params[3].get_str();
282 if (pwalletMain->IsLocked())
283 throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
285 string strError = pwalletMain->SendMoneyToDestination(address.Get(), nAmount, wtx);
287 throw JSONRPCError(RPC_WALLET_ERROR, strError);
289 return wtx.GetHash().GetHex();
292 Value listaddressgroupings(const Array& params, bool fHelp)
296 "listaddressgroupings\n"
297 "Lists groups of addresses which have had their common ownership\n"
298 "made public by common use as inputs or as the resulting change\n"
299 "in past transactions");
302 map<CTxDestination, int64> balances = pwalletMain->GetAddressBalances();
303 BOOST_FOREACH(set<CTxDestination> grouping, pwalletMain->GetAddressGroupings())
306 BOOST_FOREACH(CTxDestination address, grouping)
309 addressInfo.push_back(CBitcoinAddress(address).ToString());
310 addressInfo.push_back(ValueFromAmount(balances[address]));
312 LOCK(pwalletMain->cs_wallet);
313 if (pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get()) != pwalletMain->mapAddressBook.end())
314 addressInfo.push_back(pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get())->second);
316 jsonGrouping.push_back(addressInfo);
318 jsonGroupings.push_back(jsonGrouping);
320 return jsonGroupings;
323 Value signmessage(const Array& params, bool fHelp)
325 if (fHelp || params.size() != 2)
327 "signmessage <novacoinaddress> <message>\n"
328 "Sign a message with the private key of an address");
330 EnsureWalletIsUnlocked();
332 string strAddress = params[0].get_str();
333 string strMessage = params[1].get_str();
335 CBitcoinAddress addr(strAddress);
337 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
340 if (!addr.GetKeyID(keyID))
341 throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
344 if (!pwalletMain->GetKey(keyID, key))
345 throw JSONRPCError(RPC_WALLET_ERROR, "Private key not available");
347 CDataStream ss(SER_GETHASH, 0);
348 ss << strMessageMagic;
351 vector<unsigned char> vchSig;
352 if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
353 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed");
355 return EncodeBase64(&vchSig[0], vchSig.size());
358 Value verifymessage(const Array& params, bool fHelp)
360 if (fHelp || params.size() != 3)
362 "verifymessage <novacoinaddress> <signature> <message>\n"
363 "Verify a signed message");
365 string strAddress = params[0].get_str();
366 string strSign = params[1].get_str();
367 string strMessage = params[2].get_str();
369 CBitcoinAddress addr(strAddress);
371 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
374 if (!addr.GetKeyID(keyID))
375 throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
377 bool fInvalid = false;
378 vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
381 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Malformed base64 encoding");
383 CDataStream ss(SER_GETHASH, 0);
384 ss << strMessageMagic;
388 if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
391 return (key.GetPubKey().GetID() == keyID);
395 Value getreceivedbyaddress(const Array& params, bool fHelp)
397 if (fHelp || params.size() < 1 || params.size() > 2)
399 "getreceivedbyaddress <novacoinaddress> [minconf=1]\n"
400 "Returns the total amount received by <novacoinaddress> in transactions with at least [minconf] confirmations.");
403 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
404 CScript scriptPubKey;
405 if (!address.IsValid())
406 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
407 scriptPubKey.SetDestination(address.Get());
408 if (!IsMine(*pwalletMain,scriptPubKey))
411 // Minimum confirmations
413 if (params.size() > 1)
414 nMinDepth = params[1].get_int();
418 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
420 const CWalletTx& wtx = (*it).second;
421 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
424 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
425 if (txout.scriptPubKey == scriptPubKey)
426 if (wtx.GetDepthInMainChain() >= nMinDepth)
427 nAmount += txout.nValue;
430 return ValueFromAmount(nAmount);
434 void GetAccountAddresses(string strAccount, set<CTxDestination>& setAddress)
436 BOOST_FOREACH(const PAIRTYPE(CTxDestination, string)& item, pwalletMain->mapAddressBook)
438 const CTxDestination& address = item.first;
439 const string& strName = item.second;
440 if (strName == strAccount)
441 setAddress.insert(address);
445 Value getreceivedbyaccount(const Array& params, bool fHelp)
447 if (fHelp || params.size() < 1 || params.size() > 2)
449 "getreceivedbyaccount <account> [minconf=1]\n"
450 "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
452 // Minimum confirmations
454 if (params.size() > 1)
455 nMinDepth = params[1].get_int();
457 // Get the set of pub keys assigned to account
458 string strAccount = AccountFromValue(params[0]);
459 set<CTxDestination> setAddress;
460 GetAccountAddresses(strAccount, setAddress);
464 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
466 const CWalletTx& wtx = (*it).second;
467 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
470 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
472 CTxDestination address;
473 if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*pwalletMain, address) && setAddress.count(address))
474 if (wtx.GetDepthInMainChain() >= nMinDepth)
475 nAmount += txout.nValue;
479 return (double)nAmount / (double)COIN;
483 int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
487 // Tally wallet transactions
488 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
490 const CWalletTx& wtx = (*it).second;
494 int64 nGenerated, nReceived, nSent, nFee;
495 wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee);
497 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
498 nBalance += nReceived;
499 nBalance += nGenerated - nSent - nFee;
502 // Tally internal accounting entries
503 nBalance += walletdb.GetAccountCreditDebit(strAccount);
508 int64 GetAccountBalance(const string& strAccount, int nMinDepth)
510 CWalletDB walletdb(pwalletMain->strWalletFile);
511 return GetAccountBalance(walletdb, strAccount, nMinDepth);
515 Value getbalance(const Array& params, bool fHelp)
517 if (fHelp || params.size() > 2)
519 "getbalance [account] [minconf=1]\n"
520 "If [account] is not specified, returns the server's total available balance.\n"
521 "If [account] is specified, returns the balance in the account.");
523 if (params.size() == 0)
524 return ValueFromAmount(pwalletMain->GetBalance());
527 if (params.size() > 1)
528 nMinDepth = params[1].get_int();
530 if (params[0].get_str() == "*") {
531 // Calculate total balance a different way from GetBalance()
532 // (GetBalance() sums up all unspent TxOuts)
533 // getbalance and getbalance '*' 0 should return the same number.
535 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
537 const CWalletTx& wtx = (*it).second;
538 if (!wtx.IsTrusted())
541 int64 allGeneratedImmature, allGeneratedMature, allFee;
542 allGeneratedImmature = allGeneratedMature = allFee = 0;
544 string strSentAccount;
545 list<pair<CTxDestination, int64> > listReceived;
546 list<pair<CTxDestination, int64> > listSent;
547 wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
548 if (wtx.GetDepthInMainChain() >= nMinDepth)
550 BOOST_FOREACH(const PAIRTYPE(CTxDestination,int64)& r, listReceived)
551 nBalance += r.second;
553 BOOST_FOREACH(const PAIRTYPE(CTxDestination,int64)& r, listSent)
554 nBalance -= r.second;
556 nBalance += allGeneratedMature;
558 return ValueFromAmount(nBalance);
561 string strAccount = AccountFromValue(params[0]);
563 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
565 return ValueFromAmount(nBalance);
569 Value movecmd(const Array& params, bool fHelp)
571 if (fHelp || params.size() < 3 || params.size() > 5)
573 "move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
574 "Move from one account in your wallet to another.");
576 string strFrom = AccountFromValue(params[0]);
577 string strTo = AccountFromValue(params[1]);
578 int64 nAmount = AmountFromValue(params[2]);
580 if (nAmount < MIN_TXOUT_AMOUNT)
581 throw JSONRPCError(-101, "Send amount too small");
583 if (params.size() > 3)
584 // unused parameter, used to be nMinDepth, keep type-checking it though
585 (void)params[3].get_int();
587 if (params.size() > 4)
588 strComment = params[4].get_str();
590 CWalletDB walletdb(pwalletMain->strWalletFile);
591 if (!walletdb.TxnBegin())
592 throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
594 int64 nNow = GetAdjustedTime();
597 CAccountingEntry debit;
598 debit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
599 debit.strAccount = strFrom;
600 debit.nCreditDebit = -nAmount;
602 debit.strOtherAccount = strTo;
603 debit.strComment = strComment;
604 walletdb.WriteAccountingEntry(debit);
607 CAccountingEntry credit;
608 credit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
609 credit.strAccount = strTo;
610 credit.nCreditDebit = nAmount;
612 credit.strOtherAccount = strFrom;
613 credit.strComment = strComment;
614 walletdb.WriteAccountingEntry(credit);
616 if (!walletdb.TxnCommit())
617 throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
623 Value sendfrom(const Array& params, bool fHelp)
625 if (fHelp || params.size() < 3 || params.size() > 6)
627 "sendfrom <fromaccount> <tonovacoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
628 "<amount> is a real and is rounded to the nearest " + FormatMoney(MIN_TXOUT_AMOUNT)
629 + HelpRequiringPassphrase());
631 string strAccount = AccountFromValue(params[0]);
632 CBitcoinAddress address(params[1].get_str());
633 if (!address.IsValid())
634 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
635 int64 nAmount = AmountFromValue(params[2]);
637 if (nAmount < MIN_TXOUT_AMOUNT)
638 throw JSONRPCError(-101, "Send amount too small");
641 if (params.size() > 3)
642 nMinDepth = params[3].get_int();
645 wtx.strFromAccount = strAccount;
646 if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
647 wtx.mapValue["comment"] = params[4].get_str();
648 if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
649 wtx.mapValue["to"] = params[5].get_str();
651 EnsureWalletIsUnlocked();
654 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
655 if (nAmount > nBalance)
656 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
659 string strError = pwalletMain->SendMoneyToDestination(address.Get(), nAmount, wtx);
661 throw JSONRPCError(RPC_WALLET_ERROR, strError);
663 return wtx.GetHash().GetHex();
667 Value sendmany(const Array& params, bool fHelp)
669 if (fHelp || params.size() < 2 || params.size() > 4)
671 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
672 "amounts are double-precision floating point numbers"
673 + HelpRequiringPassphrase());
675 string strAccount = AccountFromValue(params[0]);
676 Object sendTo = params[1].get_obj();
678 if (params.size() > 2)
679 nMinDepth = params[2].get_int();
682 wtx.strFromAccount = strAccount;
683 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
684 wtx.mapValue["comment"] = params[3].get_str();
686 set<CBitcoinAddress> setAddress;
687 vector<pair<CScript, int64> > vecSend;
689 int64 totalAmount = 0;
690 BOOST_FOREACH(const Pair& s, sendTo)
692 CBitcoinAddress address(s.name_);
693 if (!address.IsValid())
694 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid NovaCoin address: ")+s.name_);
696 if (setAddress.count(address))
697 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+s.name_);
698 setAddress.insert(address);
700 CScript scriptPubKey;
701 scriptPubKey.SetDestination(address.Get());
702 int64 nAmount = AmountFromValue(s.value_);
704 if (nAmount < MIN_TXOUT_AMOUNT)
705 throw JSONRPCError(-101, "Send amount too small");
707 totalAmount += nAmount;
709 vecSend.push_back(make_pair(scriptPubKey, nAmount));
712 EnsureWalletIsUnlocked();
715 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
716 if (totalAmount > nBalance)
717 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
720 CReserveKey keyChange(pwalletMain);
721 int64 nFeeRequired = 0;
722 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
725 if (totalAmount + nFeeRequired > pwalletMain->GetBalance())
726 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds");
727 throw JSONRPCError(RPC_WALLET_ERROR, "Transaction creation failed");
729 if (!pwalletMain->CommitTransaction(wtx, keyChange))
730 throw JSONRPCError(RPC_WALLET_ERROR, "Transaction commit failed");
732 return wtx.GetHash().GetHex();
735 Value addmultisigaddress(const Array& params, bool fHelp)
737 if (fHelp || params.size() < 2 || params.size() > 3)
739 string msg = "addmultisigaddress <nrequired> <'[\"key\",\"key\"]'> [account]\n"
740 "Add a nrequired-to-sign multisignature address to the wallet\"\n"
741 "each key is a NovaCoin address or hex-encoded public key\n"
742 "If [account] is specified, assign address to [account].";
743 throw runtime_error(msg);
746 int nRequired = params[0].get_int();
747 const Array& keys = params[1].get_array();
749 if (params.size() > 2)
750 strAccount = AccountFromValue(params[2]);
752 // Gather public keys
754 throw runtime_error("a multisignature address must require at least one key to redeem");
755 if ((int)keys.size() < nRequired)
757 strprintf("not enough keys supplied "
758 "(got %"PRIszu" keys, but need at least %d to redeem)", keys.size(), nRequired));
759 std::vector<CKey> pubkeys;
760 pubkeys.resize(keys.size());
761 for (unsigned int i = 0; i < keys.size(); i++)
763 const std::string& ks = keys[i].get_str();
765 // Case 1: Bitcoin address and we have full public key:
766 CBitcoinAddress address(ks);
767 if (address.IsValid())
770 if (!address.GetKeyID(keyID))
772 strprintf("%s does not refer to a key",ks.c_str()));
774 if (!pwalletMain->GetPubKey(keyID, vchPubKey))
776 strprintf("no full public key for address %s",ks.c_str()));
777 if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey))
778 throw runtime_error(" Invalid public key: "+ks);
781 // Case 2: hex public key
784 CPubKey vchPubKey(ParseHex(ks));
785 if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey))
786 throw runtime_error(" Invalid public key: "+ks);
790 throw runtime_error(" Invalid public key: "+ks);
794 // Construct using pay-to-script-hash:
796 inner.SetMultisig(nRequired, pubkeys);
797 CScriptID innerID = inner.GetID();
798 pwalletMain->AddCScript(inner);
800 pwalletMain->SetAddressBookName(innerID, strAccount);
801 return CBitcoinAddress(innerID).ToString();
804 Value addredeemscript(const Array& params, bool fHelp)
806 if (fHelp || params.size() < 1 || params.size() > 2)
808 string msg = "addredeemscript <redeemScript> [account]\n"
809 "Add a P2SH address with a specified redeemScript to the wallet.\n"
810 "If [account] is specified, assign address to [account].";
811 throw runtime_error(msg);
815 if (params.size() > 1)
816 strAccount = AccountFromValue(params[1]);
818 // Construct using pay-to-script-hash:
819 vector<unsigned char> innerData = ParseHexV(params[0], "redeemScript");
820 CScript inner(innerData.begin(), innerData.end());
821 CScriptID innerID = inner.GetID();
822 pwalletMain->AddCScript(inner);
824 pwalletMain->SetAddressBookName(innerID, strAccount);
825 return CBitcoinAddress(innerID).ToString();
835 nConf = std::numeric_limits<int>::max();
839 Value ListReceived(const Array& params, bool fByAccounts)
841 // Minimum confirmations
843 if (params.size() > 0)
844 nMinDepth = params[0].get_int();
846 // Whether to include empty accounts
847 bool fIncludeEmpty = false;
848 if (params.size() > 1)
849 fIncludeEmpty = params[1].get_bool();
852 map<CBitcoinAddress, tallyitem> mapTally;
853 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
855 const CWalletTx& wtx = (*it).second;
857 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
860 int nDepth = wtx.GetDepthInMainChain();
861 if (nDepth < nMinDepth)
864 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
866 CTxDestination address;
867 if (!ExtractDestination(txout.scriptPubKey, address) || !IsMine(*pwalletMain, address))
870 tallyitem& item = mapTally[address];
871 item.nAmount += txout.nValue;
872 item.nConf = min(item.nConf, nDepth);
878 map<string, tallyitem> mapAccountTally;
879 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
881 const CBitcoinAddress& address = item.first;
882 const string& strAccount = item.second;
883 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
884 if (it == mapTally.end() && !fIncludeEmpty)
888 int nConf = std::numeric_limits<int>::max();
889 if (it != mapTally.end())
891 nAmount = (*it).second.nAmount;
892 nConf = (*it).second.nConf;
897 tallyitem& item = mapAccountTally[strAccount];
898 item.nAmount += nAmount;
899 item.nConf = min(item.nConf, nConf);
904 obj.push_back(Pair("address", address.ToString()));
905 obj.push_back(Pair("account", strAccount));
906 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
907 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
914 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
916 int64 nAmount = (*it).second.nAmount;
917 int nConf = (*it).second.nConf;
919 obj.push_back(Pair("account", (*it).first));
920 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
921 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
929 Value listreceivedbyaddress(const Array& params, bool fHelp)
931 if (fHelp || params.size() > 2)
933 "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
934 "[minconf] is the minimum number of confirmations before payments are included.\n"
935 "[includeempty] whether to include addresses that haven't received any payments.\n"
936 "Returns an array of objects containing:\n"
937 " \"address\" : receiving address\n"
938 " \"account\" : the account of the receiving address\n"
939 " \"amount\" : total amount received by the address\n"
940 " \"confirmations\" : number of confirmations of the most recent transaction included");
942 return ListReceived(params, false);
945 Value listreceivedbyaccount(const Array& params, bool fHelp)
947 if (fHelp || params.size() > 2)
949 "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
950 "[minconf] is the minimum number of confirmations before payments are included.\n"
951 "[includeempty] whether to include accounts that haven't received any payments.\n"
952 "Returns an array of objects containing:\n"
953 " \"account\" : the account of the receiving addresses\n"
954 " \"amount\" : total amount received by addresses with this account\n"
955 " \"confirmations\" : number of confirmations of the most recent transaction included");
957 return ListReceived(params, true);
960 static void MaybePushAddress(Object & entry, const CTxDestination &dest)
962 CBitcoinAddress addr;
964 entry.push_back(Pair("address", addr.ToString()));
967 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
969 int64 nGeneratedImmature, nGeneratedMature, nFee;
970 string strSentAccount;
971 list<pair<CTxDestination, int64> > listReceived;
972 list<pair<CTxDestination, int64> > listSent;
974 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
976 bool fAllAccounts = (strAccount == string("*"));
978 // Generated blocks assigned to account ""
979 if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
982 entry.push_back(Pair("account", string("")));
983 if (nGeneratedImmature)
985 entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
986 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
990 entry.push_back(Pair("category", "generate"));
991 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
994 WalletTxToJSON(wtx, entry);
995 ret.push_back(entry);
999 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1001 BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& s, listSent)
1004 entry.push_back(Pair("account", strSentAccount));
1005 MaybePushAddress(entry, s.first);
1007 if (wtx.GetDepthInMainChain() < 0) {
1008 entry.push_back(Pair("category", "conflicted"));
1010 entry.push_back(Pair("category", "send"));
1013 entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1014 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1016 WalletTxToJSON(wtx, entry);
1017 ret.push_back(entry);
1022 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1024 BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& r, listReceived)
1027 if (pwalletMain->mapAddressBook.count(r.first))
1028 account = pwalletMain->mapAddressBook[r.first];
1029 if (fAllAccounts || (account == strAccount))
1032 entry.push_back(Pair("account", account));
1033 MaybePushAddress(entry, r.first);
1034 if (wtx.IsCoinBase())
1036 if (wtx.GetDepthInMainChain() < 1)
1037 entry.push_back(Pair("category", "orphan"));
1038 else if (wtx.GetBlocksToMaturity() > 0)
1039 entry.push_back(Pair("category", "immature"));
1041 entry.push_back(Pair("category", "generate"));
1044 entry.push_back(Pair("category", "receive"));
1045 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1047 WalletTxToJSON(wtx, entry);
1048 ret.push_back(entry);
1054 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1056 bool fAllAccounts = (strAccount == string("*"));
1058 if (fAllAccounts || acentry.strAccount == strAccount)
1061 entry.push_back(Pair("account", acentry.strAccount));
1062 entry.push_back(Pair("category", "move"));
1063 entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
1064 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1065 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1066 entry.push_back(Pair("comment", acentry.strComment));
1067 ret.push_back(entry);
1071 Value listtransactions(const Array& params, bool fHelp)
1073 if (fHelp || params.size() > 3)
1074 throw runtime_error(
1075 "listtransactions [account] [count=10] [from=0]\n"
1076 "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1078 string strAccount = "*";
1079 if (params.size() > 0)
1080 strAccount = params[0].get_str();
1082 if (params.size() > 1)
1083 nCount = params[1].get_int();
1085 if (params.size() > 2)
1086 nFrom = params[2].get_int();
1089 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count");
1091 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative from");
1095 std::list<CAccountingEntry> acentries;
1096 CWallet::TxItems txOrdered = pwalletMain->OrderedTxItems(acentries, strAccount);
1098 // iterate backwards until we have nCount items to return:
1099 for (CWallet::TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
1101 CWalletTx *const pwtx = (*it).second.first;
1103 ListTransactions(*pwtx, strAccount, 0, true, ret);
1104 CAccountingEntry *const pacentry = (*it).second.second;
1106 AcentryToJSON(*pacentry, strAccount, ret);
1108 if ((int)ret.size() >= (nCount+nFrom)) break;
1110 // ret is newest to oldest
1112 if (nFrom > (int)ret.size())
1114 if ((nFrom + nCount) > (int)ret.size())
1115 nCount = ret.size() - nFrom;
1116 Array::iterator first = ret.begin();
1117 std::advance(first, nFrom);
1118 Array::iterator last = ret.begin();
1119 std::advance(last, nFrom+nCount);
1121 if (last != ret.end()) ret.erase(last, ret.end());
1122 if (first != ret.begin()) ret.erase(ret.begin(), first);
1124 std::reverse(ret.begin(), ret.end()); // Return oldest to newest
1129 Value listaccounts(const Array& params, bool fHelp)
1131 if (fHelp || params.size() > 1)
1132 throw runtime_error(
1133 "listaccounts [minconf=1]\n"
1134 "Returns Object that has account names as keys, account balances as values.");
1137 if (params.size() > 0)
1138 nMinDepth = params[0].get_int();
1140 map<string, int64> mapAccountBalances;
1141 BOOST_FOREACH(const PAIRTYPE(CTxDestination, string)& entry, pwalletMain->mapAddressBook) {
1142 if (IsMine(*pwalletMain, entry.first)) // This address belongs to me
1143 mapAccountBalances[entry.second] = 0;
1146 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1148 const CWalletTx& wtx = (*it).second;
1149 int64 nGeneratedImmature, nGeneratedMature, nFee;
1150 string strSentAccount;
1151 list<pair<CTxDestination, int64> > listReceived;
1152 list<pair<CTxDestination, int64> > listSent;
1153 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1154 mapAccountBalances[strSentAccount] -= nFee;
1155 BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& s, listSent)
1156 mapAccountBalances[strSentAccount] -= s.second;
1157 if (wtx.GetDepthInMainChain() >= nMinDepth)
1159 mapAccountBalances[""] += nGeneratedMature;
1160 BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& r, listReceived)
1161 if (pwalletMain->mapAddressBook.count(r.first))
1162 mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1164 mapAccountBalances[""] += r.second;
1168 list<CAccountingEntry> acentries;
1169 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1170 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1171 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1174 BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) {
1175 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1180 Value listsinceblock(const Array& params, bool fHelp)
1183 throw runtime_error(
1184 "listsinceblock [blockhash] [target-confirmations]\n"
1185 "Get all transactions in blocks since block [blockhash], or all transactions if omitted");
1187 CBlockIndex *pindex = NULL;
1188 int target_confirms = 1;
1190 if (params.size() > 0)
1192 uint256 blockId = 0;
1194 blockId.SetHex(params[0].get_str());
1195 pindex = CBlockLocator(blockId).GetBlockIndex();
1198 if (params.size() > 1)
1200 target_confirms = params[1].get_int();
1202 if (target_confirms < 1)
1203 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter");
1206 int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
1210 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1212 CWalletTx tx = (*it).second;
1214 if (depth == -1 || tx.GetDepthInMainChain() < depth)
1215 ListTransactions(tx, "*", 0, true, transactions);
1220 if (target_confirms == 1)
1222 lastblock = hashBestChain;
1226 int target_height = pindexBest->nHeight + 1 - target_confirms;
1229 for (block = pindexBest;
1230 block && block->nHeight > target_height;
1231 block = block->pprev) { }
1233 lastblock = block ? block->GetBlockHash() : 0;
1237 ret.push_back(Pair("transactions", transactions));
1238 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1243 Value gettransaction(const Array& params, bool fHelp)
1245 if (fHelp || params.size() != 1)
1246 throw runtime_error(
1247 "gettransaction <txid>\n"
1248 "Get detailed information about <txid>");
1251 hash.SetHex(params[0].get_str());
1255 if (pwalletMain->mapWallet.count(hash))
1257 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1259 TxToJSON(wtx, 0, entry);
1261 int64 nCredit = wtx.GetCredit();
1262 int64 nDebit = wtx.GetDebit();
1263 int64 nNet = nCredit - nDebit;
1264 int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
1266 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1268 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1270 WalletTxToJSON(wtx, entry);
1273 ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
1274 entry.push_back(Pair("details", details));
1279 uint256 hashBlock = 0;
1280 if (GetTransaction(hash, tx, hashBlock))
1282 TxToJSON(tx, 0, entry);
1284 entry.push_back(Pair("confirmations", 0));
1287 entry.push_back(Pair("blockhash", hashBlock.GetHex()));
1288 map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
1289 if (mi != mapBlockIndex.end() && (*mi).second)
1291 CBlockIndex* pindex = (*mi).second;
1292 if (pindex->IsInMainChain())
1293 entry.push_back(Pair("confirmations", 1 + nBestHeight - pindex->nHeight));
1295 entry.push_back(Pair("confirmations", 0));
1300 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction");
1307 Value backupwallet(const Array& params, bool fHelp)
1309 if (fHelp || params.size() != 1)
1310 throw runtime_error(
1311 "backupwallet <destination>\n"
1312 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1314 string strDest = params[0].get_str();
1315 if (!BackupWallet(*pwalletMain, strDest))
1316 throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!");
1322 Value keypoolrefill(const Array& params, bool fHelp)
1324 if (fHelp || params.size() > 1)
1325 throw runtime_error(
1326 "keypoolrefill [new-size]\n"
1327 "Fills the keypool."
1328 + HelpRequiringPassphrase());
1330 unsigned int nSize = max(GetArg("-keypool", 100), 0LL);
1331 if (params.size() > 0) {
1332 if (params[0].get_int() < 0)
1333 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size");
1334 nSize = (unsigned int) params[0].get_int();
1337 EnsureWalletIsUnlocked();
1339 pwalletMain->TopUpKeyPool(nSize);
1341 if (pwalletMain->GetKeyPoolSize() < nSize)
1342 throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool.");
1348 void ThreadTopUpKeyPool(void* parg)
1350 // Make this thread recognisable as the key-topping-up thread
1351 RenameThread("novacoin-key-top");
1353 pwalletMain->TopUpKeyPool();
1356 void ThreadCleanWalletPassphrase(void* parg)
1358 // Make this thread recognisable as the wallet relocking thread
1359 RenameThread("novacoin-lock-wa");
1361 int64 nMyWakeTime = GetTimeMillis() + *((int64*)parg) * 1000;
1363 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1365 if (nWalletUnlockTime == 0)
1367 nWalletUnlockTime = nMyWakeTime;
1371 if (nWalletUnlockTime==0)
1373 int64 nToSleep = nWalletUnlockTime - GetTimeMillis();
1377 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1379 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1383 if (nWalletUnlockTime)
1385 nWalletUnlockTime = 0;
1386 pwalletMain->Lock();
1391 if (nWalletUnlockTime < nMyWakeTime)
1392 nWalletUnlockTime = nMyWakeTime;
1395 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1397 delete (int64*)parg;
1400 Value walletpassphrase(const Array& params, bool fHelp)
1402 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 3))
1403 throw runtime_error(
1404 "walletpassphrase <passphrase> <timeout> [mintonly]\n"
1405 "Stores the wallet decryption key in memory for <timeout> seconds.\n"
1406 "mintonly is optional true/false allowing only block minting.");
1409 if (!pwalletMain->IsCrypted())
1410 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1412 if (!pwalletMain->IsLocked())
1413 throw JSONRPCError(RPC_WALLET_ALREADY_UNLOCKED, "Error: Wallet is already unlocked, use walletlock first if need to change unlock settings.");
1414 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1415 SecureString strWalletPass;
1416 strWalletPass.reserve(100);
1417 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1418 // Alternately, find a way to make params[0] mlock()'d to begin with.
1419 strWalletPass = params[0].get_str().c_str();
1421 if (strWalletPass.length() > 0)
1423 if (!pwalletMain->Unlock(strWalletPass))
1424 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
1427 throw runtime_error(
1428 "walletpassphrase <passphrase> <timeout>\n"
1429 "Stores the wallet decryption key in memory for <timeout> seconds.");
1431 NewThread(ThreadTopUpKeyPool, NULL);
1432 int64* pnSleepTime = new int64(params[1].get_int64());
1433 NewThread(ThreadCleanWalletPassphrase, pnSleepTime);
1435 // ppcoin: if user OS account compromised prevent trivial sendmoney commands
1436 if (params.size() > 2)
1437 fWalletUnlockMintOnly = params[2].get_bool();
1439 fWalletUnlockMintOnly = false;
1445 Value walletpassphrasechange(const Array& params, bool fHelp)
1447 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1448 throw runtime_error(
1449 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1450 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1453 if (!pwalletMain->IsCrypted())
1454 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1456 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1457 // Alternately, find a way to make params[0] mlock()'d to begin with.
1458 SecureString strOldWalletPass;
1459 strOldWalletPass.reserve(100);
1460 strOldWalletPass = params[0].get_str().c_str();
1462 SecureString strNewWalletPass;
1463 strNewWalletPass.reserve(100);
1464 strNewWalletPass = params[1].get_str().c_str();
1466 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1467 throw runtime_error(
1468 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1469 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1471 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1472 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
1478 Value walletlock(const Array& params, bool fHelp)
1480 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1481 throw runtime_error(
1483 "Removes the wallet encryption key from memory, locking the wallet.\n"
1484 "After calling this method, you will need to call walletpassphrase again\n"
1485 "before being able to call any methods which require the wallet to be unlocked.");
1488 if (!pwalletMain->IsCrypted())
1489 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletlock was called.");
1492 LOCK(cs_nWalletUnlockTime);
1493 pwalletMain->Lock();
1494 nWalletUnlockTime = 0;
1501 Value encryptwallet(const Array& params, bool fHelp)
1503 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1504 throw runtime_error(
1505 "encryptwallet <passphrase>\n"
1506 "Encrypts the wallet with <passphrase>.");
1509 if (pwalletMain->IsCrypted())
1510 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an encrypted wallet, but encryptwallet was called.");
1512 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1513 // Alternately, find a way to make params[0] mlock()'d to begin with.
1514 SecureString strWalletPass;
1515 strWalletPass.reserve(100);
1516 strWalletPass = params[0].get_str().c_str();
1518 if (strWalletPass.length() < 1)
1519 throw runtime_error(
1520 "encryptwallet <passphrase>\n"
1521 "Encrypts the wallet with <passphrase>.");
1523 if (!pwalletMain->EncryptWallet(strWalletPass))
1524 throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: Failed to encrypt the wallet.");
1526 // BDB seems to have a bad habit of writing old data into
1527 // slack space in .dat files; that is bad if the old data is
1528 // unencrypted private keys. So:
1530 return "wallet encrypted; NovaCoin server stopping, restart to run with encrypted wallet. The keypool has been flushed, you need to make a new backup.";
1533 class DescribeAddressVisitor : public boost::static_visitor<Object>
1538 DescribeAddressVisitor(isminetype mineIn) : mine(mineIn) {}
1540 Object operator()(const CNoDestination &dest) const { return Object(); }
1541 Object operator()(const CKeyID &keyID) const {
1544 pwalletMain->GetPubKey(keyID, vchPubKey);
1545 obj.push_back(Pair("isscript", false));
1546 if (mine == MINE_SPENDABLE) {
1547 pwalletMain->GetPubKey(keyID, vchPubKey);
1548 obj.push_back(Pair("pubkey", HexStr(vchPubKey.Raw())));
1549 obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed()));
1554 Object operator()(const CScriptID &scriptID) const {
1556 obj.push_back(Pair("isscript", true));
1557 if (mine == MINE_SPENDABLE) {
1559 pwalletMain->GetCScript(scriptID, subscript);
1560 std::vector<CTxDestination> addresses;
1561 txnouttype whichType;
1563 ExtractDestinations(subscript, whichType, addresses, nRequired);
1564 obj.push_back(Pair("script", GetTxnOutputType(whichType)));
1565 obj.push_back(Pair("hex", HexStr(subscript.begin(), subscript.end())));
1567 BOOST_FOREACH(const CTxDestination& addr, addresses)
1568 a.push_back(CBitcoinAddress(addr).ToString());
1569 obj.push_back(Pair("addresses", a));
1570 if (whichType == TX_MULTISIG)
1571 obj.push_back(Pair("sigsrequired", nRequired));
1577 Value validateaddress(const Array& params, bool fHelp)
1579 if (fHelp || params.size() != 1)
1580 throw runtime_error(
1581 "validateaddress <novacoinaddress>\n"
1582 "Return information about <novacoinaddress>.");
1584 CBitcoinAddress address(params[0].get_str());
1585 bool isValid = address.IsValid();
1588 ret.push_back(Pair("isvalid", isValid));
1591 CTxDestination dest = address.Get();
1592 string currentAddress = address.ToString();
1593 ret.push_back(Pair("address", currentAddress));
1594 isminetype mine = pwalletMain ? IsMine(*pwalletMain, dest) : MINE_NO;
1595 ret.push_back(Pair("ismine", mine != MINE_NO));
1596 if (mine != MINE_NO) {
1597 ret.push_back(Pair("watchonly", mine == MINE_WATCH_ONLY));
1598 Object detail = boost::apply_visitor(DescribeAddressVisitor(mine), dest);
1599 ret.insert(ret.end(), detail.begin(), detail.end());
1601 if (pwalletMain->mapAddressBook.count(dest))
1602 ret.push_back(Pair("account", pwalletMain->mapAddressBook[dest]));
1607 // ppcoin: reserve balance from being staked for network protection
1608 Value reservebalance(const Array& params, bool fHelp)
1610 if (fHelp || params.size() > 2)
1611 throw runtime_error(
1612 "reservebalance [<reserve> [amount]]\n"
1613 "<reserve> is true or false to turn balance reserve on or off.\n"
1614 "<amount> is a real and rounded to cent.\n"
1615 "Set reserve amount not participating in network protection.\n"
1616 "If no parameters provided current setting is printed.\n");
1618 if (params.size() > 0)
1620 bool fReserve = params[0].get_bool();
1623 if (params.size() == 1)
1624 throw runtime_error("must provide amount to reserve balance.\n");
1625 int64 nAmount = AmountFromValue(params[1]);
1626 nAmount = (nAmount / CENT) * CENT; // round to cent
1628 throw runtime_error("amount cannot be negative.\n");
1629 mapArgs["-reservebalance"] = FormatMoney(nAmount).c_str();
1633 if (params.size() > 1)
1634 throw runtime_error("cannot specify amount to turn off reserve.\n");
1635 mapArgs["-reservebalance"] = "0";
1640 int64 nReserveBalance = 0;
1641 if (mapArgs.count("-reservebalance") && !ParseMoney(mapArgs["-reservebalance"], nReserveBalance))
1642 throw runtime_error("invalid reserve balance amount\n");
1643 result.push_back(Pair("reserve", (nReserveBalance > 0)));
1644 result.push_back(Pair("amount", ValueFromAmount(nReserveBalance)));
1649 // ppcoin: check wallet integrity
1650 Value checkwallet(const Array& params, bool fHelp)
1652 if (fHelp || params.size() > 0)
1653 throw runtime_error(
1655 "Check wallet for integrity.\n");
1658 int64 nBalanceInQuestion;
1659 pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion, true);
1661 if (nMismatchSpent == 0)
1662 result.push_back(Pair("wallet check passed", true));
1665 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
1666 result.push_back(Pair("amount in question", ValueFromAmount(nBalanceInQuestion)));
1672 // ppcoin: repair wallet
1673 Value repairwallet(const Array& params, bool fHelp)
1675 if (fHelp || params.size() > 0)
1676 throw runtime_error(
1678 "Repair wallet if checkwallet reports any problem.\n");
1681 int64 nBalanceInQuestion;
1682 pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion);
1684 if (nMismatchSpent == 0)
1685 result.push_back(Pair("wallet check passed", true));
1688 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
1689 result.push_back(Pair("amount affected by repair", ValueFromAmount(nBalanceInQuestion)));
1694 // NovaCoin: resend unconfirmed wallet transactions
1695 Value resendtx(const Array& params, bool fHelp)
1697 if (fHelp || params.size() > 1)
1698 throw runtime_error(
1700 "Re-send unconfirmed transactions.\n"
1703 ResendWalletTransactions();
1708 // ppcoin: make a public-private key pair
1709 Value makekeypair(const Array& params, bool fHelp)
1711 if (fHelp || params.size() > 1)
1712 throw runtime_error(
1713 "makekeypair [prefix]\n"
1714 "Make a public/private key pair.\n"
1715 "[prefix] is optional preferred prefix for the public key.\n");
1717 string strPrefix = "";
1718 if (params.size() > 0)
1719 strPrefix = params[0].get_str();
1722 key.MakeNewKey(false);
1724 CPrivKey vchPrivKey = key.GetPrivKey();
1726 result.push_back(Pair("PrivateKey", HexStr<CPrivKey::iterator>(vchPrivKey.begin(), vchPrivKey.end())));
1727 result.push_back(Pair("PublicKey", HexStr(key.GetPubKey().Raw())));