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;
16 int64_t nWalletUnlockTime;
17 static CCriticalSection cs_nWalletUnlockTime;
19 extern int64_t nReserveBalance;
20 extern void TxToJSON(const CTransaction& tx, const uint256& hashBlock, json_spirit::Object& entry);
22 std::string HelpRequiringPassphrase()
24 return pwalletMain->IsCrypted()
25 ? "\n\nRequires wallet passphrase to be set with walletpassphrase first"
29 void EnsureWalletIsUnlocked()
31 if (pwalletMain->IsLocked())
32 throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
33 if (fWalletUnlockMintOnly)
34 throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Wallet unlocked for block minting only.");
37 void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
39 int confirms = wtx.GetDepthInMainChain();
40 entry.push_back(Pair("confirmations", confirms));
41 if (wtx.IsCoinBase() || wtx.IsCoinStake())
42 entry.push_back(Pair("generated", true));
45 entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex()));
46 entry.push_back(Pair("blockindex", wtx.nIndex));
47 entry.push_back(Pair("blocktime", (int64_t)(mapBlockIndex[wtx.hashBlock]->nTime)));
49 entry.push_back(Pair("txid", wtx.GetHash().GetHex()));
50 entry.push_back(Pair("time", (int64_t)wtx.GetTxTime()));
51 entry.push_back(Pair("timereceived", (int64_t)wtx.nTimeReceived));
52 for (const auto& item : wtx.mapValue)
53 entry.push_back(Pair(item.first, item.second));
56 std::string AccountFromValue(const Value& value)
58 std::string strAccount = value.get_str();
59 if (strAccount == "*")
60 throw JSONRPCError(RPC_WALLET_INVALID_ACCOUNT_NAME, "Invalid account name");
64 Value getinfo(const Array& params, bool fHelp)
66 if (fHelp || params.size() != 0)
67 throw std::runtime_error(
69 "Returns an object containing various state info.");
72 GetProxy(NET_IPV4, proxy);
74 Object obj, diff, timestamping;
75 obj.push_back(Pair("version", FormatFullVersion()));
76 obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION));
77 obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
78 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
79 obj.push_back(Pair("unspendable", ValueFromAmount(pwalletMain->GetWatchOnlyBalance())));
80 obj.push_back(Pair("newmint", ValueFromAmount(pwalletMain->GetNewMint())));
81 obj.push_back(Pair("stake", ValueFromAmount(pwalletMain->GetStake())));
82 obj.push_back(Pair("blocks", (int)nBestHeight));
84 timestamping.push_back(Pair("systemclock", GetTime()));
85 timestamping.push_back(Pair("adjustedtime", GetAdjustedTime()));
87 int64_t nNtpOffset = GetNtpOffset(),
88 nP2POffset = GetNodesOffset();
90 timestamping.push_back(Pair("ntpoffset", nNtpOffset != INT64_MAX ? nNtpOffset : Value::null));
91 timestamping.push_back(Pair("p2poffset", nP2POffset != INT64_MAX ? nP2POffset : Value::null));
93 obj.push_back(Pair("timestamping", timestamping));
95 obj.push_back(Pair("moneysupply", ValueFromAmount(pindexBest->nMoneySupply)));
96 obj.push_back(Pair("connections", (int)vNodes.size()));
97 obj.push_back(Pair("proxy", (proxy.first.IsValid() ? proxy.first.ToStringIPPort() : std::string())));
98 obj.push_back(Pair("ip", addrSeenByPeer.ToStringIP()));
100 diff.push_back(Pair("proof-of-work", GetDifficulty()));
101 diff.push_back(Pair("proof-of-stake", GetDifficulty(GetLastBlockIndex(pindexBest, true))));
102 obj.push_back(Pair("difficulty", diff));
104 obj.push_back(Pair("testnet", fTestNet));
105 obj.push_back(Pair("keypoololdest", (int64_t)pwalletMain->GetOldestKeyPoolTime()));
106 obj.push_back(Pair("keypoolsize", (int)pwalletMain->GetKeyPoolSize()));
107 obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee)));
108 obj.push_back(Pair("mininput", ValueFromAmount(nMinimumInputValue)));
109 if (pwalletMain->IsCrypted())
110 obj.push_back(Pair("unlocked_until", (int64_t)nWalletUnlockTime / 1000));
111 obj.push_back(Pair("errors", GetWarnings("statusbar")));
115 Value getnewaddress(const Array& params, bool fHelp)
117 if (fHelp || params.size() > 1)
118 throw std::runtime_error(
119 "getnewaddress [account]\n"
120 "Returns a new NovaCoin address for receiving payments. "
121 "If [account] is specified (recommended), it is added to the address book "
122 "so payments received with the address will be credited to [account].");
124 // Parse the account first so we don't generate a key if there's an error
125 std::string strAccount;
126 if (params.size() > 0)
127 strAccount = AccountFromValue(params[0]);
129 if (!pwalletMain->IsLocked())
130 pwalletMain->TopUpKeyPool();
132 // Generate a new key that is added to wallet
134 if (!pwalletMain->GetKeyFromPool(newKey, false))
135 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
136 CBitcoinAddress address(newKey.GetID());
138 pwalletMain->SetAddressBookName(address, strAccount);
140 return address.ToString();
144 CBitcoinAddress GetAccountAddress(std::string strAccount, bool bForceNew=false)
146 CWalletDB walletdb(pwalletMain->strWalletFile);
149 walletdb.ReadAccount(strAccount, account);
151 bool bKeyUsed = false;
153 // Check if the current key has been used
154 if (account.vchPubKey.IsValid())
156 CScript scriptPubKey;
157 scriptPubKey.SetDestination(account.vchPubKey.GetID());
158 for (auto it = pwalletMain->mapWallet.begin();
159 it != pwalletMain->mapWallet.end() && account.vchPubKey.IsValid();
162 const CWalletTx& wtx = (*it).second;
163 for (const CTxOut& txout : wtx.vout)
164 if (txout.scriptPubKey == scriptPubKey)
169 // Generate a new key
170 if (!account.vchPubKey.IsValid() || bForceNew || bKeyUsed)
172 if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false))
173 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
175 pwalletMain->SetAddressBookName(account.vchPubKey.GetID(), strAccount);
176 walletdb.WriteAccount(strAccount, account);
179 return CBitcoinAddress(account.vchPubKey.GetID());
182 Value getaccountaddress(const Array& params, bool fHelp)
184 if (fHelp || params.size() != 1)
185 throw std::runtime_error(
186 "getaccountaddress <account>\n"
187 "Returns the current NovaCoin address for receiving payments to this account.");
189 // Parse the account first so we don't generate a key if there's an error
190 std::string strAccount = AccountFromValue(params[0]);
194 ret = GetAccountAddress(strAccount).ToString();
201 Value setaccount(const Array& params, bool fHelp)
203 if (fHelp || params.size() < 1 || params.size() > 2)
204 throw std::runtime_error(
205 "setaccount <novacoinaddress> <account>\n"
206 "Sets the account associated with the given address.");
208 CBitcoinAddress address(params[0].get_str());
209 if (!address.IsValid())
210 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
213 std::string strAccount;
214 if (params.size() > 1)
215 strAccount = AccountFromValue(params[1]);
217 // Detect when changing the account of an address that is the 'unused current key' of another account:
218 if (pwalletMain->mapAddressBook.count(address))
220 std::string strOldAccount = pwalletMain->mapAddressBook[address];
221 if (address == GetAccountAddress(strOldAccount))
222 GetAccountAddress(strOldAccount, true);
225 pwalletMain->SetAddressBookName(address, strAccount);
231 Value getaccount(const Array& params, bool fHelp)
233 if (fHelp || params.size() != 1)
234 throw std::runtime_error(
235 "getaccount <novacoinaddress>\n"
236 "Returns the account associated with the given address.");
238 CBitcoinAddress address(params[0].get_str());
239 if (!address.IsValid())
240 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
242 std::string strAccount;
243 auto mi = pwalletMain->mapAddressBook.find(address);
244 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
245 strAccount = (*mi).second;
250 Value getaddressesbyaccount(const Array& params, bool fHelp)
252 if (fHelp || params.size() != 1)
253 throw std::runtime_error(
254 "getaddressesbyaccount <account>\n"
255 "Returns the list of addresses for the given account.");
257 std::string strAccount = AccountFromValue(params[0]);
259 // Find all addresses that have the given account
261 for (const auto& item : pwalletMain->mapAddressBook)
263 const CBitcoinAddress& address = item.first;
264 const std::string& strName = item.second;
265 if (strName == strAccount)
266 ret.push_back(address.ToString());
271 Value mergecoins(const Array& params, bool fHelp)
273 if (fHelp || params.size() != 3)
274 throw std::runtime_error(
275 "mergecoins <amount> <minvalue> <outputvalue>\n"
276 "<amount> is resulting inputs sum\n"
277 "<minvalue> is minimum value of inputs which are used in join process\n"
278 "<outputvalue> is resulting value of inputs which will be created\n"
279 "All values are real and and rounded to the nearest " + FormatMoney(nMinimumInputValue)
280 + HelpRequiringPassphrase());
282 if (pwalletMain->IsLocked())
283 throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
286 int64_t nAmount = AmountFromValue(params[0]);
289 int64_t nMinValue = AmountFromValue(params[1]);
292 int64_t nOutputValue = AmountFromValue(params[2]);
294 if (nAmount < nMinimumInputValue)
295 throw JSONRPCError(-101, "Send amount too small");
297 if (nMinValue < nMinimumInputValue)
298 throw JSONRPCError(-101, "Max value too small");
300 if (nOutputValue < nMinimumInputValue)
301 throw JSONRPCError(-101, "Output value too small");
303 if (nOutputValue < nMinValue)
304 throw JSONRPCError(-101, "Output value is lower than min value");
306 std::list<uint256> listMerged;
307 if (!pwalletMain->MergeCoins(nAmount, nMinValue, nOutputValue, listMerged))
311 for (const uint256 txHash : listMerged)
312 mergedHashes.push_back(txHash.GetHex());
317 Value sendtoaddress(const Array& params, bool fHelp)
319 if (fHelp || params.size() < 2 || params.size() > 4)
320 throw std::runtime_error(
321 "sendtoaddress <novacoinaddress> <amount> [comment] [comment-to]\n"
322 "<amount> is a real and is rounded to the nearest " + FormatMoney(nMinimumInputValue)
323 + HelpRequiringPassphrase());
326 CScript scriptPubKey;
327 std::string strAddress = params[0].get_str();
329 CBitcoinAddress address(strAddress);
330 if (address.IsValid())
331 scriptPubKey.SetAddress(address);
333 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
336 int64_t nAmount = AmountFromValue(params[1]);
338 if (nAmount < nMinimumInputValue)
339 throw JSONRPCError(-101, "Send amount too small");
343 if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
344 wtx.mapValue["comment"] = params[2].get_str();
345 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
346 wtx.mapValue["to"] = params[3].get_str();
348 if (pwalletMain->IsLocked())
349 throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
351 std::string strError = pwalletMain->SendMoney(scriptPubKey, nAmount, wtx);
352 if (!strError.empty())
353 throw JSONRPCError(RPC_WALLET_ERROR, strError);
355 return wtx.GetHash().GetHex();
358 Value listaddressgroupings(const Array& params, bool fHelp)
361 throw std::runtime_error(
362 "listaddressgroupings\n"
363 "Lists groups of addresses which have had their common ownership\n"
364 "made public by common use as inputs or as the resulting change\n"
365 "in past transactions");
368 auto balances = pwalletMain->GetAddressBalances();
369 for (auto grouping : pwalletMain->GetAddressGroupings())
372 for (CBitcoinAddress address : grouping)
375 addressInfo.push_back(address.ToString());
376 addressInfo.push_back(ValueFromAmount(balances[address]));
378 LOCK(pwalletMain->cs_wallet);
379 if (pwalletMain->mapAddressBook.find(address) != pwalletMain->mapAddressBook.end())
380 addressInfo.push_back(pwalletMain->mapAddressBook.find(address)->second);
382 jsonGrouping.push_back(addressInfo);
384 jsonGroupings.push_back(jsonGrouping);
386 return jsonGroupings;
389 Value signmessage(const Array& params, bool fHelp)
391 if (fHelp || params.size() != 2)
392 throw std::runtime_error(
393 "signmessage <novacoinaddress> <message>\n"
394 "Sign a message with the private key of an address");
396 EnsureWalletIsUnlocked();
398 std::string strAddress = params[0].get_str();
399 std::string strMessage = params[1].get_str();
401 CBitcoinAddress addr(strAddress);
403 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
406 if (!addr.GetKeyID(keyID))
407 throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
410 if (!pwalletMain->GetKey(keyID, key))
411 throw JSONRPCError(RPC_WALLET_ERROR, "Private key not available");
413 CDataStream ss(SER_GETHASH, 0);
414 ss << strMessageMagic;
417 std::vector<unsigned char> vchSig;
418 if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
419 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed");
421 return EncodeBase64(&vchSig[0], vchSig.size());
424 Value verifymessage(const Array& params, bool fHelp)
426 if (fHelp || params.size() != 3)
427 throw std::runtime_error(
428 "verifymessage <novacoinaddress> <signature> <message>\n"
429 "Verify a signed message");
431 std::string strAddress = params[0].get_str();
432 std::string strSign = params[1].get_str();
433 std::string strMessage = params[2].get_str();
435 CBitcoinAddress addr(strAddress);
437 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
440 if (!addr.GetKeyID(keyID))
441 throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
443 bool fInvalid = false;
444 std::vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
447 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Malformed base64 encoding");
449 CDataStream ss(SER_GETHASH, 0);
450 ss << strMessageMagic;
454 if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
457 return (key.GetID() == keyID);
461 Value getreceivedbyaddress(const Array& params, bool fHelp)
463 if (fHelp || params.size() < 1 || params.size() > 2)
464 throw std::runtime_error(
465 "getreceivedbyaddress <novacoinaddress> [minconf=1]\n"
466 "Returns the total amount received by <novacoinaddress> in transactions with at least [minconf] confirmations.");
469 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
470 if (!address.IsValid())
471 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
472 if (!IsMine(*pwalletMain,address))
475 // Minimum confirmations
477 if (params.size() > 1)
478 nMinDepth = params[1].get_int();
481 for (auto it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
483 const CWalletTx& wtx = (*it).second;
484 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
486 for (const CTxOut& txout : wtx.vout)
488 CBitcoinAddress addressRet;
489 if (!ExtractAddress(*pwalletMain, txout.scriptPubKey, addressRet))
491 if (addressRet == address)
492 if (wtx.GetDepthInMainChain() >= nMinDepth)
493 nAmount += txout.nValue;
497 return ValueFromAmount(nAmount);
500 void GetAccountAddresses(std::string strAccount, std::set<CBitcoinAddress>& setAddress)
502 for (const auto& item : pwalletMain->mapAddressBook)
504 const CBitcoinAddress& address = item.first;
505 const std::string& strName = item.second;
506 if (strName == strAccount)
507 setAddress.insert(address);
511 Value getreceivedbyaccount(const Array& params, bool fHelp)
513 if (fHelp || params.size() < 1 || params.size() > 2)
514 throw std::runtime_error(
515 "getreceivedbyaccount <account> [minconf=1]\n"
516 "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
518 // Minimum confirmations
520 if (params.size() > 1)
521 nMinDepth = params[1].get_int();
523 // Get the set of pub keys assigned to account
524 std::string strAccount = AccountFromValue(params[0]);
525 std::set<CBitcoinAddress> setAddress;
526 GetAccountAddresses(strAccount, setAddress);
530 for (auto it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
532 const CWalletTx& wtx = (*it).second;
533 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
536 for (const CTxOut& txout : wtx.vout)
538 CBitcoinAddress address;
539 if (ExtractAddress(*pwalletMain, txout.scriptPubKey, address) && IsMine(*pwalletMain, address) && setAddress.count(address))
540 if (wtx.GetDepthInMainChain() >= nMinDepth)
541 nAmount += txout.nValue;
545 return (double)nAmount / (double)COIN;
549 int64_t GetAccountBalance(CWalletDB& walletdb, const std::string& strAccount, int nMinDepth, const isminefilter& filter)
551 int64_t nBalance = 0;
553 // Tally wallet transactions
554 for (auto it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
556 const CWalletTx& wtx = (*it).second;
560 int64_t nGenerated, nReceived, nSent, nFee;
561 wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee, filter);
563 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
564 nBalance += nReceived;
565 nBalance += nGenerated - nSent - nFee;
568 // Tally internal accounting entries
569 nBalance += walletdb.GetAccountCreditDebit(strAccount);
574 int64_t GetAccountBalance(const std::string& strAccount, int nMinDepth, const isminefilter& filter)
576 CWalletDB walletdb(pwalletMain->strWalletFile);
577 return GetAccountBalance(walletdb, strAccount, nMinDepth, filter);
581 Value getbalance(const Array& params, bool fHelp)
583 if (fHelp || params.size() > 3)
584 throw std::runtime_error(
585 "getbalance [account] [minconf=1] [watchonly=0]\n"
586 "If [account] is not specified, returns the server's total available balance.\n"
587 "If [account] is specified, returns the balance in the account.\n"
588 "if [includeWatchonly] is specified, include balance in watchonly addresses (see 'importaddress').");
590 if (params.size() == 0)
591 return ValueFromAmount(pwalletMain->GetBalance());
594 if (params.size() > 1)
595 nMinDepth = params[1].get_int();
596 isminefilter filter = MINE_SPENDABLE;
597 if(params.size() > 2)
598 if(params[2].get_bool())
599 filter = filter | MINE_WATCH_ONLY;
601 if (params[0].get_str() == "*") {
602 // Calculate total balance a different way from GetBalance()
603 // (GetBalance() sums up all unspent TxOuts)
604 // getbalance and getbalance '*' 0 should return the same number.
605 int64_t nBalance = 0;
606 for (auto it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
608 const CWalletTx& wtx = (*it).second;
609 if (!wtx.IsTrusted())
612 int64_t allGeneratedImmature, allGeneratedMature, allFee;
613 allGeneratedImmature = allGeneratedMature = allFee = 0;
615 std::string strSentAccount;
616 std::list<std::pair<CBitcoinAddress, int64_t> > listReceived;
617 std::list<std::pair<CBitcoinAddress, int64_t> > listSent;
618 wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount, filter);
619 if (wtx.GetDepthInMainChain() >= nMinDepth)
621 for (const auto& r : listReceived)
622 nBalance += r.second;
624 for (const auto& r : listSent)
625 nBalance -= r.second;
627 nBalance += allGeneratedMature;
629 return ValueFromAmount(nBalance);
632 std::string strAccount = AccountFromValue(params[0]);
634 int64_t nBalance = GetAccountBalance(strAccount, nMinDepth, filter);
636 return ValueFromAmount(nBalance);
640 Value movecmd(const Array& params, bool fHelp)
642 if (fHelp || params.size() < 3 || params.size() > 5)
643 throw std::runtime_error(
644 "move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
645 "Move from one account in your wallet to another.");
647 std::string strFrom = AccountFromValue(params[0]);
648 std::string strTo = AccountFromValue(params[1]);
649 int64_t nAmount = AmountFromValue(params[2]);
651 if (nAmount < nMinimumInputValue)
652 throw JSONRPCError(-101, "Send amount too small");
654 if (params.size() > 3)
655 // unused parameter, used to be nMinDepth, keep type-checking it though
656 (void)params[3].get_int();
657 std::string strComment;
658 if (params.size() > 4)
659 strComment = params[4].get_str();
661 CWalletDB walletdb(pwalletMain->strWalletFile);
662 if (!walletdb.TxnBegin())
663 throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
665 int64_t nNow = GetAdjustedTime();
668 CAccountingEntry debit;
669 debit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
670 debit.strAccount = strFrom;
671 debit.nCreditDebit = -nAmount;
673 debit.strOtherAccount = strTo;
674 debit.strComment = strComment;
675 walletdb.WriteAccountingEntry(debit);
678 CAccountingEntry credit;
679 credit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
680 credit.strAccount = strTo;
681 credit.nCreditDebit = nAmount;
683 credit.strOtherAccount = strFrom;
684 credit.strComment = strComment;
685 walletdb.WriteAccountingEntry(credit);
687 if (!walletdb.TxnCommit())
688 throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
694 Value sendfrom(const Array& params, bool fHelp)
696 if (fHelp || params.size() < 3 || params.size() > 6)
697 throw std::runtime_error(
698 "sendfrom <fromaccount> <tonovacoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
699 "<amount> is a real and is rounded to the nearest " + FormatMoney(nMinimumInputValue)
700 + HelpRequiringPassphrase());
702 std::string strAccount = AccountFromValue(params[0]);
705 CScript scriptPubKey;
706 std::string strAddress = params[1].get_str();
708 CBitcoinAddress address(strAddress);
709 if (address.IsValid())
710 scriptPubKey.SetAddress(address);
712 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
715 int64_t nAmount = AmountFromValue(params[2]);
717 if (nAmount < nMinimumInputValue)
718 throw JSONRPCError(-101, "Send amount too small");
721 if (params.size() > 3)
722 nMinDepth = params[3].get_int();
725 wtx.strFromAccount = strAccount;
726 if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
727 wtx.mapValue["comment"] = params[4].get_str();
728 if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
729 wtx.mapValue["to"] = params[5].get_str();
731 EnsureWalletIsUnlocked();
734 int64_t nBalance = GetAccountBalance(strAccount, nMinDepth, MINE_SPENDABLE);
735 if (nAmount > nBalance)
736 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
739 std::string strError = pwalletMain->SendMoney(scriptPubKey, nAmount, wtx);
740 if (!strError.empty())
741 throw JSONRPCError(RPC_WALLET_ERROR, strError);
743 return wtx.GetHash().GetHex();
747 Value sendmany(const Array& params, bool fHelp)
749 if (fHelp || params.size() < 2 || params.size() > 4)
750 throw std::runtime_error(
751 "sendmany <fromaccount> '{address:amount,...}' [minconf=1] [comment]\n"
752 "amounts are double-precision floating point numbers"
753 + HelpRequiringPassphrase());
755 std::string strAccount = AccountFromValue(params[0]);
756 Object sendTo = params[1].get_obj();
758 if (params.size() > 2)
759 nMinDepth = params[2].get_int();
762 wtx.strFromAccount = strAccount;
763 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
764 wtx.mapValue["comment"] = params[3].get_str();
766 std::set<CBitcoinAddress> setAddress;
767 std::vector<std::pair<CScript, int64_t> > vecSend;
769 int64_t totalAmount = 0;
770 for (const Pair& s : sendTo)
772 CBitcoinAddress address(s.name_);
773 if (!address.IsValid())
774 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid NovaCoin address: ")+s.name_);
776 if (!address.IsPair())
778 if (setAddress.count(address))
779 throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ")+s.name_);
780 setAddress.insert(address);
783 CScript scriptPubKey;
784 scriptPubKey.SetAddress(address);
785 int64_t nAmount = AmountFromValue(s.value_);
787 if (nAmount < nMinimumInputValue)
788 throw JSONRPCError(-101, "Send amount too small");
790 totalAmount += nAmount;
792 vecSend.push_back(make_pair(scriptPubKey, nAmount));
795 EnsureWalletIsUnlocked();
798 int64_t nBalance = GetAccountBalance(strAccount, nMinDepth, MINE_SPENDABLE);
799 if (totalAmount > nBalance)
800 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
803 CReserveKey keyChange(pwalletMain);
804 int64_t nFeeRequired = 0;
805 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
808 int64_t nTotal = pwalletMain->GetBalance(), nWatchOnly = pwalletMain->GetWatchOnlyBalance();
809 if (totalAmount + nFeeRequired > nTotal - nWatchOnly)
810 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds");
811 throw JSONRPCError(RPC_WALLET_ERROR, "Transaction creation failed");
813 if (!pwalletMain->CommitTransaction(wtx, keyChange))
814 throw JSONRPCError(RPC_WALLET_ERROR, "Transaction commit failed");
816 return wtx.GetHash().GetHex();
819 Value addmultisigaddress(const Array& params, bool fHelp)
821 if (fHelp || params.size() < 2 || params.size() > 3)
823 std::string msg = "addmultisigaddress <nrequired> <'[\"key\",\"key\"]'> [account]\n"
824 "Add a nrequired-to-sign multisignature address to the wallet\"\n"
825 "each key is a NovaCoin address or hex-encoded public key\n"
826 "If [account] is specified, assign address to [account].";
827 throw std::runtime_error(msg);
830 int nRequired = params[0].get_int();
831 const Array& keys = params[1].get_array();
832 std::string strAccount;
833 if (params.size() > 2)
834 strAccount = AccountFromValue(params[2]);
836 // Gather public keys
838 throw std::runtime_error("a multisignature address must require at least one key to redeem");
839 if ((int)keys.size() < nRequired)
840 throw std::runtime_error(
841 strprintf("not enough keys supplied "
842 "(got %" PRIszu " keys, but need at least %d to redeem)", keys.size(), nRequired));
843 if (keys.size() > 16)
844 throw std::runtime_error("Number of addresses involved in the multisignature address creation > 16\nReduce the number");
845 std::vector<CPubKey> pubkeys;
846 pubkeys.resize(keys.size());
847 for (unsigned int i = 0; i < keys.size(); i++)
849 const std::string& ks = keys[i].get_str();
851 // Case 1: Bitcoin address and we have full public key:
852 CBitcoinAddress address(ks);
853 if (address.IsValid())
856 if (!address.GetKeyID(keyID))
857 throw std::runtime_error(
858 strprintf("%s does not refer to a key",ks.c_str()));
860 if (!pwalletMain->GetPubKey(keyID, vchPubKey))
861 throw std::runtime_error(
862 strprintf("no full public key for address %s",ks.c_str()));
863 if (!vchPubKey.IsValid())
864 throw std::runtime_error(" Invalid public key: "+ks);
865 pubkeys[i] = vchPubKey;
868 // Case 2: hex public key
871 CPubKey vchPubKey(ParseHex(ks));
872 if (!vchPubKey.IsValid())
873 throw std::runtime_error(" Invalid public key: "+ks);
874 pubkeys[i] = vchPubKey;
878 throw std::runtime_error(" Invalid public key: "+ks);
882 // Construct using pay-to-script-hash:
884 inner.SetMultisig(nRequired, pubkeys);
886 if (inner.size() > MAX_SCRIPT_ELEMENT_SIZE)
887 throw std::runtime_error(
888 strprintf("redeemScript exceeds size limit: %" PRIszu " > %d", inner.size(), MAX_SCRIPT_ELEMENT_SIZE));
890 pwalletMain->AddCScript(inner);
891 CBitcoinAddress address(inner.GetID());
893 pwalletMain->SetAddressBookName(address, strAccount);
894 return address.ToString();
897 Value addredeemscript(const Array& params, bool fHelp)
899 if (fHelp || params.size() < 1 || params.size() > 2)
901 std::string msg = "addredeemscript <redeemScript> [account]\n"
902 "Add a P2SH address with a specified redeemScript to the wallet.\n"
903 "If [account] is specified, assign address to [account].";
904 throw std::runtime_error(msg);
907 std::string strAccount;
908 if (params.size() > 1)
909 strAccount = AccountFromValue(params[1]);
911 // Construct using pay-to-script-hash:
912 auto innerData = ParseHexV(params[0], "redeemScript");
913 CScript inner(innerData.begin(), innerData.end());
914 pwalletMain->AddCScript(inner);
915 CBitcoinAddress address(inner.GetID());
917 pwalletMain->SetAddressBookName(address, strAccount);
918 return address.ToString();
928 nConf = std::numeric_limits<int>::max();
932 Value ListReceived(const Array& params, bool fByAccounts)
934 // Minimum confirmations
936 if (params.size() > 0)
937 nMinDepth = params[0].get_int();
939 // Whether to include empty accounts
940 bool fIncludeEmpty = false;
941 if (params.size() > 1)
942 fIncludeEmpty = params[1].get_bool();
945 std::map<CBitcoinAddress, tallyitem> mapTally;
946 for (auto it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
948 const CWalletTx& wtx = (*it).second;
950 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
953 int nDepth = wtx.GetDepthInMainChain();
954 if (nDepth < nMinDepth)
957 for (const CTxOut& txout : wtx.vout)
959 CTxDestination address;
960 if (!ExtractDestination(txout.scriptPubKey, address) || !IsMine(*pwalletMain, address))
963 tallyitem& item = mapTally[address];
964 item.nAmount += txout.nValue;
965 item.nConf = std::min(item.nConf, nDepth);
971 std::map<std::string, tallyitem> mapAccountTally;
972 for (const auto& item : pwalletMain->mapAddressBook)
974 const CBitcoinAddress& address = item.first;
975 const std::string& strAccount = item.second;
976 auto it = mapTally.find(address);
977 if (it == mapTally.end() && !fIncludeEmpty)
981 int nConf = std::numeric_limits<int>::max();
982 if (it != mapTally.end())
984 nAmount = (*it).second.nAmount;
985 nConf = (*it).second.nConf;
990 tallyitem& item = mapAccountTally[strAccount];
991 item.nAmount += nAmount;
992 item.nConf = std::min(item.nConf, nConf);
997 obj.push_back(Pair("address", address.ToString()));
998 obj.push_back(Pair("account", strAccount));
999 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1000 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1007 for (auto it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
1009 int64_t nAmount = (*it).second.nAmount;
1010 int nConf = (*it).second.nConf;
1012 obj.push_back(Pair("account", (*it).first));
1013 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1014 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1022 Value listreceivedbyaddress(const Array& params, bool fHelp)
1024 if (fHelp || params.size() > 2)
1025 throw std::runtime_error(
1026 "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
1027 "[minconf] is the minimum number of confirmations before payments are included.\n"
1028 "[includeempty] whether to include addresses that haven't received any payments.\n"
1029 "Returns an array of objects containing:\n"
1030 " \"address\" : receiving address\n"
1031 " \"account\" : the account of the receiving address\n"
1032 " \"amount\" : total amount received by the address\n"
1033 " \"confirmations\" : number of confirmations of the most recent transaction included");
1035 return ListReceived(params, false);
1038 Value listreceivedbyaccount(const Array& params, bool fHelp)
1040 if (fHelp || params.size() > 2)
1041 throw std::runtime_error(
1042 "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
1043 "[minconf] is the minimum number of confirmations before payments are included.\n"
1044 "[includeempty] whether to include accounts that haven't received any payments.\n"
1045 "Returns an array of objects containing:\n"
1046 " \"account\" : the account of the receiving addresses\n"
1047 " \"amount\" : total amount received by addresses with this account\n"
1048 " \"confirmations\" : number of confirmations of the most recent transaction included");
1050 return ListReceived(params, true);
1053 static void MaybePushAddress(Object & entry, const CBitcoinAddress &dest)
1055 entry.push_back(Pair("address", dest.ToString()));
1058 void ListTransactions(const CWalletTx& wtx, const std::string& strAccount, int nMinDepth, bool fLong, Array& ret, const isminefilter& filter)
1060 int64_t nGeneratedImmature, nGeneratedMature, nFee;
1061 std::string strSentAccount;
1062 std::list<std::pair<CBitcoinAddress, int64_t> > listReceived;
1063 std::list<std::pair<CBitcoinAddress, int64_t> > listSent;
1065 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount, filter);
1067 bool fAllAccounts = (strAccount == std::string("*"));
1068 bool involvesWatchonly = wtx.IsFromMe(MINE_WATCH_ONLY);
1070 // Generated blocks assigned to account ""
1071 if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount.empty()))
1074 entry.push_back(Pair("account", std::string("")));
1075 if (nGeneratedImmature)
1077 entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
1078 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
1082 entry.push_back(Pair("category", "generate"));
1083 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
1086 WalletTxToJSON(wtx, entry);
1087 ret.push_back(entry);
1091 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1093 for (const auto& s : listSent)
1096 entry.push_back(Pair("account", strSentAccount));
1097 if(involvesWatchonly || (::IsMine(*pwalletMain, s.first) & MINE_WATCH_ONLY))
1098 entry.push_back(Pair("involvesWatchonly", true));
1099 MaybePushAddress(entry, s.first);
1101 if (wtx.GetDepthInMainChain() < 0) {
1102 entry.push_back(Pair("category", "conflicted"));
1104 entry.push_back(Pair("category", "send"));
1107 entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1108 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1110 WalletTxToJSON(wtx, entry);
1111 ret.push_back(entry);
1116 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1118 for (const auto& r : listReceived)
1120 std::string account;
1121 if (pwalletMain->mapAddressBook.count(r.first))
1122 account = pwalletMain->mapAddressBook[r.first];
1123 if (fAllAccounts || (account == strAccount))
1126 entry.push_back(Pair("account", account));
1127 if(involvesWatchonly || (::IsMine(*pwalletMain, r.first) & MINE_WATCH_ONLY))
1128 entry.push_back(Pair("involvesWatchonly", true));
1129 MaybePushAddress(entry, r.first);
1130 if (wtx.IsCoinBase())
1132 if (wtx.GetDepthInMainChain() < 1)
1133 entry.push_back(Pair("category", "orphan"));
1134 else if (wtx.GetBlocksToMaturity() > 0)
1135 entry.push_back(Pair("category", "immature"));
1137 entry.push_back(Pair("category", "generate"));
1140 entry.push_back(Pair("category", "receive"));
1141 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1143 WalletTxToJSON(wtx, entry);
1144 ret.push_back(entry);
1150 void AcentryToJSON(const CAccountingEntry& acentry, const std::string& strAccount, Array& ret)
1152 bool fAllAccounts = (strAccount == std::string("*"));
1154 if (fAllAccounts || acentry.strAccount == strAccount)
1157 entry.push_back(Pair("account", acentry.strAccount));
1158 entry.push_back(Pair("category", "move"));
1159 entry.push_back(Pair("time", (int64_t)acentry.nTime));
1160 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1161 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1162 entry.push_back(Pair("comment", acentry.strComment));
1163 ret.push_back(entry);
1167 Value listtransactions(const Array& params, bool fHelp)
1169 if (fHelp || params.size() > 3)
1170 throw std::runtime_error(
1171 "listtransactions [account] [count=10] [from=0]\n"
1172 "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1174 std::string strAccount = "*";
1175 if (params.size() > 0)
1176 strAccount = params[0].get_str();
1178 if (params.size() > 1)
1179 nCount = params[1].get_int();
1181 if (params.size() > 2)
1182 nFrom = params[2].get_int();
1184 isminefilter filter = MINE_SPENDABLE;
1185 if(params.size() > 3)
1186 if(params[3].get_bool())
1187 filter = filter | MINE_WATCH_ONLY;
1190 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count");
1192 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative from");
1196 std::list<CAccountingEntry> acentries;
1197 CWallet::TxItems txOrdered = pwalletMain->OrderedTxItems(acentries, strAccount);
1199 // iterate backwards until we have nCount items to return:
1200 for (CWallet::TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
1202 CWalletTx *const pwtx = (*it).second.first;
1204 ListTransactions(*pwtx, strAccount, 0, true, ret, filter);
1205 CAccountingEntry *const pacentry = (*it).second.second;
1207 AcentryToJSON(*pacentry, strAccount, ret);
1209 if ((int)ret.size() >= (nCount+nFrom)) break;
1211 // ret is newest to oldest
1213 if (nFrom > (int)ret.size())
1215 if ((nFrom + nCount) > (int)ret.size())
1216 nCount = ret.size() - nFrom;
1217 Array::iterator first = ret.begin();
1218 std::advance(first, nFrom);
1219 Array::iterator last = ret.begin();
1220 std::advance(last, nFrom+nCount);
1222 if (last != ret.end()) ret.erase(last, ret.end());
1223 if (first != ret.begin()) ret.erase(ret.begin(), first);
1225 std::reverse(ret.begin(), ret.end()); // Return oldest to newest
1230 Value listaccounts(const Array& params, bool fHelp)
1232 if (fHelp || params.size() > 1)
1233 throw std::runtime_error(
1234 "listaccounts [minconf=1]\n"
1235 "Returns Object that has account names as keys, account balances as values.");
1238 if (params.size() > 0)
1239 nMinDepth = params[0].get_int();
1241 isminefilter includeWatchonly = MINE_SPENDABLE;
1242 if(params.size() > 1)
1243 if(params[1].get_bool())
1244 includeWatchonly = includeWatchonly | MINE_WATCH_ONLY;
1247 std::map<std::string, int64_t> mapAccountBalances;
1248 for (const auto& entry : pwalletMain->mapAddressBook) {
1249 if (IsMine(*pwalletMain, entry.first)) // This address belongs to me
1250 mapAccountBalances[entry.second] = 0;
1253 for (auto it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1255 const CWalletTx& wtx = (*it).second;
1256 int64_t nGeneratedImmature, nGeneratedMature, nFee;
1257 std::string strSentAccount;
1258 std::list<std::pair<CBitcoinAddress, int64_t> > listReceived;
1259 std::list<std::pair<CBitcoinAddress, int64_t> > listSent;
1260 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount, includeWatchonly);
1261 mapAccountBalances[strSentAccount] -= nFee;
1262 for (const auto& s : listSent)
1263 mapAccountBalances[strSentAccount] -= s.second;
1264 if (wtx.GetDepthInMainChain() >= nMinDepth)
1266 mapAccountBalances[""] += nGeneratedMature;
1267 for (const auto& r : listReceived)
1268 if (pwalletMain->mapAddressBook.count(r.first))
1269 mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1271 mapAccountBalances[""] += r.second;
1275 std::list<CAccountingEntry> acentries;
1276 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1277 for (const CAccountingEntry& entry : acentries)
1278 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1281 for (const auto& accountBalance : mapAccountBalances) {
1282 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1287 Value listsinceblock(const Array& params, bool fHelp)
1290 throw std::runtime_error(
1291 "listsinceblock [blockhash] [target-confirmations]\n"
1292 "Get all transactions in blocks since block [blockhash], or all transactions if omitted");
1294 CBlockIndex *pindex = NULL;
1295 int target_confirms = 1;
1296 isminefilter filter = MINE_SPENDABLE;
1298 if (params.size() > 0)
1300 uint256 blockId = 0;
1302 blockId.SetHex(params[0].get_str());
1303 pindex = CBlockLocator(blockId).GetBlockIndex();
1306 if (params.size() > 1)
1308 target_confirms = params[1].get_int();
1310 if (target_confirms < 1)
1311 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter");
1314 if(params.size() > 2)
1315 if(params[2].get_bool())
1316 filter = filter | MINE_WATCH_ONLY;
1318 int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
1322 for (auto it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1324 CWalletTx tx = (*it).second;
1326 if (depth == -1 || tx.GetDepthInMainChain() < depth)
1327 ListTransactions(tx, "*", 0, true, transactions, filter);
1332 if (target_confirms == 1)
1334 lastblock = hashBestChain;
1338 int target_height = pindexBest->nHeight + 1 - target_confirms;
1341 for (block = pindexBest;
1342 block && block->nHeight > target_height;
1343 block = block->pprev) { }
1345 lastblock = block ? block->GetBlockHash() : 0;
1349 ret.push_back(Pair("transactions", transactions));
1350 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1355 Value gettransaction(const Array& params, bool fHelp)
1357 if (fHelp || params.size() != 1)
1358 throw std::runtime_error(
1359 "gettransaction <txid>\n"
1360 "Get detailed information about <txid>");
1363 hash.SetHex(params[0].get_str());
1365 isminefilter filter = MINE_SPENDABLE;
1366 if(params.size() > 1)
1367 if(params[1].get_bool())
1368 filter = filter | MINE_WATCH_ONLY;
1372 if (pwalletMain->mapWallet.count(hash))
1374 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1376 TxToJSON(wtx, 0, entry);
1378 int64_t nCredit = wtx.GetCredit(filter);
1379 int64_t nDebit = wtx.GetDebit(filter);
1380 int64_t nNet = nCredit - nDebit;
1381 int64_t nFee = (wtx.IsFromMe(filter) ? wtx.GetValueOut() - nDebit : 0);
1383 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1384 if (wtx.IsFromMe(filter))
1385 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1387 WalletTxToJSON(wtx, entry);
1390 ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details, filter);
1391 entry.push_back(Pair("details", details));
1396 uint256 hashBlock = 0;
1397 if (GetTransaction(hash, tx, hashBlock))
1399 TxToJSON(tx, 0, entry);
1401 entry.push_back(Pair("confirmations", 0));
1404 entry.push_back(Pair("blockhash", hashBlock.GetHex()));
1405 auto mi = mapBlockIndex.find(hashBlock);
1406 if (mi != mapBlockIndex.end() && (*mi).second)
1408 CBlockIndex* pindex = (*mi).second;
1409 if (pindex->IsInMainChain())
1410 entry.push_back(Pair("confirmations", 1 + nBestHeight - pindex->nHeight));
1412 entry.push_back(Pair("confirmations", 0));
1417 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction");
1424 Value backupwallet(const Array& params, bool fHelp)
1426 if (fHelp || params.size() != 1)
1427 throw std::runtime_error(
1428 "backupwallet <destination>\n"
1429 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1431 std::string strDest = params[0].get_str();
1432 if (!BackupWallet(*pwalletMain, strDest))
1433 throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!");
1439 Value keypoolrefill(const Array& params, bool fHelp)
1441 if (fHelp || params.size() > 1)
1442 throw std::runtime_error(
1443 "keypoolrefill [new-size]\n"
1444 "Fills the keypool.\n"
1445 "IMPORTANT: Any previous backups you have made of your wallet file "
1446 "should be replaced with the newly generated one."
1447 + HelpRequiringPassphrase());
1449 unsigned int nSize = std::max<unsigned int>(GetArgUInt("-keypool", 100), 0);
1450 if (params.size() > 0) {
1451 if (params[0].get_int() < 0)
1452 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size");
1453 nSize = (unsigned int) params[0].get_int();
1456 EnsureWalletIsUnlocked();
1458 pwalletMain->TopUpKeyPool(nSize);
1460 if (pwalletMain->GetKeyPoolSize() < nSize)
1461 throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool.");
1466 Value keypoolreset(const Array& params, bool fHelp)
1468 if (fHelp || params.size() > 1)
1469 throw std::runtime_error(
1470 "keypoolreset [new-size]\n"
1471 "Resets the keypool.\n"
1472 "IMPORTANT: Any previous backups you have made of your wallet file "
1473 "should be replaced with the newly generated one."
1474 + HelpRequiringPassphrase());
1476 unsigned int nSize = std::max<unsigned int>(GetArgUInt("-keypool", 100), 0);
1477 if (params.size() > 0) {
1478 if (params[0].get_int() < 0)
1479 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size");
1480 nSize = (unsigned int) params[0].get_int();
1483 EnsureWalletIsUnlocked();
1485 pwalletMain->NewKeyPool(nSize);
1487 if (pwalletMain->GetKeyPoolSize() < nSize)
1488 throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool.");
1494 void ThreadTopUpKeyPool(void* parg)
1496 // Make this thread recognisable as the key-topping-up thread
1497 RenameThread("novacoin-key-top");
1499 pwalletMain->TopUpKeyPool();
1502 void ThreadCleanWalletPassphrase(void* parg)
1504 // Make this thread recognisable as the wallet relocking thread
1505 RenameThread("novacoin-lock-wa");
1507 int64_t nMyWakeTime = GetTimeMillis() + *((int64_t*)parg) * 1000;
1509 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1511 if (nWalletUnlockTime == 0)
1513 nWalletUnlockTime = nMyWakeTime;
1517 if (nWalletUnlockTime==0)
1519 int64_t nToSleep = nWalletUnlockTime - GetTimeMillis();
1523 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1525 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1529 if (nWalletUnlockTime)
1531 nWalletUnlockTime = 0;
1532 pwalletMain->Lock();
1537 if (nWalletUnlockTime < nMyWakeTime)
1538 nWalletUnlockTime = nMyWakeTime;
1541 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1543 delete (int64_t*)parg;
1546 Value walletpassphrase(const Array& params, bool fHelp)
1548 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 3))
1549 throw std::runtime_error(
1550 "walletpassphrase <passphrase> <timeout> [mintonly]\n"
1551 "Stores the wallet decryption key in memory for <timeout> seconds.\n"
1552 "mintonly is optional true/false allowing only block minting.");
1555 if (!pwalletMain->IsCrypted())
1556 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1558 if (!pwalletMain->IsLocked())
1559 throw JSONRPCError(RPC_WALLET_ALREADY_UNLOCKED, "Error: Wallet is already unlocked, use walletlock first if need to change unlock settings.");
1560 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1561 SecureString strWalletPass;
1562 strWalletPass.reserve(100);
1563 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1564 // Alternately, find a way to make params[0] mlock()'d to begin with.
1565 strWalletPass = params[0].get_str().c_str();
1567 if (strWalletPass.length() > 0)
1569 if (!pwalletMain->Unlock(strWalletPass))
1570 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
1573 throw std::runtime_error(
1574 "walletpassphrase <passphrase> <timeout>\n"
1575 "Stores the wallet decryption key in memory for <timeout> seconds.");
1577 NewThread(ThreadTopUpKeyPool, NULL);
1578 int64_t* pnSleepTime = new int64_t(params[1].get_int64());
1579 NewThread(ThreadCleanWalletPassphrase, pnSleepTime);
1581 // ppcoin: if user OS account compromised prevent trivial sendmoney commands
1582 if (params.size() > 2)
1583 fWalletUnlockMintOnly = params[2].get_bool();
1585 fWalletUnlockMintOnly = false;
1591 Value walletpassphrasechange(const Array& params, bool fHelp)
1593 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1594 throw std::runtime_error(
1595 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1596 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1599 if (!pwalletMain->IsCrypted())
1600 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1602 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1603 // Alternately, find a way to make params[0] mlock()'d to begin with.
1604 SecureString strOldWalletPass;
1605 strOldWalletPass.reserve(100);
1606 strOldWalletPass = params[0].get_str().c_str();
1608 SecureString strNewWalletPass;
1609 strNewWalletPass.reserve(100);
1610 strNewWalletPass = params[1].get_str().c_str();
1612 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1613 throw std::runtime_error(
1614 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1615 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1617 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1618 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
1624 Value walletlock(const Array& params, bool fHelp)
1626 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1627 throw std::runtime_error(
1629 "Removes the wallet encryption key from memory, locking the wallet.\n"
1630 "After calling this method, you will need to call walletpassphrase again\n"
1631 "before being able to call any methods which require the wallet to be unlocked.");
1634 if (!pwalletMain->IsCrypted())
1635 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletlock was called.");
1638 LOCK(cs_nWalletUnlockTime);
1639 pwalletMain->Lock();
1640 nWalletUnlockTime = 0;
1647 Value encryptwallet(const Array& params, bool fHelp)
1649 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1650 throw std::runtime_error(
1651 "encryptwallet <passphrase>\n"
1652 "Encrypts the wallet with <passphrase>.");
1655 if (pwalletMain->IsCrypted())
1656 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an encrypted wallet, but encryptwallet was called.");
1658 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1659 // Alternately, find a way to make params[0] mlock()'d to begin with.
1660 SecureString strWalletPass;
1661 strWalletPass.reserve(100);
1662 strWalletPass = params[0].get_str().c_str();
1664 if (strWalletPass.length() < 1)
1665 throw std::runtime_error(
1666 "encryptwallet <passphrase>\n"
1667 "Encrypts the wallet with <passphrase>.");
1669 if (!pwalletMain->EncryptWallet(strWalletPass))
1670 throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: Failed to encrypt the wallet.");
1672 // BDB seems to have a bad habit of writing old data into
1673 // slack space in .dat files; that is bad if the old data is
1674 // unencrypted private keys. So:
1676 return "wallet encrypted; NovaCoin server stopping, restart to run with encrypted wallet. The keypool has been flushed, you need to make a new backup.";
1679 class DescribeAddressVisitor
1684 DescribeAddressVisitor(isminetype mineIn) : mine(mineIn) {}
1686 Object operator()(const CNoDestination &dest) const { return Object(); }
1687 Object operator()(const CKeyID &keyID) const {
1690 pwalletMain->GetPubKey(keyID, vchPubKey);
1691 obj.push_back(Pair("isscript", false));
1692 if (mine == MINE_SPENDABLE) {
1693 pwalletMain->GetPubKey(keyID, vchPubKey);
1694 obj.push_back(Pair("pubkey", HexStr(vchPubKey.begin(), vchPubKey.end())));
1695 obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed()));
1700 Object operator()(const CScriptID &scriptID) const {
1702 obj.push_back(Pair("isscript", true));
1703 if (mine == MINE_SPENDABLE) {
1705 pwalletMain->GetCScript(scriptID, subscript);
1706 std::vector<CTxDestination> addresses;
1707 txnouttype whichType;
1709 ExtractDestinations(subscript, whichType, addresses, nRequired);
1710 obj.push_back(Pair("script", GetTxnOutputType(whichType)));
1711 obj.push_back(Pair("hex", HexStr(subscript.begin(), subscript.end())));
1713 for (const CTxDestination& addr : addresses)
1714 a.push_back(CBitcoinAddress(addr).ToString());
1715 obj.push_back(Pair("addresses", a));
1716 if (whichType == TX_MULTISIG)
1717 obj.push_back(Pair("sigsrequired", nRequired));
1723 Value validateaddress(const Array& params, bool fHelp)
1725 if (fHelp || params.size() != 1)
1726 throw std::runtime_error(
1727 "validateaddress <novacoinaddress>\n"
1728 "Return information about <novacoinaddress>.");
1730 CBitcoinAddress address(params[0].get_str());
1731 bool isValid = address.IsValid();
1734 ret.push_back(Pair("isvalid", isValid));
1737 if (address.IsPair())
1739 CMalleablePubKey mpk;
1740 mpk.setvch(address.GetData());
1741 ret.push_back(Pair("ispair", true));
1743 CMalleableKeyView view;
1744 bool isMine = pwalletMain->GetMalleableView(mpk, view);
1745 ret.push_back(Pair("ismine", isMine));
1746 ret.push_back(Pair("PubkeyPair", mpk.ToString()));
1749 ret.push_back(Pair("KeyView", view.ToString()));
1753 std::string currentAddress = address.ToString();
1754 CTxDestination dest = address.Get();
1755 ret.push_back(Pair("address", currentAddress));
1756 isminetype mine = pwalletMain ? IsMine(*pwalletMain, address) : MINE_NO;
1757 ret.push_back(Pair("ismine", mine != MINE_NO));
1758 if (mine != MINE_NO) {
1759 ret.push_back(Pair("watchonly", mine == MINE_WATCH_ONLY));
1760 Object detail = std::visit(DescribeAddressVisitor(mine), dest);
1761 ret.insert(ret.end(), detail.begin(), detail.end());
1763 if (pwalletMain->mapAddressBook.count(address))
1764 ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
1770 // ppcoin: reserve balance from being staked for network protection
1771 Value reservebalance(const Array& params, bool fHelp)
1773 if (fHelp || params.size() > 2)
1774 throw std::runtime_error(
1775 "reservebalance [<reserve> [amount]]\n"
1776 "<reserve> is true or false to turn balance reserve on or off.\n"
1777 "<amount> is a real and rounded to cent.\n"
1778 "Set reserve amount not participating in network protection.\n"
1779 "If no parameters provided current setting is printed.\n");
1781 if (params.size() > 0)
1783 bool fReserve = params[0].get_bool();
1786 if (params.size() == 1)
1787 throw std::runtime_error("must provide amount to reserve balance.\n");
1788 int64_t nAmount = AmountFromValue(params[1]);
1789 nAmount = (nAmount / CENT) * CENT; // round to cent
1791 throw std::runtime_error("amount cannot be negative.\n");
1792 mapArgs["-reservebalance"] = FormatMoney(nAmount);
1796 if (params.size() > 1)
1797 throw std::runtime_error("cannot specify amount to turn off reserve.\n");
1798 mapArgs["-reservebalance"] = "0";
1803 if (mapArgs.count("-reservebalance") && !ParseMoney(mapArgs["-reservebalance"], nReserveBalance))
1804 throw std::runtime_error("invalid reserve balance amount\n");
1805 result.push_back(Pair("reserve", (nReserveBalance > 0)));
1806 result.push_back(Pair("amount", ValueFromAmount(nReserveBalance)));
1811 // ppcoin: check wallet integrity
1812 Value checkwallet(const Array& params, bool fHelp)
1814 if (fHelp || params.size() > 0)
1815 throw std::runtime_error(
1817 "Check wallet for integrity.\n");
1820 int64_t nBalanceInQuestion;
1821 pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion, true);
1823 if (nMismatchSpent == 0)
1824 result.push_back(Pair("wallet check passed", true));
1827 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
1828 result.push_back(Pair("amount in question", ValueFromAmount(nBalanceInQuestion)));
1834 // ppcoin: repair wallet
1835 Value repairwallet(const Array& params, bool fHelp)
1837 if (fHelp || params.size() > 0)
1838 throw std::runtime_error(
1840 "Repair wallet if checkwallet reports any problem.\n");
1843 int64_t nBalanceInQuestion;
1844 pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion);
1846 if (nMismatchSpent == 0)
1847 result.push_back(Pair("wallet check passed", true));
1850 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
1851 result.push_back(Pair("amount affected by repair", ValueFromAmount(nBalanceInQuestion)));
1856 // NovaCoin: resend unconfirmed wallet transactions
1857 Value resendtx(const Array& params, bool fHelp)
1859 if (fHelp || params.size() > 1)
1860 throw std::runtime_error(
1862 "Re-send unconfirmed transactions.\n"
1865 ResendWalletTransactions(true);
1870 Value resendwallettransactions(const Array& params, bool fHelp)
1872 if (fHelp || params.size() != 0)
1873 throw std::runtime_error(
1874 "resendwallettransactions\n"
1875 "Immediately re-broadcast unconfirmed wallet transactions to all peers.\n"
1876 "Intended only for testing; the wallet code periodically re-broadcasts\n"
1878 "Returns array of transaction ids that were re-broadcast.\n"
1881 LOCK2(cs_main, pwalletMain->cs_wallet);
1883 std::vector<uint256> txids = pwalletMain->ResendWalletTransactionsBefore(GetTime());
1885 for (const uint256& txid : txids)
1887 result.push_back(txid.ToString());
1893 // Make a public-private key pair
1894 Value makekeypair(const Array& params, bool fHelp)
1896 if (fHelp || params.size() > 0)
1897 throw std::runtime_error(
1899 "Make a public/private key pair.\n");
1901 std::string strPrefix = "";
1902 if (params.size() > 0)
1903 strPrefix = params[0].get_str();
1906 key.MakeNewKey(true);
1908 CPrivKey vchPrivKey = key.GetPrivKey();
1910 result.push_back(Pair("PrivateKey", HexStr<CPrivKey::iterator>(vchPrivKey.begin(), vchPrivKey.end())));
1913 CSecret vchSecret = key.GetSecret(fCompressed);
1914 CPubKey vchPubKey = key.GetPubKey();
1915 result.push_back(Pair("Secret", HexStr<CSecret::iterator>(vchSecret.begin(), vchSecret.end())));
1916 result.push_back(Pair("PublicKey", HexStr(vchPubKey.begin(), vchPubKey.end())));
1920 Value newmalleablekey(const Array& params, bool fHelp)
1922 if (fHelp || params.size() > 1)
1923 throw std::runtime_error(
1925 "Make a malleable public/private key pair.\n");
1927 // Parse the account first so we don't generate a key if there's an error
1928 std::string strAccount;
1929 if (params.size() > 0)
1930 strAccount = AccountFromValue(params[0]);
1932 CMalleableKeyView keyView = pwalletMain->GenerateNewMalleableKey();
1935 if (!pwalletMain->GetMalleableKey(keyView, mKey))
1936 throw std::runtime_error("Unable to generate new malleable key");
1938 CMalleablePubKey mPubKey = mKey.GetMalleablePubKey();
1939 CBitcoinAddress address(mPubKey);
1941 pwalletMain->SetAddressBookName(address, strAccount);
1944 result.push_back(Pair("PublicPair", mPubKey.ToString()));
1945 result.push_back(Pair("PublicBytes", HexStr(mPubKey.Raw())));
1946 result.push_back(Pair("Address", address.ToString()));
1947 result.push_back(Pair("KeyView", keyView.ToString()));
1952 Value adjustmalleablekey(const Array& params, bool fHelp)
1954 if (fHelp || params.size() != 3)
1955 throw std::runtime_error(
1956 "adjustmalleablekey <Malleable key data> <Public key variant data> <R data>\n"
1957 "Calculate new private key using provided malleable key, public key and R data.\n");
1959 CMalleableKey malleableKey;
1960 malleableKey.SetString(params[0].get_str());
1962 CKey privKeyVariant;
1963 CPubKey vchPubKeyVariant = CPubKey(ParseHex(params[1].get_str()));
1965 CPubKey R(ParseHex(params[2].get_str()));
1967 if (!malleableKey.CheckKeyVariant(R,vchPubKeyVariant, privKeyVariant)) {
1968 throw std::runtime_error("Unable to calculate the private key");
1973 CSecret vchPrivKeyVariant = privKeyVariant.GetSecret(fCompressed);
1975 result.push_back(Pair("PrivateKey", CBitcoinSecret(vchPrivKeyVariant, fCompressed).ToString()));
1980 Value adjustmalleablepubkey(const Array& params, bool fHelp)
1982 if (fHelp || params.size() > 2 || params.size() == 0)
1983 throw std::runtime_error(
1984 "adjustmalleablepubkey <Malleable address, key view or public key pair>\n"
1985 "Calculate new public key using provided data.\n");
1987 std::string strData = params[0].get_str();
1988 CMalleablePubKey malleablePubKey;
1992 CBitcoinAddress addr(strData);
1993 if (addr.IsValid() && addr.IsPair())
1995 // Initialize malleable pubkey with address data
1996 malleablePubKey = CMalleablePubKey(addr.GetData());
1999 CMalleableKeyView viewTmp(strData);
2000 if (viewTmp.IsValid())
2002 // Shazaam, we have a valid key view here.
2003 malleablePubKey = viewTmp.GetMalleablePubKey();
2006 if (malleablePubKey.SetString(strData))
2007 break; // A valid public key pair
2009 throw std::runtime_error("Though your data seems a valid Base58 string, we were unable to recognize it.");
2013 CPubKey R, vchPubKeyVariant;
2014 malleablePubKey.GetVariant(R, vchPubKeyVariant);
2017 result.push_back(Pair("R", HexStr(R.begin(), R.end())));
2018 result.push_back(Pair("PubkeyVariant", HexStr(vchPubKeyVariant.begin(), vchPubKeyVariant.end())));
2019 result.push_back(Pair("KeyVariantID", CBitcoinAddress(vchPubKeyVariant.GetID()).ToString()));
2024 Value listmalleableviews(const Array& params, bool fHelp)
2026 if (fHelp || params.size() != 0)
2027 throw std::runtime_error(
2028 "listmalleableviews\n"
2029 "Get list of views for generated malleable keys.\n");
2031 std::list<CMalleableKeyView> keyViewList;
2032 pwalletMain->ListMalleableViews(keyViewList);
2035 for (const CMalleableKeyView &keyView : keyViewList)
2037 result.push_back(keyView.ToString());