1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2012 The Bitcoin developers
3 // Distributed under the MIT/X11 software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
8 #include "bitcoinrpc.h"
14 using namespace json_spirit;
17 int64_t nWalletUnlockTime;
18 static CCriticalSection cs_nWalletUnlockTime;
20 extern int64_t nReserveBalance;
21 extern void TxToJSON(const CTransaction& tx, const uint256& hashBlock, json_spirit::Object& entry);
23 std::string HelpRequiringPassphrase()
25 return pwalletMain->IsCrypted()
26 ? "\n\nRequires wallet passphrase to be set with walletpassphrase first"
30 void EnsureWalletIsUnlocked()
32 if (pwalletMain->IsLocked())
33 throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
34 if (fWalletUnlockMintOnly)
35 throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Wallet unlocked for block minting only.");
38 void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
40 int confirms = wtx.GetDepthInMainChain();
41 entry.push_back(Pair("confirmations", confirms));
42 if (wtx.IsCoinBase() || wtx.IsCoinStake())
43 entry.push_back(Pair("generated", true));
46 entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex()));
47 entry.push_back(Pair("blockindex", wtx.nIndex));
48 entry.push_back(Pair("blocktime", (int64_t)(mapBlockIndex[wtx.hashBlock]->nTime)));
50 entry.push_back(Pair("txid", wtx.GetHash().GetHex()));
51 entry.push_back(Pair("time", (int64_t)wtx.GetTxTime()));
52 entry.push_back(Pair("timereceived", (int64_t)wtx.nTimeReceived));
53 BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
54 entry.push_back(Pair(item.first, item.second));
57 string AccountFromValue(const Value& value)
59 string strAccount = value.get_str();
60 if (strAccount == "*")
61 throw JSONRPCError(RPC_WALLET_INVALID_ACCOUNT_NAME, "Invalid account name");
65 Value getinfo(const Array& params, bool fHelp)
67 if (fHelp || params.size() != 0)
70 "Returns an object containing various state info.");
73 GetProxy(NET_IPV4, proxy);
75 Object obj, diff, timestamping;
76 obj.push_back(Pair("version", FormatFullVersion()));
77 obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION));
78 obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
79 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
80 obj.push_back(Pair("unspendable", ValueFromAmount(pwalletMain->GetWatchOnlyBalance())));
81 obj.push_back(Pair("newmint", ValueFromAmount(pwalletMain->GetNewMint())));
82 obj.push_back(Pair("stake", ValueFromAmount(pwalletMain->GetStake())));
83 obj.push_back(Pair("blocks", (int)nBestHeight));
85 timestamping.push_back(Pair("systemclock", GetTime()));
86 timestamping.push_back(Pair("adjustedtime", GetAdjustedTime()));
88 int64_t nNtpOffset = GetNtpOffset(),
89 nP2POffset = GetNodesOffset();
91 timestamping.push_back(Pair("ntpoffset", nNtpOffset != INT64_MAX ? nNtpOffset : Value::null));
92 timestamping.push_back(Pair("p2poffset", nP2POffset != INT64_MAX ? nP2POffset : Value::null));
94 obj.push_back(Pair("timestamping", timestamping));
96 obj.push_back(Pair("moneysupply", ValueFromAmount(pindexBest->nMoneySupply)));
97 obj.push_back(Pair("connections", (int)vNodes.size()));
98 obj.push_back(Pair("proxy", (proxy.first.IsValid() ? proxy.first.ToStringIPPort() : string())));
99 obj.push_back(Pair("ip", addrSeenByPeer.ToStringIP()));
101 diff.push_back(Pair("proof-of-work", GetDifficulty()));
102 diff.push_back(Pair("proof-of-stake", GetDifficulty(GetLastBlockIndex(pindexBest, true))));
103 obj.push_back(Pair("difficulty", diff));
105 obj.push_back(Pair("testnet", fTestNet));
106 obj.push_back(Pair("keypoololdest", (int64_t)pwalletMain->GetOldestKeyPoolTime()));
107 obj.push_back(Pair("keypoolsize", (int)pwalletMain->GetKeyPoolSize()));
108 obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee)));
109 obj.push_back(Pair("mininput", ValueFromAmount(nMinimumInputValue)));
110 if (pwalletMain->IsCrypted())
111 obj.push_back(Pair("unlocked_until", (int64_t)nWalletUnlockTime / 1000));
112 obj.push_back(Pair("errors", GetWarnings("statusbar")));
116 Value getnewaddress(const Array& params, bool fHelp)
118 if (fHelp || params.size() > 1)
120 "getnewaddress [account]\n"
121 "Returns a new NovaCoin address for receiving payments. "
122 "If [account] is specified (recommended), it is added to the address book "
123 "so payments received with the address will be credited to [account].");
125 // Parse the account first so we don't generate a key if there's an error
127 if (params.size() > 0)
128 strAccount = AccountFromValue(params[0]);
130 if (!pwalletMain->IsLocked())
131 pwalletMain->TopUpKeyPool();
133 // Generate a new key that is added to wallet
135 if (!pwalletMain->GetKeyFromPool(newKey, false))
136 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
137 CKeyID keyID = newKey.GetID();
139 pwalletMain->SetAddressBookName(keyID, strAccount);
141 return CBitcoinAddress(keyID).ToString();
145 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
147 CWalletDB walletdb(pwalletMain->strWalletFile);
150 walletdb.ReadAccount(strAccount, account);
152 bool bKeyUsed = false;
154 // Check if the current key has been used
155 if (account.vchPubKey.IsValid())
157 CScript scriptPubKey;
158 scriptPubKey.SetDestination(account.vchPubKey.GetID());
159 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
160 it != pwalletMain->mapWallet.end() && account.vchPubKey.IsValid();
163 const CWalletTx& wtx = (*it).second;
164 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
165 if (txout.scriptPubKey == scriptPubKey)
170 // Generate a new key
171 if (!account.vchPubKey.IsValid() || bForceNew || bKeyUsed)
173 if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false))
174 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
176 pwalletMain->SetAddressBookName(account.vchPubKey.GetID(), strAccount);
177 walletdb.WriteAccount(strAccount, account);
180 return CBitcoinAddress(account.vchPubKey.GetID());
183 Value getaccountaddress(const Array& params, bool fHelp)
185 if (fHelp || params.size() != 1)
187 "getaccountaddress <account>\n"
188 "Returns the current NovaCoin address for receiving payments to this account.");
190 // Parse the account first so we don't generate a key if there's an error
191 string strAccount = AccountFromValue(params[0]);
195 ret = GetAccountAddress(strAccount).ToString();
202 Value setaccount(const Array& params, bool fHelp)
204 if (fHelp || params.size() < 1 || params.size() > 2)
206 "setaccount <novacoinaddress> <account>\n"
207 "Sets the account associated with the given address.");
209 CBitcoinAddress address(params[0].get_str());
210 if (!address.IsValid())
211 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
215 if (params.size() > 1)
216 strAccount = AccountFromValue(params[1]);
218 // Detect when changing the account of an address that is the 'unused current key' of another account:
219 if (pwalletMain->mapAddressBook.count(address.Get()))
221 string strOldAccount = pwalletMain->mapAddressBook[address.Get()];
222 if (address == GetAccountAddress(strOldAccount))
223 GetAccountAddress(strOldAccount, true);
226 pwalletMain->SetAddressBookName(address.Get(), strAccount);
232 Value getaccount(const Array& params, bool fHelp)
234 if (fHelp || params.size() != 1)
236 "getaccount <novacoinaddress>\n"
237 "Returns the account associated with the given address.");
239 CBitcoinAddress address(params[0].get_str());
240 if (!address.IsValid())
241 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
244 map<CTxDestination, string>::iterator mi = pwalletMain->mapAddressBook.find(address.Get());
245 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
246 strAccount = (*mi).second;
251 Value getaddressesbyaccount(const Array& params, bool fHelp)
253 if (fHelp || params.size() != 1)
255 "getaddressesbyaccount <account>\n"
256 "Returns the list of addresses for the given account.");
258 string strAccount = AccountFromValue(params[0]);
260 // Find all addresses that have the given account
262 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
264 const CBitcoinAddress& address = item.first;
265 const string& strName = item.second;
266 if (strName == strAccount)
267 ret.push_back(address.ToString());
272 Value mergecoins(const Array& params, bool fHelp)
274 if (fHelp || params.size() != 3)
276 "mergecoins <amount> <minvalue> <outputvalue>\n"
277 "<amount> is resulting inputs sum\n"
278 "<minvalue> is minimum value of inputs which are used in join process\n"
279 "<outputvalue> is resulting value of inputs which will be created\n"
280 "All values are real and and rounded to the nearest " + FormatMoney(nMinimumInputValue)
281 + HelpRequiringPassphrase());
283 if (pwalletMain->IsLocked())
284 throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
287 int64_t nAmount = AmountFromValue(params[0]);
290 int64_t nMinValue = AmountFromValue(params[1]);
293 int64_t nOutputValue = AmountFromValue(params[2]);
295 if (nAmount < nMinimumInputValue)
296 throw JSONRPCError(-101, "Send amount too small");
298 if (nMinValue < nMinimumInputValue)
299 throw JSONRPCError(-101, "Max value too small");
301 if (nOutputValue < nMinimumInputValue)
302 throw JSONRPCError(-101, "Output value too small");
304 if (nOutputValue < nMinValue)
305 throw JSONRPCError(-101, "Output value is lower than min value");
307 list<uint256> listMerged;
308 if (!pwalletMain->MergeCoins(nAmount, nMinValue, nOutputValue, listMerged))
312 BOOST_FOREACH(const uint256 txHash, listMerged)
313 mergedHashes.push_back(txHash.GetHex());
318 Value sendtoaddress(const Array& params, bool fHelp)
320 if (fHelp || params.size() < 2 || params.size() > 4)
322 "sendtoaddress <novacoinaddress> <amount> [comment] [comment-to]\n"
323 "<amount> is a real and is rounded to the nearest " + FormatMoney(nMinimumInputValue)
324 + HelpRequiringPassphrase());
326 CBitcoinAddress address(params[0].get_str());
327 if (!address.IsValid())
328 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
331 int64_t nAmount = AmountFromValue(params[1]);
333 if (nAmount < nMinimumInputValue)
334 throw JSONRPCError(-101, "Send amount too small");
338 if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
339 wtx.mapValue["comment"] = params[2].get_str();
340 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
341 wtx.mapValue["to"] = params[3].get_str();
343 if (pwalletMain->IsLocked())
344 throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
346 // Parse Bitcoin address
347 CScript scriptPubKey;
348 scriptPubKey.SetDestination(address.Get());
350 string strError = pwalletMain->SendMoney(scriptPubKey, nAmount, wtx);
352 throw JSONRPCError(RPC_WALLET_ERROR, strError);
354 return wtx.GetHash().GetHex();
357 Value listaddressgroupings(const Array& params, bool fHelp)
361 "listaddressgroupings\n"
362 "Lists groups of addresses which have had their common ownership\n"
363 "made public by common use as inputs or as the resulting change\n"
364 "in past transactions");
367 map<CTxDestination, int64_t> balances = pwalletMain->GetAddressBalances();
368 BOOST_FOREACH(set<CTxDestination> grouping, pwalletMain->GetAddressGroupings())
371 BOOST_FOREACH(CTxDestination address, grouping)
374 addressInfo.push_back(CBitcoinAddress(address).ToString());
375 addressInfo.push_back(ValueFromAmount(balances[address]));
377 LOCK(pwalletMain->cs_wallet);
378 if (pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get()) != pwalletMain->mapAddressBook.end())
379 addressInfo.push_back(pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get())->second);
381 jsonGrouping.push_back(addressInfo);
383 jsonGroupings.push_back(jsonGrouping);
385 return jsonGroupings;
388 Value signmessage(const Array& params, bool fHelp)
390 if (fHelp || params.size() != 2)
392 "signmessage <novacoinaddress> <message>\n"
393 "Sign a message with the private key of an address");
395 EnsureWalletIsUnlocked();
397 string strAddress = params[0].get_str();
398 string strMessage = params[1].get_str();
400 CBitcoinAddress addr(strAddress);
402 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
405 if (!addr.GetKeyID(keyID))
406 throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
409 if (!pwalletMain->GetKey(keyID, key))
410 throw JSONRPCError(RPC_WALLET_ERROR, "Private key not available");
412 CDataStream ss(SER_GETHASH, 0);
413 ss << strMessageMagic;
416 vector<unsigned char> vchSig;
417 if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
418 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed");
420 return EncodeBase64(&vchSig[0], vchSig.size());
423 Value verifymessage(const Array& params, bool fHelp)
425 if (fHelp || params.size() != 3)
427 "verifymessage <novacoinaddress> <signature> <message>\n"
428 "Verify a signed message");
430 string strAddress = params[0].get_str();
431 string strSign = params[1].get_str();
432 string strMessage = params[2].get_str();
434 CBitcoinAddress addr(strAddress);
436 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
439 if (!addr.GetKeyID(keyID))
440 throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
442 bool fInvalid = false;
443 vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
446 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Malformed base64 encoding");
448 CDataStream ss(SER_GETHASH, 0);
449 ss << strMessageMagic;
453 if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
456 return (key.GetPubKey().GetID() == keyID);
460 Value getreceivedbyaddress(const Array& params, bool fHelp)
462 if (fHelp || params.size() < 1 || params.size() > 2)
464 "getreceivedbyaddress <novacoinaddress> [minconf=1]\n"
465 "Returns the total amount received by <novacoinaddress> in transactions with at least [minconf] confirmations.");
468 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
469 CScript scriptPubKey;
470 if (!address.IsValid())
471 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
472 scriptPubKey.SetDestination(address.Get());
473 if (!IsMine(*pwalletMain,scriptPubKey))
476 // Minimum confirmations
478 if (params.size() > 1)
479 nMinDepth = params[1].get_int();
483 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
485 const CWalletTx& wtx = (*it).second;
486 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
489 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
490 if (txout.scriptPubKey == scriptPubKey)
491 if (wtx.GetDepthInMainChain() >= nMinDepth)
492 nAmount += txout.nValue;
495 return ValueFromAmount(nAmount);
499 void GetAccountAddresses(string strAccount, set<CTxDestination>& setAddress)
501 BOOST_FOREACH(const PAIRTYPE(CTxDestination, string)& item, pwalletMain->mapAddressBook)
503 const CTxDestination& address = item.first;
504 const string& strName = item.second;
505 if (strName == strAccount)
506 setAddress.insert(address);
510 Value getreceivedbyaccount(const Array& params, bool fHelp)
512 if (fHelp || params.size() < 1 || params.size() > 2)
514 "getreceivedbyaccount <account> [minconf=1]\n"
515 "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
517 // Minimum confirmations
519 if (params.size() > 1)
520 nMinDepth = params[1].get_int();
522 // Get the set of pub keys assigned to account
523 string strAccount = AccountFromValue(params[0]);
524 set<CTxDestination> setAddress;
525 GetAccountAddresses(strAccount, setAddress);
529 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
531 const CWalletTx& wtx = (*it).second;
532 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
535 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
537 CTxDestination address;
538 if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*pwalletMain, address) && setAddress.count(address))
539 if (wtx.GetDepthInMainChain() >= nMinDepth)
540 nAmount += txout.nValue;
544 return (double)nAmount / (double)COIN;
548 int64_t GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth, const isminefilter& filter)
550 int64_t nBalance = 0;
552 // Tally wallet transactions
553 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
555 const CWalletTx& wtx = (*it).second;
559 int64_t nGenerated, nReceived, nSent, nFee;
560 wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee, filter);
562 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
563 nBalance += nReceived;
564 nBalance += nGenerated - nSent - nFee;
567 // Tally internal accounting entries
568 nBalance += walletdb.GetAccountCreditDebit(strAccount);
573 int64_t GetAccountBalance(const string& strAccount, int nMinDepth, const isminefilter& filter)
575 CWalletDB walletdb(pwalletMain->strWalletFile);
576 return GetAccountBalance(walletdb, strAccount, nMinDepth, filter);
580 Value getbalance(const Array& params, bool fHelp)
582 if (fHelp || params.size() > 2)
584 "getbalance [account] [minconf=1] [watchonly=0]\n"
585 "If [account] is not specified, returns the server's total available balance.\n"
586 "If [account] is specified, returns the balance in the account.\n"
587 "if [includeWatchonly] is specified, include balance in watchonly addresses (see 'importaddress').");
589 if (params.size() == 0)
590 return ValueFromAmount(pwalletMain->GetBalance());
593 if (params.size() > 1)
594 nMinDepth = params[1].get_int();
595 isminefilter filter = MINE_SPENDABLE;
596 if(params.size() > 2)
597 if(params[2].get_bool())
598 filter = filter | MINE_WATCH_ONLY;
600 if (params[0].get_str() == "*") {
601 // Calculate total balance a different way from GetBalance()
602 // (GetBalance() sums up all unspent TxOuts)
603 // getbalance and getbalance '*' 0 should return the same number.
604 int64_t nBalance = 0;
605 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
607 const CWalletTx& wtx = (*it).second;
608 if (!wtx.IsTrusted())
611 int64_t allGeneratedImmature, allGeneratedMature, allFee;
612 allGeneratedImmature = allGeneratedMature = allFee = 0;
614 string strSentAccount;
615 list<pair<CTxDestination, int64_t> > listReceived;
616 list<pair<CTxDestination, int64_t> > listSent;
617 wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount, filter);
618 if (wtx.GetDepthInMainChain() >= nMinDepth)
620 BOOST_FOREACH(const PAIRTYPE(CTxDestination,int64_t)& r, listReceived)
621 nBalance += r.second;
623 BOOST_FOREACH(const PAIRTYPE(CTxDestination,int64_t)& r, listSent)
624 nBalance -= r.second;
626 nBalance += allGeneratedMature;
628 return ValueFromAmount(nBalance);
631 string strAccount = AccountFromValue(params[0]);
633 int64_t nBalance = GetAccountBalance(strAccount, nMinDepth, filter);
635 return ValueFromAmount(nBalance);
639 Value movecmd(const Array& params, bool fHelp)
641 if (fHelp || params.size() < 3 || params.size() > 5)
643 "move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
644 "Move from one account in your wallet to another.");
646 string strFrom = AccountFromValue(params[0]);
647 string strTo = AccountFromValue(params[1]);
648 int64_t nAmount = AmountFromValue(params[2]);
650 if (nAmount < nMinimumInputValue)
651 throw JSONRPCError(-101, "Send amount too small");
653 if (params.size() > 3)
654 // unused parameter, used to be nMinDepth, keep type-checking it though
655 (void)params[3].get_int();
657 if (params.size() > 4)
658 strComment = params[4].get_str();
660 CWalletDB walletdb(pwalletMain->strWalletFile);
661 if (!walletdb.TxnBegin())
662 throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
664 int64_t nNow = GetAdjustedTime();
667 CAccountingEntry debit;
668 debit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
669 debit.strAccount = strFrom;
670 debit.nCreditDebit = -nAmount;
672 debit.strOtherAccount = strTo;
673 debit.strComment = strComment;
674 walletdb.WriteAccountingEntry(debit);
677 CAccountingEntry credit;
678 credit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
679 credit.strAccount = strTo;
680 credit.nCreditDebit = nAmount;
682 credit.strOtherAccount = strFrom;
683 credit.strComment = strComment;
684 walletdb.WriteAccountingEntry(credit);
686 if (!walletdb.TxnCommit())
687 throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
693 Value sendfrom(const Array& params, bool fHelp)
695 if (fHelp || params.size() < 3 || params.size() > 6)
697 "sendfrom <fromaccount> <tonovacoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
698 "<amount> is a real and is rounded to the nearest " + FormatMoney(nMinimumInputValue)
699 + HelpRequiringPassphrase());
701 string strAccount = AccountFromValue(params[0]);
702 CBitcoinAddress address(params[1].get_str());
703 if (!address.IsValid())
704 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
705 int64_t nAmount = AmountFromValue(params[2]);
707 if (nAmount < nMinimumInputValue)
708 throw JSONRPCError(-101, "Send amount too small");
711 if (params.size() > 3)
712 nMinDepth = params[3].get_int();
715 wtx.strFromAccount = strAccount;
716 if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
717 wtx.mapValue["comment"] = params[4].get_str();
718 if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
719 wtx.mapValue["to"] = params[5].get_str();
721 EnsureWalletIsUnlocked();
724 int64_t nBalance = GetAccountBalance(strAccount, nMinDepth, MINE_SPENDABLE);
725 if (nAmount > nBalance)
726 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
728 // Parse Bitcoin address
729 CScript scriptPubKey;
730 scriptPubKey.SetDestination(address.Get());
733 string strError = pwalletMain->SendMoney(scriptPubKey, nAmount, wtx);
735 throw JSONRPCError(RPC_WALLET_ERROR, strError);
737 return wtx.GetHash().GetHex();
741 Value sendmany(const Array& params, bool fHelp)
743 if (fHelp || params.size() < 2 || params.size() > 4)
745 "sendmany <fromaccount> '{address:amount,...}' [minconf=1] [comment]\n"
746 "amounts are double-precision floating point numbers"
747 + HelpRequiringPassphrase());
749 string strAccount = AccountFromValue(params[0]);
750 Object sendTo = params[1].get_obj();
752 if (params.size() > 2)
753 nMinDepth = params[2].get_int();
756 wtx.strFromAccount = strAccount;
757 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
758 wtx.mapValue["comment"] = params[3].get_str();
760 set<CBitcoinAddress> setAddress;
761 vector<pair<CScript, int64_t> > vecSend;
763 int64_t totalAmount = 0;
764 BOOST_FOREACH(const Pair& s, sendTo)
766 CBitcoinAddress address(s.name_);
767 if (!address.IsValid())
768 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid NovaCoin address: ")+s.name_);
770 if (setAddress.count(address))
771 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+s.name_);
772 setAddress.insert(address);
774 CScript scriptPubKey;
775 scriptPubKey.SetDestination(address.Get());
776 int64_t nAmount = AmountFromValue(s.value_);
778 if (nAmount < nMinimumInputValue)
779 throw JSONRPCError(-101, "Send amount too small");
781 totalAmount += nAmount;
783 vecSend.push_back(make_pair(scriptPubKey, nAmount));
786 EnsureWalletIsUnlocked();
789 int64_t nBalance = GetAccountBalance(strAccount, nMinDepth, MINE_SPENDABLE);
790 if (totalAmount > nBalance)
791 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
794 CReserveKey keyChange(pwalletMain);
795 int64_t nFeeRequired = 0;
796 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
799 int64_t nTotal = pwalletMain->GetBalance(), nWatchOnly = pwalletMain->GetWatchOnlyBalance();
800 if (totalAmount + nFeeRequired > nTotal - nWatchOnly)
801 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds");
802 throw JSONRPCError(RPC_WALLET_ERROR, "Transaction creation failed");
804 if (!pwalletMain->CommitTransaction(wtx, keyChange))
805 throw JSONRPCError(RPC_WALLET_ERROR, "Transaction commit failed");
807 return wtx.GetHash().GetHex();
810 Value addmultisigaddress(const Array& params, bool fHelp)
812 if (fHelp || params.size() < 2 || params.size() > 3)
814 string msg = "addmultisigaddress <nrequired> <'[\"key\",\"key\"]'> [account]\n"
815 "Add a nrequired-to-sign multisignature address to the wallet\"\n"
816 "each key is a NovaCoin address or hex-encoded public key\n"
817 "If [account] is specified, assign address to [account].";
818 throw runtime_error(msg);
821 int nRequired = params[0].get_int();
822 const Array& keys = params[1].get_array();
824 if (params.size() > 2)
825 strAccount = AccountFromValue(params[2]);
827 // Gather public keys
829 throw runtime_error("a multisignature address must require at least one key to redeem");
830 if ((int)keys.size() < nRequired)
832 strprintf("not enough keys supplied "
833 "(got %" PRIszu " keys, but need at least %d to redeem)", keys.size(), nRequired));
834 if (keys.size() > 16)
835 throw runtime_error("Number of addresses involved in the multisignature address creation > 16\nReduce the number");
836 std::vector<CKey> pubkeys;
837 pubkeys.resize(keys.size());
838 for (unsigned int i = 0; i < keys.size(); i++)
840 const std::string& ks = keys[i].get_str();
842 // Case 1: Bitcoin address and we have full public key:
843 CBitcoinAddress address(ks);
844 if (address.IsValid())
847 if (!address.GetKeyID(keyID))
849 strprintf("%s does not refer to a key",ks.c_str()));
851 if (!pwalletMain->GetPubKey(keyID, vchPubKey))
853 strprintf("no full public key for address %s",ks.c_str()));
854 if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey))
855 throw runtime_error(" Invalid public key: "+ks);
858 // Case 2: hex public key
861 CPubKey vchPubKey(ParseHex(ks));
862 if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey))
863 throw runtime_error(" Invalid public key: "+ks);
867 throw runtime_error(" Invalid public key: "+ks);
871 // Construct using pay-to-script-hash:
873 inner.SetMultisig(nRequired, pubkeys);
875 if (inner.size() > MAX_SCRIPT_ELEMENT_SIZE)
877 strprintf("redeemScript exceeds size limit: %" PRIszu " > %d", inner.size(), MAX_SCRIPT_ELEMENT_SIZE));
879 CScriptID innerID = inner.GetID();
880 pwalletMain->AddCScript(inner);
882 pwalletMain->SetAddressBookName(innerID, strAccount);
883 return CBitcoinAddress(innerID).ToString();
886 Value addredeemscript(const Array& params, bool fHelp)
888 if (fHelp || params.size() < 1 || params.size() > 2)
890 string msg = "addredeemscript <redeemScript> [account]\n"
891 "Add a P2SH address with a specified redeemScript to the wallet.\n"
892 "If [account] is specified, assign address to [account].";
893 throw runtime_error(msg);
897 if (params.size() > 1)
898 strAccount = AccountFromValue(params[1]);
900 // Construct using pay-to-script-hash:
901 vector<unsigned char> innerData = ParseHexV(params[0], "redeemScript");
902 CScript inner(innerData.begin(), innerData.end());
903 CScriptID innerID = inner.GetID();
904 pwalletMain->AddCScript(inner);
906 pwalletMain->SetAddressBookName(innerID, strAccount);
907 return CBitcoinAddress(innerID).ToString();
917 nConf = std::numeric_limits<int>::max();
921 Value ListReceived(const Array& params, bool fByAccounts)
923 // Minimum confirmations
925 if (params.size() > 0)
926 nMinDepth = params[0].get_int();
928 // Whether to include empty accounts
929 bool fIncludeEmpty = false;
930 if (params.size() > 1)
931 fIncludeEmpty = params[1].get_bool();
934 map<CBitcoinAddress, tallyitem> mapTally;
935 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
937 const CWalletTx& wtx = (*it).second;
939 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
942 int nDepth = wtx.GetDepthInMainChain();
943 if (nDepth < nMinDepth)
946 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
948 CTxDestination address;
949 if (!ExtractDestination(txout.scriptPubKey, address) || !IsMine(*pwalletMain, address))
952 tallyitem& item = mapTally[address];
953 item.nAmount += txout.nValue;
954 item.nConf = min(item.nConf, nDepth);
960 map<string, tallyitem> mapAccountTally;
961 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
963 const CBitcoinAddress& address = item.first;
964 const string& strAccount = item.second;
965 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
966 if (it == mapTally.end() && !fIncludeEmpty)
970 int nConf = std::numeric_limits<int>::max();
971 if (it != mapTally.end())
973 nAmount = (*it).second.nAmount;
974 nConf = (*it).second.nConf;
979 tallyitem& item = mapAccountTally[strAccount];
980 item.nAmount += nAmount;
981 item.nConf = min(item.nConf, nConf);
986 obj.push_back(Pair("address", address.ToString()));
987 obj.push_back(Pair("account", strAccount));
988 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
989 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
996 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
998 int64_t nAmount = (*it).second.nAmount;
999 int nConf = (*it).second.nConf;
1001 obj.push_back(Pair("account", (*it).first));
1002 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1003 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1011 Value listreceivedbyaddress(const Array& params, bool fHelp)
1013 if (fHelp || params.size() > 2)
1014 throw runtime_error(
1015 "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
1016 "[minconf] is the minimum number of confirmations before payments are included.\n"
1017 "[includeempty] whether to include addresses that haven't received any payments.\n"
1018 "Returns an array of objects containing:\n"
1019 " \"address\" : receiving address\n"
1020 " \"account\" : the account of the receiving address\n"
1021 " \"amount\" : total amount received by the address\n"
1022 " \"confirmations\" : number of confirmations of the most recent transaction included");
1024 return ListReceived(params, false);
1027 Value listreceivedbyaccount(const Array& params, bool fHelp)
1029 if (fHelp || params.size() > 2)
1030 throw runtime_error(
1031 "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
1032 "[minconf] is the minimum number of confirmations before payments are included.\n"
1033 "[includeempty] whether to include accounts that haven't received any payments.\n"
1034 "Returns an array of objects containing:\n"
1035 " \"account\" : the account of the receiving addresses\n"
1036 " \"amount\" : total amount received by addresses with this account\n"
1037 " \"confirmations\" : number of confirmations of the most recent transaction included");
1039 return ListReceived(params, true);
1042 static void MaybePushAddress(Object & entry, const CTxDestination &dest)
1044 CBitcoinAddress addr;
1046 entry.push_back(Pair("address", addr.ToString()));
1049 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret, const isminefilter& filter)
1051 int64_t nGeneratedImmature, nGeneratedMature, nFee;
1052 string strSentAccount;
1053 list<pair<CTxDestination, int64_t> > listReceived;
1054 list<pair<CTxDestination, int64_t> > listSent;
1056 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount, filter);
1058 bool fAllAccounts = (strAccount == string("*"));
1059 bool involvesWatchonly = wtx.IsFromMe(MINE_WATCH_ONLY);
1061 // Generated blocks assigned to account ""
1062 if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
1065 entry.push_back(Pair("account", string("")));
1066 if (nGeneratedImmature)
1068 entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
1069 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
1073 entry.push_back(Pair("category", "generate"));
1074 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
1077 WalletTxToJSON(wtx, entry);
1078 ret.push_back(entry);
1082 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1084 BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64_t)& s, listSent)
1087 entry.push_back(Pair("account", strSentAccount));
1088 if(involvesWatchonly || (::IsMine(*pwalletMain, s.first) & MINE_WATCH_ONLY))
1089 entry.push_back(Pair("involvesWatchonly", true));
1090 MaybePushAddress(entry, s.first);
1092 if (wtx.GetDepthInMainChain() < 0) {
1093 entry.push_back(Pair("category", "conflicted"));
1095 entry.push_back(Pair("category", "send"));
1098 entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1099 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1101 WalletTxToJSON(wtx, entry);
1102 ret.push_back(entry);
1107 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1109 BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64_t)& r, listReceived)
1112 if (pwalletMain->mapAddressBook.count(r.first))
1113 account = pwalletMain->mapAddressBook[r.first];
1114 if (fAllAccounts || (account == strAccount))
1117 entry.push_back(Pair("account", account));
1118 if(involvesWatchonly || (::IsMine(*pwalletMain, r.first) & MINE_WATCH_ONLY))
1119 entry.push_back(Pair("involvesWatchonly", true));
1120 MaybePushAddress(entry, r.first);
1121 if (wtx.IsCoinBase())
1123 if (wtx.GetDepthInMainChain() < 1)
1124 entry.push_back(Pair("category", "orphan"));
1125 else if (wtx.GetBlocksToMaturity() > 0)
1126 entry.push_back(Pair("category", "immature"));
1128 entry.push_back(Pair("category", "generate"));
1131 entry.push_back(Pair("category", "receive"));
1132 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1134 WalletTxToJSON(wtx, entry);
1135 ret.push_back(entry);
1141 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1143 bool fAllAccounts = (strAccount == string("*"));
1145 if (fAllAccounts || acentry.strAccount == strAccount)
1148 entry.push_back(Pair("account", acentry.strAccount));
1149 entry.push_back(Pair("category", "move"));
1150 entry.push_back(Pair("time", (int64_t)acentry.nTime));
1151 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1152 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1153 entry.push_back(Pair("comment", acentry.strComment));
1154 ret.push_back(entry);
1158 Value listtransactions(const Array& params, bool fHelp)
1160 if (fHelp || params.size() > 3)
1161 throw runtime_error(
1162 "listtransactions [account] [count=10] [from=0]\n"
1163 "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1165 string strAccount = "*";
1166 if (params.size() > 0)
1167 strAccount = params[0].get_str();
1169 if (params.size() > 1)
1170 nCount = params[1].get_int();
1172 if (params.size() > 2)
1173 nFrom = params[2].get_int();
1175 isminefilter filter = MINE_SPENDABLE;
1176 if(params.size() > 3)
1177 if(params[3].get_bool())
1178 filter = filter | MINE_WATCH_ONLY;
1181 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count");
1183 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative from");
1187 std::list<CAccountingEntry> acentries;
1188 CWallet::TxItems txOrdered = pwalletMain->OrderedTxItems(acentries, strAccount);
1190 // iterate backwards until we have nCount items to return:
1191 for (CWallet::TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
1193 CWalletTx *const pwtx = (*it).second.first;
1195 ListTransactions(*pwtx, strAccount, 0, true, ret, filter);
1196 CAccountingEntry *const pacentry = (*it).second.second;
1198 AcentryToJSON(*pacentry, strAccount, ret);
1200 if ((int)ret.size() >= (nCount+nFrom)) break;
1202 // ret is newest to oldest
1204 if (nFrom > (int)ret.size())
1206 if ((nFrom + nCount) > (int)ret.size())
1207 nCount = ret.size() - nFrom;
1208 Array::iterator first = ret.begin();
1209 std::advance(first, nFrom);
1210 Array::iterator last = ret.begin();
1211 std::advance(last, nFrom+nCount);
1213 if (last != ret.end()) ret.erase(last, ret.end());
1214 if (first != ret.begin()) ret.erase(ret.begin(), first);
1216 std::reverse(ret.begin(), ret.end()); // Return oldest to newest
1221 Value listaccounts(const Array& params, bool fHelp)
1223 if (fHelp || params.size() > 1)
1224 throw runtime_error(
1225 "listaccounts [minconf=1]\n"
1226 "Returns Object that has account names as keys, account balances as values.");
1229 if (params.size() > 0)
1230 nMinDepth = params[0].get_int();
1232 isminefilter includeWatchonly = MINE_SPENDABLE;
1233 if(params.size() > 1)
1234 if(params[1].get_bool())
1235 includeWatchonly = includeWatchonly | MINE_WATCH_ONLY;
1238 map<string, int64_t> mapAccountBalances;
1239 BOOST_FOREACH(const PAIRTYPE(CTxDestination, string)& entry, pwalletMain->mapAddressBook) {
1240 if (IsMine(*pwalletMain, entry.first)) // This address belongs to me
1241 mapAccountBalances[entry.second] = 0;
1244 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1246 const CWalletTx& wtx = (*it).second;
1247 int64_t nGeneratedImmature, nGeneratedMature, nFee;
1248 string strSentAccount;
1249 list<pair<CTxDestination, int64_t> > listReceived;
1250 list<pair<CTxDestination, int64_t> > listSent;
1251 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount, includeWatchonly);
1252 mapAccountBalances[strSentAccount] -= nFee;
1253 BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64_t)& s, listSent)
1254 mapAccountBalances[strSentAccount] -= s.second;
1255 if (wtx.GetDepthInMainChain() >= nMinDepth)
1257 mapAccountBalances[""] += nGeneratedMature;
1258 BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64_t)& r, listReceived)
1259 if (pwalletMain->mapAddressBook.count(r.first))
1260 mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1262 mapAccountBalances[""] += r.second;
1266 list<CAccountingEntry> acentries;
1267 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1268 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1269 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1272 BOOST_FOREACH(const PAIRTYPE(string, int64_t)& accountBalance, mapAccountBalances) {
1273 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1278 Value listsinceblock(const Array& params, bool fHelp)
1281 throw runtime_error(
1282 "listsinceblock [blockhash] [target-confirmations]\n"
1283 "Get all transactions in blocks since block [blockhash], or all transactions if omitted");
1285 CBlockIndex *pindex = NULL;
1286 int target_confirms = 1;
1287 isminefilter filter = MINE_SPENDABLE;
1289 if (params.size() > 0)
1291 uint256 blockId = 0;
1293 blockId.SetHex(params[0].get_str());
1294 pindex = CBlockLocator(blockId).GetBlockIndex();
1297 if (params.size() > 1)
1299 target_confirms = params[1].get_int();
1301 if (target_confirms < 1)
1302 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter");
1305 if(params.size() > 2)
1306 if(params[2].get_bool())
1307 filter = filter | MINE_WATCH_ONLY;
1309 int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
1313 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1315 CWalletTx tx = (*it).second;
1317 if (depth == -1 || tx.GetDepthInMainChain() < depth)
1318 ListTransactions(tx, "*", 0, true, transactions, filter);
1323 if (target_confirms == 1)
1325 lastblock = hashBestChain;
1329 int target_height = pindexBest->nHeight + 1 - target_confirms;
1332 for (block = pindexBest;
1333 block && block->nHeight > target_height;
1334 block = block->pprev) { }
1336 lastblock = block ? block->GetBlockHash() : 0;
1340 ret.push_back(Pair("transactions", transactions));
1341 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1346 Value gettransaction(const Array& params, bool fHelp)
1348 if (fHelp || params.size() != 1)
1349 throw runtime_error(
1350 "gettransaction <txid>\n"
1351 "Get detailed information about <txid>");
1354 hash.SetHex(params[0].get_str());
1356 isminefilter filter = MINE_SPENDABLE;
1357 if(params.size() > 1)
1358 if(params[1].get_bool())
1359 filter = filter | MINE_WATCH_ONLY;
1363 if (pwalletMain->mapWallet.count(hash))
1365 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1367 TxToJSON(wtx, 0, entry);
1369 int64_t nCredit = wtx.GetCredit(filter);
1370 int64_t nDebit = wtx.GetDebit(filter);
1371 int64_t nNet = nCredit - nDebit;
1372 int64_t nFee = (wtx.IsFromMe(filter) ? wtx.GetValueOut() - nDebit : 0);
1374 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1375 if (wtx.IsFromMe(filter))
1376 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1378 WalletTxToJSON(wtx, entry);
1381 ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details, filter);
1382 entry.push_back(Pair("details", details));
1387 uint256 hashBlock = 0;
1388 if (GetTransaction(hash, tx, hashBlock))
1390 TxToJSON(tx, 0, entry);
1392 entry.push_back(Pair("confirmations", 0));
1395 entry.push_back(Pair("blockhash", hashBlock.GetHex()));
1396 map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
1397 if (mi != mapBlockIndex.end() && (*mi).second)
1399 CBlockIndex* pindex = (*mi).second;
1400 if (pindex->IsInMainChain())
1401 entry.push_back(Pair("confirmations", 1 + nBestHeight - pindex->nHeight));
1403 entry.push_back(Pair("confirmations", 0));
1408 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction");
1415 Value backupwallet(const Array& params, bool fHelp)
1417 if (fHelp || params.size() != 1)
1418 throw runtime_error(
1419 "backupwallet <destination>\n"
1420 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1422 string strDest = params[0].get_str();
1423 if (!BackupWallet(*pwalletMain, strDest))
1424 throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!");
1430 Value keypoolrefill(const Array& params, bool fHelp)
1432 if (fHelp || params.size() > 1)
1433 throw runtime_error(
1434 "keypoolrefill [new-size]\n"
1435 "Fills the keypool.\n"
1436 "IMPORTANT: Any previous backups you have made of your wallet file "
1437 "should be replaced with the newly generated one."
1438 + HelpRequiringPassphrase());
1440 unsigned int nSize = max<unsigned int>(GetArgUInt("-keypool", 100), 0);
1441 if (params.size() > 0) {
1442 if (params[0].get_int() < 0)
1443 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size");
1444 nSize = (unsigned int) params[0].get_int();
1447 EnsureWalletIsUnlocked();
1449 pwalletMain->TopUpKeyPool(nSize);
1451 if (pwalletMain->GetKeyPoolSize() < nSize)
1452 throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool.");
1457 Value keypoolreset(const Array& params, bool fHelp)
1459 if (fHelp || params.size() > 1)
1460 throw runtime_error(
1461 "keypoolreset [new-size]\n"
1462 "Resets the keypool.\n"
1463 "IMPORTANT: Any previous backups you have made of your wallet file "
1464 "should be replaced with the newly generated one."
1465 + HelpRequiringPassphrase());
1467 unsigned int nSize = max<unsigned int>(GetArgUInt("-keypool", 100), 0);
1468 if (params.size() > 0) {
1469 if (params[0].get_int() < 0)
1470 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size");
1471 nSize = (unsigned int) params[0].get_int();
1474 EnsureWalletIsUnlocked();
1476 pwalletMain->NewKeyPool(nSize);
1478 if (pwalletMain->GetKeyPoolSize() < nSize)
1479 throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool.");
1485 void ThreadTopUpKeyPool(void* parg)
1487 // Make this thread recognisable as the key-topping-up thread
1488 RenameThread("novacoin-key-top");
1490 pwalletMain->TopUpKeyPool();
1493 void ThreadCleanWalletPassphrase(void* parg)
1495 // Make this thread recognisable as the wallet relocking thread
1496 RenameThread("novacoin-lock-wa");
1498 int64_t nMyWakeTime = GetTimeMillis() + *((int64_t*)parg) * 1000;
1500 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1502 if (nWalletUnlockTime == 0)
1504 nWalletUnlockTime = nMyWakeTime;
1508 if (nWalletUnlockTime==0)
1510 int64_t nToSleep = nWalletUnlockTime - GetTimeMillis();
1514 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1516 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1520 if (nWalletUnlockTime)
1522 nWalletUnlockTime = 0;
1523 pwalletMain->Lock();
1528 if (nWalletUnlockTime < nMyWakeTime)
1529 nWalletUnlockTime = nMyWakeTime;
1532 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1534 delete (int64_t*)parg;
1537 Value walletpassphrase(const Array& params, bool fHelp)
1539 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 3))
1540 throw runtime_error(
1541 "walletpassphrase <passphrase> <timeout> [mintonly]\n"
1542 "Stores the wallet decryption key in memory for <timeout> seconds.\n"
1543 "mintonly is optional true/false allowing only block minting.");
1546 if (!pwalletMain->IsCrypted())
1547 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1549 if (!pwalletMain->IsLocked())
1550 throw JSONRPCError(RPC_WALLET_ALREADY_UNLOCKED, "Error: Wallet is already unlocked, use walletlock first if need to change unlock settings.");
1551 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1552 SecureString strWalletPass;
1553 strWalletPass.reserve(100);
1554 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1555 // Alternately, find a way to make params[0] mlock()'d to begin with.
1556 strWalletPass = params[0].get_str().c_str();
1558 if (strWalletPass.length() > 0)
1560 if (!pwalletMain->Unlock(strWalletPass))
1561 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
1564 throw runtime_error(
1565 "walletpassphrase <passphrase> <timeout>\n"
1566 "Stores the wallet decryption key in memory for <timeout> seconds.");
1568 NewThread(ThreadTopUpKeyPool, NULL);
1569 int64_t* pnSleepTime = new int64_t(params[1].get_int64());
1570 NewThread(ThreadCleanWalletPassphrase, pnSleepTime);
1572 // ppcoin: if user OS account compromised prevent trivial sendmoney commands
1573 if (params.size() > 2)
1574 fWalletUnlockMintOnly = params[2].get_bool();
1576 fWalletUnlockMintOnly = false;
1582 Value walletpassphrasechange(const Array& params, bool fHelp)
1584 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1585 throw runtime_error(
1586 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1587 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1590 if (!pwalletMain->IsCrypted())
1591 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1593 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1594 // Alternately, find a way to make params[0] mlock()'d to begin with.
1595 SecureString strOldWalletPass;
1596 strOldWalletPass.reserve(100);
1597 strOldWalletPass = params[0].get_str().c_str();
1599 SecureString strNewWalletPass;
1600 strNewWalletPass.reserve(100);
1601 strNewWalletPass = params[1].get_str().c_str();
1603 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1604 throw runtime_error(
1605 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1606 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1608 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1609 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
1615 Value walletlock(const Array& params, bool fHelp)
1617 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1618 throw runtime_error(
1620 "Removes the wallet encryption key from memory, locking the wallet.\n"
1621 "After calling this method, you will need to call walletpassphrase again\n"
1622 "before being able to call any methods which require the wallet to be unlocked.");
1625 if (!pwalletMain->IsCrypted())
1626 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletlock was called.");
1629 LOCK(cs_nWalletUnlockTime);
1630 pwalletMain->Lock();
1631 nWalletUnlockTime = 0;
1638 Value encryptwallet(const Array& params, bool fHelp)
1640 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1641 throw runtime_error(
1642 "encryptwallet <passphrase>\n"
1643 "Encrypts the wallet with <passphrase>.");
1646 if (pwalletMain->IsCrypted())
1647 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an encrypted wallet, but encryptwallet was called.");
1649 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1650 // Alternately, find a way to make params[0] mlock()'d to begin with.
1651 SecureString strWalletPass;
1652 strWalletPass.reserve(100);
1653 strWalletPass = params[0].get_str().c_str();
1655 if (strWalletPass.length() < 1)
1656 throw runtime_error(
1657 "encryptwallet <passphrase>\n"
1658 "Encrypts the wallet with <passphrase>.");
1660 if (!pwalletMain->EncryptWallet(strWalletPass))
1661 throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: Failed to encrypt the wallet.");
1663 // BDB seems to have a bad habit of writing old data into
1664 // slack space in .dat files; that is bad if the old data is
1665 // unencrypted private keys. So:
1667 return "wallet encrypted; NovaCoin server stopping, restart to run with encrypted wallet. The keypool has been flushed, you need to make a new backup.";
1670 class DescribeAddressVisitor : public boost::static_visitor<Object>
1675 DescribeAddressVisitor(isminetype mineIn) : mine(mineIn) {}
1677 Object operator()(const CNoDestination &dest) const { return Object(); }
1678 Object operator()(const CKeyID &keyID) const {
1681 pwalletMain->GetPubKey(keyID, vchPubKey);
1682 obj.push_back(Pair("isscript", false));
1683 if (mine == MINE_SPENDABLE) {
1684 pwalletMain->GetPubKey(keyID, vchPubKey);
1685 obj.push_back(Pair("pubkey", HexStr(vchPubKey.Raw())));
1686 obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed()));
1691 Object operator()(const CScriptID &scriptID) const {
1693 obj.push_back(Pair("isscript", true));
1694 if (mine == MINE_SPENDABLE) {
1696 pwalletMain->GetCScript(scriptID, subscript);
1697 std::vector<CTxDestination> addresses;
1698 txnouttype whichType;
1700 ExtractDestinations(subscript, whichType, addresses, nRequired);
1701 obj.push_back(Pair("script", GetTxnOutputType(whichType)));
1702 obj.push_back(Pair("hex", HexStr(subscript.begin(), subscript.end())));
1704 BOOST_FOREACH(const CTxDestination& addr, addresses)
1705 a.push_back(CBitcoinAddress(addr).ToString());
1706 obj.push_back(Pair("addresses", a));
1707 if (whichType == TX_MULTISIG)
1708 obj.push_back(Pair("sigsrequired", nRequired));
1714 Value validateaddress(const Array& params, bool fHelp)
1716 if (fHelp || params.size() != 1)
1717 throw runtime_error(
1718 "validateaddress <novacoinaddress>\n"
1719 "Return information about <novacoinaddress>.");
1721 CBitcoinAddress address(params[0].get_str());
1722 bool isValid = address.IsValid();
1725 ret.push_back(Pair("isvalid", isValid));
1728 CTxDestination dest = address.Get();
1729 string currentAddress = address.ToString();
1730 ret.push_back(Pair("address", currentAddress));
1731 isminetype mine = pwalletMain ? IsMine(*pwalletMain, dest) : MINE_NO;
1732 ret.push_back(Pair("ismine", mine != MINE_NO));
1733 if (mine != MINE_NO) {
1734 ret.push_back(Pair("watchonly", mine == MINE_WATCH_ONLY));
1735 Object detail = boost::apply_visitor(DescribeAddressVisitor(mine), dest);
1736 ret.insert(ret.end(), detail.begin(), detail.end());
1738 if (pwalletMain->mapAddressBook.count(dest))
1739 ret.push_back(Pair("account", pwalletMain->mapAddressBook[dest]));
1744 // ppcoin: reserve balance from being staked for network protection
1745 Value reservebalance(const Array& params, bool fHelp)
1747 if (fHelp || params.size() > 2)
1748 throw runtime_error(
1749 "reservebalance [<reserve> [amount]]\n"
1750 "<reserve> is true or false to turn balance reserve on or off.\n"
1751 "<amount> is a real and rounded to cent.\n"
1752 "Set reserve amount not participating in network protection.\n"
1753 "If no parameters provided current setting is printed.\n");
1755 if (params.size() > 0)
1757 bool fReserve = params[0].get_bool();
1760 if (params.size() == 1)
1761 throw runtime_error("must provide amount to reserve balance.\n");
1762 int64_t nAmount = AmountFromValue(params[1]);
1763 nAmount = (nAmount / CENT) * CENT; // round to cent
1765 throw runtime_error("amount cannot be negative.\n");
1766 mapArgs["-reservebalance"] = FormatMoney(nAmount).c_str();
1770 if (params.size() > 1)
1771 throw runtime_error("cannot specify amount to turn off reserve.\n");
1772 mapArgs["-reservebalance"] = "0";
1777 if (mapArgs.count("-reservebalance") && !ParseMoney(mapArgs["-reservebalance"], nReserveBalance))
1778 throw runtime_error("invalid reserve balance amount\n");
1779 result.push_back(Pair("reserve", (nReserveBalance > 0)));
1780 result.push_back(Pair("amount", ValueFromAmount(nReserveBalance)));
1785 // ppcoin: check wallet integrity
1786 Value checkwallet(const Array& params, bool fHelp)
1788 if (fHelp || params.size() > 0)
1789 throw runtime_error(
1791 "Check wallet for integrity.\n");
1794 int64_t nBalanceInQuestion;
1795 pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion, true);
1797 if (nMismatchSpent == 0)
1798 result.push_back(Pair("wallet check passed", true));
1801 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
1802 result.push_back(Pair("amount in question", ValueFromAmount(nBalanceInQuestion)));
1808 // ppcoin: repair wallet
1809 Value repairwallet(const Array& params, bool fHelp)
1811 if (fHelp || params.size() > 0)
1812 throw runtime_error(
1814 "Repair wallet if checkwallet reports any problem.\n");
1817 int64_t nBalanceInQuestion;
1818 pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion);
1820 if (nMismatchSpent == 0)
1821 result.push_back(Pair("wallet check passed", true));
1824 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
1825 result.push_back(Pair("amount affected by repair", ValueFromAmount(nBalanceInQuestion)));
1830 // NovaCoin: resend unconfirmed wallet transactions
1831 Value resendtx(const Array& params, bool fHelp)
1833 if (fHelp || params.size() > 1)
1834 throw runtime_error(
1836 "Re-send unconfirmed transactions.\n"
1839 ResendWalletTransactions();
1844 // Make a public-private key pair
1845 Value makekeypair(const Array& params, bool fHelp)
1847 if (fHelp || params.size() > 0)
1848 throw runtime_error(
1850 "Make a public/private key pair.\n");
1852 string strPrefix = "";
1853 if (params.size() > 0)
1854 strPrefix = params[0].get_str();
1857 key.MakeNewKey(true);
1859 CPrivKey vchPrivKey = key.GetPrivKey();
1861 result.push_back(Pair("PrivateKey", HexStr<CPrivKey::iterator>(vchPrivKey.begin(), vchPrivKey.end())));
1864 CSecret vchSecret = key.GetSecret(fCompressed);
1865 result.push_back(Pair("Secret", HexStr<CSecret::iterator>(vchSecret.begin(), vchSecret.end())));
1866 result.push_back(Pair("PublicKey", HexStr(key.GetPubKey().Raw())));
1870 Value newmalleablekey(const Array& params, bool fHelp)
1872 if (fHelp || params.size() > 0)
1873 throw runtime_error(
1875 "Make a malleable public/private key pair.\n");
1878 throw runtime_error("This feature has been disabled for mainNet clients");
1880 CMalleableKeyView keyView = pwalletMain->GenerateNewMalleableKey();
1883 if (!pwalletMain->GetMalleableKey(keyView, mKey))
1884 throw runtime_error("Unable to generate new malleable key");
1887 result.push_back(Pair("PublicPair", mKey.GetMalleablePubKey().ToString()));
1888 result.push_back(Pair("KeyView", keyView.ToString()));
1893 Value dumpmalleablekey(const Array& params, bool fHelp)
1895 if (fHelp || params.size() != 1)
1896 throw runtime_error (
1897 "dumpmalleablekey <Key view>\n"
1898 "Dump the private and public key pairs, which correspond to provided key view.\n");
1901 CMalleableKeyView keyView;
1902 keyView.SetString(params[0].get_str());
1904 if (!pwalletMain->GetMalleableKey(keyView, mKey))
1905 throw runtime_error("There is no such item in the wallet");
1908 result.push_back(Pair("PrivatePair", mKey.ToString()));
1909 result.push_back(Pair("PublicPair", mKey.GetMalleablePubKey().ToString()));
1914 Value adjustmalleablekey(const Array& params, bool fHelp)
1916 if (fHelp || params.size() != 3)
1917 throw runtime_error(
1918 "adjustmalleablekey <Malleable key data> <Public key variant data> <R data>\n"
1919 "Calculate new private key using provided malleable key, public key and R data.\n");
1921 CMalleableKey malleableKey;
1922 malleableKey.SetString(params[0].get_str());
1924 CKey privKeyVariant;
1925 CPubKey vchPubKeyVariant = CPubKey(ParseHex(params[1].get_str()));
1927 CPubKey R(ParseHex(params[2].get_str()));
1929 if (!malleableKey.CheckKeyVariant(R,vchPubKeyVariant, privKeyVariant)) {
1930 throw runtime_error("Unable to calculate the private key");
1935 CSecret vchPrivKeyVariant = privKeyVariant.GetSecret(fCompressed);
1937 result.push_back(Pair("PrivateKey", CBitcoinSecret(vchPrivKeyVariant, fCompressed).ToString()));
1942 Value adjustmalleablepubkey(const Array& params, bool fHelp)
1944 if (fHelp || params.size() > 2 || params.size() == 0)
1945 throw runtime_error(
1946 "adjustmalleablepubkey <Malleable public key data>\n"
1947 "Calculate new public key using provided malleable public key data.\n");
1949 string pubKeyPair = params[0].get_str();
1950 CMalleablePubKey malleablePubKey;
1952 if (pubKeyPair.size() == 138) {
1953 CDataStream ssPublicBytes(ParseHex(pubKeyPair), SER_NETWORK, PROTOCOL_VERSION);
1954 ssPublicBytes >> malleablePubKey;
1956 malleablePubKey.SetString(pubKeyPair);
1958 CPubKey R, vchPubKeyVariant;
1959 malleablePubKey.GetVariant(R, vchPubKeyVariant);
1962 result.push_back(Pair("R", HexStr(R.Raw())));
1963 result.push_back(Pair("PubkeyVariant", HexStr(vchPubKeyVariant.Raw())));
1964 result.push_back(Pair("KeyVariantID", CBitcoinAddress(vchPubKeyVariant.GetID()).ToString()));
1969 Value listmalleableviews(const Array& params, bool fHelp)
1971 if (fHelp || params.size() != 0)
1972 throw runtime_error(
1973 "listmalleableviews\n"
1974 "Get list of views for generated malleable keys.\n");
1976 std::list<CMalleableKeyView> keyViewList;
1977 pwalletMain->ListMalleableViews(keyViewList);
1980 BOOST_FOREACH(const CMalleableKeyView &keyView, keyViewList)
1982 result.push_back(keyView.ToString());