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 CBitcoinAddress address(newKey.GetID());
139 pwalletMain->SetAddressBookName(address, strAccount);
141 return address.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(CBitcoinAddress(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))
221 string strOldAccount = pwalletMain->mapAddressBook[address];
222 if (address == GetAccountAddress(strOldAccount))
223 GetAccountAddress(strOldAccount, true);
226 pwalletMain->SetAddressBookName(address, 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<CBitcoinAddress, string>::iterator mi = pwalletMain->mapAddressBook.find(address);
245 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
246 strAccount = (*mi).second;
251 Value getaddressesbyaccount(const Array& params, bool fHelp)
253 if (fHelp || params.size() != 1)
255 "getaddressesbyaccount <account>\n"
256 "Returns the list of addresses for the given account.");
258 string strAccount = AccountFromValue(params[0]);
260 // Find all addresses that have the given account
262 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
264 const CBitcoinAddress& address = item.first;
265 const string& strName = item.second;
266 if (strName == strAccount)
267 ret.push_back(address.ToString());
272 Value mergecoins(const Array& params, bool fHelp)
274 if (fHelp || params.size() != 3)
276 "mergecoins <amount> <minvalue> <outputvalue>\n"
277 "<amount> is resulting inputs sum\n"
278 "<minvalue> is minimum value of inputs which are used in join process\n"
279 "<outputvalue> is resulting value of inputs which will be created\n"
280 "All values are real and and rounded to the nearest " + FormatMoney(nMinimumInputValue)
281 + HelpRequiringPassphrase());
283 if (pwalletMain->IsLocked())
284 throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
287 int64_t nAmount = AmountFromValue(params[0]);
290 int64_t nMinValue = AmountFromValue(params[1]);
293 int64_t nOutputValue = AmountFromValue(params[2]);
295 if (nAmount < nMinimumInputValue)
296 throw JSONRPCError(-101, "Send amount too small");
298 if (nMinValue < nMinimumInputValue)
299 throw JSONRPCError(-101, "Max value too small");
301 if (nOutputValue < nMinimumInputValue)
302 throw JSONRPCError(-101, "Output value too small");
304 if (nOutputValue < nMinValue)
305 throw JSONRPCError(-101, "Output value is lower than min value");
307 list<uint256> listMerged;
308 if (!pwalletMain->MergeCoins(nAmount, nMinValue, nOutputValue, listMerged))
312 BOOST_FOREACH(const uint256 txHash, listMerged)
313 mergedHashes.push_back(txHash.GetHex());
318 Value sendtoaddress(const Array& params, bool fHelp)
320 if (fHelp || params.size() < 2 || params.size() > 4)
322 "sendtoaddress <novacoinaddress> <amount> [comment] [comment-to]\n"
323 "<amount> is a real and is rounded to the nearest " + FormatMoney(nMinimumInputValue)
324 + HelpRequiringPassphrase());
327 CScript scriptPubKey;
328 string strAddress = params[0].get_str();
330 CBitcoinAddress address(strAddress);
331 if (address.IsValid())
332 scriptPubKey.SetAddress(address);
334 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
337 int64_t nAmount = AmountFromValue(params[1]);
339 if (nAmount < nMinimumInputValue)
340 throw JSONRPCError(-101, "Send amount too small");
344 if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
345 wtx.mapValue["comment"] = params[2].get_str();
346 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
347 wtx.mapValue["to"] = params[3].get_str();
349 if (pwalletMain->IsLocked())
350 throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
352 string strError = pwalletMain->SendMoney(scriptPubKey, nAmount, wtx);
354 throw JSONRPCError(RPC_WALLET_ERROR, strError);
356 return wtx.GetHash().GetHex();
359 Value listaddressgroupings(const Array& params, bool fHelp)
363 "listaddressgroupings\n"
364 "Lists groups of addresses which have had their common ownership\n"
365 "made public by common use as inputs or as the resulting change\n"
366 "in past transactions");
369 map<CBitcoinAddress, int64_t> balances = pwalletMain->GetAddressBalances();
370 BOOST_FOREACH(set<CBitcoinAddress> grouping, pwalletMain->GetAddressGroupings())
373 BOOST_FOREACH(CBitcoinAddress address, grouping)
376 addressInfo.push_back(address.ToString());
377 addressInfo.push_back(ValueFromAmount(balances[address]));
379 LOCK(pwalletMain->cs_wallet);
380 if (pwalletMain->mapAddressBook.find(address) != pwalletMain->mapAddressBook.end())
381 addressInfo.push_back(pwalletMain->mapAddressBook.find(address)->second);
383 jsonGrouping.push_back(addressInfo);
385 jsonGroupings.push_back(jsonGrouping);
387 return jsonGroupings;
390 Value signmessage(const Array& params, bool fHelp)
392 if (fHelp || params.size() != 2)
394 "signmessage <novacoinaddress> <message>\n"
395 "Sign a message with the private key of an address");
397 EnsureWalletIsUnlocked();
399 string strAddress = params[0].get_str();
400 string strMessage = params[1].get_str();
402 CBitcoinAddress addr(strAddress);
404 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
407 if (!addr.GetKeyID(keyID))
408 throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
411 if (!pwalletMain->GetKey(keyID, key))
412 throw JSONRPCError(RPC_WALLET_ERROR, "Private key not available");
414 CDataStream ss(SER_GETHASH, 0);
415 ss << strMessageMagic;
418 vector<unsigned char> vchSig;
419 if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
420 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed");
422 return EncodeBase64(&vchSig[0], vchSig.size());
425 Value verifymessage(const Array& params, bool fHelp)
427 if (fHelp || params.size() != 3)
429 "verifymessage <novacoinaddress> <signature> <message>\n"
430 "Verify a signed message");
432 string strAddress = params[0].get_str();
433 string strSign = params[1].get_str();
434 string strMessage = params[2].get_str();
436 CBitcoinAddress addr(strAddress);
438 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
441 if (!addr.GetKeyID(keyID))
442 throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
444 bool fInvalid = false;
445 vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
448 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Malformed base64 encoding");
450 CDataStream ss(SER_GETHASH, 0);
451 ss << strMessageMagic;
455 if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
458 return (key.GetPubKey().GetID() == keyID);
462 Value getreceivedbyaddress(const Array& params, bool fHelp)
464 if (fHelp || params.size() < 1 || params.size() > 2)
466 "getreceivedbyaddress <novacoinaddress> [minconf=1]\n"
467 "Returns the total amount received by <novacoinaddress> in transactions with at least [minconf] confirmations.");
470 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
471 if (!address.IsValid())
472 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
473 if (!IsMine(*pwalletMain,address))
476 // Minimum confirmations
478 if (params.size() > 1)
479 nMinDepth = params[1].get_int();
482 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
484 const CWalletTx& wtx = (*it).second;
485 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
487 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
489 CBitcoinAddress addressRet;
490 if (!ExtractAddress(*pwalletMain, txout.scriptPubKey, addressRet))
492 if (addressRet == address)
493 if (wtx.GetDepthInMainChain() >= nMinDepth)
494 nAmount += txout.nValue;
498 return ValueFromAmount(nAmount);
501 void GetAccountAddresses(string strAccount, set<CBitcoinAddress>& setAddress)
503 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
505 const CBitcoinAddress& address = item.first;
506 const string& strName = item.second;
507 if (strName == strAccount)
508 setAddress.insert(address);
512 Value getreceivedbyaccount(const Array& params, bool fHelp)
514 if (fHelp || params.size() < 1 || params.size() > 2)
516 "getreceivedbyaccount <account> [minconf=1]\n"
517 "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
519 // Minimum confirmations
521 if (params.size() > 1)
522 nMinDepth = params[1].get_int();
524 // Get the set of pub keys assigned to account
525 string strAccount = AccountFromValue(params[0]);
526 set<CBitcoinAddress> setAddress;
527 GetAccountAddresses(strAccount, setAddress);
531 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
533 const CWalletTx& wtx = (*it).second;
534 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
537 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
539 CBitcoinAddress address;
540 if (ExtractAddress(*pwalletMain, txout.scriptPubKey, address) && IsMine(*pwalletMain, address) && setAddress.count(address))
541 if (wtx.GetDepthInMainChain() >= nMinDepth)
542 nAmount += txout.nValue;
546 return (double)nAmount / (double)COIN;
550 int64_t GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth, const isminefilter& filter)
552 int64_t nBalance = 0;
554 // Tally wallet transactions
555 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
557 const CWalletTx& wtx = (*it).second;
561 int64_t nGenerated, nReceived, nSent, nFee;
562 wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee, filter);
564 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
565 nBalance += nReceived;
566 nBalance += nGenerated - nSent - nFee;
569 // Tally internal accounting entries
570 nBalance += walletdb.GetAccountCreditDebit(strAccount);
575 int64_t GetAccountBalance(const string& strAccount, int nMinDepth, const isminefilter& filter)
577 CWalletDB walletdb(pwalletMain->strWalletFile);
578 return GetAccountBalance(walletdb, strAccount, nMinDepth, filter);
582 Value getbalance(const Array& params, bool fHelp)
584 if (fHelp || params.size() > 2)
586 "getbalance [account] [minconf=1] [watchonly=0]\n"
587 "If [account] is not specified, returns the server's total available balance.\n"
588 "If [account] is specified, returns the balance in the account.\n"
589 "if [includeWatchonly] is specified, include balance in watchonly addresses (see 'importaddress').");
591 if (params.size() == 0)
592 return ValueFromAmount(pwalletMain->GetBalance());
595 if (params.size() > 1)
596 nMinDepth = params[1].get_int();
597 isminefilter filter = MINE_SPENDABLE;
598 if(params.size() > 2)
599 if(params[2].get_bool())
600 filter = filter | MINE_WATCH_ONLY;
602 if (params[0].get_str() == "*") {
603 // Calculate total balance a different way from GetBalance()
604 // (GetBalance() sums up all unspent TxOuts)
605 // getbalance and getbalance '*' 0 should return the same number.
606 int64_t nBalance = 0;
607 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
609 const CWalletTx& wtx = (*it).second;
610 if (!wtx.IsTrusted())
613 int64_t allGeneratedImmature, allGeneratedMature, allFee;
614 allGeneratedImmature = allGeneratedMature = allFee = 0;
616 string strSentAccount;
617 list<pair<CBitcoinAddress, int64_t> > listReceived;
618 list<pair<CBitcoinAddress, int64_t> > listSent;
619 wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount, filter);
620 if (wtx.GetDepthInMainChain() >= nMinDepth)
622 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64_t)& r, listReceived)
623 nBalance += r.second;
625 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64_t)& r, listSent)
626 nBalance -= r.second;
628 nBalance += allGeneratedMature;
630 return ValueFromAmount(nBalance);
633 string strAccount = AccountFromValue(params[0]);
635 int64_t nBalance = GetAccountBalance(strAccount, nMinDepth, filter);
637 return ValueFromAmount(nBalance);
641 Value movecmd(const Array& params, bool fHelp)
643 if (fHelp || params.size() < 3 || params.size() > 5)
645 "move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
646 "Move from one account in your wallet to another.");
648 string strFrom = AccountFromValue(params[0]);
649 string strTo = AccountFromValue(params[1]);
650 int64_t nAmount = AmountFromValue(params[2]);
652 if (nAmount < nMinimumInputValue)
653 throw JSONRPCError(-101, "Send amount too small");
655 if (params.size() > 3)
656 // unused parameter, used to be nMinDepth, keep type-checking it though
657 (void)params[3].get_int();
659 if (params.size() > 4)
660 strComment = params[4].get_str();
662 CWalletDB walletdb(pwalletMain->strWalletFile);
663 if (!walletdb.TxnBegin())
664 throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
666 int64_t nNow = GetAdjustedTime();
669 CAccountingEntry debit;
670 debit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
671 debit.strAccount = strFrom;
672 debit.nCreditDebit = -nAmount;
674 debit.strOtherAccount = strTo;
675 debit.strComment = strComment;
676 walletdb.WriteAccountingEntry(debit);
679 CAccountingEntry credit;
680 credit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
681 credit.strAccount = strTo;
682 credit.nCreditDebit = nAmount;
684 credit.strOtherAccount = strFrom;
685 credit.strComment = strComment;
686 walletdb.WriteAccountingEntry(credit);
688 if (!walletdb.TxnCommit())
689 throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
695 Value sendfrom(const Array& params, bool fHelp)
697 if (fHelp || params.size() < 3 || params.size() > 6)
699 "sendfrom <fromaccount> <tonovacoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
700 "<amount> is a real and is rounded to the nearest " + FormatMoney(nMinimumInputValue)
701 + HelpRequiringPassphrase());
703 string strAccount = AccountFromValue(params[0]);
706 CScript scriptPubKey;
707 string strAddress = params[0].get_str();
709 CBitcoinAddress address(strAddress);
710 if (address.IsValid())
711 scriptPubKey.SetAddress(address);
713 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
716 int64_t nAmount = AmountFromValue(params[2]);
718 if (nAmount < nMinimumInputValue)
719 throw JSONRPCError(-101, "Send amount too small");
722 if (params.size() > 3)
723 nMinDepth = params[3].get_int();
726 wtx.strFromAccount = strAccount;
727 if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
728 wtx.mapValue["comment"] = params[4].get_str();
729 if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
730 wtx.mapValue["to"] = params[5].get_str();
732 EnsureWalletIsUnlocked();
735 int64_t nBalance = GetAccountBalance(strAccount, nMinDepth, MINE_SPENDABLE);
736 if (nAmount > nBalance)
737 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
740 string strError = pwalletMain->SendMoney(scriptPubKey, nAmount, wtx);
742 throw JSONRPCError(RPC_WALLET_ERROR, strError);
744 return wtx.GetHash().GetHex();
748 Value sendmany(const Array& params, bool fHelp)
750 if (fHelp || params.size() < 2 || params.size() > 4)
752 "sendmany <fromaccount> '{address:amount,...}' [minconf=1] [comment]\n"
753 "amounts are double-precision floating point numbers"
754 + HelpRequiringPassphrase());
756 string strAccount = AccountFromValue(params[0]);
757 Object sendTo = params[1].get_obj();
759 if (params.size() > 2)
760 nMinDepth = params[2].get_int();
763 wtx.strFromAccount = strAccount;
764 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
765 wtx.mapValue["comment"] = params[3].get_str();
767 set<CBitcoinAddress> setAddress;
768 vector<pair<CScript, int64_t> > vecSend;
770 int64_t totalAmount = 0;
771 BOOST_FOREACH(const Pair& s, sendTo)
773 CBitcoinAddress address(s.name_);
774 if (!address.IsValid())
775 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid NovaCoin address: ")+s.name_);
777 if (!address.IsPair())
779 if (setAddress.count(address))
780 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+s.name_);
781 setAddress.insert(address);
784 CScript scriptPubKey;
785 scriptPubKey.SetAddress(address);
786 int64_t nAmount = AmountFromValue(s.value_);
788 if (nAmount < nMinimumInputValue)
789 throw JSONRPCError(-101, "Send amount too small");
791 totalAmount += nAmount;
793 vecSend.push_back(make_pair(scriptPubKey, nAmount));
796 EnsureWalletIsUnlocked();
799 int64_t nBalance = GetAccountBalance(strAccount, nMinDepth, MINE_SPENDABLE);
800 if (totalAmount > nBalance)
801 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
804 CReserveKey keyChange(pwalletMain);
805 int64_t nFeeRequired = 0;
806 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
809 int64_t nTotal = pwalletMain->GetBalance(), nWatchOnly = pwalletMain->GetWatchOnlyBalance();
810 if (totalAmount + nFeeRequired > nTotal - nWatchOnly)
811 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds");
812 throw JSONRPCError(RPC_WALLET_ERROR, "Transaction creation failed");
814 if (!pwalletMain->CommitTransaction(wtx, keyChange))
815 throw JSONRPCError(RPC_WALLET_ERROR, "Transaction commit failed");
817 return wtx.GetHash().GetHex();
820 Value addmultisigaddress(const Array& params, bool fHelp)
822 if (fHelp || params.size() < 2 || params.size() > 3)
824 string msg = "addmultisigaddress <nrequired> <'[\"key\",\"key\"]'> [account]\n"
825 "Add a nrequired-to-sign multisignature address to the wallet\"\n"
826 "each key is a NovaCoin address or hex-encoded public key\n"
827 "If [account] is specified, assign address to [account].";
828 throw runtime_error(msg);
831 int nRequired = params[0].get_int();
832 const Array& keys = params[1].get_array();
834 if (params.size() > 2)
835 strAccount = AccountFromValue(params[2]);
837 // Gather public keys
839 throw runtime_error("a multisignature address must require at least one key to redeem");
840 if ((int)keys.size() < nRequired)
842 strprintf("not enough keys supplied "
843 "(got %" PRIszu " keys, but need at least %d to redeem)", keys.size(), nRequired));
844 if (keys.size() > 16)
845 throw runtime_error("Number of addresses involved in the multisignature address creation > 16\nReduce the number");
846 std::vector<CKey> pubkeys;
847 pubkeys.resize(keys.size());
848 for (unsigned int i = 0; i < keys.size(); i++)
850 const std::string& ks = keys[i].get_str();
852 // Case 1: Bitcoin address and we have full public key:
853 CBitcoinAddress address(ks);
854 if (address.IsValid())
857 if (!address.GetKeyID(keyID))
859 strprintf("%s does not refer to a key",ks.c_str()));
861 if (!pwalletMain->GetPubKey(keyID, vchPubKey))
863 strprintf("no full public key for address %s",ks.c_str()));
864 if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey))
865 throw runtime_error(" Invalid public key: "+ks);
868 // Case 2: hex public key
871 CPubKey vchPubKey(ParseHex(ks));
872 if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey))
873 throw runtime_error(" Invalid public key: "+ks);
877 throw runtime_error(" Invalid public key: "+ks);
881 // Construct using pay-to-script-hash:
883 inner.SetMultisig(nRequired, pubkeys);
885 if (inner.size() > MAX_SCRIPT_ELEMENT_SIZE)
887 strprintf("redeemScript exceeds size limit: %" PRIszu " > %d", inner.size(), MAX_SCRIPT_ELEMENT_SIZE));
889 pwalletMain->AddCScript(inner);
890 CBitcoinAddress address(inner.GetID());
892 pwalletMain->SetAddressBookName(address, strAccount);
893 return address.ToString();
896 Value addredeemscript(const Array& params, bool fHelp)
898 if (fHelp || params.size() < 1 || params.size() > 2)
900 string msg = "addredeemscript <redeemScript> [account]\n"
901 "Add a P2SH address with a specified redeemScript to the wallet.\n"
902 "If [account] is specified, assign address to [account].";
903 throw runtime_error(msg);
907 if (params.size() > 1)
908 strAccount = AccountFromValue(params[1]);
910 // Construct using pay-to-script-hash:
911 vector<unsigned char> innerData = ParseHexV(params[0], "redeemScript");
912 CScript inner(innerData.begin(), innerData.end());
913 pwalletMain->AddCScript(inner);
914 CBitcoinAddress address(inner.GetID());
916 pwalletMain->SetAddressBookName(address, strAccount);
917 return address.ToString();
927 nConf = std::numeric_limits<int>::max();
931 Value ListReceived(const Array& params, bool fByAccounts)
933 // Minimum confirmations
935 if (params.size() > 0)
936 nMinDepth = params[0].get_int();
938 // Whether to include empty accounts
939 bool fIncludeEmpty = false;
940 if (params.size() > 1)
941 fIncludeEmpty = params[1].get_bool();
944 map<CBitcoinAddress, tallyitem> mapTally;
945 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
947 const CWalletTx& wtx = (*it).second;
949 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
952 int nDepth = wtx.GetDepthInMainChain();
953 if (nDepth < nMinDepth)
956 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
958 CTxDestination address;
959 if (!ExtractDestination(txout.scriptPubKey, address) || !IsMine(*pwalletMain, address))
962 tallyitem& item = mapTally[address];
963 item.nAmount += txout.nValue;
964 item.nConf = min(item.nConf, nDepth);
970 map<string, tallyitem> mapAccountTally;
971 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
973 const CBitcoinAddress& address = item.first;
974 const string& strAccount = item.second;
975 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
976 if (it == mapTally.end() && !fIncludeEmpty)
980 int nConf = std::numeric_limits<int>::max();
981 if (it != mapTally.end())
983 nAmount = (*it).second.nAmount;
984 nConf = (*it).second.nConf;
989 tallyitem& item = mapAccountTally[strAccount];
990 item.nAmount += nAmount;
991 item.nConf = min(item.nConf, nConf);
996 obj.push_back(Pair("address", address.ToString()));
997 obj.push_back(Pair("account", strAccount));
998 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
999 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1006 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
1008 int64_t nAmount = (*it).second.nAmount;
1009 int nConf = (*it).second.nConf;
1011 obj.push_back(Pair("account", (*it).first));
1012 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1013 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1021 Value listreceivedbyaddress(const Array& params, bool fHelp)
1023 if (fHelp || params.size() > 2)
1024 throw runtime_error(
1025 "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
1026 "[minconf] is the minimum number of confirmations before payments are included.\n"
1027 "[includeempty] whether to include addresses that haven't received any payments.\n"
1028 "Returns an array of objects containing:\n"
1029 " \"address\" : receiving address\n"
1030 " \"account\" : the account of the receiving address\n"
1031 " \"amount\" : total amount received by the address\n"
1032 " \"confirmations\" : number of confirmations of the most recent transaction included");
1034 return ListReceived(params, false);
1037 Value listreceivedbyaccount(const Array& params, bool fHelp)
1039 if (fHelp || params.size() > 2)
1040 throw runtime_error(
1041 "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
1042 "[minconf] is the minimum number of confirmations before payments are included.\n"
1043 "[includeempty] whether to include accounts that haven't received any payments.\n"
1044 "Returns an array of objects containing:\n"
1045 " \"account\" : the account of the receiving addresses\n"
1046 " \"amount\" : total amount received by addresses with this account\n"
1047 " \"confirmations\" : number of confirmations of the most recent transaction included");
1049 return ListReceived(params, true);
1052 static void MaybePushAddress(Object & entry, const CBitcoinAddress &dest)
1054 entry.push_back(Pair("address", dest.ToString()));
1057 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret, const isminefilter& filter)
1059 int64_t nGeneratedImmature, nGeneratedMature, nFee;
1060 string strSentAccount;
1061 list<pair<CBitcoinAddress, int64_t> > listReceived;
1062 list<pair<CBitcoinAddress, int64_t> > listSent;
1064 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount, filter);
1066 bool fAllAccounts = (strAccount == string("*"));
1067 bool involvesWatchonly = wtx.IsFromMe(MINE_WATCH_ONLY);
1069 // Generated blocks assigned to account ""
1070 if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
1073 entry.push_back(Pair("account", string("")));
1074 if (nGeneratedImmature)
1076 entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
1077 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
1081 entry.push_back(Pair("category", "generate"));
1082 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
1085 WalletTxToJSON(wtx, entry);
1086 ret.push_back(entry);
1090 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1092 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64_t)& s, listSent)
1095 entry.push_back(Pair("account", strSentAccount));
1096 if(involvesWatchonly || (::IsMine(*pwalletMain, s.first) & MINE_WATCH_ONLY))
1097 entry.push_back(Pair("involvesWatchonly", true));
1098 MaybePushAddress(entry, s.first);
1100 if (wtx.GetDepthInMainChain() < 0) {
1101 entry.push_back(Pair("category", "conflicted"));
1103 entry.push_back(Pair("category", "send"));
1106 entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1107 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1109 WalletTxToJSON(wtx, entry);
1110 ret.push_back(entry);
1115 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1117 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64_t)& r, listReceived)
1120 if (pwalletMain->mapAddressBook.count(r.first))
1121 account = pwalletMain->mapAddressBook[r.first];
1122 if (fAllAccounts || (account == strAccount))
1125 entry.push_back(Pair("account", account));
1126 if(involvesWatchonly || (::IsMine(*pwalletMain, r.first) & MINE_WATCH_ONLY))
1127 entry.push_back(Pair("involvesWatchonly", true));
1128 MaybePushAddress(entry, r.first);
1129 if (wtx.IsCoinBase())
1131 if (wtx.GetDepthInMainChain() < 1)
1132 entry.push_back(Pair("category", "orphan"));
1133 else if (wtx.GetBlocksToMaturity() > 0)
1134 entry.push_back(Pair("category", "immature"));
1136 entry.push_back(Pair("category", "generate"));
1139 entry.push_back(Pair("category", "receive"));
1140 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1142 WalletTxToJSON(wtx, entry);
1143 ret.push_back(entry);
1149 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1151 bool fAllAccounts = (strAccount == string("*"));
1153 if (fAllAccounts || acentry.strAccount == strAccount)
1156 entry.push_back(Pair("account", acentry.strAccount));
1157 entry.push_back(Pair("category", "move"));
1158 entry.push_back(Pair("time", (int64_t)acentry.nTime));
1159 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1160 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1161 entry.push_back(Pair("comment", acentry.strComment));
1162 ret.push_back(entry);
1166 Value listtransactions(const Array& params, bool fHelp)
1168 if (fHelp || params.size() > 3)
1169 throw runtime_error(
1170 "listtransactions [account] [count=10] [from=0]\n"
1171 "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1173 string strAccount = "*";
1174 if (params.size() > 0)
1175 strAccount = params[0].get_str();
1177 if (params.size() > 1)
1178 nCount = params[1].get_int();
1180 if (params.size() > 2)
1181 nFrom = params[2].get_int();
1183 isminefilter filter = MINE_SPENDABLE;
1184 if(params.size() > 3)
1185 if(params[3].get_bool())
1186 filter = filter | MINE_WATCH_ONLY;
1189 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count");
1191 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative from");
1195 std::list<CAccountingEntry> acentries;
1196 CWallet::TxItems txOrdered = pwalletMain->OrderedTxItems(acentries, strAccount);
1198 // iterate backwards until we have nCount items to return:
1199 for (CWallet::TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
1201 CWalletTx *const pwtx = (*it).second.first;
1203 ListTransactions(*pwtx, strAccount, 0, true, ret, filter);
1204 CAccountingEntry *const pacentry = (*it).second.second;
1206 AcentryToJSON(*pacentry, strAccount, ret);
1208 if ((int)ret.size() >= (nCount+nFrom)) break;
1210 // ret is newest to oldest
1212 if (nFrom > (int)ret.size())
1214 if ((nFrom + nCount) > (int)ret.size())
1215 nCount = ret.size() - nFrom;
1216 Array::iterator first = ret.begin();
1217 std::advance(first, nFrom);
1218 Array::iterator last = ret.begin();
1219 std::advance(last, nFrom+nCount);
1221 if (last != ret.end()) ret.erase(last, ret.end());
1222 if (first != ret.begin()) ret.erase(ret.begin(), first);
1224 std::reverse(ret.begin(), ret.end()); // Return oldest to newest
1229 Value listaccounts(const Array& params, bool fHelp)
1231 if (fHelp || params.size() > 1)
1232 throw runtime_error(
1233 "listaccounts [minconf=1]\n"
1234 "Returns Object that has account names as keys, account balances as values.");
1237 if (params.size() > 0)
1238 nMinDepth = params[0].get_int();
1240 isminefilter includeWatchonly = MINE_SPENDABLE;
1241 if(params.size() > 1)
1242 if(params[1].get_bool())
1243 includeWatchonly = includeWatchonly | MINE_WATCH_ONLY;
1246 map<string, int64_t> mapAccountBalances;
1247 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& entry, pwalletMain->mapAddressBook) {
1248 if (IsMine(*pwalletMain, entry.first)) // This address belongs to me
1249 mapAccountBalances[entry.second] = 0;
1252 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1254 const CWalletTx& wtx = (*it).second;
1255 int64_t nGeneratedImmature, nGeneratedMature, nFee;
1256 string strSentAccount;
1257 list<pair<CBitcoinAddress, int64_t> > listReceived;
1258 list<pair<CBitcoinAddress, int64_t> > listSent;
1259 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount, includeWatchonly);
1260 mapAccountBalances[strSentAccount] -= nFee;
1261 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64_t)& s, listSent)
1262 mapAccountBalances[strSentAccount] -= s.second;
1263 if (wtx.GetDepthInMainChain() >= nMinDepth)
1265 mapAccountBalances[""] += nGeneratedMature;
1266 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64_t)& r, listReceived)
1267 if (pwalletMain->mapAddressBook.count(r.first))
1268 mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1270 mapAccountBalances[""] += r.second;
1274 list<CAccountingEntry> acentries;
1275 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1276 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1277 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1280 BOOST_FOREACH(const PAIRTYPE(string, int64_t)& accountBalance, mapAccountBalances) {
1281 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1286 Value listsinceblock(const Array& params, bool fHelp)
1289 throw runtime_error(
1290 "listsinceblock [blockhash] [target-confirmations]\n"
1291 "Get all transactions in blocks since block [blockhash], or all transactions if omitted");
1293 CBlockIndex *pindex = NULL;
1294 int target_confirms = 1;
1295 isminefilter filter = MINE_SPENDABLE;
1297 if (params.size() > 0)
1299 uint256 blockId = 0;
1301 blockId.SetHex(params[0].get_str());
1302 pindex = CBlockLocator(blockId).GetBlockIndex();
1305 if (params.size() > 1)
1307 target_confirms = params[1].get_int();
1309 if (target_confirms < 1)
1310 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter");
1313 if(params.size() > 2)
1314 if(params[2].get_bool())
1315 filter = filter | MINE_WATCH_ONLY;
1317 int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
1321 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1323 CWalletTx tx = (*it).second;
1325 if (depth == -1 || tx.GetDepthInMainChain() < depth)
1326 ListTransactions(tx, "*", 0, true, transactions, filter);
1331 if (target_confirms == 1)
1333 lastblock = hashBestChain;
1337 int target_height = pindexBest->nHeight + 1 - target_confirms;
1340 for (block = pindexBest;
1341 block && block->nHeight > target_height;
1342 block = block->pprev) { }
1344 lastblock = block ? block->GetBlockHash() : 0;
1348 ret.push_back(Pair("transactions", transactions));
1349 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1354 Value gettransaction(const Array& params, bool fHelp)
1356 if (fHelp || params.size() != 1)
1357 throw runtime_error(
1358 "gettransaction <txid>\n"
1359 "Get detailed information about <txid>");
1362 hash.SetHex(params[0].get_str());
1364 isminefilter filter = MINE_SPENDABLE;
1365 if(params.size() > 1)
1366 if(params[1].get_bool())
1367 filter = filter | MINE_WATCH_ONLY;
1371 if (pwalletMain->mapWallet.count(hash))
1373 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1375 TxToJSON(wtx, 0, entry);
1377 int64_t nCredit = wtx.GetCredit(filter);
1378 int64_t nDebit = wtx.GetDebit(filter);
1379 int64_t nNet = nCredit - nDebit;
1380 int64_t nFee = (wtx.IsFromMe(filter) ? wtx.GetValueOut() - nDebit : 0);
1382 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1383 if (wtx.IsFromMe(filter))
1384 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1386 WalletTxToJSON(wtx, entry);
1389 ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details, filter);
1390 entry.push_back(Pair("details", details));
1395 uint256 hashBlock = 0;
1396 if (GetTransaction(hash, tx, hashBlock))
1398 TxToJSON(tx, 0, entry);
1400 entry.push_back(Pair("confirmations", 0));
1403 entry.push_back(Pair("blockhash", hashBlock.GetHex()));
1404 map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
1405 if (mi != mapBlockIndex.end() && (*mi).second)
1407 CBlockIndex* pindex = (*mi).second;
1408 if (pindex->IsInMainChain())
1409 entry.push_back(Pair("confirmations", 1 + nBestHeight - pindex->nHeight));
1411 entry.push_back(Pair("confirmations", 0));
1416 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction");
1423 Value backupwallet(const Array& params, bool fHelp)
1425 if (fHelp || params.size() != 1)
1426 throw runtime_error(
1427 "backupwallet <destination>\n"
1428 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1430 string strDest = params[0].get_str();
1431 if (!BackupWallet(*pwalletMain, strDest))
1432 throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!");
1438 Value keypoolrefill(const Array& params, bool fHelp)
1440 if (fHelp || params.size() > 1)
1441 throw runtime_error(
1442 "keypoolrefill [new-size]\n"
1443 "Fills the keypool.\n"
1444 "IMPORTANT: Any previous backups you have made of your wallet file "
1445 "should be replaced with the newly generated one."
1446 + HelpRequiringPassphrase());
1448 unsigned int nSize = max<unsigned int>(GetArgUInt("-keypool", 100), 0);
1449 if (params.size() > 0) {
1450 if (params[0].get_int() < 0)
1451 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size");
1452 nSize = (unsigned int) params[0].get_int();
1455 EnsureWalletIsUnlocked();
1457 pwalletMain->TopUpKeyPool(nSize);
1459 if (pwalletMain->GetKeyPoolSize() < nSize)
1460 throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool.");
1465 Value keypoolreset(const Array& params, bool fHelp)
1467 if (fHelp || params.size() > 1)
1468 throw runtime_error(
1469 "keypoolreset [new-size]\n"
1470 "Resets the keypool.\n"
1471 "IMPORTANT: Any previous backups you have made of your wallet file "
1472 "should be replaced with the newly generated one."
1473 + HelpRequiringPassphrase());
1475 unsigned int nSize = max<unsigned int>(GetArgUInt("-keypool", 100), 0);
1476 if (params.size() > 0) {
1477 if (params[0].get_int() < 0)
1478 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size");
1479 nSize = (unsigned int) params[0].get_int();
1482 EnsureWalletIsUnlocked();
1484 pwalletMain->NewKeyPool(nSize);
1486 if (pwalletMain->GetKeyPoolSize() < nSize)
1487 throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool.");
1493 void ThreadTopUpKeyPool(void* parg)
1495 // Make this thread recognisable as the key-topping-up thread
1496 RenameThread("novacoin-key-top");
1498 pwalletMain->TopUpKeyPool();
1501 void ThreadCleanWalletPassphrase(void* parg)
1503 // Make this thread recognisable as the wallet relocking thread
1504 RenameThread("novacoin-lock-wa");
1506 int64_t nMyWakeTime = GetTimeMillis() + *((int64_t*)parg) * 1000;
1508 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1510 if (nWalletUnlockTime == 0)
1512 nWalletUnlockTime = nMyWakeTime;
1516 if (nWalletUnlockTime==0)
1518 int64_t nToSleep = nWalletUnlockTime - GetTimeMillis();
1522 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1524 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1528 if (nWalletUnlockTime)
1530 nWalletUnlockTime = 0;
1531 pwalletMain->Lock();
1536 if (nWalletUnlockTime < nMyWakeTime)
1537 nWalletUnlockTime = nMyWakeTime;
1540 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1542 delete (int64_t*)parg;
1545 Value walletpassphrase(const Array& params, bool fHelp)
1547 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 3))
1548 throw runtime_error(
1549 "walletpassphrase <passphrase> <timeout> [mintonly]\n"
1550 "Stores the wallet decryption key in memory for <timeout> seconds.\n"
1551 "mintonly is optional true/false allowing only block minting.");
1554 if (!pwalletMain->IsCrypted())
1555 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1557 if (!pwalletMain->IsLocked())
1558 throw JSONRPCError(RPC_WALLET_ALREADY_UNLOCKED, "Error: Wallet is already unlocked, use walletlock first if need to change unlock settings.");
1559 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1560 SecureString strWalletPass;
1561 strWalletPass.reserve(100);
1562 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1563 // Alternately, find a way to make params[0] mlock()'d to begin with.
1564 strWalletPass = params[0].get_str().c_str();
1566 if (strWalletPass.length() > 0)
1568 if (!pwalletMain->Unlock(strWalletPass))
1569 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
1572 throw runtime_error(
1573 "walletpassphrase <passphrase> <timeout>\n"
1574 "Stores the wallet decryption key in memory for <timeout> seconds.");
1576 NewThread(ThreadTopUpKeyPool, NULL);
1577 int64_t* pnSleepTime = new int64_t(params[1].get_int64());
1578 NewThread(ThreadCleanWalletPassphrase, pnSleepTime);
1580 // ppcoin: if user OS account compromised prevent trivial sendmoney commands
1581 if (params.size() > 2)
1582 fWalletUnlockMintOnly = params[2].get_bool();
1584 fWalletUnlockMintOnly = false;
1590 Value walletpassphrasechange(const Array& params, bool fHelp)
1592 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1593 throw runtime_error(
1594 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1595 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1598 if (!pwalletMain->IsCrypted())
1599 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1601 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1602 // Alternately, find a way to make params[0] mlock()'d to begin with.
1603 SecureString strOldWalletPass;
1604 strOldWalletPass.reserve(100);
1605 strOldWalletPass = params[0].get_str().c_str();
1607 SecureString strNewWalletPass;
1608 strNewWalletPass.reserve(100);
1609 strNewWalletPass = params[1].get_str().c_str();
1611 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1612 throw runtime_error(
1613 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1614 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1616 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1617 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
1623 Value walletlock(const Array& params, bool fHelp)
1625 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1626 throw runtime_error(
1628 "Removes the wallet encryption key from memory, locking the wallet.\n"
1629 "After calling this method, you will need to call walletpassphrase again\n"
1630 "before being able to call any methods which require the wallet to be unlocked.");
1633 if (!pwalletMain->IsCrypted())
1634 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletlock was called.");
1637 LOCK(cs_nWalletUnlockTime);
1638 pwalletMain->Lock();
1639 nWalletUnlockTime = 0;
1646 Value encryptwallet(const Array& params, bool fHelp)
1648 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1649 throw runtime_error(
1650 "encryptwallet <passphrase>\n"
1651 "Encrypts the wallet with <passphrase>.");
1654 if (pwalletMain->IsCrypted())
1655 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an encrypted wallet, but encryptwallet was called.");
1657 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1658 // Alternately, find a way to make params[0] mlock()'d to begin with.
1659 SecureString strWalletPass;
1660 strWalletPass.reserve(100);
1661 strWalletPass = params[0].get_str().c_str();
1663 if (strWalletPass.length() < 1)
1664 throw runtime_error(
1665 "encryptwallet <passphrase>\n"
1666 "Encrypts the wallet with <passphrase>.");
1668 if (!pwalletMain->EncryptWallet(strWalletPass))
1669 throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: Failed to encrypt the wallet.");
1671 // BDB seems to have a bad habit of writing old data into
1672 // slack space in .dat files; that is bad if the old data is
1673 // unencrypted private keys. So:
1675 return "wallet encrypted; NovaCoin server stopping, restart to run with encrypted wallet. The keypool has been flushed, you need to make a new backup.";
1678 class DescribeAddressVisitor : public boost::static_visitor<Object>
1683 DescribeAddressVisitor(isminetype mineIn) : mine(mineIn) {}
1685 Object operator()(const CNoDestination &dest) const { return Object(); }
1686 Object operator()(const CKeyID &keyID) const {
1689 pwalletMain->GetPubKey(keyID, vchPubKey);
1690 obj.push_back(Pair("isscript", false));
1691 if (mine == MINE_SPENDABLE) {
1692 pwalletMain->GetPubKey(keyID, vchPubKey);
1693 obj.push_back(Pair("pubkey", HexStr(vchPubKey.Raw())));
1694 obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed()));
1699 Object operator()(const CScriptID &scriptID) const {
1701 obj.push_back(Pair("isscript", true));
1702 if (mine == MINE_SPENDABLE) {
1704 pwalletMain->GetCScript(scriptID, subscript);
1705 std::vector<CTxDestination> addresses;
1706 txnouttype whichType;
1708 ExtractDestinations(subscript, whichType, addresses, nRequired);
1709 obj.push_back(Pair("script", GetTxnOutputType(whichType)));
1710 obj.push_back(Pair("hex", HexStr(subscript.begin(), subscript.end())));
1712 BOOST_FOREACH(const CTxDestination& addr, addresses)
1713 a.push_back(CBitcoinAddress(addr).ToString());
1714 obj.push_back(Pair("addresses", a));
1715 if (whichType == TX_MULTISIG)
1716 obj.push_back(Pair("sigsrequired", nRequired));
1722 Value validateaddress(const Array& params, bool fHelp)
1724 if (fHelp || params.size() != 1)
1725 throw runtime_error(
1726 "validateaddress <novacoinaddress>\n"
1727 "Return information about <novacoinaddress>.");
1729 CBitcoinAddress address(params[0].get_str());
1730 bool isValid = address.IsValid();
1733 ret.push_back(Pair("isvalid", isValid));
1736 if (address.IsPair())
1738 CMalleablePubKey mpk;
1739 mpk.setvch(address.GetData());
1740 ret.push_back(Pair("ispair", true));
1742 CMalleableKeyView view;
1743 bool isMine = pwalletMain->GetMalleableView(mpk, view);
1744 ret.push_back(Pair("ismine", isMine));
1747 ret.push_back(Pair("KeyView", view.ToString()));
1751 string currentAddress = address.ToString();
1752 CTxDestination dest = address.Get();
1753 ret.push_back(Pair("address", currentAddress));
1754 isminetype mine = pwalletMain ? IsMine(*pwalletMain, address) : MINE_NO;
1755 ret.push_back(Pair("ismine", mine != MINE_NO));
1756 if (mine != MINE_NO) {
1757 ret.push_back(Pair("watchonly", mine == MINE_WATCH_ONLY));
1758 Object detail = boost::apply_visitor(DescribeAddressVisitor(mine), dest);
1759 ret.insert(ret.end(), detail.begin(), detail.end());
1761 if (pwalletMain->mapAddressBook.count(address))
1762 ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
1768 // ppcoin: reserve balance from being staked for network protection
1769 Value reservebalance(const Array& params, bool fHelp)
1771 if (fHelp || params.size() > 2)
1772 throw runtime_error(
1773 "reservebalance [<reserve> [amount]]\n"
1774 "<reserve> is true or false to turn balance reserve on or off.\n"
1775 "<amount> is a real and rounded to cent.\n"
1776 "Set reserve amount not participating in network protection.\n"
1777 "If no parameters provided current setting is printed.\n");
1779 if (params.size() > 0)
1781 bool fReserve = params[0].get_bool();
1784 if (params.size() == 1)
1785 throw runtime_error("must provide amount to reserve balance.\n");
1786 int64_t nAmount = AmountFromValue(params[1]);
1787 nAmount = (nAmount / CENT) * CENT; // round to cent
1789 throw runtime_error("amount cannot be negative.\n");
1790 mapArgs["-reservebalance"] = FormatMoney(nAmount);
1794 if (params.size() > 1)
1795 throw runtime_error("cannot specify amount to turn off reserve.\n");
1796 mapArgs["-reservebalance"] = "0";
1801 if (mapArgs.count("-reservebalance") && !ParseMoney(mapArgs["-reservebalance"], nReserveBalance))
1802 throw runtime_error("invalid reserve balance amount\n");
1803 result.push_back(Pair("reserve", (nReserveBalance > 0)));
1804 result.push_back(Pair("amount", ValueFromAmount(nReserveBalance)));
1809 // ppcoin: check wallet integrity
1810 Value checkwallet(const Array& params, bool fHelp)
1812 if (fHelp || params.size() > 0)
1813 throw runtime_error(
1815 "Check wallet for integrity.\n");
1818 int64_t nBalanceInQuestion;
1819 pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion, true);
1821 if (nMismatchSpent == 0)
1822 result.push_back(Pair("wallet check passed", true));
1825 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
1826 result.push_back(Pair("amount in question", ValueFromAmount(nBalanceInQuestion)));
1832 // ppcoin: repair wallet
1833 Value repairwallet(const Array& params, bool fHelp)
1835 if (fHelp || params.size() > 0)
1836 throw runtime_error(
1838 "Repair wallet if checkwallet reports any problem.\n");
1841 int64_t nBalanceInQuestion;
1842 pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion);
1844 if (nMismatchSpent == 0)
1845 result.push_back(Pair("wallet check passed", true));
1848 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
1849 result.push_back(Pair("amount affected by repair", ValueFromAmount(nBalanceInQuestion)));
1854 // NovaCoin: resend unconfirmed wallet transactions
1855 Value resendtx(const Array& params, bool fHelp)
1857 if (fHelp || params.size() > 1)
1858 throw runtime_error(
1860 "Re-send unconfirmed transactions.\n"
1863 ResendWalletTransactions(true);
1868 // Make a public-private key pair
1869 Value makekeypair(const Array& params, bool fHelp)
1871 if (fHelp || params.size() > 0)
1872 throw runtime_error(
1874 "Make a public/private key pair.\n");
1876 string strPrefix = "";
1877 if (params.size() > 0)
1878 strPrefix = params[0].get_str();
1881 key.MakeNewKey(true);
1883 CPrivKey vchPrivKey = key.GetPrivKey();
1885 result.push_back(Pair("PrivateKey", HexStr<CPrivKey::iterator>(vchPrivKey.begin(), vchPrivKey.end())));
1888 CSecret vchSecret = key.GetSecret(fCompressed);
1889 result.push_back(Pair("Secret", HexStr<CSecret::iterator>(vchSecret.begin(), vchSecret.end())));
1890 result.push_back(Pair("PublicKey", HexStr(key.GetPubKey().Raw())));
1894 Value newmalleablekey(const Array& params, bool fHelp)
1896 if (fHelp || params.size() > 0)
1897 throw runtime_error(
1899 "Make a malleable public/private key pair.\n");
1901 if (!(fDebug || fTestNet) && GetTime() < SMALLDATA_SWITCH_TIME)
1902 throw runtime_error("This feature has been disabled for mainNet clients");
1904 CMalleableKeyView keyView = pwalletMain->GenerateNewMalleableKey();
1907 if (!pwalletMain->GetMalleableKey(keyView, mKey))
1908 throw runtime_error("Unable to generate new malleable key");
1910 CMalleablePubKey mPubKey = mKey.GetMalleablePubKey();
1913 result.push_back(Pair("PublicPair", mPubKey.ToString()));
1914 result.push_back(Pair("PublicBytes", HexStr(mPubKey.Raw())));
1915 result.push_back(Pair("Address", CBitcoinAddress(mPubKey).ToString()));
1916 result.push_back(Pair("KeyView", keyView.ToString()));
1921 Value adjustmalleablekey(const Array& params, bool fHelp)
1923 if (fHelp || params.size() != 3)
1924 throw runtime_error(
1925 "adjustmalleablekey <Malleable key data> <Public key variant data> <R data>\n"
1926 "Calculate new private key using provided malleable key, public key and R data.\n");
1928 CMalleableKey malleableKey;
1929 malleableKey.SetString(params[0].get_str());
1931 CKey privKeyVariant;
1932 CPubKey vchPubKeyVariant = CPubKey(ParseHex(params[1].get_str()));
1934 CPubKey R(ParseHex(params[2].get_str()));
1936 if (!malleableKey.CheckKeyVariant(R,vchPubKeyVariant, privKeyVariant)) {
1937 throw runtime_error("Unable to calculate the private key");
1942 CSecret vchPrivKeyVariant = privKeyVariant.GetSecret(fCompressed);
1944 result.push_back(Pair("PrivateKey", CBitcoinSecret(vchPrivKeyVariant, fCompressed).ToString()));
1949 Value adjustmalleablepubkey(const Array& params, bool fHelp)
1951 if (fHelp || params.size() > 2 || params.size() == 0)
1952 throw runtime_error(
1953 "adjustmalleablepubkey <Malleable public key data>\n"
1954 "Calculate new public key using provided malleable public key data.\n");
1956 string pubKeyPair = params[0].get_str();
1957 CMalleablePubKey malleablePubKey;
1959 if (pubKeyPair.size() == 136) {
1960 malleablePubKey.setvch(ParseHex(pubKeyPair));
1962 malleablePubKey.SetString(pubKeyPair);
1964 CPubKey R, vchPubKeyVariant;
1965 malleablePubKey.GetVariant(R, vchPubKeyVariant);
1968 result.push_back(Pair("R", HexStr(R.Raw())));
1969 result.push_back(Pair("PubkeyVariant", HexStr(vchPubKeyVariant.Raw())));
1970 result.push_back(Pair("KeyVariantID", CBitcoinAddress(vchPubKeyVariant.GetID()).ToString()));
1975 Value listmalleableviews(const Array& params, bool fHelp)
1977 if (fHelp || params.size() != 0)
1978 throw runtime_error(
1979 "listmalleableviews\n"
1980 "Get list of views for generated malleable keys.\n");
1982 std::list<CMalleableKeyView> keyViewList;
1983 pwalletMain->ListMalleableViews(keyViewList);
1986 BOOST_FOREACH(const CMalleableKeyView &keyView, keyViewList)
1988 result.push_back(keyView.ToString());