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(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);
353 if (!strError.empty())
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.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() > 3)
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[1].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);
741 if (!strError.empty())
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<CPubKey> 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())
865 throw runtime_error(" Invalid public key: "+ks);
866 pubkeys[i] = vchPubKey;
869 // Case 2: hex public key
872 CPubKey vchPubKey(ParseHex(ks));
873 if (!vchPubKey.IsValid())
874 throw runtime_error(" Invalid public key: "+ks);
875 pubkeys[i] = vchPubKey;
879 throw runtime_error(" Invalid public key: "+ks);
883 // Construct using pay-to-script-hash:
885 inner.SetMultisig(nRequired, pubkeys);
887 if (inner.size() > MAX_SCRIPT_ELEMENT_SIZE)
889 strprintf("redeemScript exceeds size limit: %" PRIszu " > %d", inner.size(), MAX_SCRIPT_ELEMENT_SIZE));
891 pwalletMain->AddCScript(inner);
892 CBitcoinAddress address(inner.GetID());
894 pwalletMain->SetAddressBookName(address, strAccount);
895 return address.ToString();
898 Value addredeemscript(const Array& params, bool fHelp)
900 if (fHelp || params.size() < 1 || params.size() > 2)
902 string msg = "addredeemscript <redeemScript> [account]\n"
903 "Add a P2SH address with a specified redeemScript to the wallet.\n"
904 "If [account] is specified, assign address to [account].";
905 throw runtime_error(msg);
909 if (params.size() > 1)
910 strAccount = AccountFromValue(params[1]);
912 // Construct using pay-to-script-hash:
913 vector<unsigned char> innerData = ParseHexV(params[0], "redeemScript");
914 CScript inner(innerData.begin(), innerData.end());
915 pwalletMain->AddCScript(inner);
916 CBitcoinAddress address(inner.GetID());
918 pwalletMain->SetAddressBookName(address, strAccount);
919 return address.ToString();
929 nConf = std::numeric_limits<int>::max();
933 Value ListReceived(const Array& params, bool fByAccounts)
935 // Minimum confirmations
937 if (params.size() > 0)
938 nMinDepth = params[0].get_int();
940 // Whether to include empty accounts
941 bool fIncludeEmpty = false;
942 if (params.size() > 1)
943 fIncludeEmpty = params[1].get_bool();
946 map<CBitcoinAddress, tallyitem> mapTally;
947 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
949 const CWalletTx& wtx = (*it).second;
951 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
954 int nDepth = wtx.GetDepthInMainChain();
955 if (nDepth < nMinDepth)
958 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
960 CTxDestination address;
961 if (!ExtractDestination(txout.scriptPubKey, address) || !IsMine(*pwalletMain, address))
964 tallyitem& item = mapTally[address];
965 item.nAmount += txout.nValue;
966 item.nConf = min(item.nConf, nDepth);
972 map<string, tallyitem> mapAccountTally;
973 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
975 const CBitcoinAddress& address = item.first;
976 const string& strAccount = item.second;
977 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
978 if (it == mapTally.end() && !fIncludeEmpty)
982 int nConf = std::numeric_limits<int>::max();
983 if (it != mapTally.end())
985 nAmount = (*it).second.nAmount;
986 nConf = (*it).second.nConf;
991 tallyitem& item = mapAccountTally[strAccount];
992 item.nAmount += nAmount;
993 item.nConf = min(item.nConf, nConf);
998 obj.push_back(Pair("address", address.ToString()));
999 obj.push_back(Pair("account", strAccount));
1000 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1001 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1008 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
1010 int64_t nAmount = (*it).second.nAmount;
1011 int nConf = (*it).second.nConf;
1013 obj.push_back(Pair("account", (*it).first));
1014 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1015 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1023 Value listreceivedbyaddress(const Array& params, bool fHelp)
1025 if (fHelp || params.size() > 2)
1026 throw runtime_error(
1027 "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
1028 "[minconf] is the minimum number of confirmations before payments are included.\n"
1029 "[includeempty] whether to include addresses that haven't received any payments.\n"
1030 "Returns an array of objects containing:\n"
1031 " \"address\" : receiving address\n"
1032 " \"account\" : the account of the receiving address\n"
1033 " \"amount\" : total amount received by the address\n"
1034 " \"confirmations\" : number of confirmations of the most recent transaction included");
1036 return ListReceived(params, false);
1039 Value listreceivedbyaccount(const Array& params, bool fHelp)
1041 if (fHelp || params.size() > 2)
1042 throw runtime_error(
1043 "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
1044 "[minconf] is the minimum number of confirmations before payments are included.\n"
1045 "[includeempty] whether to include accounts that haven't received any payments.\n"
1046 "Returns an array of objects containing:\n"
1047 " \"account\" : the account of the receiving addresses\n"
1048 " \"amount\" : total amount received by addresses with this account\n"
1049 " \"confirmations\" : number of confirmations of the most recent transaction included");
1051 return ListReceived(params, true);
1054 static void MaybePushAddress(Object & entry, const CBitcoinAddress &dest)
1056 entry.push_back(Pair("address", dest.ToString()));
1059 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret, const isminefilter& filter)
1061 int64_t nGeneratedImmature, nGeneratedMature, nFee;
1062 string strSentAccount;
1063 list<pair<CBitcoinAddress, int64_t> > listReceived;
1064 list<pair<CBitcoinAddress, int64_t> > listSent;
1066 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount, filter);
1068 bool fAllAccounts = (strAccount == string("*"));
1069 bool involvesWatchonly = wtx.IsFromMe(MINE_WATCH_ONLY);
1071 // Generated blocks assigned to account ""
1072 if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount.empty()))
1075 entry.push_back(Pair("account", string("")));
1076 if (nGeneratedImmature)
1078 entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
1079 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
1083 entry.push_back(Pair("category", "generate"));
1084 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
1087 WalletTxToJSON(wtx, entry);
1088 ret.push_back(entry);
1092 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1094 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64_t)& s, listSent)
1097 entry.push_back(Pair("account", strSentAccount));
1098 if(involvesWatchonly || (::IsMine(*pwalletMain, s.first) & MINE_WATCH_ONLY))
1099 entry.push_back(Pair("involvesWatchonly", true));
1100 MaybePushAddress(entry, s.first);
1102 if (wtx.GetDepthInMainChain() < 0) {
1103 entry.push_back(Pair("category", "conflicted"));
1105 entry.push_back(Pair("category", "send"));
1108 entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1109 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1111 WalletTxToJSON(wtx, entry);
1112 ret.push_back(entry);
1117 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1119 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64_t)& r, listReceived)
1122 if (pwalletMain->mapAddressBook.count(r.first))
1123 account = pwalletMain->mapAddressBook[r.first];
1124 if (fAllAccounts || (account == strAccount))
1127 entry.push_back(Pair("account", account));
1128 if(involvesWatchonly || (::IsMine(*pwalletMain, r.first) & MINE_WATCH_ONLY))
1129 entry.push_back(Pair("involvesWatchonly", true));
1130 MaybePushAddress(entry, r.first);
1131 if (wtx.IsCoinBase())
1133 if (wtx.GetDepthInMainChain() < 1)
1134 entry.push_back(Pair("category", "orphan"));
1135 else if (wtx.GetBlocksToMaturity() > 0)
1136 entry.push_back(Pair("category", "immature"));
1138 entry.push_back(Pair("category", "generate"));
1141 entry.push_back(Pair("category", "receive"));
1142 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1144 WalletTxToJSON(wtx, entry);
1145 ret.push_back(entry);
1151 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1153 bool fAllAccounts = (strAccount == string("*"));
1155 if (fAllAccounts || acentry.strAccount == strAccount)
1158 entry.push_back(Pair("account", acentry.strAccount));
1159 entry.push_back(Pair("category", "move"));
1160 entry.push_back(Pair("time", (int64_t)acentry.nTime));
1161 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1162 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1163 entry.push_back(Pair("comment", acentry.strComment));
1164 ret.push_back(entry);
1168 Value listtransactions(const Array& params, bool fHelp)
1170 if (fHelp || params.size() > 3)
1171 throw runtime_error(
1172 "listtransactions [account] [count=10] [from=0]\n"
1173 "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1175 string strAccount = "*";
1176 if (params.size() > 0)
1177 strAccount = params[0].get_str();
1179 if (params.size() > 1)
1180 nCount = params[1].get_int();
1182 if (params.size() > 2)
1183 nFrom = params[2].get_int();
1185 isminefilter filter = MINE_SPENDABLE;
1186 if(params.size() > 3)
1187 if(params[3].get_bool())
1188 filter = filter | MINE_WATCH_ONLY;
1191 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count");
1193 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative from");
1197 std::list<CAccountingEntry> acentries;
1198 CWallet::TxItems txOrdered = pwalletMain->OrderedTxItems(acentries, strAccount);
1200 // iterate backwards until we have nCount items to return:
1201 for (CWallet::TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
1203 CWalletTx *const pwtx = (*it).second.first;
1205 ListTransactions(*pwtx, strAccount, 0, true, ret, filter);
1206 CAccountingEntry *const pacentry = (*it).second.second;
1208 AcentryToJSON(*pacentry, strAccount, ret);
1210 if ((int)ret.size() >= (nCount+nFrom)) break;
1212 // ret is newest to oldest
1214 if (nFrom > (int)ret.size())
1216 if ((nFrom + nCount) > (int)ret.size())
1217 nCount = ret.size() - nFrom;
1218 Array::iterator first = ret.begin();
1219 std::advance(first, nFrom);
1220 Array::iterator last = ret.begin();
1221 std::advance(last, nFrom+nCount);
1223 if (last != ret.end()) ret.erase(last, ret.end());
1224 if (first != ret.begin()) ret.erase(ret.begin(), first);
1226 std::reverse(ret.begin(), ret.end()); // Return oldest to newest
1231 Value listaccounts(const Array& params, bool fHelp)
1233 if (fHelp || params.size() > 1)
1234 throw runtime_error(
1235 "listaccounts [minconf=1]\n"
1236 "Returns Object that has account names as keys, account balances as values.");
1239 if (params.size() > 0)
1240 nMinDepth = params[0].get_int();
1242 isminefilter includeWatchonly = MINE_SPENDABLE;
1243 if(params.size() > 1)
1244 if(params[1].get_bool())
1245 includeWatchonly = includeWatchonly | MINE_WATCH_ONLY;
1248 map<string, int64_t> mapAccountBalances;
1249 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& entry, pwalletMain->mapAddressBook) {
1250 if (IsMine(*pwalletMain, entry.first)) // This address belongs to me
1251 mapAccountBalances[entry.second] = 0;
1254 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1256 const CWalletTx& wtx = (*it).second;
1257 int64_t nGeneratedImmature, nGeneratedMature, nFee;
1258 string strSentAccount;
1259 list<pair<CBitcoinAddress, int64_t> > listReceived;
1260 list<pair<CBitcoinAddress, int64_t> > listSent;
1261 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount, includeWatchonly);
1262 mapAccountBalances[strSentAccount] -= nFee;
1263 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64_t)& s, listSent)
1264 mapAccountBalances[strSentAccount] -= s.second;
1265 if (wtx.GetDepthInMainChain() >= nMinDepth)
1267 mapAccountBalances[""] += nGeneratedMature;
1268 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64_t)& r, listReceived)
1269 if (pwalletMain->mapAddressBook.count(r.first))
1270 mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1272 mapAccountBalances[""] += r.second;
1276 list<CAccountingEntry> acentries;
1277 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1278 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1279 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1282 BOOST_FOREACH(const PAIRTYPE(string, int64_t)& accountBalance, mapAccountBalances) {
1283 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1288 Value listsinceblock(const Array& params, bool fHelp)
1291 throw runtime_error(
1292 "listsinceblock [blockhash] [target-confirmations]\n"
1293 "Get all transactions in blocks since block [blockhash], or all transactions if omitted");
1295 CBlockIndex *pindex = NULL;
1296 int target_confirms = 1;
1297 isminefilter filter = MINE_SPENDABLE;
1299 if (params.size() > 0)
1301 uint256 blockId = 0;
1303 blockId.SetHex(params[0].get_str());
1304 pindex = CBlockLocator(blockId).GetBlockIndex();
1307 if (params.size() > 1)
1309 target_confirms = params[1].get_int();
1311 if (target_confirms < 1)
1312 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter");
1315 if(params.size() > 2)
1316 if(params[2].get_bool())
1317 filter = filter | MINE_WATCH_ONLY;
1319 int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
1323 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1325 CWalletTx tx = (*it).second;
1327 if (depth == -1 || tx.GetDepthInMainChain() < depth)
1328 ListTransactions(tx, "*", 0, true, transactions, filter);
1333 if (target_confirms == 1)
1335 lastblock = hashBestChain;
1339 int target_height = pindexBest->nHeight + 1 - target_confirms;
1342 for (block = pindexBest;
1343 block && block->nHeight > target_height;
1344 block = block->pprev) { }
1346 lastblock = block ? block->GetBlockHash() : 0;
1350 ret.push_back(Pair("transactions", transactions));
1351 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1356 Value gettransaction(const Array& params, bool fHelp)
1358 if (fHelp || params.size() != 1)
1359 throw runtime_error(
1360 "gettransaction <txid>\n"
1361 "Get detailed information about <txid>");
1364 hash.SetHex(params[0].get_str());
1366 isminefilter filter = MINE_SPENDABLE;
1367 if(params.size() > 1)
1368 if(params[1].get_bool())
1369 filter = filter | MINE_WATCH_ONLY;
1373 if (pwalletMain->mapWallet.count(hash))
1375 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1377 TxToJSON(wtx, 0, entry);
1379 int64_t nCredit = wtx.GetCredit(filter);
1380 int64_t nDebit = wtx.GetDebit(filter);
1381 int64_t nNet = nCredit - nDebit;
1382 int64_t nFee = (wtx.IsFromMe(filter) ? wtx.GetValueOut() - nDebit : 0);
1384 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1385 if (wtx.IsFromMe(filter))
1386 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1388 WalletTxToJSON(wtx, entry);
1391 ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details, filter);
1392 entry.push_back(Pair("details", details));
1397 uint256 hashBlock = 0;
1398 if (GetTransaction(hash, tx, hashBlock))
1400 TxToJSON(tx, 0, entry);
1402 entry.push_back(Pair("confirmations", 0));
1405 entry.push_back(Pair("blockhash", hashBlock.GetHex()));
1406 map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
1407 if (mi != mapBlockIndex.end() && (*mi).second)
1409 CBlockIndex* pindex = (*mi).second;
1410 if (pindex->IsInMainChain())
1411 entry.push_back(Pair("confirmations", 1 + nBestHeight - pindex->nHeight));
1413 entry.push_back(Pair("confirmations", 0));
1418 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction");
1425 Value backupwallet(const Array& params, bool fHelp)
1427 if (fHelp || params.size() != 1)
1428 throw runtime_error(
1429 "backupwallet <destination>\n"
1430 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1432 string strDest = params[0].get_str();
1433 if (!BackupWallet(*pwalletMain, strDest))
1434 throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!");
1440 Value keypoolrefill(const Array& params, bool fHelp)
1442 if (fHelp || params.size() > 1)
1443 throw runtime_error(
1444 "keypoolrefill [new-size]\n"
1445 "Fills the keypool.\n"
1446 "IMPORTANT: Any previous backups you have made of your wallet file "
1447 "should be replaced with the newly generated one."
1448 + HelpRequiringPassphrase());
1450 unsigned int nSize = max<unsigned int>(GetArgUInt("-keypool", 100), 0);
1451 if (params.size() > 0) {
1452 if (params[0].get_int() < 0)
1453 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size");
1454 nSize = (unsigned int) params[0].get_int();
1457 EnsureWalletIsUnlocked();
1459 pwalletMain->TopUpKeyPool(nSize);
1461 if (pwalletMain->GetKeyPoolSize() < nSize)
1462 throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool.");
1467 Value keypoolreset(const Array& params, bool fHelp)
1469 if (fHelp || params.size() > 1)
1470 throw runtime_error(
1471 "keypoolreset [new-size]\n"
1472 "Resets the keypool.\n"
1473 "IMPORTANT: Any previous backups you have made of your wallet file "
1474 "should be replaced with the newly generated one."
1475 + HelpRequiringPassphrase());
1477 unsigned int nSize = max<unsigned int>(GetArgUInt("-keypool", 100), 0);
1478 if (params.size() > 0) {
1479 if (params[0].get_int() < 0)
1480 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size");
1481 nSize = (unsigned int) params[0].get_int();
1484 EnsureWalletIsUnlocked();
1486 pwalletMain->NewKeyPool(nSize);
1488 if (pwalletMain->GetKeyPoolSize() < nSize)
1489 throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool.");
1495 void ThreadTopUpKeyPool(void* parg)
1497 // Make this thread recognisable as the key-topping-up thread
1498 RenameThread("novacoin-key-top");
1500 pwalletMain->TopUpKeyPool();
1503 void ThreadCleanWalletPassphrase(void* parg)
1505 // Make this thread recognisable as the wallet relocking thread
1506 RenameThread("novacoin-lock-wa");
1508 int64_t nMyWakeTime = GetTimeMillis() + *((int64_t*)parg) * 1000;
1510 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1512 if (nWalletUnlockTime == 0)
1514 nWalletUnlockTime = nMyWakeTime;
1518 if (nWalletUnlockTime==0)
1520 int64_t nToSleep = nWalletUnlockTime - GetTimeMillis();
1524 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1526 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1530 if (nWalletUnlockTime)
1532 nWalletUnlockTime = 0;
1533 pwalletMain->Lock();
1538 if (nWalletUnlockTime < nMyWakeTime)
1539 nWalletUnlockTime = nMyWakeTime;
1542 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1544 delete (int64_t*)parg;
1547 Value walletpassphrase(const Array& params, bool fHelp)
1549 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 3))
1550 throw runtime_error(
1551 "walletpassphrase <passphrase> <timeout> [mintonly]\n"
1552 "Stores the wallet decryption key in memory for <timeout> seconds.\n"
1553 "mintonly is optional true/false allowing only block minting.");
1556 if (!pwalletMain->IsCrypted())
1557 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1559 if (!pwalletMain->IsLocked())
1560 throw JSONRPCError(RPC_WALLET_ALREADY_UNLOCKED, "Error: Wallet is already unlocked, use walletlock first if need to change unlock settings.");
1561 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1562 SecureString strWalletPass;
1563 strWalletPass.reserve(100);
1564 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1565 // Alternately, find a way to make params[0] mlock()'d to begin with.
1566 strWalletPass = params[0].get_str().c_str();
1568 if (strWalletPass.length() > 0)
1570 if (!pwalletMain->Unlock(strWalletPass))
1571 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
1574 throw runtime_error(
1575 "walletpassphrase <passphrase> <timeout>\n"
1576 "Stores the wallet decryption key in memory for <timeout> seconds.");
1578 NewThread(ThreadTopUpKeyPool, NULL);
1579 int64_t* pnSleepTime = new int64_t(params[1].get_int64());
1580 NewThread(ThreadCleanWalletPassphrase, pnSleepTime);
1582 // ppcoin: if user OS account compromised prevent trivial sendmoney commands
1583 if (params.size() > 2)
1584 fWalletUnlockMintOnly = params[2].get_bool();
1586 fWalletUnlockMintOnly = false;
1592 Value walletpassphrasechange(const Array& params, bool fHelp)
1594 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1595 throw runtime_error(
1596 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1597 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1600 if (!pwalletMain->IsCrypted())
1601 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1603 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1604 // Alternately, find a way to make params[0] mlock()'d to begin with.
1605 SecureString strOldWalletPass;
1606 strOldWalletPass.reserve(100);
1607 strOldWalletPass = params[0].get_str().c_str();
1609 SecureString strNewWalletPass;
1610 strNewWalletPass.reserve(100);
1611 strNewWalletPass = params[1].get_str().c_str();
1613 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1614 throw runtime_error(
1615 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1616 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1618 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1619 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
1625 Value walletlock(const Array& params, bool fHelp)
1627 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1628 throw runtime_error(
1630 "Removes the wallet encryption key from memory, locking the wallet.\n"
1631 "After calling this method, you will need to call walletpassphrase again\n"
1632 "before being able to call any methods which require the wallet to be unlocked.");
1635 if (!pwalletMain->IsCrypted())
1636 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletlock was called.");
1639 LOCK(cs_nWalletUnlockTime);
1640 pwalletMain->Lock();
1641 nWalletUnlockTime = 0;
1648 Value encryptwallet(const Array& params, bool fHelp)
1650 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1651 throw runtime_error(
1652 "encryptwallet <passphrase>\n"
1653 "Encrypts the wallet with <passphrase>.");
1656 if (pwalletMain->IsCrypted())
1657 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an encrypted wallet, but encryptwallet was called.");
1659 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1660 // Alternately, find a way to make params[0] mlock()'d to begin with.
1661 SecureString strWalletPass;
1662 strWalletPass.reserve(100);
1663 strWalletPass = params[0].get_str().c_str();
1665 if (strWalletPass.length() < 1)
1666 throw runtime_error(
1667 "encryptwallet <passphrase>\n"
1668 "Encrypts the wallet with <passphrase>.");
1670 if (!pwalletMain->EncryptWallet(strWalletPass))
1671 throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: Failed to encrypt the wallet.");
1673 // BDB seems to have a bad habit of writing old data into
1674 // slack space in .dat files; that is bad if the old data is
1675 // unencrypted private keys. So:
1677 return "wallet encrypted; NovaCoin server stopping, restart to run with encrypted wallet. The keypool has been flushed, you need to make a new backup.";
1680 class DescribeAddressVisitor : public boost::static_visitor<Object>
1685 DescribeAddressVisitor(isminetype mineIn) : mine(mineIn) {}
1687 Object operator()(const CNoDestination &dest) const { return Object(); }
1688 Object operator()(const CKeyID &keyID) const {
1691 pwalletMain->GetPubKey(keyID, vchPubKey);
1692 obj.push_back(Pair("isscript", false));
1693 if (mine == MINE_SPENDABLE) {
1694 pwalletMain->GetPubKey(keyID, vchPubKey);
1695 obj.push_back(Pair("pubkey", HexStr(vchPubKey.begin(), vchPubKey.end())));
1696 obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed()));
1701 Object operator()(const CScriptID &scriptID) const {
1703 obj.push_back(Pair("isscript", true));
1704 if (mine == MINE_SPENDABLE) {
1706 pwalletMain->GetCScript(scriptID, subscript);
1707 std::vector<CTxDestination> addresses;
1708 txnouttype whichType;
1710 ExtractDestinations(subscript, whichType, addresses, nRequired);
1711 obj.push_back(Pair("script", GetTxnOutputType(whichType)));
1712 obj.push_back(Pair("hex", HexStr(subscript.begin(), subscript.end())));
1714 BOOST_FOREACH(const CTxDestination& addr, addresses)
1715 a.push_back(CBitcoinAddress(addr).ToString());
1716 obj.push_back(Pair("addresses", a));
1717 if (whichType == TX_MULTISIG)
1718 obj.push_back(Pair("sigsrequired", nRequired));
1724 Value validateaddress(const Array& params, bool fHelp)
1726 if (fHelp || params.size() != 1)
1727 throw runtime_error(
1728 "validateaddress <novacoinaddress>\n"
1729 "Return information about <novacoinaddress>.");
1731 CBitcoinAddress address(params[0].get_str());
1732 bool isValid = address.IsValid();
1735 ret.push_back(Pair("isvalid", isValid));
1738 if (address.IsPair())
1740 CMalleablePubKey mpk;
1741 mpk.setvch(address.GetData());
1742 ret.push_back(Pair("ispair", true));
1744 CMalleableKeyView view;
1745 bool isMine = pwalletMain->GetMalleableView(mpk, view);
1746 ret.push_back(Pair("ismine", isMine));
1747 ret.push_back(Pair("PubkeyPair", mpk.ToString()));
1750 ret.push_back(Pair("KeyView", view.ToString()));
1754 string currentAddress = address.ToString();
1755 CTxDestination dest = address.Get();
1756 ret.push_back(Pair("address", currentAddress));
1757 isminetype mine = pwalletMain ? IsMine(*pwalletMain, address) : MINE_NO;
1758 ret.push_back(Pair("ismine", mine != MINE_NO));
1759 if (mine != MINE_NO) {
1760 ret.push_back(Pair("watchonly", mine == MINE_WATCH_ONLY));
1761 Object detail = boost::apply_visitor(DescribeAddressVisitor(mine), dest);
1762 ret.insert(ret.end(), detail.begin(), detail.end());
1764 if (pwalletMain->mapAddressBook.count(address))
1765 ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
1771 // ppcoin: reserve balance from being staked for network protection
1772 Value reservebalance(const Array& params, bool fHelp)
1774 if (fHelp || params.size() > 2)
1775 throw runtime_error(
1776 "reservebalance [<reserve> [amount]]\n"
1777 "<reserve> is true or false to turn balance reserve on or off.\n"
1778 "<amount> is a real and rounded to cent.\n"
1779 "Set reserve amount not participating in network protection.\n"
1780 "If no parameters provided current setting is printed.\n");
1782 if (params.size() > 0)
1784 bool fReserve = params[0].get_bool();
1787 if (params.size() == 1)
1788 throw runtime_error("must provide amount to reserve balance.\n");
1789 int64_t nAmount = AmountFromValue(params[1]);
1790 nAmount = (nAmount / CENT) * CENT; // round to cent
1792 throw runtime_error("amount cannot be negative.\n");
1793 mapArgs["-reservebalance"] = FormatMoney(nAmount);
1797 if (params.size() > 1)
1798 throw runtime_error("cannot specify amount to turn off reserve.\n");
1799 mapArgs["-reservebalance"] = "0";
1804 if (mapArgs.count("-reservebalance") && !ParseMoney(mapArgs["-reservebalance"], nReserveBalance))
1805 throw runtime_error("invalid reserve balance amount\n");
1806 result.push_back(Pair("reserve", (nReserveBalance > 0)));
1807 result.push_back(Pair("amount", ValueFromAmount(nReserveBalance)));
1812 // ppcoin: check wallet integrity
1813 Value checkwallet(const Array& params, bool fHelp)
1815 if (fHelp || params.size() > 0)
1816 throw runtime_error(
1818 "Check wallet for integrity.\n");
1821 int64_t nBalanceInQuestion;
1822 pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion, true);
1824 if (nMismatchSpent == 0)
1825 result.push_back(Pair("wallet check passed", true));
1828 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
1829 result.push_back(Pair("amount in question", ValueFromAmount(nBalanceInQuestion)));
1835 // ppcoin: repair wallet
1836 Value repairwallet(const Array& params, bool fHelp)
1838 if (fHelp || params.size() > 0)
1839 throw runtime_error(
1841 "Repair wallet if checkwallet reports any problem.\n");
1844 int64_t nBalanceInQuestion;
1845 pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion);
1847 if (nMismatchSpent == 0)
1848 result.push_back(Pair("wallet check passed", true));
1851 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
1852 result.push_back(Pair("amount affected by repair", ValueFromAmount(nBalanceInQuestion)));
1857 // NovaCoin: resend unconfirmed wallet transactions
1858 Value resendtx(const Array& params, bool fHelp)
1860 if (fHelp || params.size() > 1)
1861 throw runtime_error(
1863 "Re-send unconfirmed transactions.\n"
1866 ResendWalletTransactions(true);
1871 Value resendwallettransactions(const Array& params, bool fHelp)
1873 if (fHelp || params.size() != 0)
1874 throw runtime_error(
1875 "resendwallettransactions\n"
1876 "Immediately re-broadcast unconfirmed wallet transactions to all peers.\n"
1877 "Intended only for testing; the wallet code periodically re-broadcasts\n"
1879 "Returns array of transaction ids that were re-broadcast.\n"
1882 LOCK2(cs_main, pwalletMain->cs_wallet);
1884 std::vector<uint256> txids = pwalletMain->ResendWalletTransactionsBefore(GetTime());
1886 BOOST_FOREACH(const uint256& txid, txids)
1888 result.push_back(txid.ToString());
1894 // Make a public-private key pair
1895 Value makekeypair(const Array& params, bool fHelp)
1897 if (fHelp || params.size() > 0)
1898 throw runtime_error(
1900 "Make a public/private key pair.\n");
1902 string strPrefix = "";
1903 if (params.size() > 0)
1904 strPrefix = params[0].get_str();
1907 key.MakeNewKey(true);
1909 CPrivKey vchPrivKey = key.GetPrivKey();
1911 result.push_back(Pair("PrivateKey", HexStr<CPrivKey::iterator>(vchPrivKey.begin(), vchPrivKey.end())));
1914 CSecret vchSecret = key.GetSecret(fCompressed);
1915 CPubKey vchPubKey = key.GetPubKey();
1916 result.push_back(Pair("Secret", HexStr<CSecret::iterator>(vchSecret.begin(), vchSecret.end())));
1917 result.push_back(Pair("PublicKey", HexStr(vchPubKey.begin(), vchPubKey.end())));
1921 Value newmalleablekey(const Array& params, bool fHelp)
1923 if (fHelp || params.size() > 1)
1924 throw runtime_error(
1926 "Make a malleable public/private key pair.\n");
1928 // Parse the account first so we don't generate a key if there's an error
1930 if (params.size() > 0)
1931 strAccount = AccountFromValue(params[0]);
1933 CMalleableKeyView keyView = pwalletMain->GenerateNewMalleableKey();
1936 if (!pwalletMain->GetMalleableKey(keyView, mKey))
1937 throw runtime_error("Unable to generate new malleable key");
1939 CMalleablePubKey mPubKey = mKey.GetMalleablePubKey();
1940 CBitcoinAddress address(mPubKey);
1942 pwalletMain->SetAddressBookName(address, strAccount);
1945 result.push_back(Pair("PublicPair", mPubKey.ToString()));
1946 result.push_back(Pair("PublicBytes", HexStr(mPubKey.Raw())));
1947 result.push_back(Pair("Address", address.ToString()));
1948 result.push_back(Pair("KeyView", keyView.ToString()));
1953 Value adjustmalleablekey(const Array& params, bool fHelp)
1955 if (fHelp || params.size() != 3)
1956 throw runtime_error(
1957 "adjustmalleablekey <Malleable key data> <Public key variant data> <R data>\n"
1958 "Calculate new private key using provided malleable key, public key and R data.\n");
1960 CMalleableKey malleableKey;
1961 malleableKey.SetString(params[0].get_str());
1963 CKey privKeyVariant;
1964 CPubKey vchPubKeyVariant = CPubKey(ParseHex(params[1].get_str()));
1966 CPubKey R(ParseHex(params[2].get_str()));
1968 if (!malleableKey.CheckKeyVariant(R,vchPubKeyVariant, privKeyVariant)) {
1969 throw runtime_error("Unable to calculate the private key");
1974 CSecret vchPrivKeyVariant = privKeyVariant.GetSecret(fCompressed);
1976 result.push_back(Pair("PrivateKey", CBitcoinSecret(vchPrivKeyVariant, fCompressed).ToString()));
1981 Value adjustmalleablepubkey(const Array& params, bool fHelp)
1983 if (fHelp || params.size() > 2 || params.size() == 0)
1984 throw runtime_error(
1985 "adjustmalleablepubkey <Malleable address, key view or public key pair>\n"
1986 "Calculate new public key using provided data.\n");
1988 string strData = params[0].get_str();
1989 CMalleablePubKey malleablePubKey;
1993 CBitcoinAddress addr(strData);
1994 if (addr.IsValid() && addr.IsPair())
1996 // Initialize malleable pubkey with address data
1997 malleablePubKey = CMalleablePubKey(addr.GetData());
2000 CMalleableKeyView viewTmp(strData);
2001 if (viewTmp.IsValid())
2003 // Shazaam, we have a valid key view here.
2004 malleablePubKey = viewTmp.GetMalleablePubKey();
2007 if (malleablePubKey.SetString(strData))
2008 break; // A valid public key pair
2010 throw runtime_error("Though your data seems a valid Base58 string, we were unable to recognize it.");
2014 CPubKey R, vchPubKeyVariant;
2015 malleablePubKey.GetVariant(R, vchPubKeyVariant);
2018 result.push_back(Pair("R", HexStr(R.begin(), R.end())));
2019 result.push_back(Pair("PubkeyVariant", HexStr(vchPubKeyVariant.begin(), vchPubKeyVariant.end())));
2020 result.push_back(Pair("KeyVariantID", CBitcoinAddress(vchPubKeyVariant.GetID()).ToString()));
2025 Value listmalleableviews(const Array& params, bool fHelp)
2027 if (fHelp || params.size() != 0)
2028 throw runtime_error(
2029 "listmalleableviews\n"
2030 "Get list of views for generated malleable keys.\n");
2032 std::list<CMalleableKeyView> keyViewList;
2033 pwalletMain->ListMalleableViews(keyViewList);
2036 BOOST_FOREACH(const CMalleableKeyView &keyView, keyViewList)
2038 result.push_back(keyView.ToString());