// file license.txt or http://www.opensource.org/licenses/mit-license.php.
#include "headers.h"
-#include "cryptopp/sha.h"
#include "db.h"
#include "net.h"
#include "init.h"
#undef printf
#include <boost/asio.hpp>
+#include <boost/filesystem.hpp>
#include <boost/iostreams/concepts.hpp>
#include <boost/iostreams/stream.hpp>
#include <boost/algorithm/string.hpp>
+#include <boost/lexical_cast.hpp>
#ifdef USE_SSL
#include <boost/asio/ssl.hpp>
#include <boost/filesystem.hpp>
typedef Value(*rpcfn_type)(const Array& params, bool fHelp);
extern map<string, rpcfn_type> mapCallTable;
+static std::string strRPCUserColonPass;
+
static int64 nWalletUnlockTime;
static CCriticalSection cs_nWalletUnlockTime;
+extern Value dumpprivkey(const Array& params, bool fHelp);
+extern Value importprivkey(const Array& params, bool fHelp);
Object JSONRPCError(int code, const string& message)
{
buffer[limit-1] = 0;
}
printf("%s", buffer);
-#if defined(__WXMSW__) && defined(GUI)
- MyMessageBox(buffer, "Bitcoin", wxOK | wxICON_EXCLAMATION);
-#else
fprintf(stdout, "%s", buffer);
-#endif
}
void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
{
- entry.push_back(Pair("confirmations", wtx.GetDepthInMainChain()));
+ int confirms = wtx.GetDepthInMainChain();
+ entry.push_back(Pair("confirmations", confirms));
+ if (confirms)
+ {
+ entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex()));
+ entry.push_back(Pair("blockindex", wtx.nIndex));
+ }
entry.push_back(Pair("txid", wtx.GetHash().GetHex()));
entry.push_back(Pair("time", (boost::int64_t)wtx.GetTxTime()));
BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
// We already filter duplicates, but these deprecated screw up the sort order
if (strMethod == "getamountreceived" ||
strMethod == "getallreceived" ||
+ strMethod == "getblocknumber" || // deprecated
(strMethod.find("label") != string::npos))
continue;
if (strCommand != "" && strMethod != strCommand)
throw runtime_error(
"stop\n"
"Stop bitcoin server.");
-
+#ifndef QT_GUI
// Shutdown will take long enough that the response should get back
CreateThread(Shutdown, NULL);
return "bitcoin server stopping";
+#else
+ throw runtime_error("NYI: cannot shut down GUI with RPC command");
+#endif
}
}
+// deprecated
Value getblocknumber(const Array& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
"getblocknumber\n"
- "Returns the block number of the latest block in the longest block chain.");
+ "Deprecated. Use getblockcount.");
return nBestHeight;
}
"Returns an object containing various state info.");
Object obj;
- obj.push_back(Pair("version", (int)VERSION));
+ obj.push_back(Pair("version", (int)CLIENT_VERSION));
+ obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION));
obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
obj.push_back(Pair("blocks", (int)nBestHeight));
obj.push_back(Pair("connections", (int)vNodes.size()));
"If [account] is specified (recommended), it is added to the address book "
"so payments received with the address will be credited to [account].");
- if (!pwalletMain->IsLocked())
- pwalletMain->TopUpKeyPool();
-
- if (pwalletMain->GetKeyPoolSize() < 1)
- throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
-
// Parse the account first so we don't generate a key if there's an error
string strAccount;
if (params.size() > 0)
strAccount = AccountFromValue(params[0]);
+ if (!pwalletMain->IsLocked())
+ pwalletMain->TopUpKeyPool();
+
// Generate a new key that is added to wallet
- CBitcoinAddress address(pwalletMain->GetOrReuseKeyFromPool());
+ std::vector<unsigned char> newKey;
+ if (!pwalletMain->GetKeyFromPool(newKey, false))
+ throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
+ CBitcoinAddress address(newKey);
- // This could be done in the same main CS as GetKeyFromKeyPool.
- CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
- pwalletMain->SetAddressBookName(address, strAccount);
+ pwalletMain->SetAddressBookName(address, strAccount);
return address.ToString();
}
-// requires cs_main, cs_mapWallet, cs_mapAddressBook locks
CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
{
CWalletDB walletdb(pwalletMain->strWalletFile);
CAccount account;
- CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
- {
- walletdb.ReadAccount(strAccount, account);
+ walletdb.ReadAccount(strAccount, account);
- bool bKeyUsed = false;
+ bool bKeyUsed = false;
- // Check if the current key has been used
- if (!account.vchPubKey.empty())
+ // Check if the current key has been used
+ if (!account.vchPubKey.empty())
+ {
+ CScript scriptPubKey;
+ scriptPubKey.SetBitcoinAddress(account.vchPubKey);
+ for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
+ it != pwalletMain->mapWallet.end() && !account.vchPubKey.empty();
+ ++it)
{
- CScript scriptPubKey;
- scriptPubKey.SetBitcoinAddress(account.vchPubKey);
- for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
- it != pwalletMain->mapWallet.end() && !account.vchPubKey.empty();
- ++it)
- {
- const CWalletTx& wtx = (*it).second;
- BOOST_FOREACH(const CTxOut& txout, wtx.vout)
- if (txout.scriptPubKey == scriptPubKey)
- bKeyUsed = true;
- }
+ const CWalletTx& wtx = (*it).second;
+ BOOST_FOREACH(const CTxOut& txout, wtx.vout)
+ if (txout.scriptPubKey == scriptPubKey)
+ bKeyUsed = true;
}
+ }
- // Generate a new key
- if (account.vchPubKey.empty() || bForceNew || bKeyUsed)
- {
- if (pwalletMain->GetKeyPoolSize() < 1)
- {
- if (bKeyUsed || bForceNew)
- throw JSONRPCError(-12, "Error: Keypool ran out, please call topupkeypool first");
- }
- else
- {
- account.vchPubKey = pwalletMain->GetOrReuseKeyFromPool();
- pwalletMain->SetAddressBookName(CBitcoinAddress(account.vchPubKey), strAccount);
- walletdb.WriteAccount(strAccount, account);
- }
- }
+ // Generate a new key
+ if (account.vchPubKey.empty() || bForceNew || bKeyUsed)
+ {
+ if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false))
+ throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
+
+ pwalletMain->SetAddressBookName(CBitcoinAddress(account.vchPubKey), strAccount);
+ walletdb.WriteAccount(strAccount, account);
}
return CBitcoinAddress(account.vchPubKey);
Value ret;
- CRITICAL_BLOCK(cs_main)
- CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
- CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
- {
- ret = GetAccountAddress(strAccount).ToString();
- }
+ ret = GetAccountAddress(strAccount).ToString();
return ret;
}
strAccount = AccountFromValue(params[1]);
// Detect when changing the account of an address that is the 'unused current key' of another account:
- CRITICAL_BLOCK(cs_main)
- CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
- CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
+ if (pwalletMain->mapAddressBook.count(address))
{
- if (pwalletMain->mapAddressBook.count(address))
- {
- string strOldAccount = pwalletMain->mapAddressBook[address];
- if (address == GetAccountAddress(strOldAccount))
- GetAccountAddress(strOldAccount, true);
- }
-
- pwalletMain->SetAddressBookName(address, strAccount);
+ string strOldAccount = pwalletMain->mapAddressBook[address];
+ if (address == GetAccountAddress(strOldAccount))
+ GetAccountAddress(strOldAccount, true);
}
+ pwalletMain->SetAddressBookName(address, strAccount);
+
return Value::null;
}
throw JSONRPCError(-5, "Invalid bitcoin address");
string strAccount;
- CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
- {
- map<CBitcoinAddress, string>::iterator mi = pwalletMain->mapAddressBook.find(address);
- if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
- strAccount = (*mi).second;
- }
+ map<CBitcoinAddress, string>::iterator mi = pwalletMain->mapAddressBook.find(address);
+ if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
+ strAccount = (*mi).second;
return strAccount;
}
// Find all addresses that have the given account
Array ret;
- CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
+ BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
{
- BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
- {
- const CBitcoinAddress& address = item.first;
- const string& strName = item.second;
- if (strName == strAccount)
- ret.push_back(address.ToString());
- }
+ const CBitcoinAddress& address = item.first;
+ const string& strName = item.second;
+ if (strName == strAccount)
+ ret.push_back(address.ToString());
}
return ret;
}
if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
wtx.mapValue["to"] = params[3].get_str();
- CRITICAL_BLOCK(cs_main)
- CRITICAL_BLOCK(pwalletMain->cs_vMasterKey)
- {
- if(pwalletMain->IsLocked())
- throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
+ if (pwalletMain->IsLocked())
+ throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
- string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
- if (strError != "")
- throw JSONRPCError(-4, strError);
- }
+ string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
+ if (strError != "")
+ throw JSONRPCError(-4, strError);
return wtx.GetHash().GetHex();
}
+static const string strMessageMagic = "Bitcoin Signed Message:\n";
+
+Value signmessage(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() != 2)
+ throw runtime_error(
+ "signmessage <bitcoinaddress> <message>\n"
+ "Sign a message with the private key of an address");
+
+ if (pwalletMain->IsLocked())
+ throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
+
+ string strAddress = params[0].get_str();
+ string strMessage = params[1].get_str();
+
+ CBitcoinAddress addr(strAddress);
+ if (!addr.IsValid())
+ throw JSONRPCError(-3, "Invalid address");
+
+ CKey key;
+ if (!pwalletMain->GetKey(addr, key))
+ throw JSONRPCError(-4, "Private key not available");
+
+ CDataStream ss(SER_GETHASH);
+ ss << strMessageMagic;
+ ss << strMessage;
+
+ vector<unsigned char> vchSig;
+ if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
+ throw JSONRPCError(-5, "Sign failed");
+
+ return EncodeBase64(&vchSig[0], vchSig.size());
+}
+
+Value verifymessage(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() != 3)
+ throw runtime_error(
+ "verifymessage <bitcoinaddress> <signature> <message>\n"
+ "Verify a signed message");
+
+ string strAddress = params[0].get_str();
+ string strSign = params[1].get_str();
+ string strMessage = params[2].get_str();
+
+ CBitcoinAddress addr(strAddress);
+ if (!addr.IsValid())
+ throw JSONRPCError(-3, "Invalid address");
+
+ bool fInvalid = false;
+ vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
+
+ if (fInvalid)
+ throw JSONRPCError(-5, "Malformed base64 encoding");
+
+ CDataStream ss(SER_GETHASH);
+ ss << strMessageMagic;
+ ss << strMessage;
+
+ CKey key;
+ if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
+ return false;
+
+ return (CBitcoinAddress(key.GetPubKey()) == addr);
+}
+
Value getreceivedbyaddress(const Array& params, bool fHelp)
{
// Tally
int64 nAmount = 0;
- CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
+ for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
{
- for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
- {
- const CWalletTx& wtx = (*it).second;
- if (wtx.IsCoinBase() || !wtx.IsFinal())
- continue;
+ const CWalletTx& wtx = (*it).second;
+ if (wtx.IsCoinBase() || !wtx.IsFinal())
+ continue;
- BOOST_FOREACH(const CTxOut& txout, wtx.vout)
- if (txout.scriptPubKey == scriptPubKey)
- if (wtx.GetDepthInMainChain() >= nMinDepth)
- nAmount += txout.nValue;
- }
+ BOOST_FOREACH(const CTxOut& txout, wtx.vout)
+ if (txout.scriptPubKey == scriptPubKey)
+ if (wtx.GetDepthInMainChain() >= nMinDepth)
+ nAmount += txout.nValue;
}
return ValueFromAmount(nAmount);
void GetAccountAddresses(string strAccount, set<CBitcoinAddress>& setAddress)
{
- CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
+ BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
{
- BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
- {
- const CBitcoinAddress& address = item.first;
- const string& strName = item.second;
- if (strName == strAccount)
- setAddress.insert(address);
- }
+ const CBitcoinAddress& address = item.first;
+ const string& strName = item.second;
+ if (strName == strAccount)
+ setAddress.insert(address);
}
}
// Tally
int64 nAmount = 0;
- CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
+ for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
{
- for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
- {
- const CWalletTx& wtx = (*it).second;
- if (wtx.IsCoinBase() || !wtx.IsFinal())
- continue;
+ const CWalletTx& wtx = (*it).second;
+ if (wtx.IsCoinBase() || !wtx.IsFinal())
+ continue;
- BOOST_FOREACH(const CTxOut& txout, wtx.vout)
- {
- CBitcoinAddress address;
- if (ExtractAddress(txout.scriptPubKey, pwalletMain, address) && setAddress.count(address))
- if (wtx.GetDepthInMainChain() >= nMinDepth)
- nAmount += txout.nValue;
- }
+ BOOST_FOREACH(const CTxOut& txout, wtx.vout)
+ {
+ CBitcoinAddress address;
+ if (ExtractAddress(txout.scriptPubKey, pwalletMain, address) && setAddress.count(address))
+ if (wtx.GetDepthInMainChain() >= nMinDepth)
+ nAmount += txout.nValue;
}
}
int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
{
int64 nBalance = 0;
- CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
- {
- // Tally wallet transactions
- for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
- {
- const CWalletTx& wtx = (*it).second;
- if (!wtx.IsFinal())
- continue;
- int64 nGenerated, nReceived, nSent, nFee;
- wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee);
+ // Tally wallet transactions
+ for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
+ {
+ const CWalletTx& wtx = (*it).second;
+ if (!wtx.IsFinal())
+ continue;
- if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
- nBalance += nReceived;
- nBalance += nGenerated - nSent - nFee;
- }
+ int64 nGenerated, nReceived, nSent, nFee;
+ wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee);
- // Tally internal accounting entries
- nBalance += walletdb.GetAccountCreditDebit(strAccount);
+ if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
+ nBalance += nReceived;
+ nBalance += nGenerated - nSent - nFee;
}
+ // Tally internal accounting entries
+ nBalance += walletdb.GetAccountCreditDebit(strAccount);
+
return nBalance;
}
if (params.size() > 4)
strComment = params[4].get_str();
- CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
- {
- CWalletDB walletdb(pwalletMain->strWalletFile);
- walletdb.TxnBegin();
-
- int64 nNow = GetAdjustedTime();
-
- // Debit
- CAccountingEntry debit;
- debit.strAccount = strFrom;
- debit.nCreditDebit = -nAmount;
- debit.nTime = nNow;
- debit.strOtherAccount = strTo;
- debit.strComment = strComment;
- walletdb.WriteAccountingEntry(debit);
-
- // Credit
- CAccountingEntry credit;
- credit.strAccount = strTo;
- credit.nCreditDebit = nAmount;
- credit.nTime = nNow;
- credit.strOtherAccount = strFrom;
- credit.strComment = strComment;
- walletdb.WriteAccountingEntry(credit);
-
- walletdb.TxnCommit();
- }
+ CWalletDB walletdb(pwalletMain->strWalletFile);
+ walletdb.TxnBegin();
+
+ int64 nNow = GetAdjustedTime();
+
+ // Debit
+ CAccountingEntry debit;
+ debit.strAccount = strFrom;
+ debit.nCreditDebit = -nAmount;
+ debit.nTime = nNow;
+ debit.strOtherAccount = strTo;
+ debit.strComment = strComment;
+ walletdb.WriteAccountingEntry(debit);
+
+ // Credit
+ CAccountingEntry credit;
+ credit.strAccount = strTo;
+ credit.nCreditDebit = nAmount;
+ credit.nTime = nNow;
+ credit.strOtherAccount = strFrom;
+ credit.strComment = strComment;
+ walletdb.WriteAccountingEntry(credit);
+
+ walletdb.TxnCommit();
+
return true;
}
if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
wtx.mapValue["to"] = params[5].get_str();
- CRITICAL_BLOCK(cs_main)
- CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
- CRITICAL_BLOCK(pwalletMain->cs_vMasterKey)
- {
- if(pwalletMain->IsLocked())
- throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
+ if (pwalletMain->IsLocked())
+ throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
- // Check funds
- int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
- if (nAmount > nBalance)
- throw JSONRPCError(-6, "Account has insufficient funds");
+ // Check funds
+ int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
+ if (nAmount > nBalance)
+ throw JSONRPCError(-6, "Account has insufficient funds");
- // Send
- string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
- if (strError != "")
- throw JSONRPCError(-4, strError);
- }
+ // Send
+ string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
+ if (strError != "")
+ throw JSONRPCError(-4, strError);
return wtx.GetHash().GetHex();
}
vecSend.push_back(make_pair(scriptPubKey, nAmount));
}
- CRITICAL_BLOCK(cs_main)
- CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
- CRITICAL_BLOCK(pwalletMain->cs_vMasterKey)
- {
- if(pwalletMain->IsLocked())
- throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
+ if (pwalletMain->IsLocked())
+ throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
- // Check funds
- int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
- if (totalAmount > nBalance)
- throw JSONRPCError(-6, "Account has insufficient funds");
-
- // Send
- CReserveKey keyChange(pwalletMain);
- int64 nFeeRequired = 0;
- bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
- if (!fCreated)
- {
- if (totalAmount + nFeeRequired > pwalletMain->GetBalance())
- throw JSONRPCError(-6, "Insufficient funds");
- throw JSONRPCError(-4, "Transaction creation failed");
- }
- if (!pwalletMain->CommitTransaction(wtx, keyChange))
- throw JSONRPCError(-4, "Transaction commit failed");
+ // Check funds
+ int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
+ if (totalAmount > nBalance)
+ throw JSONRPCError(-6, "Account has insufficient funds");
+
+ // Send
+ CReserveKey keyChange(pwalletMain);
+ int64 nFeeRequired = 0;
+ bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
+ if (!fCreated)
+ {
+ if (totalAmount + nFeeRequired > pwalletMain->GetBalance())
+ throw JSONRPCError(-6, "Insufficient funds");
+ throw JSONRPCError(-4, "Transaction creation failed");
}
+ if (!pwalletMain->CommitTransaction(wtx, keyChange))
+ throw JSONRPCError(-4, "Transaction commit failed");
return wtx.GetHash().GetHex();
}
tallyitem()
{
nAmount = 0;
- nConf = INT_MAX;
+ nConf = std::numeric_limits<int>::max();
}
};
// Tally
map<CBitcoinAddress, tallyitem> mapTally;
- CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
+ for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
{
- for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
- {
- const CWalletTx& wtx = (*it).second;
- if (wtx.IsCoinBase() || !wtx.IsFinal())
- continue;
+ const CWalletTx& wtx = (*it).second;
+ if (wtx.IsCoinBase() || !wtx.IsFinal())
+ continue;
- int nDepth = wtx.GetDepthInMainChain();
- if (nDepth < nMinDepth)
- continue;
+ int nDepth = wtx.GetDepthInMainChain();
+ if (nDepth < nMinDepth)
+ continue;
- BOOST_FOREACH(const CTxOut& txout, wtx.vout)
- {
- CBitcoinAddress address;
- if (!ExtractAddress(txout.scriptPubKey, pwalletMain, address) || !address.IsValid())
- continue;
+ BOOST_FOREACH(const CTxOut& txout, wtx.vout)
+ {
+ CBitcoinAddress address;
+ if (!ExtractAddress(txout.scriptPubKey, pwalletMain, address) || !address.IsValid())
+ continue;
- tallyitem& item = mapTally[address];
- item.nAmount += txout.nValue;
- item.nConf = min(item.nConf, nDepth);
- }
+ tallyitem& item = mapTally[address];
+ item.nAmount += txout.nValue;
+ item.nConf = min(item.nConf, nDepth);
}
}
// Reply
Array ret;
map<string, tallyitem> mapAccountTally;
- CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
+ BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
{
- BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
- {
- const CBitcoinAddress& address = item.first;
- const string& strAccount = item.second;
- map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
- if (it == mapTally.end() && !fIncludeEmpty)
- continue;
+ const CBitcoinAddress& address = item.first;
+ const string& strAccount = item.second;
+ map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
+ if (it == mapTally.end() && !fIncludeEmpty)
+ continue;
- int64 nAmount = 0;
- int nConf = INT_MAX;
- if (it != mapTally.end())
- {
- nAmount = (*it).second.nAmount;
- nConf = (*it).second.nConf;
- }
+ int64 nAmount = 0;
+ int nConf = std::numeric_limits<int>::max();
+ if (it != mapTally.end())
+ {
+ nAmount = (*it).second.nAmount;
+ nConf = (*it).second.nConf;
+ }
- if (fByAccounts)
- {
- tallyitem& item = mapAccountTally[strAccount];
- item.nAmount += nAmount;
- item.nConf = min(item.nConf, nConf);
- }
- else
- {
- Object obj;
- obj.push_back(Pair("address", address.ToString()));
- obj.push_back(Pair("account", strAccount));
- obj.push_back(Pair("label", strAccount)); // deprecated
- obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
- obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
- ret.push_back(obj);
- }
+ if (fByAccounts)
+ {
+ tallyitem& item = mapAccountTally[strAccount];
+ item.nAmount += nAmount;
+ item.nConf = min(item.nConf, nConf);
+ }
+ else
+ {
+ Object obj;
+ obj.push_back(Pair("address", address.ToString()));
+ obj.push_back(Pair("account", strAccount));
+ obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
+ obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
+ ret.push_back(obj);
}
}
int nConf = (*it).second.nConf;
Object obj;
obj.push_back(Pair("account", (*it).first));
- obj.push_back(Pair("label", (*it).first)); // deprecated
obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
- obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
+ obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
ret.push_back(obj);
}
}
// Received
if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
- CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
+ BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
{
- BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
+ string account;
+ if (pwalletMain->mapAddressBook.count(r.first))
+ account = pwalletMain->mapAddressBook[r.first];
+ if (fAllAccounts || (account == strAccount))
{
- string account;
- if (pwalletMain->mapAddressBook.count(r.first))
- account = pwalletMain->mapAddressBook[r.first];
- if (fAllAccounts || (account == strAccount))
- {
- Object entry;
- entry.push_back(Pair("account", account));
- entry.push_back(Pair("address", r.first.ToString()));
- entry.push_back(Pair("category", "receive"));
- entry.push_back(Pair("amount", ValueFromAmount(r.second)));
- if (fLong)
- WalletTxToJSON(wtx, entry);
- ret.push_back(entry);
- }
+ Object entry;
+ entry.push_back(Pair("account", account));
+ entry.push_back(Pair("address", r.first.ToString()));
+ entry.push_back(Pair("category", "receive"));
+ entry.push_back(Pair("amount", ValueFromAmount(r.second)));
+ if (fLong)
+ WalletTxToJSON(wtx, entry);
+ ret.push_back(entry);
}
}
-
}
void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
Array ret;
CWalletDB walletdb(pwalletMain->strWalletFile);
- CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
- {
- // Firs: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap:
- typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
- typedef multimap<int64, TxPair > TxItems;
- TxItems txByTime;
+ // Firs: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap:
+ typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
+ typedef multimap<int64, TxPair > TxItems;
+ TxItems txByTime;
- for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
- {
- CWalletTx* wtx = &((*it).second);
- txByTime.insert(make_pair(wtx->GetTxTime(), TxPair(wtx, (CAccountingEntry*)0)));
- }
- list<CAccountingEntry> acentries;
- walletdb.ListAccountCreditDebit(strAccount, acentries);
- BOOST_FOREACH(CAccountingEntry& entry, acentries)
- {
- txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
- }
+ for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
+ {
+ CWalletTx* wtx = &((*it).second);
+ txByTime.insert(make_pair(wtx->GetTxTime(), TxPair(wtx, (CAccountingEntry*)0)));
+ }
+ list<CAccountingEntry> acentries;
+ walletdb.ListAccountCreditDebit(strAccount, acentries);
+ BOOST_FOREACH(CAccountingEntry& entry, acentries)
+ {
+ txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
+ }
- // Now: iterate backwards until we have nCount items to return:
- TxItems::reverse_iterator it = txByTime.rbegin();
- if (txByTime.size() > nFrom) std::advance(it, nFrom);
- for (; it != txByTime.rend(); ++it)
- {
- CWalletTx *const pwtx = (*it).second.first;
- if (pwtx != 0)
- ListTransactions(*pwtx, strAccount, 0, true, ret);
- CAccountingEntry *const pacentry = (*it).second.second;
- if (pacentry != 0)
- AcentryToJSON(*pacentry, strAccount, ret);
-
- if (ret.size() >= nCount) break;
- }
- // ret is now newest to oldest
+ // Now: iterate backwards until we have nCount items to return:
+ TxItems::reverse_iterator it = txByTime.rbegin();
+ if (txByTime.size() > nFrom) std::advance(it, nFrom);
+ for (; it != txByTime.rend(); ++it)
+ {
+ CWalletTx *const pwtx = (*it).second.first;
+ if (pwtx != 0)
+ ListTransactions(*pwtx, strAccount, 0, true, ret);
+ CAccountingEntry *const pacentry = (*it).second.second;
+ if (pacentry != 0)
+ AcentryToJSON(*pacentry, strAccount, ret);
+
+ if (ret.size() >= nCount) break;
}
+ // ret is now newest to oldest
// Make sure we return only last nCount items (sends-to-self might give us an extra):
if (ret.size() > nCount)
nMinDepth = params[0].get_int();
map<string, int64> mapAccountBalances;
- CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
- CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
- {
- BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& entry, pwalletMain->mapAddressBook) {
- if (pwalletMain->HaveKey(entry.first)) // This address belongs to me
- mapAccountBalances[entry.second] = 0;
- }
+ BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& entry, pwalletMain->mapAddressBook) {
+ if (pwalletMain->HaveKey(entry.first)) // This address belongs to me
+ mapAccountBalances[entry.second] = 0;
+ }
- for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
+ for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
+ {
+ const CWalletTx& wtx = (*it).second;
+ int64 nGeneratedImmature, nGeneratedMature, nFee;
+ string strSentAccount;
+ list<pair<CBitcoinAddress, int64> > listReceived;
+ list<pair<CBitcoinAddress, int64> > listSent;
+ wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
+ mapAccountBalances[strSentAccount] -= nFee;
+ BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
+ mapAccountBalances[strSentAccount] -= s.second;
+ if (wtx.GetDepthInMainChain() >= nMinDepth)
{
- const CWalletTx& wtx = (*it).second;
- int64 nGeneratedImmature, nGeneratedMature, nFee;
- string strSentAccount;
- list<pair<CBitcoinAddress, int64> > listReceived;
- list<pair<CBitcoinAddress, int64> > listSent;
- wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
- mapAccountBalances[strSentAccount] -= nFee;
- BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
- mapAccountBalances[strSentAccount] -= s.second;
- if (wtx.GetDepthInMainChain() >= nMinDepth)
- {
- mapAccountBalances[""] += nGeneratedMature;
- BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
- if (pwalletMain->mapAddressBook.count(r.first))
- mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
- else
- mapAccountBalances[""] += r.second;
- }
+ mapAccountBalances[""] += nGeneratedMature;
+ BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
+ if (pwalletMain->mapAddressBook.count(r.first))
+ mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
+ else
+ mapAccountBalances[""] += r.second;
}
}
return ret;
}
+Value listsinceblock(const Array& params, bool fHelp)
+{
+ if (fHelp)
+ throw runtime_error(
+ "listsinceblock [blockid] [target-confirmations]\n"
+ "Get all transactions in blocks since block [blockid], or all transactions if omitted");
+
+ CBlockIndex *pindex = NULL;
+ int target_confirms = 1;
+
+ if (params.size() > 0)
+ {
+ uint256 blockId = 0;
+
+ blockId.SetHex(params[0].get_str());
+ pindex = CBlockLocator(blockId).GetBlockIndex();
+ }
+
+ if (params.size() > 1)
+ {
+ target_confirms = params[1].get_int();
+
+ if (target_confirms < 1)
+ throw JSONRPCError(-8, "Invalid parameter");
+ }
+
+ int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
+
+ Array transactions;
+
+ for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
+ {
+ CWalletTx tx = (*it).second;
+
+ if (depth == -1 || tx.GetDepthInMainChain() < depth)
+ ListTransactions(tx, "*", 0, true, transactions);
+ }
+
+ uint256 lastblock;
+
+ if (target_confirms == 1)
+ {
+ printf("oops!\n");
+ lastblock = hashBestChain;
+ }
+ else
+ {
+ int target_height = pindexBest->nHeight + 1 - target_confirms;
+
+ CBlockIndex *block;
+ for (block = pindexBest;
+ block && block->nHeight > target_height;
+ block = block->pprev);
+
+ lastblock = block ? block->GetBlockHash() : 0;
+ }
+
+ Object ret;
+ ret.push_back(Pair("transactions", transactions));
+ ret.push_back(Pair("lastblock", lastblock.GetHex()));
+
+ return ret;
+}
+
Value gettransaction(const Array& params, bool fHelp)
{
if (fHelp || params.size() != 1)
hash.SetHex(params[0].get_str());
Object entry;
- CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
- {
- if (!pwalletMain->mapWallet.count(hash))
- throw JSONRPCError(-5, "Invalid or non-wallet transaction id");
- const CWalletTx& wtx = pwalletMain->mapWallet[hash];
- int64 nCredit = wtx.GetCredit();
- int64 nDebit = wtx.GetDebit();
- int64 nNet = nCredit - nDebit;
- int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
+ if (!pwalletMain->mapWallet.count(hash))
+ throw JSONRPCError(-5, "Invalid or non-wallet transaction id");
+ const CWalletTx& wtx = pwalletMain->mapWallet[hash];
- entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
- if (wtx.IsFromMe())
- entry.push_back(Pair("fee", ValueFromAmount(nFee)));
+ int64 nCredit = wtx.GetCredit();
+ int64 nDebit = wtx.GetDebit();
+ int64 nNet = nCredit - nDebit;
+ int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
- WalletTxToJSON(pwalletMain->mapWallet[hash], entry);
+ entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
+ if (wtx.IsFromMe())
+ entry.push_back(Pair("fee", ValueFromAmount(nFee)));
- Array details;
- ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
- entry.push_back(Pair("details", details));
- }
+ WalletTxToJSON(pwalletMain->mapWallet[hash], entry);
+
+ Array details;
+ ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
+ entry.push_back(Pair("details", details));
return entry;
}
"keypoolrefill\n"
"Fills the keypool.");
- CRITICAL_BLOCK(pwalletMain->cs_vMasterKey)
- {
- if (pwalletMain->IsLocked())
- throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
+ if (pwalletMain->IsLocked())
+ throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
- pwalletMain->TopUpKeyPool();
- }
+ pwalletMain->TopUpKeyPool();
if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100))
throw JSONRPCError(-4, "Error refreshing keypool.");
throw JSONRPCError(-17, "Error: Wallet is already unlocked.");
// Note that the walletpassphrase is stored in params[0] which is not mlock()ed
- string strWalletPass;
+ SecureString strWalletPass;
strWalletPass.reserve(100);
- mlock(&strWalletPass[0], strWalletPass.capacity());
- strWalletPass = params[0].get_str();
+ // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
+ // Alternately, find a way to make params[0] mlock()'d to begin with.
+ strWalletPass = params[0].get_str().c_str();
- CRITICAL_BLOCK(pwalletMain->cs_vMasterKey)
+ if (strWalletPass.length() > 0)
{
- if (strWalletPass.length() > 0)
- {
- if (!pwalletMain->Unlock(strWalletPass))
- {
- fill(strWalletPass.begin(), strWalletPass.end(), '\0');
- munlock(&strWalletPass[0], strWalletPass.capacity());
- throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
- }
- fill(strWalletPass.begin(), strWalletPass.end(), '\0');
- munlock(&strWalletPass[0], strWalletPass.capacity());
- }
- else
- throw runtime_error(
- "walletpassphrase <passphrase> <timeout>\n"
- "Stores the wallet decryption key in memory for <timeout> seconds.");
+ if (!pwalletMain->Unlock(strWalletPass))
+ throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
}
+ else
+ throw runtime_error(
+ "walletpassphrase <passphrase> <timeout>\n"
+ "Stores the wallet decryption key in memory for <timeout> seconds.");
CreateThread(ThreadTopUpKeyPool, NULL);
int* pnSleepTime = new int(params[1].get_int());
if (!pwalletMain->IsCrypted())
throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
- string strOldWalletPass;
+ // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
+ // Alternately, find a way to make params[0] mlock()'d to begin with.
+ SecureString strOldWalletPass;
strOldWalletPass.reserve(100);
- mlock(&strOldWalletPass[0], strOldWalletPass.capacity());
- strOldWalletPass = params[0].get_str();
+ strOldWalletPass = params[0].get_str().c_str();
- string strNewWalletPass;
+ SecureString strNewWalletPass;
strNewWalletPass.reserve(100);
- mlock(&strNewWalletPass[0], strNewWalletPass.capacity());
- strNewWalletPass = params[1].get_str();
+ strNewWalletPass = params[1].get_str().c_str();
if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
throw runtime_error(
"Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
- {
- fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0');
- fill(strNewWalletPass.begin(), strNewWalletPass.end(), '\0');
- munlock(&strOldWalletPass[0], strOldWalletPass.capacity());
- munlock(&strNewWalletPass[0], strNewWalletPass.capacity());
throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
- }
- fill(strNewWalletPass.begin(), strNewWalletPass.end(), '\0');
- fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0');
- munlock(&strOldWalletPass[0], strOldWalletPass.capacity());
- munlock(&strNewWalletPass[0], strNewWalletPass.capacity());
return Value::null;
}
if (pwalletMain->IsCrypted())
throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
- string strWalletPass;
+#ifdef QT_GUI
+ // shutting down via RPC while the GUI is running does not work (yet):
+ throw runtime_error("Not Yet Implemented: use GUI to encrypt wallet, not RPC command");
+#endif
+
+ // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
+ // Alternately, find a way to make params[0] mlock()'d to begin with.
+ SecureString strWalletPass;
strWalletPass.reserve(100);
- mlock(&strWalletPass[0], strWalletPass.capacity());
- strWalletPass = params[0].get_str();
+ strWalletPass = params[0].get_str().c_str();
if (strWalletPass.length() < 1)
throw runtime_error(
"Encrypts the wallet with <passphrase>.");
if (!pwalletMain->EncryptWallet(strWalletPass))
- {
- fill(strWalletPass.begin(), strWalletPass.end(), '\0');
- munlock(&strWalletPass[0], strWalletPass.capacity());
throw JSONRPCError(-16, "Error: Failed to encrypt the wallet.");
- }
- fill(strWalletPass.begin(), strWalletPass.end(), '\0');
- munlock(&strWalletPass[0], strWalletPass.capacity());
- return Value::null;
+ // BDB seems to have a bad habit of writing old data into
+ // slack space in .dat files; that is bad if the old data is
+ // unencrypted private keys. So:
+ CreateThread(Shutdown, NULL);
+ return "wallet encrypted; bitcoin server stopping, restart to run with encrypted wallet";
}
string currentAddress = address.ToString();
ret.push_back(Pair("address", currentAddress));
ret.push_back(Pair("ismine", (pwalletMain->HaveKey(address) > 0)));
- CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
- {
- if (pwalletMain->mapAddressBook.count(address))
- ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
- }
+ if (pwalletMain->mapAddressBook.count(address))
+ ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
}
return ret;
}
-
Value getwork(const Array& params, bool fHelp)
{
if (fHelp || params.size() > 1)
throw runtime_error(
"getwork [data]\n"
"If [data] is not specified, returns formatted hash data to work on:\n"
- " \"midstate\" : precomputed hash state after hashing the first half of the data\n"
+ " \"midstate\" : precomputed hash state after hashing the first half of the data (DEPRECATED)\n" // deprecated
" \"data\" : block data\n"
- " \"hash1\" : formatted hash buffer for second hash\n"
+ " \"hash1\" : formatted hash buffer for second hash (DEPRECATED)\n" // deprecated
" \"target\" : little endian hash target\n"
"If [data] is specified, tries to solve the block and returns true if it was successful.");
if (IsInitialBlockDownload())
throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
- static map<uint256, pair<CBlock*, unsigned int> > mapNewBlock;
+ typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
+ static mapNewBlock_t mapNewBlock;
static vector<CBlock*> vNewBlock;
static CReserveKey reservekey(pwalletMain);
// Update nExtraNonce
static unsigned int nExtraNonce = 0;
- static int64 nPrevTime = 0;
- IncrementExtraNonce(pblock, pindexPrev, nExtraNonce, nPrevTime);
+ IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
// Save
- mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, nExtraNonce);
+ mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
// Prebuild hash buffers
char pmidstate[32];
uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
Object result;
- result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate))));
+ result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate)))); // deprecated
result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
- result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1))));
+ result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1)))); // deprecated
result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
return result;
}
// Byte reverse
for (int i = 0; i < 128/4; i++)
- ((unsigned int*)pdata)[i] = CryptoPP::ByteReverse(((unsigned int*)pdata)[i]);
+ ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);
// Get saved block
if (!mapNewBlock.count(pdata->hashMerkleRoot))
return false;
CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
- unsigned int nExtraNonce = mapNewBlock[pdata->hashMerkleRoot].second;
pblock->nTime = pdata->nTime;
pblock->nNonce = pdata->nNonce;
- pblock->vtx[0].vin[0].scriptSig = CScript() << pblock->nBits << CBigNum(nExtraNonce);
+ pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
pblock->hashMerkleRoot = pblock->BuildMerkleTree();
return CheckWork(pblock, *pwalletMain, reservekey);
}
+Value getmemorypool(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() > 1)
+ throw runtime_error(
+ "getmemorypool [data]\n"
+ "If [data] is not specified, returns data needed to construct a block to work on:\n"
+ " \"version\" : block version\n"
+ " \"previousblockhash\" : hash of current highest block\n"
+ " \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
+ " \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
+ " \"time\" : timestamp appropriate for next block\n"
+ " \"bits\" : compressed target of next block\n"
+ "If [data] is specified, tries to solve the block and returns true if it was successful.");
+
+ if (params.size() == 0)
+ {
+ if (vNodes.empty())
+ throw JSONRPCError(-9, "Bitcoin is not connected!");
+
+ if (IsInitialBlockDownload())
+ throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
+
+ static CReserveKey reservekey(pwalletMain);
+
+ // Update block
+ static unsigned int nTransactionsUpdatedLast;
+ static CBlockIndex* pindexPrev;
+ static int64 nStart;
+ static CBlock* pblock;
+ if (pindexPrev != pindexBest ||
+ (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
+ {
+ nTransactionsUpdatedLast = nTransactionsUpdated;
+ pindexPrev = pindexBest;
+ nStart = GetTime();
+
+ // Create new block
+ if(pblock)
+ delete pblock;
+ pblock = CreateNewBlock(reservekey);
+ if (!pblock)
+ throw JSONRPCError(-7, "Out of memory");
+ }
+
+ // Update nTime
+ pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
+ pblock->nNonce = 0;
+
+ Array transactions;
+ BOOST_FOREACH(CTransaction tx, pblock->vtx) {
+ if(tx.IsCoinBase())
+ continue;
+
+ CDataStream ssTx;
+ ssTx << tx;
+
+ transactions.push_back(HexStr(ssTx.begin(), ssTx.end()));
+ }
+
+ Object result;
+ result.push_back(Pair("version", pblock->nVersion));
+ result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
+ result.push_back(Pair("transactions", transactions));
+ result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
+ result.push_back(Pair("time", (int64_t)pblock->nTime));
+
+ union {
+ int32_t nBits;
+ char cBits[4];
+ } uBits;
+ uBits.nBits = htonl((int32_t)pblock->nBits);
+ result.push_back(Pair("bits", HexStr(BEGIN(uBits.cBits), END(uBits.cBits))));
+
+ return result;
+ }
+ else
+ {
+ // Parse parameters
+ CDataStream ssBlock(ParseHex(params[0].get_str()));
+ CBlock pblock;
+ ssBlock >> pblock;
+
+ return ProcessBlock(NULL, &pblock);
+ }
+}
+
+
make_pair("getnewaddress", &getnewaddress),
make_pair("getaccountaddress", &getaccountaddress),
make_pair("setaccount", &setaccount),
- make_pair("setlabel", &setaccount), // deprecated
make_pair("getaccount", &getaccount),
- make_pair("getlabel", &getaccount), // deprecated
make_pair("getaddressesbyaccount", &getaddressesbyaccount),
- make_pair("getaddressesbylabel", &getaddressesbyaccount), // deprecated
make_pair("sendtoaddress", &sendtoaddress),
- make_pair("getamountreceived", &getreceivedbyaddress), // deprecated, renamed to getreceivedbyaddress
- make_pair("getallreceived", &listreceivedbyaddress), // deprecated, renamed to listreceivedbyaddress
make_pair("getreceivedbyaddress", &getreceivedbyaddress),
make_pair("getreceivedbyaccount", &getreceivedbyaccount),
- make_pair("getreceivedbylabel", &getreceivedbyaccount), // deprecated
make_pair("listreceivedbyaddress", &listreceivedbyaddress),
make_pair("listreceivedbyaccount", &listreceivedbyaccount),
- make_pair("listreceivedbylabel", &listreceivedbyaccount), // deprecated
make_pair("backupwallet", &backupwallet),
make_pair("keypoolrefill", &keypoolrefill),
make_pair("walletpassphrase", &walletpassphrase),
make_pair("sendmany", &sendmany),
make_pair("gettransaction", &gettransaction),
make_pair("listtransactions", &listtransactions),
+ make_pair("signmessage", &signmessage),
+ make_pair("verifymessage", &verifymessage),
make_pair("getwork", &getwork),
make_pair("listaccounts", &listaccounts),
make_pair("settxfee", &settxfee),
+ make_pair("getmemorypool", &getmemorypool),
+ make_pair("listsinceblock", &listsinceblock),
+ make_pair("dumpprivkey", &dumpprivkey),
+ make_pair("importprivkey", &importprivkey)
};
map<string, rpcfn_type> mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)/sizeof(pCallTable[0]));
"help",
"stop",
"getblockcount",
- "getblocknumber",
+ "getblocknumber", // deprecated
"getconnectioncount",
"getdifficulty",
"getgenerate",
"getinfo",
"getnewaddress",
"getaccountaddress",
- "setlabel", // deprecated
"getaccount",
- "getlabel", // deprecated
"getaddressesbyaccount",
- "getaddressesbylabel", // deprecated
"backupwallet",
"keypoolrefill",
"walletpassphrase",
"walletlock",
"validateaddress",
"getwork",
+ "getmemorypool",
};
set<string> setAllowInSafeMode(pAllowInSafeMode, pAllowInSafeMode + sizeof(pAllowInSafeMode)/sizeof(pAllowInSafeMode[0]));
<< "Host: 127.0.0.1\r\n"
<< "Content-Type: application/json\r\n"
<< "Content-Length: " << strMsg.size() << "\r\n"
+ << "Connection: close\r\n"
<< "Accept: application/json\r\n";
BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
s << item.first << ": " << item.second << "\r\n";
"</HEAD>\r\n"
"<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
"</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
- string strStatus;
- if (nStatus == 200) strStatus = "OK";
- else if (nStatus == 400) strStatus = "Bad Request";
- else if (nStatus == 403) strStatus = "Forbidden";
- else if (nStatus == 404) strStatus = "Not Found";
- else if (nStatus == 500) strStatus = "Internal Server Error";
+ const char *cStatus;
+ if (nStatus == 200) cStatus = "OK";
+ else if (nStatus == 400) cStatus = "Bad Request";
+ else if (nStatus == 403) cStatus = "Forbidden";
+ else if (nStatus == 404) cStatus = "Not Found";
+ else if (nStatus == 500) cStatus = "Internal Server Error";
+ else cStatus = "";
return strprintf(
"HTTP/1.1 %d %s\r\n"
"Date: %s\r\n"
"\r\n"
"%s",
nStatus,
- strStatus.c_str(),
+ cStatus,
rfc1123Time().c_str(),
strMsg.size(),
FormatFullVersion().c_str(),
return nStatus;
}
-string EncodeBase64(string s)
-{
- BIO *b64, *bmem;
- BUF_MEM *bptr;
-
- b64 = BIO_new(BIO_f_base64());
- BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
- bmem = BIO_new(BIO_s_mem());
- b64 = BIO_push(b64, bmem);
- BIO_write(b64, s.c_str(), s.size());
- BIO_flush(b64);
- BIO_get_mem_ptr(b64, &bptr);
-
- string result(bptr->data, bptr->length);
- BIO_free_all(b64);
-
- return result;
-}
-
-string DecodeBase64(string s)
-{
- BIO *b64, *bmem;
-
- char* buffer = static_cast<char*>(calloc(s.size(), sizeof(char)));
-
- b64 = BIO_new(BIO_f_base64());
- BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
- bmem = BIO_new_mem_buf(const_cast<char*>(s.c_str()), s.size());
- bmem = BIO_push(b64, bmem);
- BIO_read(bmem, buffer, s.size());
- BIO_free_all(bmem);
-
- string result(buffer);
- free(buffer);
- return result;
-}
-
bool HTTPAuthorized(map<string, string>& mapHeaders)
{
string strAuth = mapHeaders["authorization"];
return false;
string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
string strUserPass = DecodeBase64(strUserPass64);
- string::size_type nColon = strUserPass.find(":");
- if (nColon == string::npos)
- return false;
- string strUser = strUserPass.substr(0, nColon);
- string strPassword = strUserPass.substr(nColon+1);
- return (strUser == mapArgs["-rpcuser"] && strPassword == mapArgs["-rpcpassword"]);
+ return strUserPass == strRPCUserColonPass;
}
//
{
printf("ThreadRPCServer started\n");
- if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
+ strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
+ if (strRPCUserColonPass == ":")
{
string strWhatAmI = "To use bitcoind";
if (mapArgs.count("-server"))
else if (mapArgs.count("-daemon"))
strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
PrintConsole(
- _("Warning: %s, you must set rpcpassword=<password>\nin the configuration file: %s\n"
+ _("Error: %s, you must set rpcpassword=<password>\nin the configuration file: %s\n"
"If the file does not exist, create it with owner-readable-only file permissions.\n"),
strWhatAmI.c_str(),
GetConfigFile().c_str());
+#ifndef QT_GUI
CreateThread(Shutdown, NULL);
+#endif
return;
}
if (valMethod.type() != str_type)
throw JSONRPCError(-32600, "Method must be a string");
string strMethod = valMethod.get_str();
- if (strMethod != "getwork")
+ if (strMethod != "getwork" && strMethod != "getmemorypool")
printf("ThreadRPCServer method=%s\n", strMethod.c_str());
// Parse params
try
{
// Execute
- Value result = (*(*mi).second)(params, false);
+ Value result;
+ CRITICAL_BLOCK(cs_main)
+ CRITICAL_BLOCK(pwalletMain->cs_wallet)
+ result = (*(*mi).second)(params, false);
// Send reply
string strReply = JSONRPCReply(result, Value::null, id);
if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
- if (strMethod == "getamountreceived" && n > 1) ConvertTo<boost::int64_t>(params[1]); // deprecated
if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
- if (strMethod == "getreceivedbylabel" && n > 1) ConvertTo<boost::int64_t>(params[1]); // deprecated
- if (strMethod == "getallreceived" && n > 0) ConvertTo<boost::int64_t>(params[0]); // deprecated
- if (strMethod == "getallreceived" && n > 1) ConvertTo<bool>(params[1]); // deprecated
if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
- if (strMethod == "listreceivedbylabel" && n > 0) ConvertTo<boost::int64_t>(params[0]); // deprecated
- if (strMethod == "listreceivedbylabel" && n > 1) ConvertTo<bool>(params[1]); // deprecated
if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
+ if (strMethod == "listsinceblock" && n > 1) ConvertTo<boost::int64_t>(params[1]);
if (strMethod == "sendmany" && n > 1)
{
string s = params[1].get_str();
if (strPrint != "")
{
-#if defined(__WXMSW__) && defined(GUI)
- // Windows GUI apps can't print to command line,
- // so settle for a message box yuck
- MyMessageBox(strPrint, "Bitcoin", wxOK);
-#else
fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
-#endif
}
return nRet;
}