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"
14 using namespace json_spirit;
17 int64_t nWalletUnlockTime;
18 static CCriticalSection cs_nWalletUnlockTime;
20 extern int64_t nReserveBalance;
21 extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, json_spirit::Object& entry);
23 std::string HelpRequiringPassphrase()
25 return pwalletMain->IsCrypted()
26 ? "\n\nRequires wallet passphrase to be set with walletpassphrase first"
30 void EnsureWalletIsUnlocked()
32 if (pwalletMain->IsLocked())
33 throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
34 if (fWalletUnlockMintOnly)
35 throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Wallet unlocked for block minting only.");
38 void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
40 int confirms = wtx.GetDepthInMainChain();
41 entry.push_back(Pair("confirmations", confirms));
42 if (wtx.IsCoinBase() || wtx.IsCoinStake())
43 entry.push_back(Pair("generated", true));
46 entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex()));
47 entry.push_back(Pair("blockindex", wtx.nIndex));
48 entry.push_back(Pair("blocktime", (int64_t)(mapBlockIndex[wtx.hashBlock]->nTime)));
50 entry.push_back(Pair("txid", wtx.GetHash().GetHex()));
51 entry.push_back(Pair("time", (int64_t)wtx.GetTxTime()));
52 entry.push_back(Pair("timereceived", (int64_t)wtx.nTimeReceived));
53 BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
54 entry.push_back(Pair(item.first, item.second));
57 string AccountFromValue(const Value& value)
59 string strAccount = value.get_str();
60 if (strAccount == "*")
61 throw JSONRPCError(RPC_WALLET_INVALID_ACCOUNT_NAME, "Invalid account name");
65 Value getinfo(const Array& params, bool fHelp)
67 if (fHelp || params.size() != 0)
70 "Returns an object containing various state info.");
73 GetProxy(NET_IPV4, proxy);
75 Object obj, diff, timestamping;
76 obj.push_back(Pair("version", FormatFullVersion()));
77 obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION));
78 obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
79 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
80 obj.push_back(Pair("unspendable", ValueFromAmount(pwalletMain->GetWatchOnlyBalance())));
81 obj.push_back(Pair("newmint", ValueFromAmount(pwalletMain->GetNewMint())));
82 obj.push_back(Pair("stake", ValueFromAmount(pwalletMain->GetStake())));
83 obj.push_back(Pair("blocks", (int)nBestHeight));
85 timestamping.push_back(Pair("systemclock", GetTime()));
86 timestamping.push_back(Pair("adjustedtime", GetAdjustedTime()));
88 int64_t nNtpOffset = GetNtpOffset(),
89 nP2POffset = GetNodesOffset();
91 timestamping.push_back(Pair("ntpoffset", nNtpOffset != INT64_MAX ? nNtpOffset : Value::null));
92 timestamping.push_back(Pair("p2poffset", nP2POffset != INT64_MAX ? nP2POffset : Value::null));
94 obj.push_back(Pair("timestamping", timestamping));
96 obj.push_back(Pair("moneysupply", ValueFromAmount(pindexBest->nMoneySupply)));
97 obj.push_back(Pair("connections", (int)vNodes.size()));
98 obj.push_back(Pair("proxy", (proxy.first.IsValid() ? proxy.first.ToStringIPPort() : string())));
99 obj.push_back(Pair("ip", addrSeenByPeer.ToStringIP()));
101 diff.push_back(Pair("proof-of-work", GetDifficulty()));
102 diff.push_back(Pair("proof-of-stake", GetDifficulty(GetLastBlockIndex(pindexBest, true))));
103 obj.push_back(Pair("difficulty", diff));
105 obj.push_back(Pair("testnet", fTestNet));
106 obj.push_back(Pair("keypoololdest", (int64_t)pwalletMain->GetOldestKeyPoolTime()));
107 obj.push_back(Pair("keypoolsize", (int)pwalletMain->GetKeyPoolSize()));
108 obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee)));
109 obj.push_back(Pair("mininput", ValueFromAmount(nMinimumInputValue)));
110 if (pwalletMain->IsCrypted())
111 obj.push_back(Pair("unlocked_until", (int64_t)nWalletUnlockTime / 1000));
112 obj.push_back(Pair("errors", GetWarnings("statusbar")));
116 Value getnewaddress(const Array& params, bool fHelp)
118 if (fHelp || params.size() > 1)
120 "getnewaddress [account]\n"
121 "Returns a new NovaCoin address for receiving payments. "
122 "If [account] is specified (recommended), it is added to the address book "
123 "so payments received with the address will be credited to [account].");
125 // Parse the account first so we don't generate a key if there's an error
127 if (params.size() > 0)
128 strAccount = AccountFromValue(params[0]);
130 if (!pwalletMain->IsLocked())
131 pwalletMain->TopUpKeyPool();
133 // Generate a new key that is added to wallet
135 if (!pwalletMain->GetKeyFromPool(newKey, false))
136 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
137 CKeyID keyID = newKey.GetID();
139 pwalletMain->SetAddressBookName(keyID, strAccount);
141 return CBitcoinAddress(keyID).ToString();
145 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
147 CWalletDB walletdb(pwalletMain->strWalletFile);
150 walletdb.ReadAccount(strAccount, account);
152 bool bKeyUsed = false;
154 // Check if the current key has been used
155 if (account.vchPubKey.IsValid())
157 CScript scriptPubKey;
158 scriptPubKey.SetDestination(account.vchPubKey.GetID());
159 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
160 it != pwalletMain->mapWallet.end() && account.vchPubKey.IsValid();
163 const CWalletTx& wtx = (*it).second;
164 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
165 if (txout.scriptPubKey == scriptPubKey)
170 // Generate a new key
171 if (!account.vchPubKey.IsValid() || bForceNew || bKeyUsed)
173 if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false))
174 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
176 pwalletMain->SetAddressBookName(account.vchPubKey.GetID(), strAccount);
177 walletdb.WriteAccount(strAccount, account);
180 return CBitcoinAddress(account.vchPubKey.GetID());
183 Value getaccountaddress(const Array& params, bool fHelp)
185 if (fHelp || params.size() != 1)
187 "getaccountaddress <account>\n"
188 "Returns the current NovaCoin address for receiving payments to this account.");
190 // Parse the account first so we don't generate a key if there's an error
191 string strAccount = AccountFromValue(params[0]);
195 ret = GetAccountAddress(strAccount).ToString();
202 Value setaccount(const Array& params, bool fHelp)
204 if (fHelp || params.size() < 1 || params.size() > 2)
206 "setaccount <novacoinaddress> <account>\n"
207 "Sets the account associated with the given address.");
209 CBitcoinAddress address(params[0].get_str());
210 if (!address.IsValid())
211 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
215 if (params.size() > 1)
216 strAccount = AccountFromValue(params[1]);
218 // Detect when changing the account of an address that is the 'unused current key' of another account:
219 if (pwalletMain->mapAddressBook.count(address.Get()))
221 string strOldAccount = pwalletMain->mapAddressBook[address.Get()];
222 if (address == GetAccountAddress(strOldAccount))
223 GetAccountAddress(strOldAccount, true);
226 pwalletMain->SetAddressBookName(address.Get(), strAccount);
232 Value getaccount(const Array& params, bool fHelp)
234 if (fHelp || params.size() != 1)
236 "getaccount <novacoinaddress>\n"
237 "Returns the account associated with the given address.");
239 CBitcoinAddress address(params[0].get_str());
240 if (!address.IsValid())
241 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
244 map<CTxDestination, string>::iterator mi = pwalletMain->mapAddressBook.find(address.Get());
245 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
246 strAccount = (*mi).second;
251 Value getaddressesbyaccount(const Array& params, bool fHelp)
253 if (fHelp || params.size() != 1)
255 "getaddressesbyaccount <account>\n"
256 "Returns the list of addresses for the given account.");
258 string strAccount = AccountFromValue(params[0]);
260 // Find all addresses that have the given account
262 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
264 const CBitcoinAddress& address = item.first;
265 const string& strName = item.second;
266 if (strName == strAccount)
267 ret.push_back(address.ToString());
272 Value mergecoins(const Array& params, bool fHelp)
274 if (fHelp || params.size() != 3)
276 "mergecoins <amount> <minvalue> <outputvalue>\n"
277 "<amount> is resulting inputs sum\n"
278 "<minvalue> is minimum value of inputs which are used in join process\n"
279 "<outputvalue> is resulting value of inputs which will be created\n"
280 "All values are real and and rounded to the nearest " + FormatMoney(nMinimumInputValue)
281 + HelpRequiringPassphrase());
283 if (pwalletMain->IsLocked())
284 throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
287 int64_t nAmount = AmountFromValue(params[0]);
290 int64_t nMinValue = AmountFromValue(params[1]);
293 int64_t nOutputValue = AmountFromValue(params[2]);
295 if (nAmount < nMinimumInputValue)
296 throw JSONRPCError(-101, "Send amount too small");
298 if (nMinValue < nMinimumInputValue)
299 throw JSONRPCError(-101, "Max value too small");
301 if (nOutputValue < nMinimumInputValue)
302 throw JSONRPCError(-101, "Output value too small");
304 if (nOutputValue < nMinValue)
305 throw JSONRPCError(-101, "Output value is lower than min value");
307 list<uint256> listMerged;
308 if (!pwalletMain->MergeCoins(nAmount, nMinValue, nOutputValue, listMerged))
312 BOOST_FOREACH(const uint256 txHash, listMerged)
313 mergedHashes.push_back(txHash.GetHex());
318 Value sendtoaddress(const Array& params, bool fHelp)
320 if (fHelp || params.size() < 2 || params.size() > 4)
322 "sendtoaddress <novacoinaddress> <amount> [comment] [comment-to]\n"
323 "<amount> is a real and is rounded to the nearest " + FormatMoney(nMinimumInputValue)
324 + HelpRequiringPassphrase());
326 CBitcoinAddress address(params[0].get_str());
327 if (!address.IsValid())
328 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
331 int64_t nAmount = AmountFromValue(params[1]);
333 if (nAmount < nMinimumInputValue)
334 throw JSONRPCError(-101, "Send amount too small");
338 if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
339 wtx.mapValue["comment"] = params[2].get_str();
340 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
341 wtx.mapValue["to"] = params[3].get_str();
343 if (pwalletMain->IsLocked())
344 throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
346 string strError = pwalletMain->SendMoneyToDestination(address.Get(), nAmount, wtx);
348 throw JSONRPCError(RPC_WALLET_ERROR, strError);
350 return wtx.GetHash().GetHex();
353 Value listaddressgroupings(const Array& params, bool fHelp)
357 "listaddressgroupings\n"
358 "Lists groups of addresses which have had their common ownership\n"
359 "made public by common use as inputs or as the resulting change\n"
360 "in past transactions");
363 map<CTxDestination, int64_t> balances = pwalletMain->GetAddressBalances();
364 BOOST_FOREACH(set<CTxDestination> grouping, pwalletMain->GetAddressGroupings())
367 BOOST_FOREACH(CTxDestination address, grouping)
370 addressInfo.push_back(CBitcoinAddress(address).ToString());
371 addressInfo.push_back(ValueFromAmount(balances[address]));
373 LOCK(pwalletMain->cs_wallet);
374 if (pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get()) != pwalletMain->mapAddressBook.end())
375 addressInfo.push_back(pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get())->second);
377 jsonGrouping.push_back(addressInfo);
379 jsonGroupings.push_back(jsonGrouping);
381 return jsonGroupings;
384 Value signmessage(const Array& params, bool fHelp)
386 if (fHelp || params.size() != 2)
388 "signmessage <novacoinaddress> <message>\n"
389 "Sign a message with the private key of an address");
391 EnsureWalletIsUnlocked();
393 string strAddress = params[0].get_str();
394 string strMessage = params[1].get_str();
396 CBitcoinAddress addr(strAddress);
398 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
401 if (!addr.GetKeyID(keyID))
402 throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
405 if (!pwalletMain->GetKey(keyID, key))
406 throw JSONRPCError(RPC_WALLET_ERROR, "Private key not available");
408 CDataStream ss(SER_GETHASH, 0);
409 ss << strMessageMagic;
412 vector<unsigned char> vchSig;
413 if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
414 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed");
416 return EncodeBase64(&vchSig[0], vchSig.size());
419 Value verifymessage(const Array& params, bool fHelp)
421 if (fHelp || params.size() != 3)
423 "verifymessage <novacoinaddress> <signature> <message>\n"
424 "Verify a signed message");
426 string strAddress = params[0].get_str();
427 string strSign = params[1].get_str();
428 string strMessage = params[2].get_str();
430 CBitcoinAddress addr(strAddress);
432 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
435 if (!addr.GetKeyID(keyID))
436 throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
438 bool fInvalid = false;
439 vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
442 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Malformed base64 encoding");
444 CDataStream ss(SER_GETHASH, 0);
445 ss << strMessageMagic;
449 if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
452 return (key.GetPubKey().GetID() == keyID);
456 Value getreceivedbyaddress(const Array& params, bool fHelp)
458 if (fHelp || params.size() < 1 || params.size() > 2)
460 "getreceivedbyaddress <novacoinaddress> [minconf=1]\n"
461 "Returns the total amount received by <novacoinaddress> in transactions with at least [minconf] confirmations.");
464 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
465 CScript scriptPubKey;
466 if (!address.IsValid())
467 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
468 scriptPubKey.SetDestination(address.Get());
469 if (!IsMine(*pwalletMain,scriptPubKey))
472 // Minimum confirmations
474 if (params.size() > 1)
475 nMinDepth = params[1].get_int();
479 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
481 const CWalletTx& wtx = (*it).second;
482 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
485 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
486 if (txout.scriptPubKey == scriptPubKey)
487 if (wtx.GetDepthInMainChain() >= nMinDepth)
488 nAmount += txout.nValue;
491 return ValueFromAmount(nAmount);
495 void GetAccountAddresses(string strAccount, set<CTxDestination>& setAddress)
497 BOOST_FOREACH(const PAIRTYPE(CTxDestination, string)& item, pwalletMain->mapAddressBook)
499 const CTxDestination& address = item.first;
500 const string& strName = item.second;
501 if (strName == strAccount)
502 setAddress.insert(address);
506 Value getreceivedbyaccount(const Array& params, bool fHelp)
508 if (fHelp || params.size() < 1 || params.size() > 2)
510 "getreceivedbyaccount <account> [minconf=1]\n"
511 "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
513 // Minimum confirmations
515 if (params.size() > 1)
516 nMinDepth = params[1].get_int();
518 // Get the set of pub keys assigned to account
519 string strAccount = AccountFromValue(params[0]);
520 set<CTxDestination> setAddress;
521 GetAccountAddresses(strAccount, setAddress);
525 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
527 const CWalletTx& wtx = (*it).second;
528 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
531 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
533 CTxDestination address;
534 if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*pwalletMain, address) && setAddress.count(address))
535 if (wtx.GetDepthInMainChain() >= nMinDepth)
536 nAmount += txout.nValue;
540 return (double)nAmount / (double)COIN;
544 int64_t GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth, const isminefilter& filter)
546 int64_t nBalance = 0;
548 // Tally wallet transactions
549 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
551 const CWalletTx& wtx = (*it).second;
555 int64_t nGenerated, nReceived, nSent, nFee;
556 wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee, filter);
558 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
559 nBalance += nReceived;
560 nBalance += nGenerated - nSent - nFee;
563 // Tally internal accounting entries
564 nBalance += walletdb.GetAccountCreditDebit(strAccount);
569 int64_t GetAccountBalance(const string& strAccount, int nMinDepth, const isminefilter& filter)
571 CWalletDB walletdb(pwalletMain->strWalletFile);
572 return GetAccountBalance(walletdb, strAccount, nMinDepth, filter);
576 Value getbalance(const Array& params, bool fHelp)
578 if (fHelp || params.size() > 2)
580 "getbalance [account] [minconf=1] [watchonly=0]\n"
581 "If [account] is not specified, returns the server's total available balance.\n"
582 "If [account] is specified, returns the balance in the account.\n"
583 "if [includeWatchonly] is specified, include balance in watchonly addresses (see 'importaddress').");
585 if (params.size() == 0)
586 return ValueFromAmount(pwalletMain->GetBalance());
589 if (params.size() > 1)
590 nMinDepth = params[1].get_int();
591 isminefilter filter = MINE_SPENDABLE;
592 if(params.size() > 2)
593 if(params[2].get_bool())
594 filter = filter | MINE_WATCH_ONLY;
596 if (params[0].get_str() == "*") {
597 // Calculate total balance a different way from GetBalance()
598 // (GetBalance() sums up all unspent TxOuts)
599 // getbalance and getbalance '*' 0 should return the same number.
600 int64_t nBalance = 0;
601 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
603 const CWalletTx& wtx = (*it).second;
604 if (!wtx.IsTrusted())
607 int64_t allGeneratedImmature, allGeneratedMature, allFee;
608 allGeneratedImmature = allGeneratedMature = allFee = 0;
610 string strSentAccount;
611 list<pair<CTxDestination, int64_t> > listReceived;
612 list<pair<CTxDestination, int64_t> > listSent;
613 wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount, filter);
614 if (wtx.GetDepthInMainChain() >= nMinDepth)
616 BOOST_FOREACH(const PAIRTYPE(CTxDestination,int64_t)& r, listReceived)
617 nBalance += r.second;
619 BOOST_FOREACH(const PAIRTYPE(CTxDestination,int64_t)& r, listSent)
620 nBalance -= r.second;
622 nBalance += allGeneratedMature;
624 return ValueFromAmount(nBalance);
627 string strAccount = AccountFromValue(params[0]);
629 int64_t nBalance = GetAccountBalance(strAccount, nMinDepth, filter);
631 return ValueFromAmount(nBalance);
635 Value movecmd(const Array& params, bool fHelp)
637 if (fHelp || params.size() < 3 || params.size() > 5)
639 "move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
640 "Move from one account in your wallet to another.");
642 string strFrom = AccountFromValue(params[0]);
643 string strTo = AccountFromValue(params[1]);
644 int64_t nAmount = AmountFromValue(params[2]);
646 if (nAmount < nMinimumInputValue)
647 throw JSONRPCError(-101, "Send amount too small");
649 if (params.size() > 3)
650 // unused parameter, used to be nMinDepth, keep type-checking it though
651 (void)params[3].get_int();
653 if (params.size() > 4)
654 strComment = params[4].get_str();
656 CWalletDB walletdb(pwalletMain->strWalletFile);
657 if (!walletdb.TxnBegin())
658 throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
660 int64_t nNow = GetAdjustedTime();
663 CAccountingEntry debit;
664 debit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
665 debit.strAccount = strFrom;
666 debit.nCreditDebit = -nAmount;
668 debit.strOtherAccount = strTo;
669 debit.strComment = strComment;
670 walletdb.WriteAccountingEntry(debit);
673 CAccountingEntry credit;
674 credit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
675 credit.strAccount = strTo;
676 credit.nCreditDebit = nAmount;
678 credit.strOtherAccount = strFrom;
679 credit.strComment = strComment;
680 walletdb.WriteAccountingEntry(credit);
682 if (!walletdb.TxnCommit())
683 throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
689 Value sendfrom(const Array& params, bool fHelp)
691 if (fHelp || params.size() < 3 || params.size() > 6)
693 "sendfrom <fromaccount> <tonovacoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
694 "<amount> is a real and is rounded to the nearest " + FormatMoney(nMinimumInputValue)
695 + HelpRequiringPassphrase());
697 string strAccount = AccountFromValue(params[0]);
698 CBitcoinAddress address(params[1].get_str());
699 if (!address.IsValid())
700 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
701 int64_t nAmount = AmountFromValue(params[2]);
703 if (nAmount < nMinimumInputValue)
704 throw JSONRPCError(-101, "Send amount too small");
707 if (params.size() > 3)
708 nMinDepth = params[3].get_int();
711 wtx.strFromAccount = strAccount;
712 if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
713 wtx.mapValue["comment"] = params[4].get_str();
714 if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
715 wtx.mapValue["to"] = params[5].get_str();
717 EnsureWalletIsUnlocked();
720 int64_t nBalance = GetAccountBalance(strAccount, nMinDepth, MINE_SPENDABLE);
721 if (nAmount > nBalance)
722 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
725 string strError = pwalletMain->SendMoneyToDestination(address.Get(), nAmount, wtx);
727 throw JSONRPCError(RPC_WALLET_ERROR, strError);
729 return wtx.GetHash().GetHex();
733 Value sendmany(const Array& params, bool fHelp)
735 if (fHelp || params.size() < 2 || params.size() > 4)
737 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
738 "amounts are double-precision floating point numbers"
739 + HelpRequiringPassphrase());
741 string strAccount = AccountFromValue(params[0]);
742 Object sendTo = params[1].get_obj();
744 if (params.size() > 2)
745 nMinDepth = params[2].get_int();
748 wtx.strFromAccount = strAccount;
749 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
750 wtx.mapValue["comment"] = params[3].get_str();
752 set<CBitcoinAddress> setAddress;
753 vector<pair<CScript, int64_t> > vecSend;
755 int64_t totalAmount = 0;
756 BOOST_FOREACH(const Pair& s, sendTo)
758 CBitcoinAddress address(s.name_);
759 if (!address.IsValid())
760 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid NovaCoin address: ")+s.name_);
762 if (setAddress.count(address))
763 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+s.name_);
764 setAddress.insert(address);
766 CScript scriptPubKey;
767 scriptPubKey.SetDestination(address.Get());
768 int64_t nAmount = AmountFromValue(s.value_);
770 if (nAmount < nMinimumInputValue)
771 throw JSONRPCError(-101, "Send amount too small");
773 totalAmount += nAmount;
775 vecSend.push_back(make_pair(scriptPubKey, nAmount));
778 EnsureWalletIsUnlocked();
781 int64_t nBalance = GetAccountBalance(strAccount, nMinDepth, MINE_SPENDABLE);
782 if (totalAmount > nBalance)
783 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
786 CReserveKey keyChange(pwalletMain);
787 int64_t nFeeRequired = 0;
788 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
791 int64_t nTotal = pwalletMain->GetBalance(), nWatchOnly = pwalletMain->GetWatchOnlyBalance();
792 if (totalAmount + nFeeRequired > nTotal - nWatchOnly)
793 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds");
794 throw JSONRPCError(RPC_WALLET_ERROR, "Transaction creation failed");
796 if (!pwalletMain->CommitTransaction(wtx, keyChange))
797 throw JSONRPCError(RPC_WALLET_ERROR, "Transaction commit failed");
799 return wtx.GetHash().GetHex();
802 Value addmultisigaddress(const Array& params, bool fHelp)
804 if (fHelp || params.size() < 2 || params.size() > 3)
806 string msg = "addmultisigaddress <nrequired> <'[\"key\",\"key\"]'> [account]\n"
807 "Add a nrequired-to-sign multisignature address to the wallet\"\n"
808 "each key is a NovaCoin address or hex-encoded public key\n"
809 "If [account] is specified, assign address to [account].";
810 throw runtime_error(msg);
813 int nRequired = params[0].get_int();
814 const Array& keys = params[1].get_array();
816 if (params.size() > 2)
817 strAccount = AccountFromValue(params[2]);
819 // Gather public keys
821 throw runtime_error("a multisignature address must require at least one key to redeem");
822 if ((int)keys.size() < nRequired)
824 strprintf("not enough keys supplied "
825 "(got %" PRIszu " keys, but need at least %d to redeem)", keys.size(), nRequired));
826 if (keys.size() > 16)
827 throw runtime_error("Number of addresses involved in the multisignature address creation > 16\nReduce the number");
828 std::vector<CKey> pubkeys;
829 pubkeys.resize(keys.size());
830 for (unsigned int i = 0; i < keys.size(); i++)
832 const std::string& ks = keys[i].get_str();
834 // Case 1: Bitcoin address and we have full public key:
835 CBitcoinAddress address(ks);
836 if (address.IsValid())
839 if (!address.GetKeyID(keyID))
841 strprintf("%s does not refer to a key",ks.c_str()));
843 if (!pwalletMain->GetPubKey(keyID, vchPubKey))
845 strprintf("no full public key for address %s",ks.c_str()));
846 if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey))
847 throw runtime_error(" Invalid public key: "+ks);
850 // Case 2: hex public key
853 CPubKey vchPubKey(ParseHex(ks));
854 if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey))
855 throw runtime_error(" Invalid public key: "+ks);
859 throw runtime_error(" Invalid public key: "+ks);
863 // Construct using pay-to-script-hash:
865 inner.SetMultisig(nRequired, pubkeys);
867 if (inner.size() > MAX_SCRIPT_ELEMENT_SIZE)
869 strprintf("redeemScript exceeds size limit: %" PRIszu " > %d", inner.size(), MAX_SCRIPT_ELEMENT_SIZE));
871 CScriptID innerID = inner.GetID();
872 pwalletMain->AddCScript(inner);
874 pwalletMain->SetAddressBookName(innerID, strAccount);
875 return CBitcoinAddress(innerID).ToString();
878 Value addredeemscript(const Array& params, bool fHelp)
880 if (fHelp || params.size() < 1 || params.size() > 2)
882 string msg = "addredeemscript <redeemScript> [account]\n"
883 "Add a P2SH address with a specified redeemScript to the wallet.\n"
884 "If [account] is specified, assign address to [account].";
885 throw runtime_error(msg);
889 if (params.size() > 1)
890 strAccount = AccountFromValue(params[1]);
892 // Construct using pay-to-script-hash:
893 vector<unsigned char> innerData = ParseHexV(params[0], "redeemScript");
894 CScript inner(innerData.begin(), innerData.end());
895 CScriptID innerID = inner.GetID();
896 pwalletMain->AddCScript(inner);
898 pwalletMain->SetAddressBookName(innerID, strAccount);
899 return CBitcoinAddress(innerID).ToString();
909 nConf = std::numeric_limits<int>::max();
913 Value ListReceived(const Array& params, bool fByAccounts)
915 // Minimum confirmations
917 if (params.size() > 0)
918 nMinDepth = params[0].get_int();
920 // Whether to include empty accounts
921 bool fIncludeEmpty = false;
922 if (params.size() > 1)
923 fIncludeEmpty = params[1].get_bool();
926 map<CBitcoinAddress, tallyitem> mapTally;
927 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
929 const CWalletTx& wtx = (*it).second;
931 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
934 int nDepth = wtx.GetDepthInMainChain();
935 if (nDepth < nMinDepth)
938 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
940 CTxDestination address;
941 if (!ExtractDestination(txout.scriptPubKey, address) || !IsMine(*pwalletMain, address))
944 tallyitem& item = mapTally[address];
945 item.nAmount += txout.nValue;
946 item.nConf = min(item.nConf, nDepth);
952 map<string, tallyitem> mapAccountTally;
953 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
955 const CBitcoinAddress& address = item.first;
956 const string& strAccount = item.second;
957 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
958 if (it == mapTally.end() && !fIncludeEmpty)
962 int nConf = std::numeric_limits<int>::max();
963 if (it != mapTally.end())
965 nAmount = (*it).second.nAmount;
966 nConf = (*it).second.nConf;
971 tallyitem& item = mapAccountTally[strAccount];
972 item.nAmount += nAmount;
973 item.nConf = min(item.nConf, nConf);
978 obj.push_back(Pair("address", address.ToString()));
979 obj.push_back(Pair("account", strAccount));
980 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
981 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
988 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
990 int64_t nAmount = (*it).second.nAmount;
991 int nConf = (*it).second.nConf;
993 obj.push_back(Pair("account", (*it).first));
994 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
995 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1003 Value listreceivedbyaddress(const Array& params, bool fHelp)
1005 if (fHelp || params.size() > 2)
1006 throw runtime_error(
1007 "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
1008 "[minconf] is the minimum number of confirmations before payments are included.\n"
1009 "[includeempty] whether to include addresses that haven't received any payments.\n"
1010 "Returns an array of objects containing:\n"
1011 " \"address\" : receiving address\n"
1012 " \"account\" : the account of the receiving address\n"
1013 " \"amount\" : total amount received by the address\n"
1014 " \"confirmations\" : number of confirmations of the most recent transaction included");
1016 return ListReceived(params, false);
1019 Value listreceivedbyaccount(const Array& params, bool fHelp)
1021 if (fHelp || params.size() > 2)
1022 throw runtime_error(
1023 "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
1024 "[minconf] is the minimum number of confirmations before payments are included.\n"
1025 "[includeempty] whether to include accounts that haven't received any payments.\n"
1026 "Returns an array of objects containing:\n"
1027 " \"account\" : the account of the receiving addresses\n"
1028 " \"amount\" : total amount received by addresses with this account\n"
1029 " \"confirmations\" : number of confirmations of the most recent transaction included");
1031 return ListReceived(params, true);
1034 static void MaybePushAddress(Object & entry, const CTxDestination &dest)
1036 CBitcoinAddress addr;
1038 entry.push_back(Pair("address", addr.ToString()));
1041 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret, const isminefilter& filter)
1043 int64_t nGeneratedImmature, nGeneratedMature, nFee;
1044 string strSentAccount;
1045 list<pair<CTxDestination, int64_t> > listReceived;
1046 list<pair<CTxDestination, int64_t> > listSent;
1048 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount, filter);
1050 bool fAllAccounts = (strAccount == string("*"));
1051 bool involvesWatchonly = wtx.IsFromMe(MINE_WATCH_ONLY);
1053 // Generated blocks assigned to account ""
1054 if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
1057 entry.push_back(Pair("account", string("")));
1058 if (nGeneratedImmature)
1060 entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
1061 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
1065 entry.push_back(Pair("category", "generate"));
1066 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
1069 WalletTxToJSON(wtx, entry);
1070 ret.push_back(entry);
1074 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1076 BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64_t)& s, listSent)
1079 entry.push_back(Pair("account", strSentAccount));
1080 if(involvesWatchonly || (::IsMine(*pwalletMain, s.first) & MINE_WATCH_ONLY))
1081 entry.push_back(Pair("involvesWatchonly", true));
1082 MaybePushAddress(entry, s.first);
1084 if (wtx.GetDepthInMainChain() < 0) {
1085 entry.push_back(Pair("category", "conflicted"));
1087 entry.push_back(Pair("category", "send"));
1090 entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1091 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1093 WalletTxToJSON(wtx, entry);
1094 ret.push_back(entry);
1099 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1101 BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64_t)& r, listReceived)
1104 if (pwalletMain->mapAddressBook.count(r.first))
1105 account = pwalletMain->mapAddressBook[r.first];
1106 if (fAllAccounts || (account == strAccount))
1109 entry.push_back(Pair("account", account));
1110 if(involvesWatchonly || (::IsMine(*pwalletMain, r.first) & MINE_WATCH_ONLY))
1111 entry.push_back(Pair("involvesWatchonly", true));
1112 MaybePushAddress(entry, r.first);
1113 if (wtx.IsCoinBase())
1115 if (wtx.GetDepthInMainChain() < 1)
1116 entry.push_back(Pair("category", "orphan"));
1117 else if (wtx.GetBlocksToMaturity() > 0)
1118 entry.push_back(Pair("category", "immature"));
1120 entry.push_back(Pair("category", "generate"));
1123 entry.push_back(Pair("category", "receive"));
1124 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1126 WalletTxToJSON(wtx, entry);
1127 ret.push_back(entry);
1133 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1135 bool fAllAccounts = (strAccount == string("*"));
1137 if (fAllAccounts || acentry.strAccount == strAccount)
1140 entry.push_back(Pair("account", acentry.strAccount));
1141 entry.push_back(Pair("category", "move"));
1142 entry.push_back(Pair("time", (int64_t)acentry.nTime));
1143 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1144 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1145 entry.push_back(Pair("comment", acentry.strComment));
1146 ret.push_back(entry);
1150 Value listtransactions(const Array& params, bool fHelp)
1152 if (fHelp || params.size() > 3)
1153 throw runtime_error(
1154 "listtransactions [account] [count=10] [from=0]\n"
1155 "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1157 string strAccount = "*";
1158 if (params.size() > 0)
1159 strAccount = params[0].get_str();
1161 if (params.size() > 1)
1162 nCount = params[1].get_int();
1164 if (params.size() > 2)
1165 nFrom = params[2].get_int();
1167 isminefilter filter = MINE_SPENDABLE;
1168 if(params.size() > 3)
1169 if(params[3].get_bool())
1170 filter = filter | MINE_WATCH_ONLY;
1173 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count");
1175 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative from");
1179 std::list<CAccountingEntry> acentries;
1180 CWallet::TxItems txOrdered = pwalletMain->OrderedTxItems(acentries, strAccount);
1182 // iterate backwards until we have nCount items to return:
1183 for (CWallet::TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
1185 CWalletTx *const pwtx = (*it).second.first;
1187 ListTransactions(*pwtx, strAccount, 0, true, ret, filter);
1188 CAccountingEntry *const pacentry = (*it).second.second;
1190 AcentryToJSON(*pacentry, strAccount, ret);
1192 if ((int)ret.size() >= (nCount+nFrom)) break;
1194 // ret is newest to oldest
1196 if (nFrom > (int)ret.size())
1198 if ((nFrom + nCount) > (int)ret.size())
1199 nCount = ret.size() - nFrom;
1200 Array::iterator first = ret.begin();
1201 std::advance(first, nFrom);
1202 Array::iterator last = ret.begin();
1203 std::advance(last, nFrom+nCount);
1205 if (last != ret.end()) ret.erase(last, ret.end());
1206 if (first != ret.begin()) ret.erase(ret.begin(), first);
1208 std::reverse(ret.begin(), ret.end()); // Return oldest to newest
1213 Value listaccounts(const Array& params, bool fHelp)
1215 if (fHelp || params.size() > 1)
1216 throw runtime_error(
1217 "listaccounts [minconf=1]\n"
1218 "Returns Object that has account names as keys, account balances as values.");
1221 if (params.size() > 0)
1222 nMinDepth = params[0].get_int();
1224 isminefilter includeWatchonly = MINE_SPENDABLE;
1225 if(params.size() > 1)
1226 if(params[1].get_bool())
1227 includeWatchonly = includeWatchonly | MINE_WATCH_ONLY;
1230 map<string, int64_t> mapAccountBalances;
1231 BOOST_FOREACH(const PAIRTYPE(CTxDestination, string)& entry, pwalletMain->mapAddressBook) {
1232 if (IsMine(*pwalletMain, entry.first)) // This address belongs to me
1233 mapAccountBalances[entry.second] = 0;
1236 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1238 const CWalletTx& wtx = (*it).second;
1239 int64_t nGeneratedImmature, nGeneratedMature, nFee;
1240 string strSentAccount;
1241 list<pair<CTxDestination, int64_t> > listReceived;
1242 list<pair<CTxDestination, int64_t> > listSent;
1243 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount, includeWatchonly);
1244 mapAccountBalances[strSentAccount] -= nFee;
1245 BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64_t)& s, listSent)
1246 mapAccountBalances[strSentAccount] -= s.second;
1247 if (wtx.GetDepthInMainChain() >= nMinDepth)
1249 mapAccountBalances[""] += nGeneratedMature;
1250 BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64_t)& r, listReceived)
1251 if (pwalletMain->mapAddressBook.count(r.first))
1252 mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1254 mapAccountBalances[""] += r.second;
1258 list<CAccountingEntry> acentries;
1259 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1260 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1261 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1264 BOOST_FOREACH(const PAIRTYPE(string, int64_t)& accountBalance, mapAccountBalances) {
1265 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1270 Value listsinceblock(const Array& params, bool fHelp)
1273 throw runtime_error(
1274 "listsinceblock [blockhash] [target-confirmations]\n"
1275 "Get all transactions in blocks since block [blockhash], or all transactions if omitted");
1277 CBlockIndex *pindex = NULL;
1278 int target_confirms = 1;
1279 isminefilter filter = MINE_SPENDABLE;
1281 if (params.size() > 0)
1283 uint256 blockId = 0;
1285 blockId.SetHex(params[0].get_str());
1286 pindex = CBlockLocator(blockId).GetBlockIndex();
1289 if (params.size() > 1)
1291 target_confirms = params[1].get_int();
1293 if (target_confirms < 1)
1294 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter");
1297 if(params.size() > 2)
1298 if(params[2].get_bool())
1299 filter = filter | MINE_WATCH_ONLY;
1301 int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
1305 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1307 CWalletTx tx = (*it).second;
1309 if (depth == -1 || tx.GetDepthInMainChain() < depth)
1310 ListTransactions(tx, "*", 0, true, transactions, filter);
1315 if (target_confirms == 1)
1317 lastblock = hashBestChain;
1321 int target_height = pindexBest->nHeight + 1 - target_confirms;
1324 for (block = pindexBest;
1325 block && block->nHeight > target_height;
1326 block = block->pprev) { }
1328 lastblock = block ? block->GetBlockHash() : 0;
1332 ret.push_back(Pair("transactions", transactions));
1333 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1338 Value gettransaction(const Array& params, bool fHelp)
1340 if (fHelp || params.size() != 1)
1341 throw runtime_error(
1342 "gettransaction <txid>\n"
1343 "Get detailed information about <txid>");
1346 hash.SetHex(params[0].get_str());
1348 isminefilter filter = MINE_SPENDABLE;
1349 if(params.size() > 1)
1350 if(params[1].get_bool())
1351 filter = filter | MINE_WATCH_ONLY;
1355 if (pwalletMain->mapWallet.count(hash))
1357 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1359 TxToJSON(wtx, 0, entry);
1361 int64_t nCredit = wtx.GetCredit(filter);
1362 int64_t nDebit = wtx.GetDebit(filter);
1363 int64_t nNet = nCredit - nDebit;
1364 int64_t nFee = (wtx.IsFromMe(filter) ? wtx.GetValueOut() - nDebit : 0);
1366 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1367 if (wtx.IsFromMe(filter))
1368 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1370 WalletTxToJSON(wtx, entry);
1373 ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details, filter);
1374 entry.push_back(Pair("details", details));
1379 uint256 hashBlock = 0;
1380 if (GetTransaction(hash, tx, hashBlock))
1382 TxToJSON(tx, 0, entry);
1384 entry.push_back(Pair("confirmations", 0));
1387 entry.push_back(Pair("blockhash", hashBlock.GetHex()));
1388 map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
1389 if (mi != mapBlockIndex.end() && (*mi).second)
1391 CBlockIndex* pindex = (*mi).second;
1392 if (pindex->IsInMainChain())
1393 entry.push_back(Pair("confirmations", 1 + nBestHeight - pindex->nHeight));
1395 entry.push_back(Pair("confirmations", 0));
1400 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction");
1407 Value backupwallet(const Array& params, bool fHelp)
1409 if (fHelp || params.size() != 1)
1410 throw runtime_error(
1411 "backupwallet <destination>\n"
1412 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1414 string strDest = params[0].get_str();
1415 if (!BackupWallet(*pwalletMain, strDest))
1416 throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!");
1422 Value keypoolrefill(const Array& params, bool fHelp)
1424 if (fHelp || params.size() > 1)
1425 throw runtime_error(
1426 "keypoolrefill [new-size]\n"
1427 "Fills the keypool.\n"
1428 "IMPORTANT: Any previous backups you have made of your wallet file "
1429 "should be replaced with the newly generated one."
1430 + HelpRequiringPassphrase());
1432 unsigned int nSize = max<unsigned int>(GetArgUInt("-keypool", 100), 0);
1433 if (params.size() > 0) {
1434 if (params[0].get_int() < 0)
1435 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size");
1436 nSize = (unsigned int) params[0].get_int();
1439 EnsureWalletIsUnlocked();
1441 pwalletMain->TopUpKeyPool(nSize);
1443 if (pwalletMain->GetKeyPoolSize() < nSize)
1444 throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool.");
1449 Value keypoolreset(const Array& params, bool fHelp)
1451 if (fHelp || params.size() > 1)
1452 throw runtime_error(
1453 "keypoolreset [new-size]\n"
1454 "Resets the keypool.\n"
1455 "IMPORTANT: Any previous backups you have made of your wallet file "
1456 "should be replaced with the newly generated one."
1457 + HelpRequiringPassphrase());
1459 unsigned int nSize = max<unsigned int>(GetArgUInt("-keypool", 100), 0);
1460 if (params.size() > 0) {
1461 if (params[0].get_int() < 0)
1462 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size");
1463 nSize = (unsigned int) params[0].get_int();
1466 EnsureWalletIsUnlocked();
1468 pwalletMain->NewKeyPool(nSize);
1470 if (pwalletMain->GetKeyPoolSize() < nSize)
1471 throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool.");
1477 void ThreadTopUpKeyPool(void* parg)
1479 // Make this thread recognisable as the key-topping-up thread
1480 RenameThread("novacoin-key-top");
1482 pwalletMain->TopUpKeyPool();
1485 void ThreadCleanWalletPassphrase(void* parg)
1487 // Make this thread recognisable as the wallet relocking thread
1488 RenameThread("novacoin-lock-wa");
1490 int64_t nMyWakeTime = GetTimeMillis() + *((int64_t*)parg) * 1000;
1492 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1494 if (nWalletUnlockTime == 0)
1496 nWalletUnlockTime = nMyWakeTime;
1500 if (nWalletUnlockTime==0)
1502 int64_t nToSleep = nWalletUnlockTime - GetTimeMillis();
1506 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1508 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1512 if (nWalletUnlockTime)
1514 nWalletUnlockTime = 0;
1515 pwalletMain->Lock();
1520 if (nWalletUnlockTime < nMyWakeTime)
1521 nWalletUnlockTime = nMyWakeTime;
1524 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1526 delete (int64_t*)parg;
1529 Value walletpassphrase(const Array& params, bool fHelp)
1531 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 3))
1532 throw runtime_error(
1533 "walletpassphrase <passphrase> <timeout> [mintonly]\n"
1534 "Stores the wallet decryption key in memory for <timeout> seconds.\n"
1535 "mintonly is optional true/false allowing only block minting.");
1538 if (!pwalletMain->IsCrypted())
1539 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1541 if (!pwalletMain->IsLocked())
1542 throw JSONRPCError(RPC_WALLET_ALREADY_UNLOCKED, "Error: Wallet is already unlocked, use walletlock first if need to change unlock settings.");
1543 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1544 SecureString strWalletPass;
1545 strWalletPass.reserve(100);
1546 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1547 // Alternately, find a way to make params[0] mlock()'d to begin with.
1548 strWalletPass = params[0].get_str().c_str();
1550 if (strWalletPass.length() > 0)
1552 if (!pwalletMain->Unlock(strWalletPass))
1553 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
1556 throw runtime_error(
1557 "walletpassphrase <passphrase> <timeout>\n"
1558 "Stores the wallet decryption key in memory for <timeout> seconds.");
1560 NewThread(ThreadTopUpKeyPool, NULL);
1561 int64_t* pnSleepTime = new int64_t(params[1].get_int64());
1562 NewThread(ThreadCleanWalletPassphrase, pnSleepTime);
1564 // ppcoin: if user OS account compromised prevent trivial sendmoney commands
1565 if (params.size() > 2)
1566 fWalletUnlockMintOnly = params[2].get_bool();
1568 fWalletUnlockMintOnly = false;
1574 Value walletpassphrasechange(const Array& params, bool fHelp)
1576 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1577 throw runtime_error(
1578 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1579 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1582 if (!pwalletMain->IsCrypted())
1583 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1585 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1586 // Alternately, find a way to make params[0] mlock()'d to begin with.
1587 SecureString strOldWalletPass;
1588 strOldWalletPass.reserve(100);
1589 strOldWalletPass = params[0].get_str().c_str();
1591 SecureString strNewWalletPass;
1592 strNewWalletPass.reserve(100);
1593 strNewWalletPass = params[1].get_str().c_str();
1595 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1596 throw runtime_error(
1597 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1598 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1600 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1601 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
1607 Value walletlock(const Array& params, bool fHelp)
1609 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1610 throw runtime_error(
1612 "Removes the wallet encryption key from memory, locking the wallet.\n"
1613 "After calling this method, you will need to call walletpassphrase again\n"
1614 "before being able to call any methods which require the wallet to be unlocked.");
1617 if (!pwalletMain->IsCrypted())
1618 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletlock was called.");
1621 LOCK(cs_nWalletUnlockTime);
1622 pwalletMain->Lock();
1623 nWalletUnlockTime = 0;
1630 Value encryptwallet(const Array& params, bool fHelp)
1632 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1633 throw runtime_error(
1634 "encryptwallet <passphrase>\n"
1635 "Encrypts the wallet with <passphrase>.");
1638 if (pwalletMain->IsCrypted())
1639 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an encrypted wallet, but encryptwallet was called.");
1641 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1642 // Alternately, find a way to make params[0] mlock()'d to begin with.
1643 SecureString strWalletPass;
1644 strWalletPass.reserve(100);
1645 strWalletPass = params[0].get_str().c_str();
1647 if (strWalletPass.length() < 1)
1648 throw runtime_error(
1649 "encryptwallet <passphrase>\n"
1650 "Encrypts the wallet with <passphrase>.");
1652 if (!pwalletMain->EncryptWallet(strWalletPass))
1653 throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: Failed to encrypt the wallet.");
1655 // BDB seems to have a bad habit of writing old data into
1656 // slack space in .dat files; that is bad if the old data is
1657 // unencrypted private keys. So:
1659 return "wallet encrypted; NovaCoin server stopping, restart to run with encrypted wallet. The keypool has been flushed, you need to make a new backup.";
1662 class DescribeAddressVisitor : public boost::static_visitor<Object>
1667 DescribeAddressVisitor(isminetype mineIn) : mine(mineIn) {}
1669 Object operator()(const CNoDestination &dest) const { return Object(); }
1670 Object operator()(const CKeyID &keyID) const {
1673 pwalletMain->GetPubKey(keyID, vchPubKey);
1674 obj.push_back(Pair("isscript", false));
1675 if (mine == MINE_SPENDABLE) {
1676 pwalletMain->GetPubKey(keyID, vchPubKey);
1677 obj.push_back(Pair("pubkey", HexStr(vchPubKey.Raw())));
1678 obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed()));
1683 Object operator()(const CScriptID &scriptID) const {
1685 obj.push_back(Pair("isscript", true));
1686 if (mine == MINE_SPENDABLE) {
1688 pwalletMain->GetCScript(scriptID, subscript);
1689 std::vector<CTxDestination> addresses;
1690 txnouttype whichType;
1692 ExtractDestinations(subscript, whichType, addresses, nRequired);
1693 obj.push_back(Pair("script", GetTxnOutputType(whichType)));
1694 obj.push_back(Pair("hex", HexStr(subscript.begin(), subscript.end())));
1696 BOOST_FOREACH(const CTxDestination& addr, addresses)
1697 a.push_back(CBitcoinAddress(addr).ToString());
1698 obj.push_back(Pair("addresses", a));
1699 if (whichType == TX_MULTISIG)
1700 obj.push_back(Pair("sigsrequired", nRequired));
1706 Value validateaddress(const Array& params, bool fHelp)
1708 if (fHelp || params.size() != 1)
1709 throw runtime_error(
1710 "validateaddress <novacoinaddress>\n"
1711 "Return information about <novacoinaddress>.");
1713 CBitcoinAddress address(params[0].get_str());
1714 bool isValid = address.IsValid();
1717 ret.push_back(Pair("isvalid", isValid));
1720 CTxDestination dest = address.Get();
1721 string currentAddress = address.ToString();
1722 ret.push_back(Pair("address", currentAddress));
1723 isminetype mine = pwalletMain ? IsMine(*pwalletMain, dest) : MINE_NO;
1724 ret.push_back(Pair("ismine", mine != MINE_NO));
1725 if (mine != MINE_NO) {
1726 ret.push_back(Pair("watchonly", mine == MINE_WATCH_ONLY));
1727 Object detail = boost::apply_visitor(DescribeAddressVisitor(mine), dest);
1728 ret.insert(ret.end(), detail.begin(), detail.end());
1730 if (pwalletMain->mapAddressBook.count(dest))
1731 ret.push_back(Pair("account", pwalletMain->mapAddressBook[dest]));
1736 // ppcoin: reserve balance from being staked for network protection
1737 Value reservebalance(const Array& params, bool fHelp)
1739 if (fHelp || params.size() > 2)
1740 throw runtime_error(
1741 "reservebalance [<reserve> [amount]]\n"
1742 "<reserve> is true or false to turn balance reserve on or off.\n"
1743 "<amount> is a real and rounded to cent.\n"
1744 "Set reserve amount not participating in network protection.\n"
1745 "If no parameters provided current setting is printed.\n");
1747 if (params.size() > 0)
1749 bool fReserve = params[0].get_bool();
1752 if (params.size() == 1)
1753 throw runtime_error("must provide amount to reserve balance.\n");
1754 int64_t nAmount = AmountFromValue(params[1]);
1755 nAmount = (nAmount / CENT) * CENT; // round to cent
1757 throw runtime_error("amount cannot be negative.\n");
1758 mapArgs["-reservebalance"] = FormatMoney(nAmount).c_str();
1762 if (params.size() > 1)
1763 throw runtime_error("cannot specify amount to turn off reserve.\n");
1764 mapArgs["-reservebalance"] = "0";
1769 if (mapArgs.count("-reservebalance") && !ParseMoney(mapArgs["-reservebalance"], nReserveBalance))
1770 throw runtime_error("invalid reserve balance amount\n");
1771 result.push_back(Pair("reserve", (nReserveBalance > 0)));
1772 result.push_back(Pair("amount", ValueFromAmount(nReserveBalance)));
1777 // ppcoin: check wallet integrity
1778 Value checkwallet(const Array& params, bool fHelp)
1780 if (fHelp || params.size() > 0)
1781 throw runtime_error(
1783 "Check wallet for integrity.\n");
1786 int64_t nBalanceInQuestion;
1787 pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion, true);
1789 if (nMismatchSpent == 0)
1790 result.push_back(Pair("wallet check passed", true));
1793 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
1794 result.push_back(Pair("amount in question", ValueFromAmount(nBalanceInQuestion)));
1800 // ppcoin: repair wallet
1801 Value repairwallet(const Array& params, bool fHelp)
1803 if (fHelp || params.size() > 0)
1804 throw runtime_error(
1806 "Repair wallet if checkwallet reports any problem.\n");
1809 int64_t nBalanceInQuestion;
1810 pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion);
1812 if (nMismatchSpent == 0)
1813 result.push_back(Pair("wallet check passed", true));
1816 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
1817 result.push_back(Pair("amount affected by repair", ValueFromAmount(nBalanceInQuestion)));
1822 // NovaCoin: resend unconfirmed wallet transactions
1823 Value resendtx(const Array& params, bool fHelp)
1825 if (fHelp || params.size() > 1)
1826 throw runtime_error(
1828 "Re-send unconfirmed transactions.\n"
1831 ResendWalletTransactions();
1836 // ppcoin: make a public-private key pair
1837 Value makekeypair(const Array& params, bool fHelp)
1839 if (fHelp || params.size() > 1)
1840 throw runtime_error(
1841 "makekeypair [prefix]\n"
1842 "Make a public/private key pair.\n"
1843 "[prefix] is optional preferred prefix for the public key.\n");
1845 string strPrefix = "";
1846 if (params.size() > 0)
1847 strPrefix = params[0].get_str();
1850 key.MakeNewKey(false);
1852 CPrivKey vchPrivKey = key.GetPrivKey();
1854 result.push_back(Pair("PrivateKey", HexStr<CPrivKey::iterator>(vchPrivKey.begin(), vchPrivKey.end())));
1855 result.push_back(Pair("PublicKey", HexStr(key.GetPubKey().Raw())));