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_t nWalletUnlockTime;
16 static CCriticalSection cs_nWalletUnlockTime;
18 extern int64_t nReserveBalance;
19 extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, json_spirit::Object& entry);
21 std::string HelpRequiringPassphrase()
23 return pwalletMain->IsCrypted()
24 ? "\n\nRequires wallet passphrase to be set with walletpassphrase first"
28 void EnsureWalletIsUnlocked()
30 if (pwalletMain->IsLocked())
31 throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
32 if (fWalletUnlockMintOnly)
33 throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Wallet unlocked for block minting only.");
36 void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
38 int confirms = wtx.GetDepthInMainChain();
39 entry.push_back(Pair("confirmations", confirms));
40 if (wtx.IsCoinBase() || wtx.IsCoinStake())
41 entry.push_back(Pair("generated", true));
44 entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex()));
45 entry.push_back(Pair("blockindex", wtx.nIndex));
46 entry.push_back(Pair("blocktime", (int64_t)(mapBlockIndex[wtx.hashBlock]->nTime)));
48 entry.push_back(Pair("txid", wtx.GetHash().GetHex()));
49 entry.push_back(Pair("time", (int64_t)wtx.GetTxTime()));
50 entry.push_back(Pair("timereceived", (int64_t)wtx.nTimeReceived));
51 BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
52 entry.push_back(Pair(item.first, item.second));
55 string AccountFromValue(const Value& value)
57 string strAccount = value.get_str();
58 if (strAccount == "*")
59 throw JSONRPCError(RPC_WALLET_INVALID_ACCOUNT_NAME, "Invalid account name");
63 Value getinfo(const Array& params, bool fHelp)
65 if (fHelp || params.size() != 0)
68 "Returns an object containing various state info.");
71 GetProxy(NET_IPV4, proxy);
74 obj.push_back(Pair("version", FormatFullVersion()));
75 obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION));
76 obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
77 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
78 obj.push_back(Pair("unspendable", ValueFromAmount(pwalletMain->GetWatchOnlyBalance())));
79 obj.push_back(Pair("newmint", ValueFromAmount(pwalletMain->GetNewMint())));
80 obj.push_back(Pair("stake", ValueFromAmount(pwalletMain->GetStake())));
81 obj.push_back(Pair("blocks", (int)nBestHeight));
82 obj.push_back(Pair("timeoffset", (int64_t)GetTimeOffset()));
83 obj.push_back(Pair("moneysupply", ValueFromAmount(pindexBest->nMoneySupply)));
84 obj.push_back(Pair("connections", (int)vNodes.size()));
85 obj.push_back(Pair("proxy", (proxy.first.IsValid() ? proxy.first.ToStringIPPort() : string())));
86 obj.push_back(Pair("ip", addrSeenByPeer.ToStringIP()));
88 diff.push_back(Pair("proof-of-work", GetDifficulty()));
89 diff.push_back(Pair("proof-of-stake", GetDifficulty(GetLastBlockIndex(pindexBest, true))));
90 obj.push_back(Pair("difficulty", diff));
92 obj.push_back(Pair("testnet", fTestNet));
93 obj.push_back(Pair("keypoololdest", (int64_t)pwalletMain->GetOldestKeyPoolTime()));
94 obj.push_back(Pair("keypoolsize", (int)pwalletMain->GetKeyPoolSize()));
95 obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee)));
96 obj.push_back(Pair("mininput", ValueFromAmount(nMinimumInputValue)));
97 if (pwalletMain->IsCrypted())
98 obj.push_back(Pair("unlocked_until", (int64_t)nWalletUnlockTime / 1000));
99 obj.push_back(Pair("errors", GetWarnings("statusbar")));
103 Value getnewaddress(const Array& params, bool fHelp)
105 if (fHelp || params.size() > 1)
107 "getnewaddress [account]\n"
108 "Returns a new NovaCoin address for receiving payments. "
109 "If [account] is specified (recommended), it is added to the address book "
110 "so payments received with the address will be credited to [account].");
112 // Parse the account first so we don't generate a key if there's an error
114 if (params.size() > 0)
115 strAccount = AccountFromValue(params[0]);
117 if (!pwalletMain->IsLocked())
118 pwalletMain->TopUpKeyPool();
120 // Generate a new key that is added to wallet
122 if (!pwalletMain->GetKeyFromPool(newKey, false))
123 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
124 CKeyID keyID = newKey.GetID();
126 pwalletMain->SetAddressBookName(keyID, strAccount);
128 return CBitcoinAddress(keyID).ToString();
132 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
134 CWalletDB walletdb(pwalletMain->strWalletFile);
137 walletdb.ReadAccount(strAccount, account);
139 bool bKeyUsed = false;
141 // Check if the current key has been used
142 if (account.vchPubKey.IsValid())
144 CScript scriptPubKey;
145 scriptPubKey.SetDestination(account.vchPubKey.GetID());
146 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
147 it != pwalletMain->mapWallet.end() && account.vchPubKey.IsValid();
150 const CWalletTx& wtx = (*it).second;
151 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
152 if (txout.scriptPubKey == scriptPubKey)
157 // Generate a new key
158 if (!account.vchPubKey.IsValid() || bForceNew || bKeyUsed)
160 if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false))
161 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
163 pwalletMain->SetAddressBookName(account.vchPubKey.GetID(), strAccount);
164 walletdb.WriteAccount(strAccount, account);
167 return CBitcoinAddress(account.vchPubKey.GetID());
170 Value getaccountaddress(const Array& params, bool fHelp)
172 if (fHelp || params.size() != 1)
174 "getaccountaddress <account>\n"
175 "Returns the current NovaCoin address for receiving payments to this account.");
177 // Parse the account first so we don't generate a key if there's an error
178 string strAccount = AccountFromValue(params[0]);
182 ret = GetAccountAddress(strAccount).ToString();
189 Value setaccount(const Array& params, bool fHelp)
191 if (fHelp || params.size() < 1 || params.size() > 2)
193 "setaccount <novacoinaddress> <account>\n"
194 "Sets the account associated with the given address.");
196 CBitcoinAddress address(params[0].get_str());
197 if (!address.IsValid())
198 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
202 if (params.size() > 1)
203 strAccount = AccountFromValue(params[1]);
205 // Detect when changing the account of an address that is the 'unused current key' of another account:
206 if (pwalletMain->mapAddressBook.count(address.Get()))
208 string strOldAccount = pwalletMain->mapAddressBook[address.Get()];
209 if (address == GetAccountAddress(strOldAccount))
210 GetAccountAddress(strOldAccount, true);
213 pwalletMain->SetAddressBookName(address.Get(), strAccount);
219 Value getaccount(const Array& params, bool fHelp)
221 if (fHelp || params.size() != 1)
223 "getaccount <novacoinaddress>\n"
224 "Returns the account associated with the given address.");
226 CBitcoinAddress address(params[0].get_str());
227 if (!address.IsValid())
228 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
231 map<CTxDestination, string>::iterator mi = pwalletMain->mapAddressBook.find(address.Get());
232 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
233 strAccount = (*mi).second;
238 Value getaddressesbyaccount(const Array& params, bool fHelp)
240 if (fHelp || params.size() != 1)
242 "getaddressesbyaccount <account>\n"
243 "Returns the list of addresses for the given account.");
245 string strAccount = AccountFromValue(params[0]);
247 // Find all addresses that have the given account
249 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
251 const CBitcoinAddress& address = item.first;
252 const string& strName = item.second;
253 if (strName == strAccount)
254 ret.push_back(address.ToString());
259 Value mergecoins(const Array& params, bool fHelp)
261 if (fHelp || params.size() != 3)
263 "mergecoins <amount> <minvalue> <outputvalue>\n"
264 "<amount> is resulting inputs sum\n"
265 "<minvalue> is minimum value of inputs which are used in join process\n"
266 "<outputvalue> is resulting value of inputs which will be created\n"
267 "All values are real and and rounded to the nearest " + FormatMoney(nMinimumInputValue)
268 + HelpRequiringPassphrase());
270 if (pwalletMain->IsLocked())
271 throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
274 int64_t nAmount = AmountFromValue(params[0]);
277 int64_t nMinValue = AmountFromValue(params[1]);
280 int64_t nOutputValue = AmountFromValue(params[2]);
282 if (nAmount < nMinimumInputValue)
283 throw JSONRPCError(-101, "Send amount too small");
285 if (nMinValue < nMinimumInputValue)
286 throw JSONRPCError(-101, "Max value too small");
288 if (nOutputValue < nMinimumInputValue)
289 throw JSONRPCError(-101, "Output value too small");
291 if (nOutputValue < nMinValue)
292 throw JSONRPCError(-101, "Output value is lower than min value");
294 list<uint256> listMerged;
295 if (!pwalletMain->MergeCoins(nAmount, nMinValue, nOutputValue, listMerged))
299 BOOST_FOREACH(const uint256 txHash, listMerged)
300 mergedHashes.push_back(txHash.GetHex());
305 Value sendtoaddress(const Array& params, bool fHelp)
307 if (fHelp || params.size() < 2 || params.size() > 4)
309 "sendtoaddress <novacoinaddress> <amount> [comment] [comment-to]\n"
310 "<amount> is a real and is rounded to the nearest " + FormatMoney(nMinimumInputValue)
311 + HelpRequiringPassphrase());
313 CBitcoinAddress address(params[0].get_str());
314 if (!address.IsValid())
315 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
318 int64_t nAmount = AmountFromValue(params[1]);
320 if (nAmount < nMinimumInputValue)
321 throw JSONRPCError(-101, "Send amount too small");
325 if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
326 wtx.mapValue["comment"] = params[2].get_str();
327 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
328 wtx.mapValue["to"] = params[3].get_str();
330 if (pwalletMain->IsLocked())
331 throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
333 string strError = pwalletMain->SendMoneyToDestination(address.Get(), nAmount, wtx);
335 throw JSONRPCError(RPC_WALLET_ERROR, strError);
337 return wtx.GetHash().GetHex();
340 Value listaddressgroupings(const Array& params, bool fHelp)
344 "listaddressgroupings\n"
345 "Lists groups of addresses which have had their common ownership\n"
346 "made public by common use as inputs or as the resulting change\n"
347 "in past transactions");
350 map<CTxDestination, int64_t> balances = pwalletMain->GetAddressBalances();
351 BOOST_FOREACH(set<CTxDestination> grouping, pwalletMain->GetAddressGroupings())
354 BOOST_FOREACH(CTxDestination address, grouping)
357 addressInfo.push_back(CBitcoinAddress(address).ToString());
358 addressInfo.push_back(ValueFromAmount(balances[address]));
360 LOCK(pwalletMain->cs_wallet);
361 if (pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get()) != pwalletMain->mapAddressBook.end())
362 addressInfo.push_back(pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get())->second);
364 jsonGrouping.push_back(addressInfo);
366 jsonGroupings.push_back(jsonGrouping);
368 return jsonGroupings;
371 Value signmessage(const Array& params, bool fHelp)
373 if (fHelp || params.size() != 2)
375 "signmessage <novacoinaddress> <message>\n"
376 "Sign a message with the private key of an address");
378 EnsureWalletIsUnlocked();
380 string strAddress = params[0].get_str();
381 string strMessage = params[1].get_str();
383 CBitcoinAddress addr(strAddress);
385 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
388 if (!addr.GetKeyID(keyID))
389 throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
392 if (!pwalletMain->GetKey(keyID, key))
393 throw JSONRPCError(RPC_WALLET_ERROR, "Private key not available");
395 CDataStream ss(SER_GETHASH, 0);
396 ss << strMessageMagic;
399 vector<unsigned char> vchSig;
400 if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
401 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed");
403 return EncodeBase64(&vchSig[0], vchSig.size());
406 Value verifymessage(const Array& params, bool fHelp)
408 if (fHelp || params.size() != 3)
410 "verifymessage <novacoinaddress> <signature> <message>\n"
411 "Verify a signed message");
413 string strAddress = params[0].get_str();
414 string strSign = params[1].get_str();
415 string strMessage = params[2].get_str();
417 CBitcoinAddress addr(strAddress);
419 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
422 if (!addr.GetKeyID(keyID))
423 throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
425 bool fInvalid = false;
426 vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
429 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Malformed base64 encoding");
431 CDataStream ss(SER_GETHASH, 0);
432 ss << strMessageMagic;
436 if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
439 return (key.GetPubKey().GetID() == keyID);
443 Value getreceivedbyaddress(const Array& params, bool fHelp)
445 if (fHelp || params.size() < 1 || params.size() > 2)
447 "getreceivedbyaddress <novacoinaddress> [minconf=1]\n"
448 "Returns the total amount received by <novacoinaddress> in transactions with at least [minconf] confirmations.");
451 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
452 CScript scriptPubKey;
453 if (!address.IsValid())
454 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
455 scriptPubKey.SetDestination(address.Get());
456 if (!IsMine(*pwalletMain,scriptPubKey))
459 // Minimum confirmations
461 if (params.size() > 1)
462 nMinDepth = params[1].get_int();
466 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
468 const CWalletTx& wtx = (*it).second;
469 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
472 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
473 if (txout.scriptPubKey == scriptPubKey)
474 if (wtx.GetDepthInMainChain() >= nMinDepth)
475 nAmount += txout.nValue;
478 return ValueFromAmount(nAmount);
482 void GetAccountAddresses(string strAccount, set<CTxDestination>& setAddress)
484 BOOST_FOREACH(const PAIRTYPE(CTxDestination, string)& item, pwalletMain->mapAddressBook)
486 const CTxDestination& address = item.first;
487 const string& strName = item.second;
488 if (strName == strAccount)
489 setAddress.insert(address);
493 Value getreceivedbyaccount(const Array& params, bool fHelp)
495 if (fHelp || params.size() < 1 || params.size() > 2)
497 "getreceivedbyaccount <account> [minconf=1]\n"
498 "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
500 // Minimum confirmations
502 if (params.size() > 1)
503 nMinDepth = params[1].get_int();
505 // Get the set of pub keys assigned to account
506 string strAccount = AccountFromValue(params[0]);
507 set<CTxDestination> setAddress;
508 GetAccountAddresses(strAccount, setAddress);
512 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
514 const CWalletTx& wtx = (*it).second;
515 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
518 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
520 CTxDestination address;
521 if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*pwalletMain, address) && setAddress.count(address))
522 if (wtx.GetDepthInMainChain() >= nMinDepth)
523 nAmount += txout.nValue;
527 return (double)nAmount / (double)COIN;
531 int64_t GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth, const isminefilter& filter)
533 int64_t nBalance = 0;
535 // Tally wallet transactions
536 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
538 const CWalletTx& wtx = (*it).second;
542 int64_t nGenerated, nReceived, nSent, nFee;
543 wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee, filter);
545 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
546 nBalance += nReceived;
547 nBalance += nGenerated - nSent - nFee;
550 // Tally internal accounting entries
551 nBalance += walletdb.GetAccountCreditDebit(strAccount);
556 int64_t GetAccountBalance(const string& strAccount, int nMinDepth, const isminefilter& filter)
558 CWalletDB walletdb(pwalletMain->strWalletFile);
559 return GetAccountBalance(walletdb, strAccount, nMinDepth, filter);
563 Value getbalance(const Array& params, bool fHelp)
565 if (fHelp || params.size() > 2)
567 "getbalance [account] [minconf=1] [watchonly=0]\n"
568 "If [account] is not specified, returns the server's total available balance.\n"
569 "If [account] is specified, returns the balance in the account.\n"
570 "if [includeWatchonly] is specified, include balance in watchonly addresses (see 'importaddress').");
572 if (params.size() == 0)
573 return ValueFromAmount(pwalletMain->GetBalance());
576 if (params.size() > 1)
577 nMinDepth = params[1].get_int();
578 isminefilter filter = MINE_SPENDABLE;
579 if(params.size() > 2)
580 if(params[2].get_bool())
581 filter = filter | MINE_WATCH_ONLY;
583 if (params[0].get_str() == "*") {
584 // Calculate total balance a different way from GetBalance()
585 // (GetBalance() sums up all unspent TxOuts)
586 // getbalance and getbalance '*' 0 should return the same number.
587 int64_t nBalance = 0;
588 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
590 const CWalletTx& wtx = (*it).second;
591 if (!wtx.IsTrusted())
594 int64_t allGeneratedImmature, allGeneratedMature, allFee;
595 allGeneratedImmature = allGeneratedMature = allFee = 0;
597 string strSentAccount;
598 list<pair<CTxDestination, int64_t> > listReceived;
599 list<pair<CTxDestination, int64_t> > listSent;
600 wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount, filter);
601 if (wtx.GetDepthInMainChain() >= nMinDepth)
603 BOOST_FOREACH(const PAIRTYPE(CTxDestination,int64_t)& r, listReceived)
604 nBalance += r.second;
606 BOOST_FOREACH(const PAIRTYPE(CTxDestination,int64_t)& r, listSent)
607 nBalance -= r.second;
609 nBalance += allGeneratedMature;
611 return ValueFromAmount(nBalance);
614 string strAccount = AccountFromValue(params[0]);
616 int64_t nBalance = GetAccountBalance(strAccount, nMinDepth, filter);
618 return ValueFromAmount(nBalance);
622 Value movecmd(const Array& params, bool fHelp)
624 if (fHelp || params.size() < 3 || params.size() > 5)
626 "move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
627 "Move from one account in your wallet to another.");
629 string strFrom = AccountFromValue(params[0]);
630 string strTo = AccountFromValue(params[1]);
631 int64_t nAmount = AmountFromValue(params[2]);
633 if (nAmount < nMinimumInputValue)
634 throw JSONRPCError(-101, "Send amount too small");
636 if (params.size() > 3)
637 // unused parameter, used to be nMinDepth, keep type-checking it though
638 (void)params[3].get_int();
640 if (params.size() > 4)
641 strComment = params[4].get_str();
643 CWalletDB walletdb(pwalletMain->strWalletFile);
644 if (!walletdb.TxnBegin())
645 throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
647 int64_t nNow = GetAdjustedTime();
650 CAccountingEntry debit;
651 debit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
652 debit.strAccount = strFrom;
653 debit.nCreditDebit = -nAmount;
655 debit.strOtherAccount = strTo;
656 debit.strComment = strComment;
657 walletdb.WriteAccountingEntry(debit);
660 CAccountingEntry credit;
661 credit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
662 credit.strAccount = strTo;
663 credit.nCreditDebit = nAmount;
665 credit.strOtherAccount = strFrom;
666 credit.strComment = strComment;
667 walletdb.WriteAccountingEntry(credit);
669 if (!walletdb.TxnCommit())
670 throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
676 Value sendfrom(const Array& params, bool fHelp)
678 if (fHelp || params.size() < 3 || params.size() > 6)
680 "sendfrom <fromaccount> <tonovacoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
681 "<amount> is a real and is rounded to the nearest " + FormatMoney(nMinimumInputValue)
682 + HelpRequiringPassphrase());
684 string strAccount = AccountFromValue(params[0]);
685 CBitcoinAddress address(params[1].get_str());
686 if (!address.IsValid())
687 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
688 int64_t nAmount = AmountFromValue(params[2]);
690 if (nAmount < nMinimumInputValue)
691 throw JSONRPCError(-101, "Send amount too small");
694 if (params.size() > 3)
695 nMinDepth = params[3].get_int();
698 wtx.strFromAccount = strAccount;
699 if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
700 wtx.mapValue["comment"] = params[4].get_str();
701 if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
702 wtx.mapValue["to"] = params[5].get_str();
704 EnsureWalletIsUnlocked();
707 int64_t nBalance = GetAccountBalance(strAccount, nMinDepth, MINE_SPENDABLE);
708 if (nAmount > nBalance)
709 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
712 string strError = pwalletMain->SendMoneyToDestination(address.Get(), nAmount, wtx);
714 throw JSONRPCError(RPC_WALLET_ERROR, strError);
716 return wtx.GetHash().GetHex();
720 Value sendmany(const Array& params, bool fHelp)
722 if (fHelp || params.size() < 2 || params.size() > 4)
724 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
725 "amounts are double-precision floating point numbers"
726 + HelpRequiringPassphrase());
728 string strAccount = AccountFromValue(params[0]);
729 Object sendTo = params[1].get_obj();
731 if (params.size() > 2)
732 nMinDepth = params[2].get_int();
735 wtx.strFromAccount = strAccount;
736 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
737 wtx.mapValue["comment"] = params[3].get_str();
739 set<CBitcoinAddress> setAddress;
740 vector<pair<CScript, int64_t> > vecSend;
742 int64_t totalAmount = 0;
743 BOOST_FOREACH(const Pair& s, sendTo)
745 CBitcoinAddress address(s.name_);
746 if (!address.IsValid())
747 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid NovaCoin address: ")+s.name_);
749 if (setAddress.count(address))
750 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+s.name_);
751 setAddress.insert(address);
753 CScript scriptPubKey;
754 scriptPubKey.SetDestination(address.Get());
755 int64_t nAmount = AmountFromValue(s.value_);
757 if (nAmount < nMinimumInputValue)
758 throw JSONRPCError(-101, "Send amount too small");
760 totalAmount += nAmount;
762 vecSend.push_back(make_pair(scriptPubKey, nAmount));
765 EnsureWalletIsUnlocked();
768 int64_t nBalance = GetAccountBalance(strAccount, nMinDepth, MINE_SPENDABLE);
769 if (totalAmount > nBalance)
770 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
773 CReserveKey keyChange(pwalletMain);
774 int64_t nFeeRequired = 0;
775 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
778 int64_t nTotal = pwalletMain->GetBalance(), nWatchOnly = pwalletMain->GetWatchOnlyBalance();
779 if (totalAmount + nFeeRequired > nTotal - nWatchOnly)
780 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds");
781 throw JSONRPCError(RPC_WALLET_ERROR, "Transaction creation failed");
783 if (!pwalletMain->CommitTransaction(wtx, keyChange))
784 throw JSONRPCError(RPC_WALLET_ERROR, "Transaction commit failed");
786 return wtx.GetHash().GetHex();
789 Value addmultisigaddress(const Array& params, bool fHelp)
791 if (fHelp || params.size() < 2 || params.size() > 3)
793 string msg = "addmultisigaddress <nrequired> <'[\"key\",\"key\"]'> [account]\n"
794 "Add a nrequired-to-sign multisignature address to the wallet\"\n"
795 "each key is a NovaCoin address or hex-encoded public key\n"
796 "If [account] is specified, assign address to [account].";
797 throw runtime_error(msg);
800 int nRequired = params[0].get_int();
801 const Array& keys = params[1].get_array();
803 if (params.size() > 2)
804 strAccount = AccountFromValue(params[2]);
806 // Gather public keys
808 throw runtime_error("a multisignature address must require at least one key to redeem");
809 if ((int)keys.size() < nRequired)
811 strprintf("not enough keys supplied "
812 "(got %" PRIszu " keys, but need at least %d to redeem)", keys.size(), nRequired));
813 if (keys.size() > 16)
814 throw runtime_error("Number of addresses involved in the multisignature address creation > 16\nReduce the number");
815 std::vector<CKey> pubkeys;
816 pubkeys.resize(keys.size());
817 for (unsigned int i = 0; i < keys.size(); i++)
819 const std::string& ks = keys[i].get_str();
821 // Case 1: Bitcoin address and we have full public key:
822 CBitcoinAddress address(ks);
823 if (address.IsValid())
826 if (!address.GetKeyID(keyID))
828 strprintf("%s does not refer to a key",ks.c_str()));
830 if (!pwalletMain->GetPubKey(keyID, vchPubKey))
832 strprintf("no full public key for address %s",ks.c_str()));
833 if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey))
834 throw runtime_error(" Invalid public key: "+ks);
837 // Case 2: hex public key
840 CPubKey vchPubKey(ParseHex(ks));
841 if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey))
842 throw runtime_error(" Invalid public key: "+ks);
846 throw runtime_error(" Invalid public key: "+ks);
850 // Construct using pay-to-script-hash:
852 inner.SetMultisig(nRequired, pubkeys);
854 if (inner.size() > MAX_SCRIPT_ELEMENT_SIZE)
856 strprintf("redeemScript exceeds size limit: %" PRIszu " > %d", inner.size(), MAX_SCRIPT_ELEMENT_SIZE));
858 CScriptID innerID = inner.GetID();
859 pwalletMain->AddCScript(inner);
861 pwalletMain->SetAddressBookName(innerID, strAccount);
862 return CBitcoinAddress(innerID).ToString();
865 Value addredeemscript(const Array& params, bool fHelp)
867 if (fHelp || params.size() < 1 || params.size() > 2)
869 string msg = "addredeemscript <redeemScript> [account]\n"
870 "Add a P2SH address with a specified redeemScript to the wallet.\n"
871 "If [account] is specified, assign address to [account].";
872 throw runtime_error(msg);
876 if (params.size() > 1)
877 strAccount = AccountFromValue(params[1]);
879 // Construct using pay-to-script-hash:
880 vector<unsigned char> innerData = ParseHexV(params[0], "redeemScript");
881 CScript inner(innerData.begin(), innerData.end());
882 CScriptID innerID = inner.GetID();
883 pwalletMain->AddCScript(inner);
885 pwalletMain->SetAddressBookName(innerID, strAccount);
886 return CBitcoinAddress(innerID).ToString();
896 nConf = std::numeric_limits<int>::max();
900 Value ListReceived(const Array& params, bool fByAccounts)
902 // Minimum confirmations
904 if (params.size() > 0)
905 nMinDepth = params[0].get_int();
907 // Whether to include empty accounts
908 bool fIncludeEmpty = false;
909 if (params.size() > 1)
910 fIncludeEmpty = params[1].get_bool();
913 map<CBitcoinAddress, tallyitem> mapTally;
914 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
916 const CWalletTx& wtx = (*it).second;
918 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
921 int nDepth = wtx.GetDepthInMainChain();
922 if (nDepth < nMinDepth)
925 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
927 CTxDestination address;
928 if (!ExtractDestination(txout.scriptPubKey, address) || !IsMine(*pwalletMain, address))
931 tallyitem& item = mapTally[address];
932 item.nAmount += txout.nValue;
933 item.nConf = min(item.nConf, nDepth);
939 map<string, tallyitem> mapAccountTally;
940 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
942 const CBitcoinAddress& address = item.first;
943 const string& strAccount = item.second;
944 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
945 if (it == mapTally.end() && !fIncludeEmpty)
949 int nConf = std::numeric_limits<int>::max();
950 if (it != mapTally.end())
952 nAmount = (*it).second.nAmount;
953 nConf = (*it).second.nConf;
958 tallyitem& item = mapAccountTally[strAccount];
959 item.nAmount += nAmount;
960 item.nConf = min(item.nConf, nConf);
965 obj.push_back(Pair("address", address.ToString()));
966 obj.push_back(Pair("account", strAccount));
967 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
968 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
975 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
977 int64_t nAmount = (*it).second.nAmount;
978 int nConf = (*it).second.nConf;
980 obj.push_back(Pair("account", (*it).first));
981 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
982 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
990 Value listreceivedbyaddress(const Array& params, bool fHelp)
992 if (fHelp || params.size() > 2)
994 "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
995 "[minconf] is the minimum number of confirmations before payments are included.\n"
996 "[includeempty] whether to include addresses that haven't received any payments.\n"
997 "Returns an array of objects containing:\n"
998 " \"address\" : receiving address\n"
999 " \"account\" : the account of the receiving address\n"
1000 " \"amount\" : total amount received by the address\n"
1001 " \"confirmations\" : number of confirmations of the most recent transaction included");
1003 return ListReceived(params, false);
1006 Value listreceivedbyaccount(const Array& params, bool fHelp)
1008 if (fHelp || params.size() > 2)
1009 throw runtime_error(
1010 "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
1011 "[minconf] is the minimum number of confirmations before payments are included.\n"
1012 "[includeempty] whether to include accounts that haven't received any payments.\n"
1013 "Returns an array of objects containing:\n"
1014 " \"account\" : the account of the receiving addresses\n"
1015 " \"amount\" : total amount received by addresses with this account\n"
1016 " \"confirmations\" : number of confirmations of the most recent transaction included");
1018 return ListReceived(params, true);
1021 static void MaybePushAddress(Object & entry, const CTxDestination &dest)
1023 CBitcoinAddress addr;
1025 entry.push_back(Pair("address", addr.ToString()));
1028 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret, const isminefilter& filter)
1030 int64_t nGeneratedImmature, nGeneratedMature, nFee;
1031 string strSentAccount;
1032 list<pair<CTxDestination, int64_t> > listReceived;
1033 list<pair<CTxDestination, int64_t> > listSent;
1035 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount, filter);
1037 bool fAllAccounts = (strAccount == string("*"));
1038 bool involvesWatchonly = wtx.IsFromMe(MINE_WATCH_ONLY);
1040 // Generated blocks assigned to account ""
1041 if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
1044 entry.push_back(Pair("account", string("")));
1045 if (nGeneratedImmature)
1047 entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
1048 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
1052 entry.push_back(Pair("category", "generate"));
1053 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
1056 WalletTxToJSON(wtx, entry);
1057 ret.push_back(entry);
1061 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1063 BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64_t)& s, listSent)
1066 entry.push_back(Pair("account", strSentAccount));
1067 if(involvesWatchonly || (::IsMine(*pwalletMain, s.first) & MINE_WATCH_ONLY))
1068 entry.push_back(Pair("involvesWatchonly", true));
1069 MaybePushAddress(entry, s.first);
1071 if (wtx.GetDepthInMainChain() < 0) {
1072 entry.push_back(Pair("category", "conflicted"));
1074 entry.push_back(Pair("category", "send"));
1077 entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1078 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1080 WalletTxToJSON(wtx, entry);
1081 ret.push_back(entry);
1086 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1088 BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64_t)& r, listReceived)
1091 if (pwalletMain->mapAddressBook.count(r.first))
1092 account = pwalletMain->mapAddressBook[r.first];
1093 if (fAllAccounts || (account == strAccount))
1096 entry.push_back(Pair("account", account));
1097 if(involvesWatchonly || (::IsMine(*pwalletMain, r.first) & MINE_WATCH_ONLY))
1098 entry.push_back(Pair("involvesWatchonly", true));
1099 MaybePushAddress(entry, r.first);
1100 if (wtx.IsCoinBase())
1102 if (wtx.GetDepthInMainChain() < 1)
1103 entry.push_back(Pair("category", "orphan"));
1104 else if (wtx.GetBlocksToMaturity() > 0)
1105 entry.push_back(Pair("category", "immature"));
1107 entry.push_back(Pair("category", "generate"));
1110 entry.push_back(Pair("category", "receive"));
1111 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1113 WalletTxToJSON(wtx, entry);
1114 ret.push_back(entry);
1120 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1122 bool fAllAccounts = (strAccount == string("*"));
1124 if (fAllAccounts || acentry.strAccount == strAccount)
1127 entry.push_back(Pair("account", acentry.strAccount));
1128 entry.push_back(Pair("category", "move"));
1129 entry.push_back(Pair("time", (int64_t)acentry.nTime));
1130 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1131 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1132 entry.push_back(Pair("comment", acentry.strComment));
1133 ret.push_back(entry);
1137 Value listtransactions(const Array& params, bool fHelp)
1139 if (fHelp || params.size() > 3)
1140 throw runtime_error(
1141 "listtransactions [account] [count=10] [from=0]\n"
1142 "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1144 string strAccount = "*";
1145 if (params.size() > 0)
1146 strAccount = params[0].get_str();
1148 if (params.size() > 1)
1149 nCount = params[1].get_int();
1151 if (params.size() > 2)
1152 nFrom = params[2].get_int();
1154 isminefilter filter = MINE_SPENDABLE;
1155 if(params.size() > 3)
1156 if(params[3].get_bool())
1157 filter = filter | MINE_WATCH_ONLY;
1160 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count");
1162 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative from");
1166 std::list<CAccountingEntry> acentries;
1167 CWallet::TxItems txOrdered = pwalletMain->OrderedTxItems(acentries, strAccount);
1169 // iterate backwards until we have nCount items to return:
1170 for (CWallet::TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
1172 CWalletTx *const pwtx = (*it).second.first;
1174 ListTransactions(*pwtx, strAccount, 0, true, ret, filter);
1175 CAccountingEntry *const pacentry = (*it).second.second;
1177 AcentryToJSON(*pacentry, strAccount, ret);
1179 if ((int)ret.size() >= (nCount+nFrom)) break;
1181 // ret is newest to oldest
1183 if (nFrom > (int)ret.size())
1185 if ((nFrom + nCount) > (int)ret.size())
1186 nCount = ret.size() - nFrom;
1187 Array::iterator first = ret.begin();
1188 std::advance(first, nFrom);
1189 Array::iterator last = ret.begin();
1190 std::advance(last, nFrom+nCount);
1192 if (last != ret.end()) ret.erase(last, ret.end());
1193 if (first != ret.begin()) ret.erase(ret.begin(), first);
1195 std::reverse(ret.begin(), ret.end()); // Return oldest to newest
1200 Value listaccounts(const Array& params, bool fHelp)
1202 if (fHelp || params.size() > 1)
1203 throw runtime_error(
1204 "listaccounts [minconf=1]\n"
1205 "Returns Object that has account names as keys, account balances as values.");
1208 if (params.size() > 0)
1209 nMinDepth = params[0].get_int();
1211 isminefilter includeWatchonly = MINE_SPENDABLE;
1212 if(params.size() > 1)
1213 if(params[1].get_bool())
1214 includeWatchonly = includeWatchonly | MINE_WATCH_ONLY;
1217 map<string, int64_t> mapAccountBalances;
1218 BOOST_FOREACH(const PAIRTYPE(CTxDestination, string)& entry, pwalletMain->mapAddressBook) {
1219 if (IsMine(*pwalletMain, entry.first)) // This address belongs to me
1220 mapAccountBalances[entry.second] = 0;
1223 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1225 const CWalletTx& wtx = (*it).second;
1226 int64_t nGeneratedImmature, nGeneratedMature, nFee;
1227 string strSentAccount;
1228 list<pair<CTxDestination, int64_t> > listReceived;
1229 list<pair<CTxDestination, int64_t> > listSent;
1230 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount, includeWatchonly);
1231 mapAccountBalances[strSentAccount] -= nFee;
1232 BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64_t)& s, listSent)
1233 mapAccountBalances[strSentAccount] -= s.second;
1234 if (wtx.GetDepthInMainChain() >= nMinDepth)
1236 mapAccountBalances[""] += nGeneratedMature;
1237 BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64_t)& r, listReceived)
1238 if (pwalletMain->mapAddressBook.count(r.first))
1239 mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1241 mapAccountBalances[""] += r.second;
1245 list<CAccountingEntry> acentries;
1246 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1247 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1248 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1251 BOOST_FOREACH(const PAIRTYPE(string, int64_t)& accountBalance, mapAccountBalances) {
1252 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1257 Value listsinceblock(const Array& params, bool fHelp)
1260 throw runtime_error(
1261 "listsinceblock [blockhash] [target-confirmations]\n"
1262 "Get all transactions in blocks since block [blockhash], or all transactions if omitted");
1264 CBlockIndex *pindex = NULL;
1265 int target_confirms = 1;
1266 isminefilter filter = MINE_SPENDABLE;
1268 if (params.size() > 0)
1270 uint256 blockId = 0;
1272 blockId.SetHex(params[0].get_str());
1273 pindex = CBlockLocator(blockId).GetBlockIndex();
1276 if (params.size() > 1)
1278 target_confirms = params[1].get_int();
1280 if (target_confirms < 1)
1281 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter");
1284 if(params.size() > 2)
1285 if(params[2].get_bool())
1286 filter = filter | MINE_WATCH_ONLY;
1288 int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
1292 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1294 CWalletTx tx = (*it).second;
1296 if (depth == -1 || tx.GetDepthInMainChain() < depth)
1297 ListTransactions(tx, "*", 0, true, transactions, filter);
1302 if (target_confirms == 1)
1304 lastblock = hashBestChain;
1308 int target_height = pindexBest->nHeight + 1 - target_confirms;
1311 for (block = pindexBest;
1312 block && block->nHeight > target_height;
1313 block = block->pprev) { }
1315 lastblock = block ? block->GetBlockHash() : 0;
1319 ret.push_back(Pair("transactions", transactions));
1320 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1325 Value gettransaction(const Array& params, bool fHelp)
1327 if (fHelp || params.size() != 1)
1328 throw runtime_error(
1329 "gettransaction <txid>\n"
1330 "Get detailed information about <txid>");
1333 hash.SetHex(params[0].get_str());
1335 isminefilter filter = MINE_SPENDABLE;
1336 if(params.size() > 1)
1337 if(params[1].get_bool())
1338 filter = filter | MINE_WATCH_ONLY;
1342 if (pwalletMain->mapWallet.count(hash))
1344 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1346 TxToJSON(wtx, 0, entry);
1348 int64_t nCredit = wtx.GetCredit(filter);
1349 int64_t nDebit = wtx.GetDebit(filter);
1350 int64_t nNet = nCredit - nDebit;
1351 int64_t nFee = (wtx.IsFromMe(filter) ? wtx.GetValueOut() - nDebit : 0);
1353 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1354 if (wtx.IsFromMe(filter))
1355 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1357 WalletTxToJSON(wtx, entry);
1360 ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details, filter);
1361 entry.push_back(Pair("details", details));
1366 uint256 hashBlock = 0;
1367 if (GetTransaction(hash, tx, hashBlock))
1369 TxToJSON(tx, 0, entry);
1371 entry.push_back(Pair("confirmations", 0));
1374 entry.push_back(Pair("blockhash", hashBlock.GetHex()));
1375 map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
1376 if (mi != mapBlockIndex.end() && (*mi).second)
1378 CBlockIndex* pindex = (*mi).second;
1379 if (pindex->IsInMainChain())
1380 entry.push_back(Pair("confirmations", 1 + nBestHeight - pindex->nHeight));
1382 entry.push_back(Pair("confirmations", 0));
1387 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction");
1394 Value backupwallet(const Array& params, bool fHelp)
1396 if (fHelp || params.size() != 1)
1397 throw runtime_error(
1398 "backupwallet <destination>\n"
1399 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1401 string strDest = params[0].get_str();
1402 if (!BackupWallet(*pwalletMain, strDest))
1403 throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!");
1409 Value keypoolrefill(const Array& params, bool fHelp)
1411 if (fHelp || params.size() > 1)
1412 throw runtime_error(
1413 "keypoolrefill [new-size]\n"
1414 "Fills the keypool.\n"
1415 "IMPORTANT: Any previous backups you have made of your wallet file "
1416 "should be replaced with the newly generated one."
1417 + HelpRequiringPassphrase());
1419 unsigned int nSize = max<unsigned int>(GetArg("-keypool", 100), 0);
1420 if (params.size() > 0) {
1421 if (params[0].get_int() < 0)
1422 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size");
1423 nSize = (unsigned int) params[0].get_int();
1426 EnsureWalletIsUnlocked();
1428 pwalletMain->TopUpKeyPool(nSize);
1430 if (pwalletMain->GetKeyPoolSize() < nSize)
1431 throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool.");
1436 Value keypoolreset(const Array& params, bool fHelp)
1438 if (fHelp || params.size() > 1)
1439 throw runtime_error(
1440 "keypoolreset [new-size]\n"
1441 "Resets the keypool.\n"
1442 "IMPORTANT: Any previous backups you have made of your wallet file "
1443 "should be replaced with the newly generated one."
1444 + HelpRequiringPassphrase());
1446 unsigned int nSize = max<unsigned int>(GetArg("-keypool", 100), 0);
1447 if (params.size() > 0) {
1448 if (params[0].get_int() < 0)
1449 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size");
1450 nSize = (unsigned int) params[0].get_int();
1453 EnsureWalletIsUnlocked();
1455 pwalletMain->NewKeyPool(nSize);
1457 if (pwalletMain->GetKeyPoolSize() < nSize)
1458 throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool.");
1464 void ThreadTopUpKeyPool(void* parg)
1466 // Make this thread recognisable as the key-topping-up thread
1467 RenameThread("novacoin-key-top");
1469 pwalletMain->TopUpKeyPool();
1472 void ThreadCleanWalletPassphrase(void* parg)
1474 // Make this thread recognisable as the wallet relocking thread
1475 RenameThread("novacoin-lock-wa");
1477 int64_t nMyWakeTime = GetTimeMillis() + *((int64_t*)parg) * 1000;
1479 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1481 if (nWalletUnlockTime == 0)
1483 nWalletUnlockTime = nMyWakeTime;
1487 if (nWalletUnlockTime==0)
1489 int64_t nToSleep = nWalletUnlockTime - GetTimeMillis();
1493 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1495 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1499 if (nWalletUnlockTime)
1501 nWalletUnlockTime = 0;
1502 pwalletMain->Lock();
1507 if (nWalletUnlockTime < nMyWakeTime)
1508 nWalletUnlockTime = nMyWakeTime;
1511 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1513 delete (int64_t*)parg;
1516 Value walletpassphrase(const Array& params, bool fHelp)
1518 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 3))
1519 throw runtime_error(
1520 "walletpassphrase <passphrase> <timeout> [mintonly]\n"
1521 "Stores the wallet decryption key in memory for <timeout> seconds.\n"
1522 "mintonly is optional true/false allowing only block minting.");
1525 if (!pwalletMain->IsCrypted())
1526 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1528 if (!pwalletMain->IsLocked())
1529 throw JSONRPCError(RPC_WALLET_ALREADY_UNLOCKED, "Error: Wallet is already unlocked, use walletlock first if need to change unlock settings.");
1530 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1531 SecureString strWalletPass;
1532 strWalletPass.reserve(100);
1533 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1534 // Alternately, find a way to make params[0] mlock()'d to begin with.
1535 strWalletPass = params[0].get_str().c_str();
1537 if (strWalletPass.length() > 0)
1539 if (!pwalletMain->Unlock(strWalletPass))
1540 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
1543 throw runtime_error(
1544 "walletpassphrase <passphrase> <timeout>\n"
1545 "Stores the wallet decryption key in memory for <timeout> seconds.");
1547 NewThread(ThreadTopUpKeyPool, NULL);
1548 int64_t* pnSleepTime = new int64_t(params[1].get_int64());
1549 NewThread(ThreadCleanWalletPassphrase, pnSleepTime);
1551 // ppcoin: if user OS account compromised prevent trivial sendmoney commands
1552 if (params.size() > 2)
1553 fWalletUnlockMintOnly = params[2].get_bool();
1555 fWalletUnlockMintOnly = false;
1561 Value walletpassphrasechange(const Array& params, bool fHelp)
1563 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1564 throw runtime_error(
1565 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1566 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1569 if (!pwalletMain->IsCrypted())
1570 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1572 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1573 // Alternately, find a way to make params[0] mlock()'d to begin with.
1574 SecureString strOldWalletPass;
1575 strOldWalletPass.reserve(100);
1576 strOldWalletPass = params[0].get_str().c_str();
1578 SecureString strNewWalletPass;
1579 strNewWalletPass.reserve(100);
1580 strNewWalletPass = params[1].get_str().c_str();
1582 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1583 throw runtime_error(
1584 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1585 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1587 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1588 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
1594 Value walletlock(const Array& params, bool fHelp)
1596 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1597 throw runtime_error(
1599 "Removes the wallet encryption key from memory, locking the wallet.\n"
1600 "After calling this method, you will need to call walletpassphrase again\n"
1601 "before being able to call any methods which require the wallet to be unlocked.");
1604 if (!pwalletMain->IsCrypted())
1605 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletlock was called.");
1608 LOCK(cs_nWalletUnlockTime);
1609 pwalletMain->Lock();
1610 nWalletUnlockTime = 0;
1617 Value encryptwallet(const Array& params, bool fHelp)
1619 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1620 throw runtime_error(
1621 "encryptwallet <passphrase>\n"
1622 "Encrypts the wallet with <passphrase>.");
1625 if (pwalletMain->IsCrypted())
1626 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an encrypted wallet, but encryptwallet was called.");
1628 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1629 // Alternately, find a way to make params[0] mlock()'d to begin with.
1630 SecureString strWalletPass;
1631 strWalletPass.reserve(100);
1632 strWalletPass = params[0].get_str().c_str();
1634 if (strWalletPass.length() < 1)
1635 throw runtime_error(
1636 "encryptwallet <passphrase>\n"
1637 "Encrypts the wallet with <passphrase>.");
1639 if (!pwalletMain->EncryptWallet(strWalletPass))
1640 throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: Failed to encrypt the wallet.");
1642 // BDB seems to have a bad habit of writing old data into
1643 // slack space in .dat files; that is bad if the old data is
1644 // unencrypted private keys. So:
1646 return "wallet encrypted; NovaCoin server stopping, restart to run with encrypted wallet. The keypool has been flushed, you need to make a new backup.";
1649 class DescribeAddressVisitor : public boost::static_visitor<Object>
1654 DescribeAddressVisitor(isminetype mineIn) : mine(mineIn) {}
1656 Object operator()(const CNoDestination &dest) const { return Object(); }
1657 Object operator()(const CKeyID &keyID) const {
1660 pwalletMain->GetPubKey(keyID, vchPubKey);
1661 obj.push_back(Pair("isscript", false));
1662 if (mine == MINE_SPENDABLE) {
1663 pwalletMain->GetPubKey(keyID, vchPubKey);
1664 obj.push_back(Pair("pubkey", HexStr(vchPubKey.Raw())));
1665 obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed()));
1670 Object operator()(const CScriptID &scriptID) const {
1672 obj.push_back(Pair("isscript", true));
1673 if (mine == MINE_SPENDABLE) {
1675 pwalletMain->GetCScript(scriptID, subscript);
1676 std::vector<CTxDestination> addresses;
1677 txnouttype whichType;
1679 ExtractDestinations(subscript, whichType, addresses, nRequired);
1680 obj.push_back(Pair("script", GetTxnOutputType(whichType)));
1681 obj.push_back(Pair("hex", HexStr(subscript.begin(), subscript.end())));
1683 BOOST_FOREACH(const CTxDestination& addr, addresses)
1684 a.push_back(CBitcoinAddress(addr).ToString());
1685 obj.push_back(Pair("addresses", a));
1686 if (whichType == TX_MULTISIG)
1687 obj.push_back(Pair("sigsrequired", nRequired));
1693 Value validateaddress(const Array& params, bool fHelp)
1695 if (fHelp || params.size() != 1)
1696 throw runtime_error(
1697 "validateaddress <novacoinaddress>\n"
1698 "Return information about <novacoinaddress>.");
1700 CBitcoinAddress address(params[0].get_str());
1701 bool isValid = address.IsValid();
1704 ret.push_back(Pair("isvalid", isValid));
1707 CTxDestination dest = address.Get();
1708 string currentAddress = address.ToString();
1709 ret.push_back(Pair("address", currentAddress));
1710 isminetype mine = pwalletMain ? IsMine(*pwalletMain, dest) : MINE_NO;
1711 ret.push_back(Pair("ismine", mine != MINE_NO));
1712 if (mine != MINE_NO) {
1713 ret.push_back(Pair("watchonly", mine == MINE_WATCH_ONLY));
1714 Object detail = boost::apply_visitor(DescribeAddressVisitor(mine), dest);
1715 ret.insert(ret.end(), detail.begin(), detail.end());
1717 if (pwalletMain->mapAddressBook.count(dest))
1718 ret.push_back(Pair("account", pwalletMain->mapAddressBook[dest]));
1723 // ppcoin: reserve balance from being staked for network protection
1724 Value reservebalance(const Array& params, bool fHelp)
1726 if (fHelp || params.size() > 2)
1727 throw runtime_error(
1728 "reservebalance [<reserve> [amount]]\n"
1729 "<reserve> is true or false to turn balance reserve on or off.\n"
1730 "<amount> is a real and rounded to cent.\n"
1731 "Set reserve amount not participating in network protection.\n"
1732 "If no parameters provided current setting is printed.\n");
1734 if (params.size() > 0)
1736 bool fReserve = params[0].get_bool();
1739 if (params.size() == 1)
1740 throw runtime_error("must provide amount to reserve balance.\n");
1741 int64_t nAmount = AmountFromValue(params[1]);
1742 nAmount = (nAmount / CENT) * CENT; // round to cent
1744 throw runtime_error("amount cannot be negative.\n");
1745 mapArgs["-reservebalance"] = FormatMoney(nAmount).c_str();
1749 if (params.size() > 1)
1750 throw runtime_error("cannot specify amount to turn off reserve.\n");
1751 mapArgs["-reservebalance"] = "0";
1756 if (mapArgs.count("-reservebalance") && !ParseMoney(mapArgs["-reservebalance"], nReserveBalance))
1757 throw runtime_error("invalid reserve balance amount\n");
1758 result.push_back(Pair("reserve", (nReserveBalance > 0)));
1759 result.push_back(Pair("amount", ValueFromAmount(nReserveBalance)));
1764 // ppcoin: check wallet integrity
1765 Value checkwallet(const Array& params, bool fHelp)
1767 if (fHelp || params.size() > 0)
1768 throw runtime_error(
1770 "Check wallet for integrity.\n");
1773 int64_t nBalanceInQuestion;
1774 pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion, true);
1776 if (nMismatchSpent == 0)
1777 result.push_back(Pair("wallet check passed", true));
1780 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
1781 result.push_back(Pair("amount in question", ValueFromAmount(nBalanceInQuestion)));
1787 // ppcoin: repair wallet
1788 Value repairwallet(const Array& params, bool fHelp)
1790 if (fHelp || params.size() > 0)
1791 throw runtime_error(
1793 "Repair wallet if checkwallet reports any problem.\n");
1796 int64_t nBalanceInQuestion;
1797 pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion);
1799 if (nMismatchSpent == 0)
1800 result.push_back(Pair("wallet check passed", true));
1803 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
1804 result.push_back(Pair("amount affected by repair", ValueFromAmount(nBalanceInQuestion)));
1809 // NovaCoin: resend unconfirmed wallet transactions
1810 Value resendtx(const Array& params, bool fHelp)
1812 if (fHelp || params.size() > 1)
1813 throw runtime_error(
1815 "Re-send unconfirmed transactions.\n"
1818 ResendWalletTransactions();
1823 // ppcoin: make a public-private key pair
1824 Value makekeypair(const Array& params, bool fHelp)
1826 if (fHelp || params.size() > 1)
1827 throw runtime_error(
1828 "makekeypair [prefix]\n"
1829 "Make a public/private key pair.\n"
1830 "[prefix] is optional preferred prefix for the public key.\n");
1832 string strPrefix = "";
1833 if (params.size() > 0)
1834 strPrefix = params[0].get_str();
1837 key.MakeNewKey(false);
1839 CPrivKey vchPrivKey = key.GetPrivKey();
1841 result.push_back(Pair("PrivateKey", HexStr<CPrivKey::iterator>(vchPrivKey.begin(), vchPrivKey.end())));
1842 result.push_back(Pair("PublicKey", HexStr(key.GetPubKey().Raw())));