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()));
85 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
86 obj.push_back(Pair("testnet", fTestNet));
87 obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
88 obj.push_back(Pair("keypoolsize", pwalletMain->GetKeyPoolSize()));
89 obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee)));
90 if (pwalletMain->IsCrypted())
91 obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime / 1000));
92 obj.push_back(Pair("errors", GetWarnings("statusbar")));
97 Value getnewpubkey(const Array& params, bool fHelp)
99 if (fHelp || params.size() > 1)
101 "getnewpubkey [account]\n"
102 "Returns new public key for coinbase generation.");
104 // Parse the account first so we don't generate a key if there's an error
106 if (params.size() > 0)
107 strAccount = AccountFromValue(params[0]);
109 if (!pwalletMain->IsLocked())
110 pwalletMain->TopUpKeyPool();
112 // Generate a new key that is added to wallet
114 if (!pwalletMain->GetKeyFromPool(newKey, false))
115 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
116 CKeyID keyID = newKey.GetID();
118 pwalletMain->SetAddressBookName(keyID, strAccount);
119 vector<unsigned char> vchPubKey = newKey.Raw();
121 return HexStr(vchPubKey.begin(), vchPubKey.end());
125 Value getnewaddress(const Array& params, bool fHelp)
127 if (fHelp || params.size() > 1)
129 "getnewaddress [account]\n"
130 "Returns a new NovaCoin address for receiving payments. "
131 "If [account] is specified (recommended), it is added to the address book "
132 "so payments received with the address will be credited to [account].");
134 // Parse the account first so we don't generate a key if there's an error
136 if (params.size() > 0)
137 strAccount = AccountFromValue(params[0]);
139 if (!pwalletMain->IsLocked())
140 pwalletMain->TopUpKeyPool();
142 // Generate a new key that is added to wallet
144 if (!pwalletMain->GetKeyFromPool(newKey, false))
145 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
146 CKeyID keyID = newKey.GetID();
148 pwalletMain->SetAddressBookName(keyID, strAccount);
150 return CBitcoinAddress(keyID).ToString();
154 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
156 CWalletDB walletdb(pwalletMain->strWalletFile);
159 walletdb.ReadAccount(strAccount, account);
161 bool bKeyUsed = false;
163 // Check if the current key has been used
164 if (account.vchPubKey.IsValid())
166 CScript scriptPubKey;
167 scriptPubKey.SetDestination(account.vchPubKey.GetID());
168 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
169 it != pwalletMain->mapWallet.end() && account.vchPubKey.IsValid();
172 const CWalletTx& wtx = (*it).second;
173 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
174 if (txout.scriptPubKey == scriptPubKey)
179 // Generate a new key
180 if (!account.vchPubKey.IsValid() || bForceNew || bKeyUsed)
182 if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false))
183 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
185 pwalletMain->SetAddressBookName(account.vchPubKey.GetID(), strAccount);
186 walletdb.WriteAccount(strAccount, account);
189 return CBitcoinAddress(account.vchPubKey.GetID());
192 Value getaccountaddress(const Array& params, bool fHelp)
194 if (fHelp || params.size() != 1)
196 "getaccountaddress <account>\n"
197 "Returns the current NovaCoin address for receiving payments to this account.");
199 // Parse the account first so we don't generate a key if there's an error
200 string strAccount = AccountFromValue(params[0]);
204 ret = GetAccountAddress(strAccount).ToString();
211 Value setaccount(const Array& params, bool fHelp)
213 if (fHelp || params.size() < 1 || params.size() > 2)
215 "setaccount <novacoinaddress> <account>\n"
216 "Sets the account associated with the given address.");
218 CBitcoinAddress address(params[0].get_str());
219 if (!address.IsValid())
220 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
224 if (params.size() > 1)
225 strAccount = AccountFromValue(params[1]);
227 // Detect when changing the account of an address that is the 'unused current key' of another account:
228 if (pwalletMain->mapAddressBook.count(address.Get()))
230 string strOldAccount = pwalletMain->mapAddressBook[address.Get()];
231 if (address == GetAccountAddress(strOldAccount))
232 GetAccountAddress(strOldAccount, true);
235 pwalletMain->SetAddressBookName(address.Get(), strAccount);
241 Value getaccount(const Array& params, bool fHelp)
243 if (fHelp || params.size() != 1)
245 "getaccount <novacoinaddress>\n"
246 "Returns the account associated with the given address.");
248 CBitcoinAddress address(params[0].get_str());
249 if (!address.IsValid())
250 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
253 map<CTxDestination, string>::iterator mi = pwalletMain->mapAddressBook.find(address.Get());
254 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
255 strAccount = (*mi).second;
260 Value getaddressesbyaccount(const Array& params, bool fHelp)
262 if (fHelp || params.size() != 1)
264 "getaddressesbyaccount <account>\n"
265 "Returns the list of addresses for the given account.");
267 string strAccount = AccountFromValue(params[0]);
269 // Find all addresses that have the given account
271 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
273 const CBitcoinAddress& address = item.first;
274 const string& strName = item.second;
275 if (strName == strAccount)
276 ret.push_back(address.ToString());
281 Value sendtoaddress(const Array& params, bool fHelp)
283 if (fHelp || params.size() < 2 || params.size() > 4)
285 "sendtoaddress <novacoinaddress> <amount> [comment] [comment-to]\n"
286 "<amount> is a real and is rounded to the nearest 0.000001"
287 + HelpRequiringPassphrase());
289 CBitcoinAddress address(params[0].get_str());
290 if (!address.IsValid())
291 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
294 int64 nAmount = AmountFromValue(params[1]);
296 if (nAmount < MIN_TXOUT_AMOUNT)
297 throw JSONRPCError(-101, "Send amount too small");
301 if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
302 wtx.mapValue["comment"] = params[2].get_str();
303 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
304 wtx.mapValue["to"] = params[3].get_str();
306 if (pwalletMain->IsLocked())
307 throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
309 string strError = pwalletMain->SendMoneyToDestination(address.Get(), nAmount, wtx);
311 throw JSONRPCError(RPC_WALLET_ERROR, strError);
313 return wtx.GetHash().GetHex();
316 Value listaddressgroupings(const Array& params, bool fHelp)
320 "listaddressgroupings\n"
321 "Lists groups of addresses which have had their common ownership\n"
322 "made public by common use as inputs or as the resulting change\n"
323 "in past transactions");
326 map<CTxDestination, int64> balances = pwalletMain->GetAddressBalances();
327 BOOST_FOREACH(set<CTxDestination> grouping, pwalletMain->GetAddressGroupings())
330 BOOST_FOREACH(CTxDestination address, grouping)
333 addressInfo.push_back(CBitcoinAddress(address).ToString());
334 addressInfo.push_back(ValueFromAmount(balances[address]));
336 LOCK(pwalletMain->cs_wallet);
337 if (pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get()) != pwalletMain->mapAddressBook.end())
338 addressInfo.push_back(pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get())->second);
340 jsonGrouping.push_back(addressInfo);
342 jsonGroupings.push_back(jsonGrouping);
344 return jsonGroupings;
347 Value signmessage(const Array& params, bool fHelp)
349 if (fHelp || params.size() != 2)
351 "signmessage <novacoinaddress> <message>\n"
352 "Sign a message with the private key of an address");
354 EnsureWalletIsUnlocked();
356 string strAddress = params[0].get_str();
357 string strMessage = params[1].get_str();
359 CBitcoinAddress addr(strAddress);
361 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
364 if (!addr.GetKeyID(keyID))
365 throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
368 if (!pwalletMain->GetKey(keyID, key))
369 throw JSONRPCError(RPC_WALLET_ERROR, "Private key not available");
371 CDataStream ss(SER_GETHASH, 0);
372 ss << strMessageMagic;
375 vector<unsigned char> vchSig;
376 if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
377 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed");
379 return EncodeBase64(&vchSig[0], vchSig.size());
382 Value verifymessage(const Array& params, bool fHelp)
384 if (fHelp || params.size() != 3)
386 "verifymessage <novacoinaddress> <signature> <message>\n"
387 "Verify a signed message");
389 string strAddress = params[0].get_str();
390 string strSign = params[1].get_str();
391 string strMessage = params[2].get_str();
393 CBitcoinAddress addr(strAddress);
395 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
398 if (!addr.GetKeyID(keyID))
399 throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
401 bool fInvalid = false;
402 vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
405 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Malformed base64 encoding");
407 CDataStream ss(SER_GETHASH, 0);
408 ss << strMessageMagic;
412 if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
415 return (key.GetPubKey().GetID() == keyID);
419 Value getreceivedbyaddress(const Array& params, bool fHelp)
421 if (fHelp || params.size() < 1 || params.size() > 2)
423 "getreceivedbyaddress <novacoinaddress> [minconf=1]\n"
424 "Returns the total amount received by <novacoinaddress> in transactions with at least [minconf] confirmations.");
427 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
428 CScript scriptPubKey;
429 if (!address.IsValid())
430 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
431 scriptPubKey.SetDestination(address.Get());
432 if (!IsMine(*pwalletMain,scriptPubKey))
435 // Minimum confirmations
437 if (params.size() > 1)
438 nMinDepth = params[1].get_int();
442 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
444 const CWalletTx& wtx = (*it).second;
445 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
448 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
449 if (txout.scriptPubKey == scriptPubKey)
450 if (wtx.GetDepthInMainChain() >= nMinDepth)
451 nAmount += txout.nValue;
454 return ValueFromAmount(nAmount);
458 void GetAccountAddresses(string strAccount, set<CTxDestination>& setAddress)
460 BOOST_FOREACH(const PAIRTYPE(CTxDestination, string)& item, pwalletMain->mapAddressBook)
462 const CTxDestination& address = item.first;
463 const string& strName = item.second;
464 if (strName == strAccount)
465 setAddress.insert(address);
469 Value getreceivedbyaccount(const Array& params, bool fHelp)
471 if (fHelp || params.size() < 1 || params.size() > 2)
473 "getreceivedbyaccount <account> [minconf=1]\n"
474 "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
476 // Minimum confirmations
478 if (params.size() > 1)
479 nMinDepth = params[1].get_int();
481 // Get the set of pub keys assigned to account
482 string strAccount = AccountFromValue(params[0]);
483 set<CTxDestination> setAddress;
484 GetAccountAddresses(strAccount, setAddress);
488 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
490 const CWalletTx& wtx = (*it).second;
491 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
494 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
496 CTxDestination address;
497 if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*pwalletMain, address) && setAddress.count(address))
498 if (wtx.GetDepthInMainChain() >= nMinDepth)
499 nAmount += txout.nValue;
503 return (double)nAmount / (double)COIN;
507 int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
511 // Tally wallet transactions
512 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
514 const CWalletTx& wtx = (*it).second;
518 int64 nGenerated, nReceived, nSent, nFee;
519 wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee);
521 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
522 nBalance += nReceived;
523 nBalance += nGenerated - nSent - nFee;
526 // Tally internal accounting entries
527 nBalance += walletdb.GetAccountCreditDebit(strAccount);
532 int64 GetAccountBalance(const string& strAccount, int nMinDepth)
534 CWalletDB walletdb(pwalletMain->strWalletFile);
535 return GetAccountBalance(walletdb, strAccount, nMinDepth);
539 Value getbalance(const Array& params, bool fHelp)
541 if (fHelp || params.size() > 2)
543 "getbalance [account] [minconf=1]\n"
544 "If [account] is not specified, returns the server's total available balance.\n"
545 "If [account] is specified, returns the balance in the account.");
547 if (params.size() == 0)
548 return ValueFromAmount(pwalletMain->GetBalance());
551 if (params.size() > 1)
552 nMinDepth = params[1].get_int();
554 if (params[0].get_str() == "*") {
555 // Calculate total balance a different way from GetBalance()
556 // (GetBalance() sums up all unspent TxOuts)
557 // getbalance and getbalance '*' 0 should return the same number.
559 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
561 const CWalletTx& wtx = (*it).second;
562 if (!wtx.IsConfirmed())
565 int64 allGeneratedImmature, allGeneratedMature, allFee;
566 allGeneratedImmature = allGeneratedMature = allFee = 0;
568 string strSentAccount;
569 list<pair<CTxDestination, int64> > listReceived;
570 list<pair<CTxDestination, int64> > listSent;
571 wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
572 if (wtx.GetDepthInMainChain() >= nMinDepth)
574 BOOST_FOREACH(const PAIRTYPE(CTxDestination,int64)& r, listReceived)
575 nBalance += r.second;
577 BOOST_FOREACH(const PAIRTYPE(CTxDestination,int64)& r, listSent)
578 nBalance -= r.second;
580 nBalance += allGeneratedMature;
582 return ValueFromAmount(nBalance);
585 string strAccount = AccountFromValue(params[0]);
587 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
589 return ValueFromAmount(nBalance);
593 Value movecmd(const Array& params, bool fHelp)
595 if (fHelp || params.size() < 3 || params.size() > 5)
597 "move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
598 "Move from one account in your wallet to another.");
600 string strFrom = AccountFromValue(params[0]);
601 string strTo = AccountFromValue(params[1]);
602 int64 nAmount = AmountFromValue(params[2]);
604 if (nAmount < MIN_TXOUT_AMOUNT)
605 throw JSONRPCError(-101, "Send amount too small");
607 if (params.size() > 3)
608 // unused parameter, used to be nMinDepth, keep type-checking it though
609 (void)params[3].get_int();
611 if (params.size() > 4)
612 strComment = params[4].get_str();
614 CWalletDB walletdb(pwalletMain->strWalletFile);
615 if (!walletdb.TxnBegin())
616 throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
618 int64 nNow = GetAdjustedTime();
621 CAccountingEntry debit;
622 debit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
623 debit.strAccount = strFrom;
624 debit.nCreditDebit = -nAmount;
626 debit.strOtherAccount = strTo;
627 debit.strComment = strComment;
628 walletdb.WriteAccountingEntry(debit);
631 CAccountingEntry credit;
632 credit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
633 credit.strAccount = strTo;
634 credit.nCreditDebit = nAmount;
636 credit.strOtherAccount = strFrom;
637 credit.strComment = strComment;
638 walletdb.WriteAccountingEntry(credit);
640 if (!walletdb.TxnCommit())
641 throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
647 Value sendfrom(const Array& params, bool fHelp)
649 if (fHelp || params.size() < 3 || params.size() > 6)
651 "sendfrom <fromaccount> <tonovacoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
652 "<amount> is a real and is rounded to the nearest 0.000001"
653 + HelpRequiringPassphrase());
655 string strAccount = AccountFromValue(params[0]);
656 CBitcoinAddress address(params[1].get_str());
657 if (!address.IsValid())
658 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
659 int64 nAmount = AmountFromValue(params[2]);
661 if (nAmount < MIN_TXOUT_AMOUNT)
662 throw JSONRPCError(-101, "Send amount too small");
665 if (params.size() > 3)
666 nMinDepth = params[3].get_int();
669 wtx.strFromAccount = strAccount;
670 if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
671 wtx.mapValue["comment"] = params[4].get_str();
672 if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
673 wtx.mapValue["to"] = params[5].get_str();
675 EnsureWalletIsUnlocked();
678 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
679 if (nAmount > nBalance)
680 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
683 string strError = pwalletMain->SendMoneyToDestination(address.Get(), nAmount, wtx);
685 throw JSONRPCError(RPC_WALLET_ERROR, strError);
687 return wtx.GetHash().GetHex();
691 Value sendmany(const Array& params, bool fHelp)
693 if (fHelp || params.size() < 2 || params.size() > 4)
695 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
696 "amounts are double-precision floating point numbers"
697 + HelpRequiringPassphrase());
699 string strAccount = AccountFromValue(params[0]);
700 Object sendTo = params[1].get_obj();
702 if (params.size() > 2)
703 nMinDepth = params[2].get_int();
706 wtx.strFromAccount = strAccount;
707 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
708 wtx.mapValue["comment"] = params[3].get_str();
710 set<CBitcoinAddress> setAddress;
711 vector<pair<CScript, int64> > vecSend;
713 int64 totalAmount = 0;
714 BOOST_FOREACH(const Pair& s, sendTo)
716 CBitcoinAddress address(s.name_);
717 if (!address.IsValid())
718 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid NovaCoin address: ")+s.name_);
720 if (setAddress.count(address))
721 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+s.name_);
722 setAddress.insert(address);
724 CScript scriptPubKey;
725 scriptPubKey.SetDestination(address.Get());
726 int64 nAmount = AmountFromValue(s.value_);
728 if (nAmount < MIN_TXOUT_AMOUNT)
729 throw JSONRPCError(-101, "Send amount too small");
731 totalAmount += nAmount;
733 vecSend.push_back(make_pair(scriptPubKey, nAmount));
736 EnsureWalletIsUnlocked();
739 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
740 if (totalAmount > nBalance)
741 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
744 CReserveKey keyChange(pwalletMain);
745 int64 nFeeRequired = 0;
746 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
749 if (totalAmount + nFeeRequired > pwalletMain->GetBalance())
750 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds");
751 throw JSONRPCError(RPC_WALLET_ERROR, "Transaction creation failed");
753 if (!pwalletMain->CommitTransaction(wtx, keyChange))
754 throw JSONRPCError(RPC_WALLET_ERROR, "Transaction commit failed");
756 return wtx.GetHash().GetHex();
759 Value addmultisigaddress(const Array& params, bool fHelp)
761 if (fHelp || params.size() < 2 || params.size() > 3)
763 string msg = "addmultisigaddress <nrequired> <'[\"key\",\"key\"]'> [account]\n"
764 "Add a nrequired-to-sign multisignature address to the wallet\"\n"
765 "each key is a NovaCoin address or hex-encoded public key\n"
766 "If [account] is specified, assign address to [account].";
767 throw runtime_error(msg);
770 int nRequired = params[0].get_int();
771 const Array& keys = params[1].get_array();
773 if (params.size() > 2)
774 strAccount = AccountFromValue(params[2]);
776 // Gather public keys
778 throw runtime_error("a multisignature address must require at least one key to redeem");
779 if ((int)keys.size() < nRequired)
781 strprintf("not enough keys supplied "
782 "(got %"PRIszu" keys, but need at least %d to redeem)", keys.size(), nRequired));
783 std::vector<CKey> pubkeys;
784 pubkeys.resize(keys.size());
785 for (unsigned int i = 0; i < keys.size(); i++)
787 const std::string& ks = keys[i].get_str();
789 // Case 1: Bitcoin address and we have full public key:
790 CBitcoinAddress address(ks);
791 if (address.IsValid())
794 if (!address.GetKeyID(keyID))
796 strprintf("%s does not refer to a key",ks.c_str()));
798 if (!pwalletMain->GetPubKey(keyID, vchPubKey))
800 strprintf("no full public key for address %s",ks.c_str()));
801 if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey))
802 throw runtime_error(" Invalid public key: "+ks);
805 // Case 2: hex public key
808 CPubKey vchPubKey(ParseHex(ks));
809 if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey))
810 throw runtime_error(" Invalid public key: "+ks);
814 throw runtime_error(" Invalid public key: "+ks);
818 // Construct using pay-to-script-hash:
820 inner.SetMultisig(nRequired, pubkeys);
821 CScriptID innerID = inner.GetID();
822 pwalletMain->AddCScript(inner);
824 pwalletMain->SetAddressBookName(innerID, strAccount);
825 return CBitcoinAddress(innerID).ToString();
836 nConf = std::numeric_limits<int>::max();
840 Value ListReceived(const Array& params, bool fByAccounts)
842 // Minimum confirmations
844 if (params.size() > 0)
845 nMinDepth = params[0].get_int();
847 // Whether to include empty accounts
848 bool fIncludeEmpty = false;
849 if (params.size() > 1)
850 fIncludeEmpty = params[1].get_bool();
853 map<CBitcoinAddress, tallyitem> mapTally;
854 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
856 const CWalletTx& wtx = (*it).second;
858 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
861 int nDepth = wtx.GetDepthInMainChain();
862 if (nDepth < nMinDepth)
865 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
867 CTxDestination address;
868 if (!ExtractDestination(txout.scriptPubKey, address) || !IsMine(*pwalletMain, address))
871 tallyitem& item = mapTally[address];
872 item.nAmount += txout.nValue;
873 item.nConf = min(item.nConf, nDepth);
879 map<string, tallyitem> mapAccountTally;
880 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
882 const CBitcoinAddress& address = item.first;
883 const string& strAccount = item.second;
884 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
885 if (it == mapTally.end() && !fIncludeEmpty)
889 int nConf = std::numeric_limits<int>::max();
890 if (it != mapTally.end())
892 nAmount = (*it).second.nAmount;
893 nConf = (*it).second.nConf;
898 tallyitem& item = mapAccountTally[strAccount];
899 item.nAmount += nAmount;
900 item.nConf = min(item.nConf, nConf);
905 obj.push_back(Pair("address", address.ToString()));
906 obj.push_back(Pair("account", strAccount));
907 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
908 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
915 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
917 int64 nAmount = (*it).second.nAmount;
918 int nConf = (*it).second.nConf;
920 obj.push_back(Pair("account", (*it).first));
921 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
922 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
930 Value listreceivedbyaddress(const Array& params, bool fHelp)
932 if (fHelp || params.size() > 2)
934 "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
935 "[minconf] is the minimum number of confirmations before payments are included.\n"
936 "[includeempty] whether to include addresses that haven't received any payments.\n"
937 "Returns an array of objects containing:\n"
938 " \"address\" : receiving address\n"
939 " \"account\" : the account of the receiving address\n"
940 " \"amount\" : total amount received by the address\n"
941 " \"confirmations\" : number of confirmations of the most recent transaction included");
943 return ListReceived(params, false);
946 Value listreceivedbyaccount(const Array& params, bool fHelp)
948 if (fHelp || params.size() > 2)
950 "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
951 "[minconf] is the minimum number of confirmations before payments are included.\n"
952 "[includeempty] whether to include accounts that haven't received any payments.\n"
953 "Returns an array of objects containing:\n"
954 " \"account\" : the account of the receiving addresses\n"
955 " \"amount\" : total amount received by addresses with this account\n"
956 " \"confirmations\" : number of confirmations of the most recent transaction included");
958 return ListReceived(params, true);
961 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
963 int64 nGeneratedImmature, nGeneratedMature, nFee;
964 string strSentAccount;
965 list<pair<CTxDestination, int64> > listReceived;
966 list<pair<CTxDestination, int64> > listSent;
968 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
970 bool fAllAccounts = (strAccount == string("*"));
972 // Generated blocks assigned to account ""
973 if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
976 entry.push_back(Pair("account", string("")));
977 if (nGeneratedImmature)
979 entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
980 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
984 entry.push_back(Pair("category", "generate"));
985 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
988 WalletTxToJSON(wtx, entry);
989 ret.push_back(entry);
993 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
995 BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& s, listSent)
998 entry.push_back(Pair("account", strSentAccount));
999 entry.push_back(Pair("address", CBitcoinAddress(s.first).ToString()));
1000 entry.push_back(Pair("category", "send"));
1001 entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1002 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1004 WalletTxToJSON(wtx, entry);
1005 ret.push_back(entry);
1010 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1012 BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& r, listReceived)
1015 if (pwalletMain->mapAddressBook.count(r.first))
1016 account = pwalletMain->mapAddressBook[r.first];
1017 if (fAllAccounts || (account == strAccount))
1020 entry.push_back(Pair("account", account));
1021 entry.push_back(Pair("address", CBitcoinAddress(r.first).ToString()));
1022 if (wtx.IsCoinBase())
1024 if (wtx.GetDepthInMainChain() < 1)
1025 entry.push_back(Pair("category", "orphan"));
1026 else if (wtx.GetBlocksToMaturity() > 0)
1027 entry.push_back(Pair("category", "immature"));
1029 entry.push_back(Pair("category", "generate"));
1032 entry.push_back(Pair("category", "receive"));
1033 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1035 WalletTxToJSON(wtx, entry);
1036 ret.push_back(entry);
1042 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1044 bool fAllAccounts = (strAccount == string("*"));
1046 if (fAllAccounts || acentry.strAccount == strAccount)
1049 entry.push_back(Pair("account", acentry.strAccount));
1050 entry.push_back(Pair("category", "move"));
1051 entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
1052 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1053 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1054 entry.push_back(Pair("comment", acentry.strComment));
1055 ret.push_back(entry);
1059 Value listtransactions(const Array& params, bool fHelp)
1061 if (fHelp || params.size() > 3)
1062 throw runtime_error(
1063 "listtransactions [account] [count=10] [from=0]\n"
1064 "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1066 string strAccount = "*";
1067 if (params.size() > 0)
1068 strAccount = params[0].get_str();
1070 if (params.size() > 1)
1071 nCount = params[1].get_int();
1073 if (params.size() > 2)
1074 nFrom = params[2].get_int();
1077 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count");
1079 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative from");
1083 std::list<CAccountingEntry> acentries;
1084 CWallet::TxItems txOrdered = pwalletMain->OrderedTxItems(acentries, strAccount);
1086 // iterate backwards until we have nCount items to return:
1087 for (CWallet::TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
1089 CWalletTx *const pwtx = (*it).second.first;
1091 ListTransactions(*pwtx, strAccount, 0, true, ret);
1092 CAccountingEntry *const pacentry = (*it).second.second;
1094 AcentryToJSON(*pacentry, strAccount, ret);
1096 if ((int)ret.size() >= (nCount+nFrom)) break;
1098 // ret is newest to oldest
1100 if (nFrom > (int)ret.size())
1102 if ((nFrom + nCount) > (int)ret.size())
1103 nCount = ret.size() - nFrom;
1104 Array::iterator first = ret.begin();
1105 std::advance(first, nFrom);
1106 Array::iterator last = ret.begin();
1107 std::advance(last, nFrom+nCount);
1109 if (last != ret.end()) ret.erase(last, ret.end());
1110 if (first != ret.begin()) ret.erase(ret.begin(), first);
1112 std::reverse(ret.begin(), ret.end()); // Return oldest to newest
1117 Value listaccounts(const Array& params, bool fHelp)
1119 if (fHelp || params.size() > 1)
1120 throw runtime_error(
1121 "listaccounts [minconf=1]\n"
1122 "Returns Object that has account names as keys, account balances as values.");
1125 if (params.size() > 0)
1126 nMinDepth = params[0].get_int();
1128 map<string, int64> mapAccountBalances;
1129 BOOST_FOREACH(const PAIRTYPE(CTxDestination, string)& entry, pwalletMain->mapAddressBook) {
1130 if (IsMine(*pwalletMain, entry.first)) // This address belongs to me
1131 mapAccountBalances[entry.second] = 0;
1134 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1136 const CWalletTx& wtx = (*it).second;
1137 int64 nGeneratedImmature, nGeneratedMature, nFee;
1138 string strSentAccount;
1139 list<pair<CTxDestination, int64> > listReceived;
1140 list<pair<CTxDestination, int64> > listSent;
1141 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1142 mapAccountBalances[strSentAccount] -= nFee;
1143 BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& s, listSent)
1144 mapAccountBalances[strSentAccount] -= s.second;
1145 if (wtx.GetDepthInMainChain() >= nMinDepth)
1147 mapAccountBalances[""] += nGeneratedMature;
1148 BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& r, listReceived)
1149 if (pwalletMain->mapAddressBook.count(r.first))
1150 mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1152 mapAccountBalances[""] += r.second;
1156 list<CAccountingEntry> acentries;
1157 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1158 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1159 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1162 BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) {
1163 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1168 Value listsinceblock(const Array& params, bool fHelp)
1171 throw runtime_error(
1172 "listsinceblock [blockhash] [target-confirmations]\n"
1173 "Get all transactions in blocks since block [blockhash], or all transactions if omitted");
1175 CBlockIndex *pindex = NULL;
1176 int target_confirms = 1;
1178 if (params.size() > 0)
1180 uint256 blockId = 0;
1182 blockId.SetHex(params[0].get_str());
1183 pindex = CBlockLocator(blockId).GetBlockIndex();
1186 if (params.size() > 1)
1188 target_confirms = params[1].get_int();
1190 if (target_confirms < 1)
1191 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter");
1194 int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
1198 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1200 CWalletTx tx = (*it).second;
1202 if (depth == -1 || tx.GetDepthInMainChain() < depth)
1203 ListTransactions(tx, "*", 0, true, transactions);
1208 if (target_confirms == 1)
1210 lastblock = hashBestChain;
1214 int target_height = pindexBest->nHeight + 1 - target_confirms;
1217 for (block = pindexBest;
1218 block && block->nHeight > target_height;
1219 block = block->pprev) { }
1221 lastblock = block ? block->GetBlockHash() : 0;
1225 ret.push_back(Pair("transactions", transactions));
1226 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1231 Value gettransaction(const Array& params, bool fHelp)
1233 if (fHelp || params.size() != 1)
1234 throw runtime_error(
1235 "gettransaction <txid>\n"
1236 "Get detailed information about <txid>");
1239 hash.SetHex(params[0].get_str());
1243 if (pwalletMain->mapWallet.count(hash))
1245 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1247 TxToJSON(wtx, 0, entry);
1249 int64 nCredit = wtx.GetCredit();
1250 int64 nDebit = wtx.GetDebit();
1251 int64 nNet = nCredit - nDebit;
1252 int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
1254 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1256 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1258 WalletTxToJSON(wtx, entry);
1261 ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
1262 entry.push_back(Pair("details", details));
1267 uint256 hashBlock = 0;
1268 if (GetTransaction(hash, tx, hashBlock))
1270 entry.push_back(Pair("txid", hash.GetHex()));
1271 TxToJSON(tx, 0, entry);
1273 entry.push_back(Pair("confirmations", 0));
1276 entry.push_back(Pair("blockhash", hashBlock.GetHex()));
1277 map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
1278 if (mi != mapBlockIndex.end() && (*mi).second)
1280 CBlockIndex* pindex = (*mi).second;
1281 if (pindex->IsInMainChain())
1283 entry.push_back(Pair("confirmations", 1 + nBestHeight - pindex->nHeight));
1284 entry.push_back(Pair("txntime", (boost::int64_t)tx.nTime));
1285 entry.push_back(Pair("time", (boost::int64_t)pindex->nTime));
1288 entry.push_back(Pair("confirmations", 0));
1293 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction");
1300 Value backupwallet(const Array& params, bool fHelp)
1302 if (fHelp || params.size() != 1)
1303 throw runtime_error(
1304 "backupwallet <destination>\n"
1305 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1307 string strDest = params[0].get_str();
1308 if (!BackupWallet(*pwalletMain, strDest))
1309 throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!");
1315 Value keypoolrefill(const Array& params, bool fHelp)
1317 if (fHelp || params.size() > 0)
1318 throw runtime_error(
1320 "Fills the keypool."
1321 + HelpRequiringPassphrase());
1323 EnsureWalletIsUnlocked();
1325 pwalletMain->TopUpKeyPool();
1327 if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100))
1328 throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool.");
1334 void ThreadTopUpKeyPool(void* parg)
1336 // Make this thread recognisable as the key-topping-up thread
1337 RenameThread("bitcoin-key-top");
1339 pwalletMain->TopUpKeyPool();
1342 void ThreadCleanWalletPassphrase(void* parg)
1344 // Make this thread recognisable as the wallet relocking thread
1345 RenameThread("bitcoin-lock-wa");
1347 int64 nMyWakeTime = GetTimeMillis() + *((int64*)parg) * 1000;
1349 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1351 if (nWalletUnlockTime == 0)
1353 nWalletUnlockTime = nMyWakeTime;
1357 if (nWalletUnlockTime==0)
1359 int64 nToSleep = nWalletUnlockTime - GetTimeMillis();
1363 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1365 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1369 if (nWalletUnlockTime)
1371 nWalletUnlockTime = 0;
1372 pwalletMain->Lock();
1377 if (nWalletUnlockTime < nMyWakeTime)
1378 nWalletUnlockTime = nMyWakeTime;
1381 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1383 delete (int64*)parg;
1386 Value walletpassphrase(const Array& params, bool fHelp)
1388 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 3))
1389 throw runtime_error(
1390 "walletpassphrase <passphrase> <timeout> [mintonly]\n"
1391 "Stores the wallet decryption key in memory for <timeout> seconds.\n"
1392 "mintonly is optional true/false allowing only block minting.");
1395 if (!pwalletMain->IsCrypted())
1396 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1398 if (!pwalletMain->IsLocked())
1399 throw JSONRPCError(RPC_WALLET_ALREADY_UNLOCKED, "Error: Wallet is already unlocked, use walletlock first if need to change unlock settings.");
1400 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1401 SecureString strWalletPass;
1402 strWalletPass.reserve(100);
1403 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1404 // Alternately, find a way to make params[0] mlock()'d to begin with.
1405 strWalletPass = params[0].get_str().c_str();
1407 if (strWalletPass.length() > 0)
1409 if (!pwalletMain->Unlock(strWalletPass))
1410 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
1413 throw runtime_error(
1414 "walletpassphrase <passphrase> <timeout>\n"
1415 "Stores the wallet decryption key in memory for <timeout> seconds.");
1417 NewThread(ThreadTopUpKeyPool, NULL);
1418 int64* pnSleepTime = new int64(params[1].get_int64());
1419 NewThread(ThreadCleanWalletPassphrase, pnSleepTime);
1421 // ppcoin: if user OS account compromised prevent trivial sendmoney commands
1422 if (params.size() > 2)
1423 fWalletUnlockMintOnly = params[2].get_bool();
1425 fWalletUnlockMintOnly = false;
1431 Value walletpassphrasechange(const Array& params, bool fHelp)
1433 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1434 throw runtime_error(
1435 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1436 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1439 if (!pwalletMain->IsCrypted())
1440 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1442 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1443 // Alternately, find a way to make params[0] mlock()'d to begin with.
1444 SecureString strOldWalletPass;
1445 strOldWalletPass.reserve(100);
1446 strOldWalletPass = params[0].get_str().c_str();
1448 SecureString strNewWalletPass;
1449 strNewWalletPass.reserve(100);
1450 strNewWalletPass = params[1].get_str().c_str();
1452 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1453 throw runtime_error(
1454 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1455 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1457 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1458 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
1464 Value walletlock(const Array& params, bool fHelp)
1466 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1467 throw runtime_error(
1469 "Removes the wallet encryption key from memory, locking the wallet.\n"
1470 "After calling this method, you will need to call walletpassphrase again\n"
1471 "before being able to call any methods which require the wallet to be unlocked.");
1474 if (!pwalletMain->IsCrypted())
1475 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletlock was called.");
1478 LOCK(cs_nWalletUnlockTime);
1479 pwalletMain->Lock();
1480 nWalletUnlockTime = 0;
1487 Value encryptwallet(const Array& params, bool fHelp)
1489 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1490 throw runtime_error(
1491 "encryptwallet <passphrase>\n"
1492 "Encrypts the wallet with <passphrase>.");
1495 if (pwalletMain->IsCrypted())
1496 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an encrypted wallet, but encryptwallet was called.");
1498 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1499 // Alternately, find a way to make params[0] mlock()'d to begin with.
1500 SecureString strWalletPass;
1501 strWalletPass.reserve(100);
1502 strWalletPass = params[0].get_str().c_str();
1504 if (strWalletPass.length() < 1)
1505 throw runtime_error(
1506 "encryptwallet <passphrase>\n"
1507 "Encrypts the wallet with <passphrase>.");
1509 if (!pwalletMain->EncryptWallet(strWalletPass))
1510 throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: Failed to encrypt the wallet.");
1512 // BDB seems to have a bad habit of writing old data into
1513 // slack space in .dat files; that is bad if the old data is
1514 // unencrypted private keys. So:
1516 return "wallet encrypted; NovaCoin server stopping, restart to run with encrypted wallet. The keypool has been flushed, you need to make a new backup.";
1519 class DescribeAddressVisitor : public boost::static_visitor<Object>
1522 Object operator()(const CNoDestination &dest) const { return Object(); }
1524 Object operator()(const CKeyID &keyID) const {
1527 pwalletMain->GetPubKey(keyID, vchPubKey);
1528 obj.push_back(Pair("isscript", false));
1529 obj.push_back(Pair("pubkey", HexStr(vchPubKey.Raw())));
1530 obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed()));
1534 Object operator()(const CScriptID &scriptID) const {
1536 obj.push_back(Pair("isscript", true));
1538 pwalletMain->GetCScript(scriptID, subscript);
1539 std::vector<CTxDestination> addresses;
1540 txnouttype whichType;
1542 ExtractDestinations(subscript, whichType, addresses, nRequired);
1543 obj.push_back(Pair("script", GetTxnOutputType(whichType)));
1545 BOOST_FOREACH(const CTxDestination& addr, addresses)
1546 a.push_back(CBitcoinAddress(addr).ToString());
1547 obj.push_back(Pair("addresses", a));
1548 if (whichType == TX_MULTISIG)
1549 obj.push_back(Pair("sigsrequired", nRequired));
1554 Value validateaddress(const Array& params, bool fHelp)
1556 if (fHelp || params.size() != 1)
1557 throw runtime_error(
1558 "validateaddress <novacoinaddress>\n"
1559 "Return information about <novacoinaddress>.");
1561 CBitcoinAddress address(params[0].get_str());
1562 bool isValid = address.IsValid();
1565 ret.push_back(Pair("isvalid", isValid));
1568 CTxDestination dest = address.Get();
1569 string currentAddress = address.ToString();
1570 ret.push_back(Pair("address", currentAddress));
1571 bool fMine = IsMine(*pwalletMain, dest);
1572 ret.push_back(Pair("ismine", fMine));
1574 Object detail = boost::apply_visitor(DescribeAddressVisitor(), dest);
1575 ret.insert(ret.end(), detail.begin(), detail.end());
1577 if (pwalletMain->mapAddressBook.count(dest))
1578 ret.push_back(Pair("account", pwalletMain->mapAddressBook[dest]));
1583 Value validatepubkey(const Array& params, bool fHelp)
1585 if (fHelp || !params.size() || params.size() > 2)
1586 throw runtime_error(
1587 "validatepubkey <novacoinpubkey>\n"
1588 "Return information about <novacoinpubkey>.");
1590 std::vector<unsigned char> vchPubKey = ParseHex(params[0].get_str());
1591 CPubKey pubKey(vchPubKey);
1593 bool isValid = pubKey.IsValid();
1594 bool isCompressed = pubKey.IsCompressed();
1595 CKeyID keyID = pubKey.GetID();
1597 CBitcoinAddress address;
1601 ret.push_back(Pair("isvalid", isValid));
1604 CTxDestination dest = address.Get();
1605 string currentAddress = address.ToString();
1606 ret.push_back(Pair("address", currentAddress));
1607 bool fMine = IsMine(*pwalletMain, dest);
1608 ret.push_back(Pair("ismine", fMine));
1609 ret.push_back(Pair("iscompressed", isCompressed));
1611 Object detail = boost::apply_visitor(DescribeAddressVisitor(), dest);
1612 ret.insert(ret.end(), detail.begin(), detail.end());
1614 if (pwalletMain->mapAddressBook.count(dest))
1615 ret.push_back(Pair("account", pwalletMain->mapAddressBook[dest]));
1620 // ppcoin: reserve balance from being staked for network protection
1621 Value reservebalance(const Array& params, bool fHelp)
1623 if (fHelp || params.size() > 2)
1624 throw runtime_error(
1625 "reservebalance [<reserve> [amount]]\n"
1626 "<reserve> is true or false to turn balance reserve on or off.\n"
1627 "<amount> is a real and rounded to cent.\n"
1628 "Set reserve amount not participating in network protection.\n"
1629 "If no parameters provided current setting is printed.\n");
1631 if (params.size() > 0)
1633 bool fReserve = params[0].get_bool();
1636 if (params.size() == 1)
1637 throw runtime_error("must provide amount to reserve balance.\n");
1638 int64 nAmount = AmountFromValue(params[1]);
1639 nAmount = (nAmount / CENT) * CENT; // round to cent
1641 throw runtime_error("amount cannot be negative.\n");
1642 mapArgs["-reservebalance"] = FormatMoney(nAmount).c_str();
1646 if (params.size() > 1)
1647 throw runtime_error("cannot specify amount to turn off reserve.\n");
1648 mapArgs["-reservebalance"] = "0";
1653 int64 nReserveBalance = 0;
1654 if (mapArgs.count("-reservebalance") && !ParseMoney(mapArgs["-reservebalance"], nReserveBalance))
1655 throw runtime_error("invalid reserve balance amount\n");
1656 result.push_back(Pair("reserve", (nReserveBalance > 0)));
1657 result.push_back(Pair("amount", ValueFromAmount(nReserveBalance)));
1662 // ppcoin: check wallet integrity
1663 Value checkwallet(const Array& params, bool fHelp)
1665 if (fHelp || params.size() > 0)
1666 throw runtime_error(
1668 "Check wallet for integrity.\n");
1671 int64 nBalanceInQuestion;
1672 pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion, true);
1674 if (nMismatchSpent == 0)
1675 result.push_back(Pair("wallet check passed", true));
1678 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
1679 result.push_back(Pair("amount in question", ValueFromAmount(nBalanceInQuestion)));
1685 // ppcoin: repair wallet
1686 Value repairwallet(const Array& params, bool fHelp)
1688 if (fHelp || params.size() > 0)
1689 throw runtime_error(
1691 "Repair wallet if checkwallet reports any problem.\n");
1694 int64 nBalanceInQuestion;
1695 pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion);
1697 if (nMismatchSpent == 0)
1698 result.push_back(Pair("wallet check passed", true));
1701 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
1702 result.push_back(Pair("amount affected by repair", ValueFromAmount(nBalanceInQuestion)));
1707 // NovaCoin: resend unconfirmed wallet transactions
1708 Value resendtx(const Array& params, bool fHelp)
1710 if (fHelp || params.size() > 1)
1711 throw runtime_error(
1713 "Re-send unconfirmed transactions.\n"
1716 ResendWalletTransactions();
1721 // ppcoin: make a public-private key pair
1722 Value makekeypair(const Array& params, bool fHelp)
1724 if (fHelp || params.size() > 1)
1725 throw runtime_error(
1726 "makekeypair [prefix]\n"
1727 "Make a public/private key pair.\n"
1728 "[prefix] is optional preferred prefix for the public key.\n");
1730 string strPrefix = "";
1731 if (params.size() > 0)
1732 strPrefix = params[0].get_str();
1735 key.MakeNewKey(false);
1737 CPrivKey vchPrivKey = key.GetPrivKey();
1739 result.push_back(Pair("PrivateKey", HexStr<CPrivKey::iterator>(vchPrivKey.begin(), vchPrivKey.end())));
1740 result.push_back(Pair("PublicKey", HexStr(key.GetPubKey().Raw())));