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());
327 CScript scriptPubKey;
328 string strAddress = params[0].get_str();
330 CBitcoinAddress address(strAddress);
331 if (address.IsValid())
332 scriptPubKey.SetDestination(address.Get());
335 CMalleablePubKey mpk(strAddress);
337 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
339 CPubKey R, pubKeyVariant;
340 mpk.GetVariant(R, pubKeyVariant);
341 scriptPubKey.SetDestination(R, pubKeyVariant);
345 int64_t nAmount = AmountFromValue(params[1]);
347 if (nAmount < nMinimumInputValue)
348 throw JSONRPCError(-101, "Send amount too small");
352 if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
353 wtx.mapValue["comment"] = params[2].get_str();
354 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
355 wtx.mapValue["to"] = params[3].get_str();
357 if (pwalletMain->IsLocked())
358 throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
360 string strError = pwalletMain->SendMoney(scriptPubKey, nAmount, wtx);
362 throw JSONRPCError(RPC_WALLET_ERROR, strError);
364 return wtx.GetHash().GetHex();
367 Value listaddressgroupings(const Array& params, bool fHelp)
371 "listaddressgroupings\n"
372 "Lists groups of addresses which have had their common ownership\n"
373 "made public by common use as inputs or as the resulting change\n"
374 "in past transactions");
377 map<CTxDestination, int64_t> balances = pwalletMain->GetAddressBalances();
378 BOOST_FOREACH(set<CTxDestination> grouping, pwalletMain->GetAddressGroupings())
381 BOOST_FOREACH(CTxDestination address, grouping)
384 addressInfo.push_back(CBitcoinAddress(address).ToString());
385 addressInfo.push_back(ValueFromAmount(balances[address]));
387 LOCK(pwalletMain->cs_wallet);
388 if (pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get()) != pwalletMain->mapAddressBook.end())
389 addressInfo.push_back(pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get())->second);
391 jsonGrouping.push_back(addressInfo);
393 jsonGroupings.push_back(jsonGrouping);
395 return jsonGroupings;
398 Value signmessage(const Array& params, bool fHelp)
400 if (fHelp || params.size() != 2)
402 "signmessage <novacoinaddress> <message>\n"
403 "Sign a message with the private key of an address");
405 EnsureWalletIsUnlocked();
407 string strAddress = params[0].get_str();
408 string strMessage = params[1].get_str();
410 CBitcoinAddress addr(strAddress);
412 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
415 if (!addr.GetKeyID(keyID))
416 throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
419 if (!pwalletMain->GetKey(keyID, key))
420 throw JSONRPCError(RPC_WALLET_ERROR, "Private key not available");
422 CDataStream ss(SER_GETHASH, 0);
423 ss << strMessageMagic;
426 vector<unsigned char> vchSig;
427 if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
428 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed");
430 return EncodeBase64(&vchSig[0], vchSig.size());
433 Value verifymessage(const Array& params, bool fHelp)
435 if (fHelp || params.size() != 3)
437 "verifymessage <novacoinaddress> <signature> <message>\n"
438 "Verify a signed message");
440 string strAddress = params[0].get_str();
441 string strSign = params[1].get_str();
442 string strMessage = params[2].get_str();
444 CBitcoinAddress addr(strAddress);
446 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
449 if (!addr.GetKeyID(keyID))
450 throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
452 bool fInvalid = false;
453 vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
456 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Malformed base64 encoding");
458 CDataStream ss(SER_GETHASH, 0);
459 ss << strMessageMagic;
463 if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
466 return (key.GetPubKey().GetID() == keyID);
470 Value getreceivedbyaddress(const Array& params, bool fHelp)
472 if (fHelp || params.size() < 1 || params.size() > 2)
474 "getreceivedbyaddress <novacoinaddress> [minconf=1]\n"
475 "Returns the total amount received by <novacoinaddress> in transactions with at least [minconf] confirmations.");
478 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
479 CScript scriptPubKey;
480 if (!address.IsValid())
481 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
482 scriptPubKey.SetDestination(address.Get());
483 if (!IsMine(*pwalletMain,scriptPubKey))
486 // Minimum confirmations
488 if (params.size() > 1)
489 nMinDepth = params[1].get_int();
493 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
495 const CWalletTx& wtx = (*it).second;
496 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
499 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
500 if (txout.scriptPubKey == scriptPubKey)
501 if (wtx.GetDepthInMainChain() >= nMinDepth)
502 nAmount += txout.nValue;
505 return ValueFromAmount(nAmount);
509 void GetAccountAddresses(string strAccount, set<CTxDestination>& setAddress)
511 BOOST_FOREACH(const PAIRTYPE(CTxDestination, string)& item, pwalletMain->mapAddressBook)
513 const CTxDestination& address = item.first;
514 const string& strName = item.second;
515 if (strName == strAccount)
516 setAddress.insert(address);
520 Value getreceivedbyaccount(const Array& params, bool fHelp)
522 if (fHelp || params.size() < 1 || params.size() > 2)
524 "getreceivedbyaccount <account> [minconf=1]\n"
525 "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
527 // Minimum confirmations
529 if (params.size() > 1)
530 nMinDepth = params[1].get_int();
532 // Get the set of pub keys assigned to account
533 string strAccount = AccountFromValue(params[0]);
534 set<CTxDestination> setAddress;
535 GetAccountAddresses(strAccount, setAddress);
539 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
541 const CWalletTx& wtx = (*it).second;
542 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
545 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
547 CTxDestination address;
548 if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*pwalletMain, address) && setAddress.count(address))
549 if (wtx.GetDepthInMainChain() >= nMinDepth)
550 nAmount += txout.nValue;
554 return (double)nAmount / (double)COIN;
558 int64_t GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth, const isminefilter& filter)
560 int64_t nBalance = 0;
562 // Tally wallet transactions
563 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
565 const CWalletTx& wtx = (*it).second;
569 int64_t nGenerated, nReceived, nSent, nFee;
570 wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee, filter);
572 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
573 nBalance += nReceived;
574 nBalance += nGenerated - nSent - nFee;
577 // Tally internal accounting entries
578 nBalance += walletdb.GetAccountCreditDebit(strAccount);
583 int64_t GetAccountBalance(const string& strAccount, int nMinDepth, const isminefilter& filter)
585 CWalletDB walletdb(pwalletMain->strWalletFile);
586 return GetAccountBalance(walletdb, strAccount, nMinDepth, filter);
590 Value getbalance(const Array& params, bool fHelp)
592 if (fHelp || params.size() > 2)
594 "getbalance [account] [minconf=1] [watchonly=0]\n"
595 "If [account] is not specified, returns the server's total available balance.\n"
596 "If [account] is specified, returns the balance in the account.\n"
597 "if [includeWatchonly] is specified, include balance in watchonly addresses (see 'importaddress').");
599 if (params.size() == 0)
600 return ValueFromAmount(pwalletMain->GetBalance());
603 if (params.size() > 1)
604 nMinDepth = params[1].get_int();
605 isminefilter filter = MINE_SPENDABLE;
606 if(params.size() > 2)
607 if(params[2].get_bool())
608 filter = filter | MINE_WATCH_ONLY;
610 if (params[0].get_str() == "*") {
611 // Calculate total balance a different way from GetBalance()
612 // (GetBalance() sums up all unspent TxOuts)
613 // getbalance and getbalance '*' 0 should return the same number.
614 int64_t nBalance = 0;
615 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
617 const CWalletTx& wtx = (*it).second;
618 if (!wtx.IsTrusted())
621 int64_t allGeneratedImmature, allGeneratedMature, allFee;
622 allGeneratedImmature = allGeneratedMature = allFee = 0;
624 string strSentAccount;
625 list<pair<CTxDestination, int64_t> > listReceived;
626 list<pair<CTxDestination, int64_t> > listSent;
627 wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount, filter);
628 if (wtx.GetDepthInMainChain() >= nMinDepth)
630 BOOST_FOREACH(const PAIRTYPE(CTxDestination,int64_t)& r, listReceived)
631 nBalance += r.second;
633 BOOST_FOREACH(const PAIRTYPE(CTxDestination,int64_t)& r, listSent)
634 nBalance -= r.second;
636 nBalance += allGeneratedMature;
638 return ValueFromAmount(nBalance);
641 string strAccount = AccountFromValue(params[0]);
643 int64_t nBalance = GetAccountBalance(strAccount, nMinDepth, filter);
645 return ValueFromAmount(nBalance);
649 Value movecmd(const Array& params, bool fHelp)
651 if (fHelp || params.size() < 3 || params.size() > 5)
653 "move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
654 "Move from one account in your wallet to another.");
656 string strFrom = AccountFromValue(params[0]);
657 string strTo = AccountFromValue(params[1]);
658 int64_t nAmount = AmountFromValue(params[2]);
660 if (nAmount < nMinimumInputValue)
661 throw JSONRPCError(-101, "Send amount too small");
663 if (params.size() > 3)
664 // unused parameter, used to be nMinDepth, keep type-checking it though
665 (void)params[3].get_int();
667 if (params.size() > 4)
668 strComment = params[4].get_str();
670 CWalletDB walletdb(pwalletMain->strWalletFile);
671 if (!walletdb.TxnBegin())
672 throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
674 int64_t nNow = GetAdjustedTime();
677 CAccountingEntry debit;
678 debit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
679 debit.strAccount = strFrom;
680 debit.nCreditDebit = -nAmount;
682 debit.strOtherAccount = strTo;
683 debit.strComment = strComment;
684 walletdb.WriteAccountingEntry(debit);
687 CAccountingEntry credit;
688 credit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
689 credit.strAccount = strTo;
690 credit.nCreditDebit = nAmount;
692 credit.strOtherAccount = strFrom;
693 credit.strComment = strComment;
694 walletdb.WriteAccountingEntry(credit);
696 if (!walletdb.TxnCommit())
697 throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
703 Value sendfrom(const Array& params, bool fHelp)
705 if (fHelp || params.size() < 3 || params.size() > 6)
707 "sendfrom <fromaccount> <tonovacoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
708 "<amount> is a real and is rounded to the nearest " + FormatMoney(nMinimumInputValue)
709 + HelpRequiringPassphrase());
711 string strAccount = AccountFromValue(params[0]);
714 CScript scriptPubKey;
715 string strAddress = params[0].get_str();
717 CBitcoinAddress address(strAddress);
718 if (address.IsValid())
719 scriptPubKey.SetDestination(address.Get());
722 CMalleablePubKey mpk(strAddress);
724 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
726 CPubKey R, pubKeyVariant;
727 mpk.GetVariant(R, pubKeyVariant);
728 scriptPubKey.SetDestination(R, pubKeyVariant);
731 int64_t nAmount = AmountFromValue(params[2]);
733 if (nAmount < nMinimumInputValue)
734 throw JSONRPCError(-101, "Send amount too small");
737 if (params.size() > 3)
738 nMinDepth = params[3].get_int();
741 wtx.strFromAccount = strAccount;
742 if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
743 wtx.mapValue["comment"] = params[4].get_str();
744 if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
745 wtx.mapValue["to"] = params[5].get_str();
747 EnsureWalletIsUnlocked();
750 int64_t nBalance = GetAccountBalance(strAccount, nMinDepth, MINE_SPENDABLE);
751 if (nAmount > nBalance)
752 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
755 string strError = pwalletMain->SendMoney(scriptPubKey, nAmount, wtx);
757 throw JSONRPCError(RPC_WALLET_ERROR, strError);
759 return wtx.GetHash().GetHex();
763 Value sendmany(const Array& params, bool fHelp)
765 if (fHelp || params.size() < 2 || params.size() > 4)
767 "sendmany <fromaccount> '{address:amount,...}' [minconf=1] [comment]\n"
768 "amounts are double-precision floating point numbers"
769 + HelpRequiringPassphrase());
771 string strAccount = AccountFromValue(params[0]);
772 Object sendTo = params[1].get_obj();
774 if (params.size() > 2)
775 nMinDepth = params[2].get_int();
778 wtx.strFromAccount = strAccount;
779 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
780 wtx.mapValue["comment"] = params[3].get_str();
782 set<CBitcoinAddress> setAddress;
783 vector<pair<CScript, int64_t> > vecSend;
785 int64_t totalAmount = 0;
786 BOOST_FOREACH(const Pair& s, sendTo)
788 CBitcoinAddress address(s.name_);
789 if (!address.IsValid())
790 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid NovaCoin address: ")+s.name_);
792 if (setAddress.count(address))
793 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+s.name_);
794 setAddress.insert(address);
796 CScript scriptPubKey;
797 scriptPubKey.SetDestination(address.Get());
798 int64_t nAmount = AmountFromValue(s.value_);
800 if (nAmount < nMinimumInputValue)
801 throw JSONRPCError(-101, "Send amount too small");
803 totalAmount += nAmount;
805 vecSend.push_back(make_pair(scriptPubKey, nAmount));
808 EnsureWalletIsUnlocked();
811 int64_t nBalance = GetAccountBalance(strAccount, nMinDepth, MINE_SPENDABLE);
812 if (totalAmount > nBalance)
813 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
816 CReserveKey keyChange(pwalletMain);
817 int64_t nFeeRequired = 0;
818 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
821 int64_t nTotal = pwalletMain->GetBalance(), nWatchOnly = pwalletMain->GetWatchOnlyBalance();
822 if (totalAmount + nFeeRequired > nTotal - nWatchOnly)
823 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds");
824 throw JSONRPCError(RPC_WALLET_ERROR, "Transaction creation failed");
826 if (!pwalletMain->CommitTransaction(wtx, keyChange))
827 throw JSONRPCError(RPC_WALLET_ERROR, "Transaction commit failed");
829 return wtx.GetHash().GetHex();
832 Value addmultisigaddress(const Array& params, bool fHelp)
834 if (fHelp || params.size() < 2 || params.size() > 3)
836 string msg = "addmultisigaddress <nrequired> <'[\"key\",\"key\"]'> [account]\n"
837 "Add a nrequired-to-sign multisignature address to the wallet\"\n"
838 "each key is a NovaCoin address or hex-encoded public key\n"
839 "If [account] is specified, assign address to [account].";
840 throw runtime_error(msg);
843 int nRequired = params[0].get_int();
844 const Array& keys = params[1].get_array();
846 if (params.size() > 2)
847 strAccount = AccountFromValue(params[2]);
849 // Gather public keys
851 throw runtime_error("a multisignature address must require at least one key to redeem");
852 if ((int)keys.size() < nRequired)
854 strprintf("not enough keys supplied "
855 "(got %" PRIszu " keys, but need at least %d to redeem)", keys.size(), nRequired));
856 if (keys.size() > 16)
857 throw runtime_error("Number of addresses involved in the multisignature address creation > 16\nReduce the number");
858 std::vector<CKey> pubkeys;
859 pubkeys.resize(keys.size());
860 for (unsigned int i = 0; i < keys.size(); i++)
862 const std::string& ks = keys[i].get_str();
864 // Case 1: Bitcoin address and we have full public key:
865 CBitcoinAddress address(ks);
866 if (address.IsValid())
869 if (!address.GetKeyID(keyID))
871 strprintf("%s does not refer to a key",ks.c_str()));
873 if (!pwalletMain->GetPubKey(keyID, vchPubKey))
875 strprintf("no full public key for address %s",ks.c_str()));
876 if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey))
877 throw runtime_error(" Invalid public key: "+ks);
880 // Case 2: hex public key
883 CPubKey vchPubKey(ParseHex(ks));
884 if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey))
885 throw runtime_error(" Invalid public key: "+ks);
889 throw runtime_error(" Invalid public key: "+ks);
893 // Construct using pay-to-script-hash:
895 inner.SetMultisig(nRequired, pubkeys);
897 if (inner.size() > MAX_SCRIPT_ELEMENT_SIZE)
899 strprintf("redeemScript exceeds size limit: %" PRIszu " > %d", inner.size(), MAX_SCRIPT_ELEMENT_SIZE));
901 CScriptID innerID = inner.GetID();
902 pwalletMain->AddCScript(inner);
904 pwalletMain->SetAddressBookName(innerID, strAccount);
905 return CBitcoinAddress(innerID).ToString();
908 Value addredeemscript(const Array& params, bool fHelp)
910 if (fHelp || params.size() < 1 || params.size() > 2)
912 string msg = "addredeemscript <redeemScript> [account]\n"
913 "Add a P2SH address with a specified redeemScript to the wallet.\n"
914 "If [account] is specified, assign address to [account].";
915 throw runtime_error(msg);
919 if (params.size() > 1)
920 strAccount = AccountFromValue(params[1]);
922 // Construct using pay-to-script-hash:
923 vector<unsigned char> innerData = ParseHexV(params[0], "redeemScript");
924 CScript inner(innerData.begin(), innerData.end());
925 CScriptID innerID = inner.GetID();
926 pwalletMain->AddCScript(inner);
928 pwalletMain->SetAddressBookName(innerID, strAccount);
929 return CBitcoinAddress(innerID).ToString();
939 nConf = std::numeric_limits<int>::max();
943 Value ListReceived(const Array& params, bool fByAccounts)
945 // Minimum confirmations
947 if (params.size() > 0)
948 nMinDepth = params[0].get_int();
950 // Whether to include empty accounts
951 bool fIncludeEmpty = false;
952 if (params.size() > 1)
953 fIncludeEmpty = params[1].get_bool();
956 map<CBitcoinAddress, tallyitem> mapTally;
957 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
959 const CWalletTx& wtx = (*it).second;
961 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
964 int nDepth = wtx.GetDepthInMainChain();
965 if (nDepth < nMinDepth)
968 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
970 CTxDestination address;
971 if (!ExtractDestination(txout.scriptPubKey, address) || !IsMine(*pwalletMain, address))
974 tallyitem& item = mapTally[address];
975 item.nAmount += txout.nValue;
976 item.nConf = min(item.nConf, nDepth);
982 map<string, tallyitem> mapAccountTally;
983 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
985 const CBitcoinAddress& address = item.first;
986 const string& strAccount = item.second;
987 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
988 if (it == mapTally.end() && !fIncludeEmpty)
992 int nConf = std::numeric_limits<int>::max();
993 if (it != mapTally.end())
995 nAmount = (*it).second.nAmount;
996 nConf = (*it).second.nConf;
1001 tallyitem& item = mapAccountTally[strAccount];
1002 item.nAmount += nAmount;
1003 item.nConf = min(item.nConf, nConf);
1008 obj.push_back(Pair("address", address.ToString()));
1009 obj.push_back(Pair("account", strAccount));
1010 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1011 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1018 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
1020 int64_t nAmount = (*it).second.nAmount;
1021 int nConf = (*it).second.nConf;
1023 obj.push_back(Pair("account", (*it).first));
1024 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1025 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1033 Value listreceivedbyaddress(const Array& params, bool fHelp)
1035 if (fHelp || params.size() > 2)
1036 throw runtime_error(
1037 "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
1038 "[minconf] is the minimum number of confirmations before payments are included.\n"
1039 "[includeempty] whether to include addresses that haven't received any payments.\n"
1040 "Returns an array of objects containing:\n"
1041 " \"address\" : receiving address\n"
1042 " \"account\" : the account of the receiving address\n"
1043 " \"amount\" : total amount received by the address\n"
1044 " \"confirmations\" : number of confirmations of the most recent transaction included");
1046 return ListReceived(params, false);
1049 Value listreceivedbyaccount(const Array& params, bool fHelp)
1051 if (fHelp || params.size() > 2)
1052 throw runtime_error(
1053 "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
1054 "[minconf] is the minimum number of confirmations before payments are included.\n"
1055 "[includeempty] whether to include accounts that haven't received any payments.\n"
1056 "Returns an array of objects containing:\n"
1057 " \"account\" : the account of the receiving addresses\n"
1058 " \"amount\" : total amount received by addresses with this account\n"
1059 " \"confirmations\" : number of confirmations of the most recent transaction included");
1061 return ListReceived(params, true);
1064 static void MaybePushAddress(Object & entry, const CTxDestination &dest)
1066 CBitcoinAddress addr;
1068 entry.push_back(Pair("address", addr.ToString()));
1071 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret, const isminefilter& filter)
1073 int64_t nGeneratedImmature, nGeneratedMature, nFee;
1074 string strSentAccount;
1075 list<pair<CTxDestination, int64_t> > listReceived;
1076 list<pair<CTxDestination, int64_t> > listSent;
1078 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount, filter);
1080 bool fAllAccounts = (strAccount == string("*"));
1081 bool involvesWatchonly = wtx.IsFromMe(MINE_WATCH_ONLY);
1083 // Generated blocks assigned to account ""
1084 if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
1087 entry.push_back(Pair("account", string("")));
1088 if (nGeneratedImmature)
1090 entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
1091 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
1095 entry.push_back(Pair("category", "generate"));
1096 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
1099 WalletTxToJSON(wtx, entry);
1100 ret.push_back(entry);
1104 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1106 BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64_t)& s, listSent)
1109 entry.push_back(Pair("account", strSentAccount));
1110 if(involvesWatchonly || (::IsMine(*pwalletMain, s.first) & MINE_WATCH_ONLY))
1111 entry.push_back(Pair("involvesWatchonly", true));
1112 MaybePushAddress(entry, s.first);
1114 if (wtx.GetDepthInMainChain() < 0) {
1115 entry.push_back(Pair("category", "conflicted"));
1117 entry.push_back(Pair("category", "send"));
1120 entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1121 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1123 WalletTxToJSON(wtx, entry);
1124 ret.push_back(entry);
1129 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1131 BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64_t)& r, listReceived)
1134 if (pwalletMain->mapAddressBook.count(r.first))
1135 account = pwalletMain->mapAddressBook[r.first];
1136 if (fAllAccounts || (account == strAccount))
1139 entry.push_back(Pair("account", account));
1140 if(involvesWatchonly || (::IsMine(*pwalletMain, r.first) & MINE_WATCH_ONLY))
1141 entry.push_back(Pair("involvesWatchonly", true));
1142 MaybePushAddress(entry, r.first);
1143 if (wtx.IsCoinBase())
1145 if (wtx.GetDepthInMainChain() < 1)
1146 entry.push_back(Pair("category", "orphan"));
1147 else if (wtx.GetBlocksToMaturity() > 0)
1148 entry.push_back(Pair("category", "immature"));
1150 entry.push_back(Pair("category", "generate"));
1153 entry.push_back(Pair("category", "receive"));
1154 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1156 WalletTxToJSON(wtx, entry);
1157 ret.push_back(entry);
1163 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1165 bool fAllAccounts = (strAccount == string("*"));
1167 if (fAllAccounts || acentry.strAccount == strAccount)
1170 entry.push_back(Pair("account", acentry.strAccount));
1171 entry.push_back(Pair("category", "move"));
1172 entry.push_back(Pair("time", (int64_t)acentry.nTime));
1173 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1174 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1175 entry.push_back(Pair("comment", acentry.strComment));
1176 ret.push_back(entry);
1180 Value listtransactions(const Array& params, bool fHelp)
1182 if (fHelp || params.size() > 3)
1183 throw runtime_error(
1184 "listtransactions [account] [count=10] [from=0]\n"
1185 "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1187 string strAccount = "*";
1188 if (params.size() > 0)
1189 strAccount = params[0].get_str();
1191 if (params.size() > 1)
1192 nCount = params[1].get_int();
1194 if (params.size() > 2)
1195 nFrom = params[2].get_int();
1197 isminefilter filter = MINE_SPENDABLE;
1198 if(params.size() > 3)
1199 if(params[3].get_bool())
1200 filter = filter | MINE_WATCH_ONLY;
1203 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count");
1205 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative from");
1209 std::list<CAccountingEntry> acentries;
1210 CWallet::TxItems txOrdered = pwalletMain->OrderedTxItems(acentries, strAccount);
1212 // iterate backwards until we have nCount items to return:
1213 for (CWallet::TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
1215 CWalletTx *const pwtx = (*it).second.first;
1217 ListTransactions(*pwtx, strAccount, 0, true, ret, filter);
1218 CAccountingEntry *const pacentry = (*it).second.second;
1220 AcentryToJSON(*pacentry, strAccount, ret);
1222 if ((int)ret.size() >= (nCount+nFrom)) break;
1224 // ret is newest to oldest
1226 if (nFrom > (int)ret.size())
1228 if ((nFrom + nCount) > (int)ret.size())
1229 nCount = ret.size() - nFrom;
1230 Array::iterator first = ret.begin();
1231 std::advance(first, nFrom);
1232 Array::iterator last = ret.begin();
1233 std::advance(last, nFrom+nCount);
1235 if (last != ret.end()) ret.erase(last, ret.end());
1236 if (first != ret.begin()) ret.erase(ret.begin(), first);
1238 std::reverse(ret.begin(), ret.end()); // Return oldest to newest
1243 Value listaccounts(const Array& params, bool fHelp)
1245 if (fHelp || params.size() > 1)
1246 throw runtime_error(
1247 "listaccounts [minconf=1]\n"
1248 "Returns Object that has account names as keys, account balances as values.");
1251 if (params.size() > 0)
1252 nMinDepth = params[0].get_int();
1254 isminefilter includeWatchonly = MINE_SPENDABLE;
1255 if(params.size() > 1)
1256 if(params[1].get_bool())
1257 includeWatchonly = includeWatchonly | MINE_WATCH_ONLY;
1260 map<string, int64_t> mapAccountBalances;
1261 BOOST_FOREACH(const PAIRTYPE(CTxDestination, string)& entry, pwalletMain->mapAddressBook) {
1262 if (IsMine(*pwalletMain, entry.first)) // This address belongs to me
1263 mapAccountBalances[entry.second] = 0;
1266 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1268 const CWalletTx& wtx = (*it).second;
1269 int64_t nGeneratedImmature, nGeneratedMature, nFee;
1270 string strSentAccount;
1271 list<pair<CTxDestination, int64_t> > listReceived;
1272 list<pair<CTxDestination, int64_t> > listSent;
1273 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount, includeWatchonly);
1274 mapAccountBalances[strSentAccount] -= nFee;
1275 BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64_t)& s, listSent)
1276 mapAccountBalances[strSentAccount] -= s.second;
1277 if (wtx.GetDepthInMainChain() >= nMinDepth)
1279 mapAccountBalances[""] += nGeneratedMature;
1280 BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64_t)& r, listReceived)
1281 if (pwalletMain->mapAddressBook.count(r.first))
1282 mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1284 mapAccountBalances[""] += r.second;
1288 list<CAccountingEntry> acentries;
1289 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1290 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1291 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1294 BOOST_FOREACH(const PAIRTYPE(string, int64_t)& accountBalance, mapAccountBalances) {
1295 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1300 Value listsinceblock(const Array& params, bool fHelp)
1303 throw runtime_error(
1304 "listsinceblock [blockhash] [target-confirmations]\n"
1305 "Get all transactions in blocks since block [blockhash], or all transactions if omitted");
1307 CBlockIndex *pindex = NULL;
1308 int target_confirms = 1;
1309 isminefilter filter = MINE_SPENDABLE;
1311 if (params.size() > 0)
1313 uint256 blockId = 0;
1315 blockId.SetHex(params[0].get_str());
1316 pindex = CBlockLocator(blockId).GetBlockIndex();
1319 if (params.size() > 1)
1321 target_confirms = params[1].get_int();
1323 if (target_confirms < 1)
1324 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter");
1327 if(params.size() > 2)
1328 if(params[2].get_bool())
1329 filter = filter | MINE_WATCH_ONLY;
1331 int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
1335 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1337 CWalletTx tx = (*it).second;
1339 if (depth == -1 || tx.GetDepthInMainChain() < depth)
1340 ListTransactions(tx, "*", 0, true, transactions, filter);
1345 if (target_confirms == 1)
1347 lastblock = hashBestChain;
1351 int target_height = pindexBest->nHeight + 1 - target_confirms;
1354 for (block = pindexBest;
1355 block && block->nHeight > target_height;
1356 block = block->pprev) { }
1358 lastblock = block ? block->GetBlockHash() : 0;
1362 ret.push_back(Pair("transactions", transactions));
1363 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1368 Value gettransaction(const Array& params, bool fHelp)
1370 if (fHelp || params.size() != 1)
1371 throw runtime_error(
1372 "gettransaction <txid>\n"
1373 "Get detailed information about <txid>");
1376 hash.SetHex(params[0].get_str());
1378 isminefilter filter = MINE_SPENDABLE;
1379 if(params.size() > 1)
1380 if(params[1].get_bool())
1381 filter = filter | MINE_WATCH_ONLY;
1385 if (pwalletMain->mapWallet.count(hash))
1387 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1389 TxToJSON(wtx, 0, entry);
1391 int64_t nCredit = wtx.GetCredit(filter);
1392 int64_t nDebit = wtx.GetDebit(filter);
1393 int64_t nNet = nCredit - nDebit;
1394 int64_t nFee = (wtx.IsFromMe(filter) ? wtx.GetValueOut() - nDebit : 0);
1396 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1397 if (wtx.IsFromMe(filter))
1398 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1400 WalletTxToJSON(wtx, entry);
1403 ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details, filter);
1404 entry.push_back(Pair("details", details));
1409 uint256 hashBlock = 0;
1410 if (GetTransaction(hash, tx, hashBlock))
1412 TxToJSON(tx, 0, entry);
1414 entry.push_back(Pair("confirmations", 0));
1417 entry.push_back(Pair("blockhash", hashBlock.GetHex()));
1418 map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
1419 if (mi != mapBlockIndex.end() && (*mi).second)
1421 CBlockIndex* pindex = (*mi).second;
1422 if (pindex->IsInMainChain())
1423 entry.push_back(Pair("confirmations", 1 + nBestHeight - pindex->nHeight));
1425 entry.push_back(Pair("confirmations", 0));
1430 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction");
1437 Value backupwallet(const Array& params, bool fHelp)
1439 if (fHelp || params.size() != 1)
1440 throw runtime_error(
1441 "backupwallet <destination>\n"
1442 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1444 string strDest = params[0].get_str();
1445 if (!BackupWallet(*pwalletMain, strDest))
1446 throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!");
1452 Value keypoolrefill(const Array& params, bool fHelp)
1454 if (fHelp || params.size() > 1)
1455 throw runtime_error(
1456 "keypoolrefill [new-size]\n"
1457 "Fills the keypool.\n"
1458 "IMPORTANT: Any previous backups you have made of your wallet file "
1459 "should be replaced with the newly generated one."
1460 + HelpRequiringPassphrase());
1462 unsigned int nSize = max<unsigned int>(GetArgUInt("-keypool", 100), 0);
1463 if (params.size() > 0) {
1464 if (params[0].get_int() < 0)
1465 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size");
1466 nSize = (unsigned int) params[0].get_int();
1469 EnsureWalletIsUnlocked();
1471 pwalletMain->TopUpKeyPool(nSize);
1473 if (pwalletMain->GetKeyPoolSize() < nSize)
1474 throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool.");
1479 Value keypoolreset(const Array& params, bool fHelp)
1481 if (fHelp || params.size() > 1)
1482 throw runtime_error(
1483 "keypoolreset [new-size]\n"
1484 "Resets the keypool.\n"
1485 "IMPORTANT: Any previous backups you have made of your wallet file "
1486 "should be replaced with the newly generated one."
1487 + HelpRequiringPassphrase());
1489 unsigned int nSize = max<unsigned int>(GetArgUInt("-keypool", 100), 0);
1490 if (params.size() > 0) {
1491 if (params[0].get_int() < 0)
1492 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size");
1493 nSize = (unsigned int) params[0].get_int();
1496 EnsureWalletIsUnlocked();
1498 pwalletMain->NewKeyPool(nSize);
1500 if (pwalletMain->GetKeyPoolSize() < nSize)
1501 throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool.");
1507 void ThreadTopUpKeyPool(void* parg)
1509 // Make this thread recognisable as the key-topping-up thread
1510 RenameThread("novacoin-key-top");
1512 pwalletMain->TopUpKeyPool();
1515 void ThreadCleanWalletPassphrase(void* parg)
1517 // Make this thread recognisable as the wallet relocking thread
1518 RenameThread("novacoin-lock-wa");
1520 int64_t nMyWakeTime = GetTimeMillis() + *((int64_t*)parg) * 1000;
1522 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1524 if (nWalletUnlockTime == 0)
1526 nWalletUnlockTime = nMyWakeTime;
1530 if (nWalletUnlockTime==0)
1532 int64_t nToSleep = nWalletUnlockTime - GetTimeMillis();
1536 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1538 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1542 if (nWalletUnlockTime)
1544 nWalletUnlockTime = 0;
1545 pwalletMain->Lock();
1550 if (nWalletUnlockTime < nMyWakeTime)
1551 nWalletUnlockTime = nMyWakeTime;
1554 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1556 delete (int64_t*)parg;
1559 Value walletpassphrase(const Array& params, bool fHelp)
1561 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 3))
1562 throw runtime_error(
1563 "walletpassphrase <passphrase> <timeout> [mintonly]\n"
1564 "Stores the wallet decryption key in memory for <timeout> seconds.\n"
1565 "mintonly is optional true/false allowing only block minting.");
1568 if (!pwalletMain->IsCrypted())
1569 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1571 if (!pwalletMain->IsLocked())
1572 throw JSONRPCError(RPC_WALLET_ALREADY_UNLOCKED, "Error: Wallet is already unlocked, use walletlock first if need to change unlock settings.");
1573 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1574 SecureString strWalletPass;
1575 strWalletPass.reserve(100);
1576 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1577 // Alternately, find a way to make params[0] mlock()'d to begin with.
1578 strWalletPass = params[0].get_str().c_str();
1580 if (strWalletPass.length() > 0)
1582 if (!pwalletMain->Unlock(strWalletPass))
1583 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
1586 throw runtime_error(
1587 "walletpassphrase <passphrase> <timeout>\n"
1588 "Stores the wallet decryption key in memory for <timeout> seconds.");
1590 NewThread(ThreadTopUpKeyPool, NULL);
1591 int64_t* pnSleepTime = new int64_t(params[1].get_int64());
1592 NewThread(ThreadCleanWalletPassphrase, pnSleepTime);
1594 // ppcoin: if user OS account compromised prevent trivial sendmoney commands
1595 if (params.size() > 2)
1596 fWalletUnlockMintOnly = params[2].get_bool();
1598 fWalletUnlockMintOnly = false;
1604 Value walletpassphrasechange(const Array& params, bool fHelp)
1606 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1607 throw runtime_error(
1608 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1609 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1612 if (!pwalletMain->IsCrypted())
1613 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1615 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1616 // Alternately, find a way to make params[0] mlock()'d to begin with.
1617 SecureString strOldWalletPass;
1618 strOldWalletPass.reserve(100);
1619 strOldWalletPass = params[0].get_str().c_str();
1621 SecureString strNewWalletPass;
1622 strNewWalletPass.reserve(100);
1623 strNewWalletPass = params[1].get_str().c_str();
1625 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1626 throw runtime_error(
1627 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1628 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1630 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1631 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
1637 Value walletlock(const Array& params, bool fHelp)
1639 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1640 throw runtime_error(
1642 "Removes the wallet encryption key from memory, locking the wallet.\n"
1643 "After calling this method, you will need to call walletpassphrase again\n"
1644 "before being able to call any methods which require the wallet to be unlocked.");
1647 if (!pwalletMain->IsCrypted())
1648 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletlock was called.");
1651 LOCK(cs_nWalletUnlockTime);
1652 pwalletMain->Lock();
1653 nWalletUnlockTime = 0;
1660 Value encryptwallet(const Array& params, bool fHelp)
1662 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1663 throw runtime_error(
1664 "encryptwallet <passphrase>\n"
1665 "Encrypts the wallet with <passphrase>.");
1668 if (pwalletMain->IsCrypted())
1669 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an encrypted wallet, but encryptwallet was called.");
1671 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1672 // Alternately, find a way to make params[0] mlock()'d to begin with.
1673 SecureString strWalletPass;
1674 strWalletPass.reserve(100);
1675 strWalletPass = params[0].get_str().c_str();
1677 if (strWalletPass.length() < 1)
1678 throw runtime_error(
1679 "encryptwallet <passphrase>\n"
1680 "Encrypts the wallet with <passphrase>.");
1682 if (!pwalletMain->EncryptWallet(strWalletPass))
1683 throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: Failed to encrypt the wallet.");
1685 // BDB seems to have a bad habit of writing old data into
1686 // slack space in .dat files; that is bad if the old data is
1687 // unencrypted private keys. So:
1689 return "wallet encrypted; NovaCoin server stopping, restart to run with encrypted wallet. The keypool has been flushed, you need to make a new backup.";
1692 class DescribeAddressVisitor : public boost::static_visitor<Object>
1697 DescribeAddressVisitor(isminetype mineIn) : mine(mineIn) {}
1699 Object operator()(const CNoDestination &dest) const { return Object(); }
1700 Object operator()(const CKeyID &keyID) const {
1703 pwalletMain->GetPubKey(keyID, vchPubKey);
1704 obj.push_back(Pair("isscript", false));
1705 if (mine == MINE_SPENDABLE) {
1706 pwalletMain->GetPubKey(keyID, vchPubKey);
1707 obj.push_back(Pair("pubkey", HexStr(vchPubKey.Raw())));
1708 obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed()));
1713 Object operator()(const CScriptID &scriptID) const {
1715 obj.push_back(Pair("isscript", true));
1716 if (mine == MINE_SPENDABLE) {
1718 pwalletMain->GetCScript(scriptID, subscript);
1719 std::vector<CTxDestination> addresses;
1720 txnouttype whichType;
1722 ExtractDestinations(subscript, whichType, addresses, nRequired);
1723 obj.push_back(Pair("script", GetTxnOutputType(whichType)));
1724 obj.push_back(Pair("hex", HexStr(subscript.begin(), subscript.end())));
1726 BOOST_FOREACH(const CTxDestination& addr, addresses)
1727 a.push_back(CBitcoinAddress(addr).ToString());
1728 obj.push_back(Pair("addresses", a));
1729 if (whichType == TX_MULTISIG)
1730 obj.push_back(Pair("sigsrequired", nRequired));
1736 Value validateaddress(const Array& params, bool fHelp)
1738 if (fHelp || params.size() != 1)
1739 throw runtime_error(
1740 "validateaddress <novacoinaddress>\n"
1741 "Return information about <novacoinaddress>.");
1743 CBitcoinAddress address(params[0].get_str());
1744 bool isValid = address.IsValid();
1747 ret.push_back(Pair("isvalid", isValid));
1750 CTxDestination dest = address.Get();
1751 string currentAddress = address.ToString();
1752 ret.push_back(Pair("address", currentAddress));
1753 isminetype mine = pwalletMain ? IsMine(*pwalletMain, dest) : MINE_NO;
1754 ret.push_back(Pair("ismine", mine != MINE_NO));
1755 if (mine != MINE_NO) {
1756 ret.push_back(Pair("watchonly", mine == MINE_WATCH_ONLY));
1757 Object detail = boost::apply_visitor(DescribeAddressVisitor(mine), dest);
1758 ret.insert(ret.end(), detail.begin(), detail.end());
1760 if (pwalletMain->mapAddressBook.count(dest))
1761 ret.push_back(Pair("account", pwalletMain->mapAddressBook[dest]));
1766 // ppcoin: reserve balance from being staked for network protection
1767 Value reservebalance(const Array& params, bool fHelp)
1769 if (fHelp || params.size() > 2)
1770 throw runtime_error(
1771 "reservebalance [<reserve> [amount]]\n"
1772 "<reserve> is true or false to turn balance reserve on or off.\n"
1773 "<amount> is a real and rounded to cent.\n"
1774 "Set reserve amount not participating in network protection.\n"
1775 "If no parameters provided current setting is printed.\n");
1777 if (params.size() > 0)
1779 bool fReserve = params[0].get_bool();
1782 if (params.size() == 1)
1783 throw runtime_error("must provide amount to reserve balance.\n");
1784 int64_t nAmount = AmountFromValue(params[1]);
1785 nAmount = (nAmount / CENT) * CENT; // round to cent
1787 throw runtime_error("amount cannot be negative.\n");
1788 mapArgs["-reservebalance"] = FormatMoney(nAmount).c_str();
1792 if (params.size() > 1)
1793 throw runtime_error("cannot specify amount to turn off reserve.\n");
1794 mapArgs["-reservebalance"] = "0";
1799 if (mapArgs.count("-reservebalance") && !ParseMoney(mapArgs["-reservebalance"], nReserveBalance))
1800 throw runtime_error("invalid reserve balance amount\n");
1801 result.push_back(Pair("reserve", (nReserveBalance > 0)));
1802 result.push_back(Pair("amount", ValueFromAmount(nReserveBalance)));
1807 // ppcoin: check wallet integrity
1808 Value checkwallet(const Array& params, bool fHelp)
1810 if (fHelp || params.size() > 0)
1811 throw runtime_error(
1813 "Check wallet for integrity.\n");
1816 int64_t nBalanceInQuestion;
1817 pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion, true);
1819 if (nMismatchSpent == 0)
1820 result.push_back(Pair("wallet check passed", true));
1823 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
1824 result.push_back(Pair("amount in question", ValueFromAmount(nBalanceInQuestion)));
1830 // ppcoin: repair wallet
1831 Value repairwallet(const Array& params, bool fHelp)
1833 if (fHelp || params.size() > 0)
1834 throw runtime_error(
1836 "Repair wallet if checkwallet reports any problem.\n");
1839 int64_t nBalanceInQuestion;
1840 pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion);
1842 if (nMismatchSpent == 0)
1843 result.push_back(Pair("wallet check passed", true));
1846 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
1847 result.push_back(Pair("amount affected by repair", ValueFromAmount(nBalanceInQuestion)));
1852 // NovaCoin: resend unconfirmed wallet transactions
1853 Value resendtx(const Array& params, bool fHelp)
1855 if (fHelp || params.size() > 1)
1856 throw runtime_error(
1858 "Re-send unconfirmed transactions.\n"
1861 ResendWalletTransactions();
1866 // Make a public-private key pair
1867 Value makekeypair(const Array& params, bool fHelp)
1869 if (fHelp || params.size() > 0)
1870 throw runtime_error(
1872 "Make a public/private key pair.\n");
1874 string strPrefix = "";
1875 if (params.size() > 0)
1876 strPrefix = params[0].get_str();
1879 key.MakeNewKey(true);
1881 CPrivKey vchPrivKey = key.GetPrivKey();
1883 result.push_back(Pair("PrivateKey", HexStr<CPrivKey::iterator>(vchPrivKey.begin(), vchPrivKey.end())));
1886 CSecret vchSecret = key.GetSecret(fCompressed);
1887 result.push_back(Pair("Secret", HexStr<CSecret::iterator>(vchSecret.begin(), vchSecret.end())));
1888 result.push_back(Pair("PublicKey", HexStr(key.GetPubKey().Raw())));
1892 Value newmalleablekey(const Array& params, bool fHelp)
1894 if (fHelp || params.size() > 0)
1895 throw runtime_error(
1897 "Make a malleable public/private key pair.\n");
1900 throw runtime_error("This feature has been disabled for mainNet clients");
1902 CMalleableKeyView keyView = pwalletMain->GenerateNewMalleableKey();
1905 if (!pwalletMain->GetMalleableKey(keyView, mKey))
1906 throw runtime_error("Unable to generate new malleable key");
1909 result.push_back(Pair("PublicPair", mKey.GetMalleablePubKey().ToString()));
1910 result.push_back(Pair("KeyView", keyView.ToString()));
1915 Value dumpmalleablekey(const Array& params, bool fHelp)
1917 if (fHelp || params.size() != 1)
1918 throw runtime_error (
1919 "dumpmalleablekey <Key view>\n"
1920 "Dump the private and public key pairs, which correspond to provided key view.\n");
1923 CMalleableKeyView keyView;
1924 keyView.SetString(params[0].get_str());
1926 if (!pwalletMain->GetMalleableKey(keyView, mKey))
1927 throw runtime_error("There is no such item in the wallet");
1930 result.push_back(Pair("PrivatePair", mKey.ToString()));
1931 result.push_back(Pair("PublicPair", mKey.GetMalleablePubKey().ToString()));
1936 Value adjustmalleablekey(const Array& params, bool fHelp)
1938 if (fHelp || params.size() != 3)
1939 throw runtime_error(
1940 "adjustmalleablekey <Malleable key data> <Public key variant data> <R data>\n"
1941 "Calculate new private key using provided malleable key, public key and R data.\n");
1943 CMalleableKey malleableKey;
1944 malleableKey.SetString(params[0].get_str());
1946 CKey privKeyVariant;
1947 CPubKey vchPubKeyVariant = CPubKey(ParseHex(params[1].get_str()));
1949 CPubKey R(ParseHex(params[2].get_str()));
1951 if (!malleableKey.CheckKeyVariant(R,vchPubKeyVariant, privKeyVariant)) {
1952 throw runtime_error("Unable to calculate the private key");
1957 CSecret vchPrivKeyVariant = privKeyVariant.GetSecret(fCompressed);
1959 result.push_back(Pair("PrivateKey", CBitcoinSecret(vchPrivKeyVariant, fCompressed).ToString()));
1964 Value adjustmalleablepubkey(const Array& params, bool fHelp)
1966 if (fHelp || params.size() > 2 || params.size() == 0)
1967 throw runtime_error(
1968 "adjustmalleablepubkey <Malleable public key data>\n"
1969 "Calculate new public key using provided malleable public key data.\n");
1971 string pubKeyPair = params[0].get_str();
1972 CMalleablePubKey malleablePubKey;
1974 if (pubKeyPair.size() == 138) {
1975 CDataStream ssPublicBytes(ParseHex(pubKeyPair), SER_NETWORK, PROTOCOL_VERSION);
1976 ssPublicBytes >> malleablePubKey;
1978 malleablePubKey.SetString(pubKeyPair);
1980 CPubKey R, vchPubKeyVariant;
1981 malleablePubKey.GetVariant(R, vchPubKeyVariant);
1984 result.push_back(Pair("R", HexStr(R.Raw())));
1985 result.push_back(Pair("PubkeyVariant", HexStr(vchPubKeyVariant.Raw())));
1986 result.push_back(Pair("KeyVariantID", CBitcoinAddress(vchPubKeyVariant.GetID()).ToString()));
1991 Value listmalleableviews(const Array& params, bool fHelp)
1993 if (fHelp || params.size() != 0)
1994 throw runtime_error(
1995 "listmalleableviews\n"
1996 "Get list of views for generated malleable keys.\n");
1998 std::list<CMalleableKeyView> keyViewList;
1999 pwalletMain->ListMalleableViews(keyViewList);
2002 BOOST_FOREACH(const CMalleableKeyView &keyView, keyViewList)
2004 result.push_back(keyView.ToString());