1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2012 The Bitcoin developers
3 // Distributed under the MIT/X11 software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
8 #include "bitcoinrpc.h"
14 using namespace json_spirit;
17 int64_t nWalletUnlockTime;
18 static CCriticalSection cs_nWalletUnlockTime;
20 extern int64_t nReserveBalance;
21 extern void TxToJSON(const CTransaction& tx, const uint256& hashBlock, json_spirit::Object& entry);
23 std::string HelpRequiringPassphrase()
25 return pwalletMain->IsCrypted()
26 ? "\n\nRequires wallet passphrase to be set with walletpassphrase first"
30 void EnsureWalletIsUnlocked()
32 if (pwalletMain->IsLocked())
33 throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
34 if (fWalletUnlockMintOnly)
35 throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Wallet unlocked for block minting only.");
38 void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
40 int confirms = wtx.GetDepthInMainChain();
41 entry.push_back(Pair("confirmations", confirms));
42 if (wtx.IsCoinBase() || wtx.IsCoinStake())
43 entry.push_back(Pair("generated", true));
46 entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex()));
47 entry.push_back(Pair("blockindex", wtx.nIndex));
48 entry.push_back(Pair("blocktime", (int64_t)(mapBlockIndex[wtx.hashBlock]->nTime)));
50 entry.push_back(Pair("txid", wtx.GetHash().GetHex()));
51 entry.push_back(Pair("time", (int64_t)wtx.GetTxTime()));
52 entry.push_back(Pair("timereceived", (int64_t)wtx.nTimeReceived));
53 BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
54 entry.push_back(Pair(item.first, item.second));
57 string AccountFromValue(const Value& value)
59 string strAccount = value.get_str();
60 if (strAccount == "*")
61 throw JSONRPCError(RPC_WALLET_INVALID_ACCOUNT_NAME, "Invalid account name");
65 Value getinfo(const Array& params, bool fHelp)
67 if (fHelp || params.size() != 0)
70 "Returns an object containing various state info.");
73 GetProxy(NET_IPV4, proxy);
75 Object obj, diff, timestamping;
76 obj.push_back(Pair("version", FormatFullVersion()));
77 obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION));
78 obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
79 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
80 obj.push_back(Pair("unspendable", ValueFromAmount(pwalletMain->GetWatchOnlyBalance())));
81 obj.push_back(Pair("newmint", ValueFromAmount(pwalletMain->GetNewMint())));
82 obj.push_back(Pair("stake", ValueFromAmount(pwalletMain->GetStake())));
83 obj.push_back(Pair("blocks", (int)nBestHeight));
85 timestamping.push_back(Pair("systemclock", GetTime()));
86 timestamping.push_back(Pair("adjustedtime", GetAdjustedTime()));
88 int64_t nNtpOffset = GetNtpOffset(),
89 nP2POffset = GetNodesOffset();
91 timestamping.push_back(Pair("ntpoffset", nNtpOffset != INT64_MAX ? nNtpOffset : Value::null));
92 timestamping.push_back(Pair("p2poffset", nP2POffset != INT64_MAX ? nP2POffset : Value::null));
94 obj.push_back(Pair("timestamping", timestamping));
96 obj.push_back(Pair("moneysupply", ValueFromAmount(pindexBest->nMoneySupply)));
97 obj.push_back(Pair("connections", (int)vNodes.size()));
98 obj.push_back(Pair("proxy", (proxy.first.IsValid() ? proxy.first.ToStringIPPort() : string())));
99 obj.push_back(Pair("ip", addrSeenByPeer.ToStringIP()));
101 diff.push_back(Pair("proof-of-work", GetDifficulty()));
102 diff.push_back(Pair("proof-of-stake", GetDifficulty(GetLastBlockIndex(pindexBest, true))));
103 obj.push_back(Pair("difficulty", diff));
105 obj.push_back(Pair("testnet", fTestNet));
106 obj.push_back(Pair("keypoololdest", (int64_t)pwalletMain->GetOldestKeyPoolTime()));
107 obj.push_back(Pair("keypoolsize", (int)pwalletMain->GetKeyPoolSize()));
108 obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee)));
109 obj.push_back(Pair("mininput", ValueFromAmount(nMinimumInputValue)));
110 if (pwalletMain->IsCrypted())
111 obj.push_back(Pair("unlocked_until", (int64_t)nWalletUnlockTime / 1000));
112 obj.push_back(Pair("errors", GetWarnings("statusbar")));
116 Value getnewaddress(const Array& params, bool fHelp)
118 if (fHelp || params.size() > 1)
120 "getnewaddress [account]\n"
121 "Returns a new NovaCoin address for receiving payments. "
122 "If [account] is specified (recommended), it is added to the address book "
123 "so payments received with the address will be credited to [account].");
125 // Parse the account first so we don't generate a key if there's an error
127 if (params.size() > 0)
128 strAccount = AccountFromValue(params[0]);
130 if (!pwalletMain->IsLocked())
131 pwalletMain->TopUpKeyPool();
133 // Generate a new key that is added to wallet
135 if (!pwalletMain->GetKeyFromPool(newKey, false))
136 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
137 CKeyID keyID = newKey.GetID();
139 pwalletMain->SetAddressBookName(keyID, strAccount);
141 return CBitcoinAddress(keyID).ToString();
145 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
147 CWalletDB walletdb(pwalletMain->strWalletFile);
150 walletdb.ReadAccount(strAccount, account);
152 bool bKeyUsed = false;
154 // Check if the current key has been used
155 if (account.vchPubKey.IsValid())
157 CScript scriptPubKey;
158 scriptPubKey.SetDestination(account.vchPubKey.GetID());
159 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
160 it != pwalletMain->mapWallet.end() && account.vchPubKey.IsValid();
163 const CWalletTx& wtx = (*it).second;
164 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
165 if (txout.scriptPubKey == scriptPubKey)
170 // Generate a new key
171 if (!account.vchPubKey.IsValid() || bForceNew || bKeyUsed)
173 if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false))
174 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
176 pwalletMain->SetAddressBookName(account.vchPubKey.GetID(), strAccount);
177 walletdb.WriteAccount(strAccount, account);
180 return CBitcoinAddress(account.vchPubKey.GetID());
183 Value getaccountaddress(const Array& params, bool fHelp)
185 if (fHelp || params.size() != 1)
187 "getaccountaddress <account>\n"
188 "Returns the current NovaCoin address for receiving payments to this account.");
190 // Parse the account first so we don't generate a key if there's an error
191 string strAccount = AccountFromValue(params[0]);
195 ret = GetAccountAddress(strAccount).ToString();
202 Value setaccount(const Array& params, bool fHelp)
204 if (fHelp || params.size() < 1 || params.size() > 2)
206 "setaccount <novacoinaddress> <account>\n"
207 "Sets the account associated with the given address.");
209 CBitcoinAddress address(params[0].get_str());
210 if (!address.IsValid())
211 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
215 if (params.size() > 1)
216 strAccount = AccountFromValue(params[1]);
218 // Detect when changing the account of an address that is the 'unused current key' of another account:
219 if (pwalletMain->mapAddressBook.count(address.Get()))
221 string strOldAccount = pwalletMain->mapAddressBook[address.Get()];
222 if (address == GetAccountAddress(strOldAccount))
223 GetAccountAddress(strOldAccount, true);
226 pwalletMain->SetAddressBookName(address.Get(), strAccount);
232 Value getaccount(const Array& params, bool fHelp)
234 if (fHelp || params.size() != 1)
236 "getaccount <novacoinaddress>\n"
237 "Returns the account associated with the given address.");
239 CBitcoinAddress address(params[0].get_str());
240 if (!address.IsValid())
241 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
244 map<CTxDestination, string>::iterator mi = pwalletMain->mapAddressBook.find(address.Get());
245 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
246 strAccount = (*mi).second;
251 Value getaddressesbyaccount(const Array& params, bool fHelp)
253 if (fHelp || params.size() != 1)
255 "getaddressesbyaccount <account>\n"
256 "Returns the list of addresses for the given account.");
258 string strAccount = AccountFromValue(params[0]);
260 // Find all addresses that have the given account
262 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
264 const CBitcoinAddress& address = item.first;
265 const string& strName = item.second;
266 if (strName == strAccount)
267 ret.push_back(address.ToString());
272 Value mergecoins(const Array& params, bool fHelp)
274 if (fHelp || params.size() != 3)
276 "mergecoins <amount> <minvalue> <outputvalue>\n"
277 "<amount> is resulting inputs sum\n"
278 "<minvalue> is minimum value of inputs which are used in join process\n"
279 "<outputvalue> is resulting value of inputs which will be created\n"
280 "All values are real and and rounded to the nearest " + FormatMoney(nMinimumInputValue)
281 + HelpRequiringPassphrase());
283 if (pwalletMain->IsLocked())
284 throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
287 int64_t nAmount = AmountFromValue(params[0]);
290 int64_t nMinValue = AmountFromValue(params[1]);
293 int64_t nOutputValue = AmountFromValue(params[2]);
295 if (nAmount < nMinimumInputValue)
296 throw JSONRPCError(-101, "Send amount too small");
298 if (nMinValue < nMinimumInputValue)
299 throw JSONRPCError(-101, "Max value too small");
301 if (nOutputValue < nMinimumInputValue)
302 throw JSONRPCError(-101, "Output value too small");
304 if (nOutputValue < nMinValue)
305 throw JSONRPCError(-101, "Output value is lower than min value");
307 list<uint256> listMerged;
308 if (!pwalletMain->MergeCoins(nAmount, nMinValue, nOutputValue, listMerged))
312 BOOST_FOREACH(const uint256 txHash, listMerged)
313 mergedHashes.push_back(txHash.GetHex());
318 Value sendtoaddress(const Array& params, bool fHelp)
320 if (fHelp || params.size() < 2 || params.size() > 4)
322 "sendtoaddress <novacoinaddress> <amount> [comment] [comment-to]\n"
323 "<amount> is a real and is rounded to the nearest " + FormatMoney(nMinimumInputValue)
324 + HelpRequiringPassphrase());
327 CScript scriptPubKey;
328 string strAddress = params[0].get_str();
330 CBitcoinAddress address(strAddress);
331 if (address.IsValid())
333 if (!address.IsPair())
334 scriptPubKey.SetDestination(address.Get());
337 CMalleablePubKey mpk;
338 if (!mpk.setvch(address.GetData()))
339 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
341 CPubKey R, pubKeyVariant;
342 mpk.GetVariant(R, pubKeyVariant);
343 scriptPubKey.SetDestination(R, pubKeyVariant);
347 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
350 int64_t nAmount = AmountFromValue(params[1]);
352 if (nAmount < nMinimumInputValue)
353 throw JSONRPCError(-101, "Send amount too small");
357 if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
358 wtx.mapValue["comment"] = params[2].get_str();
359 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
360 wtx.mapValue["to"] = params[3].get_str();
362 if (pwalletMain->IsLocked())
363 throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
365 string strError = pwalletMain->SendMoney(scriptPubKey, nAmount, wtx);
367 throw JSONRPCError(RPC_WALLET_ERROR, strError);
369 return wtx.GetHash().GetHex();
372 Value listaddressgroupings(const Array& params, bool fHelp)
376 "listaddressgroupings\n"
377 "Lists groups of addresses which have had their common ownership\n"
378 "made public by common use as inputs or as the resulting change\n"
379 "in past transactions");
382 map<CTxDestination, int64_t> balances = pwalletMain->GetAddressBalances();
383 BOOST_FOREACH(set<CTxDestination> grouping, pwalletMain->GetAddressGroupings())
386 BOOST_FOREACH(CTxDestination address, grouping)
389 addressInfo.push_back(CBitcoinAddress(address).ToString());
390 addressInfo.push_back(ValueFromAmount(balances[address]));
392 LOCK(pwalletMain->cs_wallet);
393 if (pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get()) != pwalletMain->mapAddressBook.end())
394 addressInfo.push_back(pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get())->second);
396 jsonGrouping.push_back(addressInfo);
398 jsonGroupings.push_back(jsonGrouping);
400 return jsonGroupings;
403 Value signmessage(const Array& params, bool fHelp)
405 if (fHelp || params.size() != 2)
407 "signmessage <novacoinaddress> <message>\n"
408 "Sign a message with the private key of an address");
410 EnsureWalletIsUnlocked();
412 string strAddress = params[0].get_str();
413 string strMessage = params[1].get_str();
415 CBitcoinAddress addr(strAddress);
417 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
420 if (!addr.GetKeyID(keyID))
421 throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
424 if (!pwalletMain->GetKey(keyID, key))
425 throw JSONRPCError(RPC_WALLET_ERROR, "Private key not available");
427 CDataStream ss(SER_GETHASH, 0);
428 ss << strMessageMagic;
431 vector<unsigned char> vchSig;
432 if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
433 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed");
435 return EncodeBase64(&vchSig[0], vchSig.size());
438 Value verifymessage(const Array& params, bool fHelp)
440 if (fHelp || params.size() != 3)
442 "verifymessage <novacoinaddress> <signature> <message>\n"
443 "Verify a signed message");
445 string strAddress = params[0].get_str();
446 string strSign = params[1].get_str();
447 string strMessage = params[2].get_str();
449 CBitcoinAddress addr(strAddress);
451 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
454 if (!addr.GetKeyID(keyID))
455 throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
457 bool fInvalid = false;
458 vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
461 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Malformed base64 encoding");
463 CDataStream ss(SER_GETHASH, 0);
464 ss << strMessageMagic;
468 if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
471 return (key.GetPubKey().GetID() == keyID);
475 Value getreceivedbyaddress(const Array& params, bool fHelp)
477 if (fHelp || params.size() < 1 || params.size() > 2)
479 "getreceivedbyaddress <novacoinaddress> [minconf=1]\n"
480 "Returns the total amount received by <novacoinaddress> in transactions with at least [minconf] confirmations.");
483 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
484 CScript scriptPubKey;
485 if (!address.IsValid())
486 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
487 scriptPubKey.SetDestination(address.Get());
488 if (!IsMine(*pwalletMain,scriptPubKey))
491 // Minimum confirmations
493 if (params.size() > 1)
494 nMinDepth = params[1].get_int();
498 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
500 const CWalletTx& wtx = (*it).second;
501 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
504 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
505 if (txout.scriptPubKey == scriptPubKey)
506 if (wtx.GetDepthInMainChain() >= nMinDepth)
507 nAmount += txout.nValue;
510 return ValueFromAmount(nAmount);
514 void GetAccountAddresses(string strAccount, set<CTxDestination>& setAddress)
516 BOOST_FOREACH(const PAIRTYPE(CTxDestination, string)& item, pwalletMain->mapAddressBook)
518 const CTxDestination& address = item.first;
519 const string& strName = item.second;
520 if (strName == strAccount)
521 setAddress.insert(address);
525 Value getreceivedbyaccount(const Array& params, bool fHelp)
527 if (fHelp || params.size() < 1 || params.size() > 2)
529 "getreceivedbyaccount <account> [minconf=1]\n"
530 "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
532 // Minimum confirmations
534 if (params.size() > 1)
535 nMinDepth = params[1].get_int();
537 // Get the set of pub keys assigned to account
538 string strAccount = AccountFromValue(params[0]);
539 set<CTxDestination> setAddress;
540 GetAccountAddresses(strAccount, setAddress);
544 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
546 const CWalletTx& wtx = (*it).second;
547 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
550 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
552 CTxDestination address;
553 if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*pwalletMain, address) && setAddress.count(address))
554 if (wtx.GetDepthInMainChain() >= nMinDepth)
555 nAmount += txout.nValue;
559 return (double)nAmount / (double)COIN;
563 int64_t GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth, const isminefilter& filter)
565 int64_t nBalance = 0;
567 // Tally wallet transactions
568 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
570 const CWalletTx& wtx = (*it).second;
574 int64_t nGenerated, nReceived, nSent, nFee;
575 wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee, filter);
577 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
578 nBalance += nReceived;
579 nBalance += nGenerated - nSent - nFee;
582 // Tally internal accounting entries
583 nBalance += walletdb.GetAccountCreditDebit(strAccount);
588 int64_t GetAccountBalance(const string& strAccount, int nMinDepth, const isminefilter& filter)
590 CWalletDB walletdb(pwalletMain->strWalletFile);
591 return GetAccountBalance(walletdb, strAccount, nMinDepth, filter);
595 Value getbalance(const Array& params, bool fHelp)
597 if (fHelp || params.size() > 2)
599 "getbalance [account] [minconf=1] [watchonly=0]\n"
600 "If [account] is not specified, returns the server's total available balance.\n"
601 "If [account] is specified, returns the balance in the account.\n"
602 "if [includeWatchonly] is specified, include balance in watchonly addresses (see 'importaddress').");
604 if (params.size() == 0)
605 return ValueFromAmount(pwalletMain->GetBalance());
608 if (params.size() > 1)
609 nMinDepth = params[1].get_int();
610 isminefilter filter = MINE_SPENDABLE;
611 if(params.size() > 2)
612 if(params[2].get_bool())
613 filter = filter | MINE_WATCH_ONLY;
615 if (params[0].get_str() == "*") {
616 // Calculate total balance a different way from GetBalance()
617 // (GetBalance() sums up all unspent TxOuts)
618 // getbalance and getbalance '*' 0 should return the same number.
619 int64_t nBalance = 0;
620 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
622 const CWalletTx& wtx = (*it).second;
623 if (!wtx.IsTrusted())
626 int64_t allGeneratedImmature, allGeneratedMature, allFee;
627 allGeneratedImmature = allGeneratedMature = allFee = 0;
629 string strSentAccount;
630 list<pair<CTxDestination, int64_t> > listReceived;
631 list<pair<CTxDestination, int64_t> > listSent;
632 wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount, filter);
633 if (wtx.GetDepthInMainChain() >= nMinDepth)
635 BOOST_FOREACH(const PAIRTYPE(CTxDestination,int64_t)& r, listReceived)
636 nBalance += r.second;
638 BOOST_FOREACH(const PAIRTYPE(CTxDestination,int64_t)& r, listSent)
639 nBalance -= r.second;
641 nBalance += allGeneratedMature;
643 return ValueFromAmount(nBalance);
646 string strAccount = AccountFromValue(params[0]);
648 int64_t nBalance = GetAccountBalance(strAccount, nMinDepth, filter);
650 return ValueFromAmount(nBalance);
654 Value movecmd(const Array& params, bool fHelp)
656 if (fHelp || params.size() < 3 || params.size() > 5)
658 "move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
659 "Move from one account in your wallet to another.");
661 string strFrom = AccountFromValue(params[0]);
662 string strTo = AccountFromValue(params[1]);
663 int64_t nAmount = AmountFromValue(params[2]);
665 if (nAmount < nMinimumInputValue)
666 throw JSONRPCError(-101, "Send amount too small");
668 if (params.size() > 3)
669 // unused parameter, used to be nMinDepth, keep type-checking it though
670 (void)params[3].get_int();
672 if (params.size() > 4)
673 strComment = params[4].get_str();
675 CWalletDB walletdb(pwalletMain->strWalletFile);
676 if (!walletdb.TxnBegin())
677 throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
679 int64_t nNow = GetAdjustedTime();
682 CAccountingEntry debit;
683 debit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
684 debit.strAccount = strFrom;
685 debit.nCreditDebit = -nAmount;
687 debit.strOtherAccount = strTo;
688 debit.strComment = strComment;
689 walletdb.WriteAccountingEntry(debit);
692 CAccountingEntry credit;
693 credit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
694 credit.strAccount = strTo;
695 credit.nCreditDebit = nAmount;
697 credit.strOtherAccount = strFrom;
698 credit.strComment = strComment;
699 walletdb.WriteAccountingEntry(credit);
701 if (!walletdb.TxnCommit())
702 throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
708 Value sendfrom(const Array& params, bool fHelp)
710 if (fHelp || params.size() < 3 || params.size() > 6)
712 "sendfrom <fromaccount> <tonovacoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
713 "<amount> is a real and is rounded to the nearest " + FormatMoney(nMinimumInputValue)
714 + HelpRequiringPassphrase());
716 string strAccount = AccountFromValue(params[0]);
719 CScript scriptPubKey;
720 string strAddress = params[0].get_str();
722 CBitcoinAddress address(strAddress);
723 if (address.IsValid())
725 if (!address.IsPair())
726 scriptPubKey.SetDestination(address.Get());
729 CMalleablePubKey mpk;
730 if (!mpk.setvch(address.GetData()))
731 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
733 CPubKey R, pubKeyVariant;
734 mpk.GetVariant(R, pubKeyVariant);
735 scriptPubKey.SetDestination(R, pubKeyVariant);
739 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
742 int64_t nAmount = AmountFromValue(params[2]);
744 if (nAmount < nMinimumInputValue)
745 throw JSONRPCError(-101, "Send amount too small");
748 if (params.size() > 3)
749 nMinDepth = params[3].get_int();
752 wtx.strFromAccount = strAccount;
753 if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
754 wtx.mapValue["comment"] = params[4].get_str();
755 if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
756 wtx.mapValue["to"] = params[5].get_str();
758 EnsureWalletIsUnlocked();
761 int64_t nBalance = GetAccountBalance(strAccount, nMinDepth, MINE_SPENDABLE);
762 if (nAmount > nBalance)
763 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
766 string strError = pwalletMain->SendMoney(scriptPubKey, nAmount, wtx);
768 throw JSONRPCError(RPC_WALLET_ERROR, strError);
770 return wtx.GetHash().GetHex();
774 Value sendmany(const Array& params, bool fHelp)
776 if (fHelp || params.size() < 2 || params.size() > 4)
778 "sendmany <fromaccount> '{address:amount,...}' [minconf=1] [comment]\n"
779 "amounts are double-precision floating point numbers"
780 + HelpRequiringPassphrase());
782 string strAccount = AccountFromValue(params[0]);
783 Object sendTo = params[1].get_obj();
785 if (params.size() > 2)
786 nMinDepth = params[2].get_int();
789 wtx.strFromAccount = strAccount;
790 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
791 wtx.mapValue["comment"] = params[3].get_str();
793 set<CBitcoinAddress> setAddress;
794 vector<pair<CScript, int64_t> > vecSend;
796 int64_t totalAmount = 0;
797 BOOST_FOREACH(const Pair& s, sendTo)
799 CBitcoinAddress address(s.name_);
800 if (!address.IsValid())
801 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid NovaCoin address: ")+s.name_);
803 if (setAddress.count(address))
804 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+s.name_);
805 setAddress.insert(address);
807 CScript scriptPubKey;
808 scriptPubKey.SetDestination(address.Get());
809 int64_t nAmount = AmountFromValue(s.value_);
811 if (nAmount < nMinimumInputValue)
812 throw JSONRPCError(-101, "Send amount too small");
814 totalAmount += nAmount;
816 vecSend.push_back(make_pair(scriptPubKey, nAmount));
819 EnsureWalletIsUnlocked();
822 int64_t nBalance = GetAccountBalance(strAccount, nMinDepth, MINE_SPENDABLE);
823 if (totalAmount > nBalance)
824 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
827 CReserveKey keyChange(pwalletMain);
828 int64_t nFeeRequired = 0;
829 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
832 int64_t nTotal = pwalletMain->GetBalance(), nWatchOnly = pwalletMain->GetWatchOnlyBalance();
833 if (totalAmount + nFeeRequired > nTotal - nWatchOnly)
834 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds");
835 throw JSONRPCError(RPC_WALLET_ERROR, "Transaction creation failed");
837 if (!pwalletMain->CommitTransaction(wtx, keyChange))
838 throw JSONRPCError(RPC_WALLET_ERROR, "Transaction commit failed");
840 return wtx.GetHash().GetHex();
843 Value addmultisigaddress(const Array& params, bool fHelp)
845 if (fHelp || params.size() < 2 || params.size() > 3)
847 string msg = "addmultisigaddress <nrequired> <'[\"key\",\"key\"]'> [account]\n"
848 "Add a nrequired-to-sign multisignature address to the wallet\"\n"
849 "each key is a NovaCoin address or hex-encoded public key\n"
850 "If [account] is specified, assign address to [account].";
851 throw runtime_error(msg);
854 int nRequired = params[0].get_int();
855 const Array& keys = params[1].get_array();
857 if (params.size() > 2)
858 strAccount = AccountFromValue(params[2]);
860 // Gather public keys
862 throw runtime_error("a multisignature address must require at least one key to redeem");
863 if ((int)keys.size() < nRequired)
865 strprintf("not enough keys supplied "
866 "(got %" PRIszu " keys, but need at least %d to redeem)", keys.size(), nRequired));
867 if (keys.size() > 16)
868 throw runtime_error("Number of addresses involved in the multisignature address creation > 16\nReduce the number");
869 std::vector<CKey> pubkeys;
870 pubkeys.resize(keys.size());
871 for (unsigned int i = 0; i < keys.size(); i++)
873 const std::string& ks = keys[i].get_str();
875 // Case 1: Bitcoin address and we have full public key:
876 CBitcoinAddress address(ks);
877 if (address.IsValid())
880 if (!address.GetKeyID(keyID))
882 strprintf("%s does not refer to a key",ks.c_str()));
884 if (!pwalletMain->GetPubKey(keyID, vchPubKey))
886 strprintf("no full public key for address %s",ks.c_str()));
887 if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey))
888 throw runtime_error(" Invalid public key: "+ks);
891 // Case 2: hex public key
894 CPubKey vchPubKey(ParseHex(ks));
895 if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey))
896 throw runtime_error(" Invalid public key: "+ks);
900 throw runtime_error(" Invalid public key: "+ks);
904 // Construct using pay-to-script-hash:
906 inner.SetMultisig(nRequired, pubkeys);
908 if (inner.size() > MAX_SCRIPT_ELEMENT_SIZE)
910 strprintf("redeemScript exceeds size limit: %" PRIszu " > %d", inner.size(), MAX_SCRIPT_ELEMENT_SIZE));
912 CScriptID innerID = inner.GetID();
913 pwalletMain->AddCScript(inner);
915 pwalletMain->SetAddressBookName(innerID, strAccount);
916 return CBitcoinAddress(innerID).ToString();
919 Value addredeemscript(const Array& params, bool fHelp)
921 if (fHelp || params.size() < 1 || params.size() > 2)
923 string msg = "addredeemscript <redeemScript> [account]\n"
924 "Add a P2SH address with a specified redeemScript to the wallet.\n"
925 "If [account] is specified, assign address to [account].";
926 throw runtime_error(msg);
930 if (params.size() > 1)
931 strAccount = AccountFromValue(params[1]);
933 // Construct using pay-to-script-hash:
934 vector<unsigned char> innerData = ParseHexV(params[0], "redeemScript");
935 CScript inner(innerData.begin(), innerData.end());
936 CScriptID innerID = inner.GetID();
937 pwalletMain->AddCScript(inner);
939 pwalletMain->SetAddressBookName(innerID, strAccount);
940 return CBitcoinAddress(innerID).ToString();
950 nConf = std::numeric_limits<int>::max();
954 Value ListReceived(const Array& params, bool fByAccounts)
956 // Minimum confirmations
958 if (params.size() > 0)
959 nMinDepth = params[0].get_int();
961 // Whether to include empty accounts
962 bool fIncludeEmpty = false;
963 if (params.size() > 1)
964 fIncludeEmpty = params[1].get_bool();
967 map<CBitcoinAddress, tallyitem> mapTally;
968 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
970 const CWalletTx& wtx = (*it).second;
972 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
975 int nDepth = wtx.GetDepthInMainChain();
976 if (nDepth < nMinDepth)
979 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
981 CTxDestination address;
982 if (!ExtractDestination(txout.scriptPubKey, address) || !IsMine(*pwalletMain, address))
985 tallyitem& item = mapTally[address];
986 item.nAmount += txout.nValue;
987 item.nConf = min(item.nConf, nDepth);
993 map<string, tallyitem> mapAccountTally;
994 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
996 const CBitcoinAddress& address = item.first;
997 const string& strAccount = item.second;
998 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
999 if (it == mapTally.end() && !fIncludeEmpty)
1002 int64_t nAmount = 0;
1003 int nConf = std::numeric_limits<int>::max();
1004 if (it != mapTally.end())
1006 nAmount = (*it).second.nAmount;
1007 nConf = (*it).second.nConf;
1012 tallyitem& item = mapAccountTally[strAccount];
1013 item.nAmount += nAmount;
1014 item.nConf = min(item.nConf, nConf);
1019 obj.push_back(Pair("address", address.ToString()));
1020 obj.push_back(Pair("account", strAccount));
1021 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1022 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1029 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
1031 int64_t nAmount = (*it).second.nAmount;
1032 int nConf = (*it).second.nConf;
1034 obj.push_back(Pair("account", (*it).first));
1035 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1036 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1044 Value listreceivedbyaddress(const Array& params, bool fHelp)
1046 if (fHelp || params.size() > 2)
1047 throw runtime_error(
1048 "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
1049 "[minconf] is the minimum number of confirmations before payments are included.\n"
1050 "[includeempty] whether to include addresses that haven't received any payments.\n"
1051 "Returns an array of objects containing:\n"
1052 " \"address\" : receiving address\n"
1053 " \"account\" : the account of the receiving address\n"
1054 " \"amount\" : total amount received by the address\n"
1055 " \"confirmations\" : number of confirmations of the most recent transaction included");
1057 return ListReceived(params, false);
1060 Value listreceivedbyaccount(const Array& params, bool fHelp)
1062 if (fHelp || params.size() > 2)
1063 throw runtime_error(
1064 "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
1065 "[minconf] is the minimum number of confirmations before payments are included.\n"
1066 "[includeempty] whether to include accounts that haven't received any payments.\n"
1067 "Returns an array of objects containing:\n"
1068 " \"account\" : the account of the receiving addresses\n"
1069 " \"amount\" : total amount received by addresses with this account\n"
1070 " \"confirmations\" : number of confirmations of the most recent transaction included");
1072 return ListReceived(params, true);
1075 static void MaybePushAddress(Object & entry, const CTxDestination &dest)
1077 CBitcoinAddress addr;
1079 entry.push_back(Pair("address", addr.ToString()));
1082 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret, const isminefilter& filter)
1084 int64_t nGeneratedImmature, nGeneratedMature, nFee;
1085 string strSentAccount;
1086 list<pair<CTxDestination, int64_t> > listReceived;
1087 list<pair<CTxDestination, int64_t> > listSent;
1089 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount, filter);
1091 bool fAllAccounts = (strAccount == string("*"));
1092 bool involvesWatchonly = wtx.IsFromMe(MINE_WATCH_ONLY);
1094 // Generated blocks assigned to account ""
1095 if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
1098 entry.push_back(Pair("account", string("")));
1099 if (nGeneratedImmature)
1101 entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
1102 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
1106 entry.push_back(Pair("category", "generate"));
1107 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
1110 WalletTxToJSON(wtx, entry);
1111 ret.push_back(entry);
1115 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1117 BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64_t)& s, listSent)
1120 entry.push_back(Pair("account", strSentAccount));
1121 if(involvesWatchonly || (::IsMine(*pwalletMain, s.first) & MINE_WATCH_ONLY))
1122 entry.push_back(Pair("involvesWatchonly", true));
1123 MaybePushAddress(entry, s.first);
1125 if (wtx.GetDepthInMainChain() < 0) {
1126 entry.push_back(Pair("category", "conflicted"));
1128 entry.push_back(Pair("category", "send"));
1131 entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1132 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1134 WalletTxToJSON(wtx, entry);
1135 ret.push_back(entry);
1140 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1142 BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64_t)& r, listReceived)
1145 if (pwalletMain->mapAddressBook.count(r.first))
1146 account = pwalletMain->mapAddressBook[r.first];
1147 if (fAllAccounts || (account == strAccount))
1150 entry.push_back(Pair("account", account));
1151 if(involvesWatchonly || (::IsMine(*pwalletMain, r.first) & MINE_WATCH_ONLY))
1152 entry.push_back(Pair("involvesWatchonly", true));
1153 MaybePushAddress(entry, r.first);
1154 if (wtx.IsCoinBase())
1156 if (wtx.GetDepthInMainChain() < 1)
1157 entry.push_back(Pair("category", "orphan"));
1158 else if (wtx.GetBlocksToMaturity() > 0)
1159 entry.push_back(Pair("category", "immature"));
1161 entry.push_back(Pair("category", "generate"));
1164 entry.push_back(Pair("category", "receive"));
1165 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1167 WalletTxToJSON(wtx, entry);
1168 ret.push_back(entry);
1174 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1176 bool fAllAccounts = (strAccount == string("*"));
1178 if (fAllAccounts || acentry.strAccount == strAccount)
1181 entry.push_back(Pair("account", acentry.strAccount));
1182 entry.push_back(Pair("category", "move"));
1183 entry.push_back(Pair("time", (int64_t)acentry.nTime));
1184 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1185 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1186 entry.push_back(Pair("comment", acentry.strComment));
1187 ret.push_back(entry);
1191 Value listtransactions(const Array& params, bool fHelp)
1193 if (fHelp || params.size() > 3)
1194 throw runtime_error(
1195 "listtransactions [account] [count=10] [from=0]\n"
1196 "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1198 string strAccount = "*";
1199 if (params.size() > 0)
1200 strAccount = params[0].get_str();
1202 if (params.size() > 1)
1203 nCount = params[1].get_int();
1205 if (params.size() > 2)
1206 nFrom = params[2].get_int();
1208 isminefilter filter = MINE_SPENDABLE;
1209 if(params.size() > 3)
1210 if(params[3].get_bool())
1211 filter = filter | MINE_WATCH_ONLY;
1214 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count");
1216 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative from");
1220 std::list<CAccountingEntry> acentries;
1221 CWallet::TxItems txOrdered = pwalletMain->OrderedTxItems(acentries, strAccount);
1223 // iterate backwards until we have nCount items to return:
1224 for (CWallet::TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
1226 CWalletTx *const pwtx = (*it).second.first;
1228 ListTransactions(*pwtx, strAccount, 0, true, ret, filter);
1229 CAccountingEntry *const pacentry = (*it).second.second;
1231 AcentryToJSON(*pacentry, strAccount, ret);
1233 if ((int)ret.size() >= (nCount+nFrom)) break;
1235 // ret is newest to oldest
1237 if (nFrom > (int)ret.size())
1239 if ((nFrom + nCount) > (int)ret.size())
1240 nCount = ret.size() - nFrom;
1241 Array::iterator first = ret.begin();
1242 std::advance(first, nFrom);
1243 Array::iterator last = ret.begin();
1244 std::advance(last, nFrom+nCount);
1246 if (last != ret.end()) ret.erase(last, ret.end());
1247 if (first != ret.begin()) ret.erase(ret.begin(), first);
1249 std::reverse(ret.begin(), ret.end()); // Return oldest to newest
1254 Value listaccounts(const Array& params, bool fHelp)
1256 if (fHelp || params.size() > 1)
1257 throw runtime_error(
1258 "listaccounts [minconf=1]\n"
1259 "Returns Object that has account names as keys, account balances as values.");
1262 if (params.size() > 0)
1263 nMinDepth = params[0].get_int();
1265 isminefilter includeWatchonly = MINE_SPENDABLE;
1266 if(params.size() > 1)
1267 if(params[1].get_bool())
1268 includeWatchonly = includeWatchonly | MINE_WATCH_ONLY;
1271 map<string, int64_t> mapAccountBalances;
1272 BOOST_FOREACH(const PAIRTYPE(CTxDestination, string)& entry, pwalletMain->mapAddressBook) {
1273 if (IsMine(*pwalletMain, entry.first)) // This address belongs to me
1274 mapAccountBalances[entry.second] = 0;
1277 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1279 const CWalletTx& wtx = (*it).second;
1280 int64_t nGeneratedImmature, nGeneratedMature, nFee;
1281 string strSentAccount;
1282 list<pair<CTxDestination, int64_t> > listReceived;
1283 list<pair<CTxDestination, int64_t> > listSent;
1284 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount, includeWatchonly);
1285 mapAccountBalances[strSentAccount] -= nFee;
1286 BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64_t)& s, listSent)
1287 mapAccountBalances[strSentAccount] -= s.second;
1288 if (wtx.GetDepthInMainChain() >= nMinDepth)
1290 mapAccountBalances[""] += nGeneratedMature;
1291 BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64_t)& r, listReceived)
1292 if (pwalletMain->mapAddressBook.count(r.first))
1293 mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1295 mapAccountBalances[""] += r.second;
1299 list<CAccountingEntry> acentries;
1300 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1301 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1302 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1305 BOOST_FOREACH(const PAIRTYPE(string, int64_t)& accountBalance, mapAccountBalances) {
1306 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1311 Value listsinceblock(const Array& params, bool fHelp)
1314 throw runtime_error(
1315 "listsinceblock [blockhash] [target-confirmations]\n"
1316 "Get all transactions in blocks since block [blockhash], or all transactions if omitted");
1318 CBlockIndex *pindex = NULL;
1319 int target_confirms = 1;
1320 isminefilter filter = MINE_SPENDABLE;
1322 if (params.size() > 0)
1324 uint256 blockId = 0;
1326 blockId.SetHex(params[0].get_str());
1327 pindex = CBlockLocator(blockId).GetBlockIndex();
1330 if (params.size() > 1)
1332 target_confirms = params[1].get_int();
1334 if (target_confirms < 1)
1335 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter");
1338 if(params.size() > 2)
1339 if(params[2].get_bool())
1340 filter = filter | MINE_WATCH_ONLY;
1342 int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
1346 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1348 CWalletTx tx = (*it).second;
1350 if (depth == -1 || tx.GetDepthInMainChain() < depth)
1351 ListTransactions(tx, "*", 0, true, transactions, filter);
1356 if (target_confirms == 1)
1358 lastblock = hashBestChain;
1362 int target_height = pindexBest->nHeight + 1 - target_confirms;
1365 for (block = pindexBest;
1366 block && block->nHeight > target_height;
1367 block = block->pprev) { }
1369 lastblock = block ? block->GetBlockHash() : 0;
1373 ret.push_back(Pair("transactions", transactions));
1374 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1379 Value gettransaction(const Array& params, bool fHelp)
1381 if (fHelp || params.size() != 1)
1382 throw runtime_error(
1383 "gettransaction <txid>\n"
1384 "Get detailed information about <txid>");
1387 hash.SetHex(params[0].get_str());
1389 isminefilter filter = MINE_SPENDABLE;
1390 if(params.size() > 1)
1391 if(params[1].get_bool())
1392 filter = filter | MINE_WATCH_ONLY;
1396 if (pwalletMain->mapWallet.count(hash))
1398 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1400 TxToJSON(wtx, 0, entry);
1402 int64_t nCredit = wtx.GetCredit(filter);
1403 int64_t nDebit = wtx.GetDebit(filter);
1404 int64_t nNet = nCredit - nDebit;
1405 int64_t nFee = (wtx.IsFromMe(filter) ? wtx.GetValueOut() - nDebit : 0);
1407 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1408 if (wtx.IsFromMe(filter))
1409 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1411 WalletTxToJSON(wtx, entry);
1414 ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details, filter);
1415 entry.push_back(Pair("details", details));
1420 uint256 hashBlock = 0;
1421 if (GetTransaction(hash, tx, hashBlock))
1423 TxToJSON(tx, 0, entry);
1425 entry.push_back(Pair("confirmations", 0));
1428 entry.push_back(Pair("blockhash", hashBlock.GetHex()));
1429 map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
1430 if (mi != mapBlockIndex.end() && (*mi).second)
1432 CBlockIndex* pindex = (*mi).second;
1433 if (pindex->IsInMainChain())
1434 entry.push_back(Pair("confirmations", 1 + nBestHeight - pindex->nHeight));
1436 entry.push_back(Pair("confirmations", 0));
1441 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction");
1448 Value backupwallet(const Array& params, bool fHelp)
1450 if (fHelp || params.size() != 1)
1451 throw runtime_error(
1452 "backupwallet <destination>\n"
1453 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1455 string strDest = params[0].get_str();
1456 if (!BackupWallet(*pwalletMain, strDest))
1457 throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!");
1463 Value keypoolrefill(const Array& params, bool fHelp)
1465 if (fHelp || params.size() > 1)
1466 throw runtime_error(
1467 "keypoolrefill [new-size]\n"
1468 "Fills the keypool.\n"
1469 "IMPORTANT: Any previous backups you have made of your wallet file "
1470 "should be replaced with the newly generated one."
1471 + HelpRequiringPassphrase());
1473 unsigned int nSize = max<unsigned int>(GetArgUInt("-keypool", 100), 0);
1474 if (params.size() > 0) {
1475 if (params[0].get_int() < 0)
1476 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size");
1477 nSize = (unsigned int) params[0].get_int();
1480 EnsureWalletIsUnlocked();
1482 pwalletMain->TopUpKeyPool(nSize);
1484 if (pwalletMain->GetKeyPoolSize() < nSize)
1485 throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool.");
1490 Value keypoolreset(const Array& params, bool fHelp)
1492 if (fHelp || params.size() > 1)
1493 throw runtime_error(
1494 "keypoolreset [new-size]\n"
1495 "Resets the keypool.\n"
1496 "IMPORTANT: Any previous backups you have made of your wallet file "
1497 "should be replaced with the newly generated one."
1498 + HelpRequiringPassphrase());
1500 unsigned int nSize = max<unsigned int>(GetArgUInt("-keypool", 100), 0);
1501 if (params.size() > 0) {
1502 if (params[0].get_int() < 0)
1503 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size");
1504 nSize = (unsigned int) params[0].get_int();
1507 EnsureWalletIsUnlocked();
1509 pwalletMain->NewKeyPool(nSize);
1511 if (pwalletMain->GetKeyPoolSize() < nSize)
1512 throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool.");
1518 void ThreadTopUpKeyPool(void* parg)
1520 // Make this thread recognisable as the key-topping-up thread
1521 RenameThread("novacoin-key-top");
1523 pwalletMain->TopUpKeyPool();
1526 void ThreadCleanWalletPassphrase(void* parg)
1528 // Make this thread recognisable as the wallet relocking thread
1529 RenameThread("novacoin-lock-wa");
1531 int64_t nMyWakeTime = GetTimeMillis() + *((int64_t*)parg) * 1000;
1533 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1535 if (nWalletUnlockTime == 0)
1537 nWalletUnlockTime = nMyWakeTime;
1541 if (nWalletUnlockTime==0)
1543 int64_t nToSleep = nWalletUnlockTime - GetTimeMillis();
1547 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1549 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1553 if (nWalletUnlockTime)
1555 nWalletUnlockTime = 0;
1556 pwalletMain->Lock();
1561 if (nWalletUnlockTime < nMyWakeTime)
1562 nWalletUnlockTime = nMyWakeTime;
1565 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1567 delete (int64_t*)parg;
1570 Value walletpassphrase(const Array& params, bool fHelp)
1572 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 3))
1573 throw runtime_error(
1574 "walletpassphrase <passphrase> <timeout> [mintonly]\n"
1575 "Stores the wallet decryption key in memory for <timeout> seconds.\n"
1576 "mintonly is optional true/false allowing only block minting.");
1579 if (!pwalletMain->IsCrypted())
1580 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1582 if (!pwalletMain->IsLocked())
1583 throw JSONRPCError(RPC_WALLET_ALREADY_UNLOCKED, "Error: Wallet is already unlocked, use walletlock first if need to change unlock settings.");
1584 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1585 SecureString strWalletPass;
1586 strWalletPass.reserve(100);
1587 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1588 // Alternately, find a way to make params[0] mlock()'d to begin with.
1589 strWalletPass = params[0].get_str().c_str();
1591 if (strWalletPass.length() > 0)
1593 if (!pwalletMain->Unlock(strWalletPass))
1594 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
1597 throw runtime_error(
1598 "walletpassphrase <passphrase> <timeout>\n"
1599 "Stores the wallet decryption key in memory for <timeout> seconds.");
1601 NewThread(ThreadTopUpKeyPool, NULL);
1602 int64_t* pnSleepTime = new int64_t(params[1].get_int64());
1603 NewThread(ThreadCleanWalletPassphrase, pnSleepTime);
1605 // ppcoin: if user OS account compromised prevent trivial sendmoney commands
1606 if (params.size() > 2)
1607 fWalletUnlockMintOnly = params[2].get_bool();
1609 fWalletUnlockMintOnly = false;
1615 Value walletpassphrasechange(const Array& params, bool fHelp)
1617 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1618 throw runtime_error(
1619 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1620 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1623 if (!pwalletMain->IsCrypted())
1624 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1626 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1627 // Alternately, find a way to make params[0] mlock()'d to begin with.
1628 SecureString strOldWalletPass;
1629 strOldWalletPass.reserve(100);
1630 strOldWalletPass = params[0].get_str().c_str();
1632 SecureString strNewWalletPass;
1633 strNewWalletPass.reserve(100);
1634 strNewWalletPass = params[1].get_str().c_str();
1636 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1637 throw runtime_error(
1638 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1639 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1641 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1642 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
1648 Value walletlock(const Array& params, bool fHelp)
1650 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1651 throw runtime_error(
1653 "Removes the wallet encryption key from memory, locking the wallet.\n"
1654 "After calling this method, you will need to call walletpassphrase again\n"
1655 "before being able to call any methods which require the wallet to be unlocked.");
1658 if (!pwalletMain->IsCrypted())
1659 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletlock was called.");
1662 LOCK(cs_nWalletUnlockTime);
1663 pwalletMain->Lock();
1664 nWalletUnlockTime = 0;
1671 Value encryptwallet(const Array& params, bool fHelp)
1673 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1674 throw runtime_error(
1675 "encryptwallet <passphrase>\n"
1676 "Encrypts the wallet with <passphrase>.");
1679 if (pwalletMain->IsCrypted())
1680 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an encrypted wallet, but encryptwallet was called.");
1682 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1683 // Alternately, find a way to make params[0] mlock()'d to begin with.
1684 SecureString strWalletPass;
1685 strWalletPass.reserve(100);
1686 strWalletPass = params[0].get_str().c_str();
1688 if (strWalletPass.length() < 1)
1689 throw runtime_error(
1690 "encryptwallet <passphrase>\n"
1691 "Encrypts the wallet with <passphrase>.");
1693 if (!pwalletMain->EncryptWallet(strWalletPass))
1694 throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: Failed to encrypt the wallet.");
1696 // BDB seems to have a bad habit of writing old data into
1697 // slack space in .dat files; that is bad if the old data is
1698 // unencrypted private keys. So:
1700 return "wallet encrypted; NovaCoin server stopping, restart to run with encrypted wallet. The keypool has been flushed, you need to make a new backup.";
1703 class DescribeAddressVisitor : public boost::static_visitor<Object>
1708 DescribeAddressVisitor(isminetype mineIn) : mine(mineIn) {}
1710 Object operator()(const CNoDestination &dest) const { return Object(); }
1711 Object operator()(const CKeyID &keyID) const {
1714 pwalletMain->GetPubKey(keyID, vchPubKey);
1715 obj.push_back(Pair("isscript", false));
1716 if (mine == MINE_SPENDABLE) {
1717 pwalletMain->GetPubKey(keyID, vchPubKey);
1718 obj.push_back(Pair("pubkey", HexStr(vchPubKey.Raw())));
1719 obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed()));
1724 Object operator()(const CScriptID &scriptID) const {
1726 obj.push_back(Pair("isscript", true));
1727 if (mine == MINE_SPENDABLE) {
1729 pwalletMain->GetCScript(scriptID, subscript);
1730 std::vector<CTxDestination> addresses;
1731 txnouttype whichType;
1733 ExtractDestinations(subscript, whichType, addresses, nRequired);
1734 obj.push_back(Pair("script", GetTxnOutputType(whichType)));
1735 obj.push_back(Pair("hex", HexStr(subscript.begin(), subscript.end())));
1737 BOOST_FOREACH(const CTxDestination& addr, addresses)
1738 a.push_back(CBitcoinAddress(addr).ToString());
1739 obj.push_back(Pair("addresses", a));
1740 if (whichType == TX_MULTISIG)
1741 obj.push_back(Pair("sigsrequired", nRequired));
1747 Value validateaddress(const Array& params, bool fHelp)
1749 if (fHelp || params.size() != 1)
1750 throw runtime_error(
1751 "validateaddress <novacoinaddress>\n"
1752 "Return information about <novacoinaddress>.");
1754 CBitcoinAddress address(params[0].get_str());
1755 bool isValid = address.IsValid();
1758 ret.push_back(Pair("isvalid", isValid));
1761 if (address.IsPair())
1763 CMalleablePubKey mpk;
1764 mpk.setvch(address.GetData());
1765 ret.push_back(Pair("ispair", true));
1767 CMalleableKeyView view;
1768 bool isMine = pwalletMain->GetMalleableView(mpk, view);
1769 ret.push_back(Pair("ismine", isMine));
1772 ret.push_back(Pair("KeyView", view.ToString()));
1776 CTxDestination dest = address.Get();
1777 string currentAddress = address.ToString();
1778 ret.push_back(Pair("address", currentAddress));
1779 isminetype mine = pwalletMain ? IsMine(*pwalletMain, dest) : MINE_NO;
1780 ret.push_back(Pair("ismine", mine != MINE_NO));
1781 if (mine != MINE_NO) {
1782 ret.push_back(Pair("watchonly", mine == MINE_WATCH_ONLY));
1783 Object detail = boost::apply_visitor(DescribeAddressVisitor(mine), dest);
1784 ret.insert(ret.end(), detail.begin(), detail.end());
1786 if (pwalletMain->mapAddressBook.count(dest))
1787 ret.push_back(Pair("account", pwalletMain->mapAddressBook[dest]));
1793 // ppcoin: reserve balance from being staked for network protection
1794 Value reservebalance(const Array& params, bool fHelp)
1796 if (fHelp || params.size() > 2)
1797 throw runtime_error(
1798 "reservebalance [<reserve> [amount]]\n"
1799 "<reserve> is true or false to turn balance reserve on or off.\n"
1800 "<amount> is a real and rounded to cent.\n"
1801 "Set reserve amount not participating in network protection.\n"
1802 "If no parameters provided current setting is printed.\n");
1804 if (params.size() > 0)
1806 bool fReserve = params[0].get_bool();
1809 if (params.size() == 1)
1810 throw runtime_error("must provide amount to reserve balance.\n");
1811 int64_t nAmount = AmountFromValue(params[1]);
1812 nAmount = (nAmount / CENT) * CENT; // round to cent
1814 throw runtime_error("amount cannot be negative.\n");
1815 mapArgs["-reservebalance"] = FormatMoney(nAmount);
1819 if (params.size() > 1)
1820 throw runtime_error("cannot specify amount to turn off reserve.\n");
1821 mapArgs["-reservebalance"] = "0";
1826 if (mapArgs.count("-reservebalance") && !ParseMoney(mapArgs["-reservebalance"], nReserveBalance))
1827 throw runtime_error("invalid reserve balance amount\n");
1828 result.push_back(Pair("reserve", (nReserveBalance > 0)));
1829 result.push_back(Pair("amount", ValueFromAmount(nReserveBalance)));
1834 // ppcoin: check wallet integrity
1835 Value checkwallet(const Array& params, bool fHelp)
1837 if (fHelp || params.size() > 0)
1838 throw runtime_error(
1840 "Check wallet for integrity.\n");
1843 int64_t nBalanceInQuestion;
1844 pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion, true);
1846 if (nMismatchSpent == 0)
1847 result.push_back(Pair("wallet check passed", true));
1850 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
1851 result.push_back(Pair("amount in question", ValueFromAmount(nBalanceInQuestion)));
1857 // ppcoin: repair wallet
1858 Value repairwallet(const Array& params, bool fHelp)
1860 if (fHelp || params.size() > 0)
1861 throw runtime_error(
1863 "Repair wallet if checkwallet reports any problem.\n");
1866 int64_t nBalanceInQuestion;
1867 pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion);
1869 if (nMismatchSpent == 0)
1870 result.push_back(Pair("wallet check passed", true));
1873 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
1874 result.push_back(Pair("amount affected by repair", ValueFromAmount(nBalanceInQuestion)));
1879 // NovaCoin: resend unconfirmed wallet transactions
1880 Value resendtx(const Array& params, bool fHelp)
1882 if (fHelp || params.size() > 1)
1883 throw runtime_error(
1885 "Re-send unconfirmed transactions.\n"
1888 ResendWalletTransactions();
1893 // Make a public-private key pair
1894 Value makekeypair(const Array& params, bool fHelp)
1896 if (fHelp || params.size() > 0)
1897 throw runtime_error(
1899 "Make a public/private key pair.\n");
1901 string strPrefix = "";
1902 if (params.size() > 0)
1903 strPrefix = params[0].get_str();
1906 key.MakeNewKey(true);
1908 CPrivKey vchPrivKey = key.GetPrivKey();
1910 result.push_back(Pair("PrivateKey", HexStr<CPrivKey::iterator>(vchPrivKey.begin(), vchPrivKey.end())));
1913 CSecret vchSecret = key.GetSecret(fCompressed);
1914 result.push_back(Pair("Secret", HexStr<CSecret::iterator>(vchSecret.begin(), vchSecret.end())));
1915 result.push_back(Pair("PublicKey", HexStr(key.GetPubKey().Raw())));
1919 Value newmalleablekey(const Array& params, bool fHelp)
1921 if (fHelp || params.size() > 0)
1922 throw runtime_error(
1924 "Make a malleable public/private key pair.\n");
1926 if (!(fDebug || fTestNet) && GetTime() < SMALLDATA_SWITCH_TIME)
1927 throw runtime_error("This feature has been disabled for mainNet clients");
1929 CMalleableKeyView keyView = pwalletMain->GenerateNewMalleableKey();
1932 if (!pwalletMain->GetMalleableKey(keyView, mKey))
1933 throw runtime_error("Unable to generate new malleable key");
1935 CMalleablePubKey mPubKey = mKey.GetMalleablePubKey();
1938 result.push_back(Pair("PublicPair", mPubKey.ToString()));
1939 result.push_back(Pair("PublicBytes", HexStr(mPubKey.Raw())));
1940 result.push_back(Pair("Address", CBitcoinAddress(mPubKey).ToString()));
1941 result.push_back(Pair("KeyView", keyView.ToString()));
1946 Value adjustmalleablekey(const Array& params, bool fHelp)
1948 if (fHelp || params.size() != 3)
1949 throw runtime_error(
1950 "adjustmalleablekey <Malleable key data> <Public key variant data> <R data>\n"
1951 "Calculate new private key using provided malleable key, public key and R data.\n");
1953 CMalleableKey malleableKey;
1954 malleableKey.SetString(params[0].get_str());
1956 CKey privKeyVariant;
1957 CPubKey vchPubKeyVariant = CPubKey(ParseHex(params[1].get_str()));
1959 CPubKey R(ParseHex(params[2].get_str()));
1961 if (!malleableKey.CheckKeyVariant(R,vchPubKeyVariant, privKeyVariant)) {
1962 throw runtime_error("Unable to calculate the private key");
1967 CSecret vchPrivKeyVariant = privKeyVariant.GetSecret(fCompressed);
1969 result.push_back(Pair("PrivateKey", CBitcoinSecret(vchPrivKeyVariant, fCompressed).ToString()));
1974 Value adjustmalleablepubkey(const Array& params, bool fHelp)
1976 if (fHelp || params.size() > 2 || params.size() == 0)
1977 throw runtime_error(
1978 "adjustmalleablepubkey <Malleable public key data>\n"
1979 "Calculate new public key using provided malleable public key data.\n");
1981 string pubKeyPair = params[0].get_str();
1982 CMalleablePubKey malleablePubKey;
1984 if (pubKeyPair.size() == 136) {
1985 malleablePubKey.setvch(ParseHex(pubKeyPair));
1987 malleablePubKey.SetString(pubKeyPair);
1989 CPubKey R, vchPubKeyVariant;
1990 malleablePubKey.GetVariant(R, vchPubKeyVariant);
1993 result.push_back(Pair("R", HexStr(R.Raw())));
1994 result.push_back(Pair("PubkeyVariant", HexStr(vchPubKeyVariant.Raw())));
1995 result.push_back(Pair("KeyVariantID", CBitcoinAddress(vchPubKeyVariant.GetID()).ToString()));
2000 Value listmalleableviews(const Array& params, bool fHelp)
2002 if (fHelp || params.size() != 0)
2003 throw runtime_error(
2004 "listmalleableviews\n"
2005 "Get list of views for generated malleable keys.\n");
2007 std::list<CMalleableKeyView> keyViewList;
2008 pwalletMain->ListMalleableViews(keyViewList);
2011 BOOST_FOREACH(const CMalleableKeyView &keyView, keyViewList)
2013 result.push_back(keyView.ToString());