aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/base58.cpp4
-rw-r--r--src/bitcoin-cli-res.rc2
-rw-r--r--src/checkpoints.cpp7
-rw-r--r--src/checkpoints.h7
-rw-r--r--src/init.h2
-rw-r--r--src/key.cpp3
-rw-r--r--src/main.cpp61
-rw-r--r--src/main.h2
-rw-r--r--src/net.h3
-rw-r--r--src/qt/forms/sendcoinsentry.ui2
-rw-r--r--src/qt/forms/signverifymessagedialog.ui4
-rw-r--r--src/qt/guiutil.cpp4
-rw-r--r--src/qt/signverifymessagedialog.cpp1
-rw-r--r--src/qt/utilitydialog.cpp1
-rw-r--r--src/rpcblockchain.cpp2
-rw-r--r--src/rpcmining.cpp2
-rw-r--r--src/rpcmisc.cpp2
-rw-r--r--src/rpcprotocol.cpp39
-rw-r--r--src/rpcprotocol.h6
-rw-r--r--src/rpcserver.cpp153
-rw-r--r--src/rpcserver.h11
-rw-r--r--src/script.cpp5
-rw-r--r--src/test/script_P2SH_tests.cpp118
-rw-r--r--src/util.cpp3
24 files changed, 253 insertions, 191 deletions
diff --git a/src/base58.cpp b/src/base58.cpp
index 1bd64684e5..c9e91beef1 100644
--- a/src/base58.cpp
+++ b/src/base58.cpp
@@ -186,6 +186,7 @@ int CBase58Data::CompareTo(const CBase58Data& b58) const {
}
namespace {
+
class CBitcoinAddressVisitor : public boost::static_visitor<bool> {
private:
CBitcoinAddress *addr;
@@ -196,7 +197,8 @@ namespace {
bool operator()(const CScriptID &id) const { return addr->Set(id); }
bool operator()(const CNoDestination &no) const { return false; }
};
-};
+
+} // anon namespace
bool CBitcoinAddress::Set(const CKeyID &id) {
SetData(Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS), &id, 20);
diff --git a/src/bitcoin-cli-res.rc b/src/bitcoin-cli-res.rc
index f8bfb3a881..a4a0c47ea5 100644
--- a/src/bitcoin-cli-res.rc
+++ b/src/bitcoin-cli-res.rc
@@ -5,7 +5,7 @@
#define VER_PRODUCTVERSION_STR STRINGIZE(CLIENT_VERSION_MAJOR) "." STRINGIZE(CLIENT_VERSION_MINOR) "." STRINGIZE(CLIENT_VERSION_REVISION) "." STRINGIZE(CLIENT_VERSION_BUILD)
#define VER_FILEVERSION VER_PRODUCTVERSION
#define VER_FILEVERSION_STR VER_PRODUCTVERSION_STR
-#define COPYRIGHT_STR "2009-" STRINGIZE(COPYRIGHT_YEAR) " The Bitcoin Core developers"
+#define COPYRIGHT_STR "2009-" STRINGIZE(COPYRIGHT_YEAR) " The Bitcoin Core Developers"
VS_VERSION_INFO VERSIONINFO
FILEVERSION VER_FILEVERSION
diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp
index 75ac418916..80479b47fb 100644
--- a/src/checkpoints.cpp
+++ b/src/checkpoints.cpp
@@ -12,8 +12,8 @@
#include <boost/assign/list_of.hpp> // for 'map_list_of()'
#include <boost/foreach.hpp>
-namespace Checkpoints
-{
+namespace Checkpoints {
+
typedef std::map<int, uint256> MapCheckpoints;
// How many times we expect transactions after the last checkpoint to
@@ -161,4 +161,5 @@ namespace Checkpoints
}
return NULL;
}
-}
+
+} // namespace Checkpoints
diff --git a/src/checkpoints.h b/src/checkpoints.h
index 1b4aacee20..2cf8d41b9d 100644
--- a/src/checkpoints.h
+++ b/src/checkpoints.h
@@ -13,8 +13,8 @@ class uint256;
/** Block-chain checkpoints are compiled-in sanity checks.
* They are updated every release or three.
*/
-namespace Checkpoints
-{
+namespace Checkpoints {
+
// Returns true if block passes checkpoint checks
bool CheckBlock(int nHeight, const uint256& hash);
@@ -27,6 +27,7 @@ namespace Checkpoints
double GuessVerificationProgress(CBlockIndex *pindex, bool fSigchecks = true);
extern bool fEnabled;
-}
+
+} //namespace Checkpoints
#endif
diff --git a/src/init.h b/src/init.h
index 52daa47616..626525c9ad 100644
--- a/src/init.h
+++ b/src/init.h
@@ -12,7 +12,7 @@ class CWallet;
namespace boost {
class thread_group;
-};
+} // namespace boost
extern CWallet* pwalletMain;
diff --git a/src/key.cpp b/src/key.cpp
index 96b1ac439c..784085da34 100644
--- a/src/key.cpp
+++ b/src/key.cpp
@@ -377,8 +377,7 @@ const unsigned char vchMaxModHalfOrder[32] = {
const unsigned char vchZero[0] = {};
-
-}; // end of anonymous namespace
+} // anon namespace
bool CKey::Check(const unsigned char *vch) {
return CompareBigEndian(vch, 32, vchZero, 0) > 0 &&
diff --git a/src/main.cpp b/src/main.cpp
index e06c519ee2..336a5a9a86 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -72,6 +72,7 @@ const string strMessageMagic = "Bitcoin Signed Message:\n";
// Internal stuff
namespace {
+
struct CBlockIndexWorkComparator
{
bool operator()(CBlockIndex *pa, CBlockIndex *pb) {
@@ -120,7 +121,8 @@ namespace {
};
map<uint256, pair<NodeId, list<QueuedBlock>::iterator> > mapBlocksInFlight;
map<uint256, pair<NodeId, list<uint256>::iterator> > mapBlocksToDownload;
-}
+
+} // anon namespace
//////////////////////////////////////////////////////////////////////////////
//
@@ -130,6 +132,7 @@ namespace {
// These functions dispatch to one or all registered wallets
namespace {
+
struct CMainSignals {
// Notifies listeners of updated transaction data (transaction, and optionally the block it is found in.
boost::signals2::signal<void (const CTransaction &, const CBlock *)> SyncTransaction;
@@ -144,7 +147,8 @@ struct CMainSignals {
// Tells listeners to broadcast their data.
boost::signals2::signal<void ()> Broadcast;
} g_signals;
-}
+
+} // anon namespace
void RegisterWallet(CWalletInterface* pwalletIn) {
g_signals.SyncTransaction.connect(boost::bind(&CWalletInterface::SyncTransaction, pwalletIn, _1, _2));
@@ -274,7 +278,6 @@ void MarkBlockAsReceived(const uint256 &hash, NodeId nodeFrom = -1) {
state->nLastBlockReceive = GetTimeMicros();
mapBlocksInFlight.erase(itInFlight);
}
-
}
// Requires cs_main.
@@ -310,7 +313,7 @@ void MarkBlockAsInFlight(NodeId nodeid, const uint256 &hash) {
mapBlocksInFlight[hash] = std::make_pair(nodeid, it);
}
-}
+} // anon namespace
bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats) {
LOCK(cs_main);
@@ -488,7 +491,7 @@ bool IsStandardTx(const CTransaction& tx, string& reason)
// Treat non-final transactions as non-standard to prevent a specific type
// of double-spend attack, as well as DoS attacks. (if the transaction
// can't be mined, the attacker isn't expending resources broadcasting it)
- // Basically we don't want to propagate transactions that can't included in
+ // Basically we don't want to propagate transactions that can't be included in
// the next block.
//
// However, IsFinalTx() is confusing... Without arguments, it uses
@@ -521,7 +524,7 @@ bool IsStandardTx(const CTransaction& tx, string& reason)
{
// Biggest 'standard' txin is a 15-of-15 P2SH multisig with compressed
// keys. (remember the 520 byte limit on redeemScript size) That works
- // out to a (15*(33+1))+3=513 byte redeemScript, 513+1+15*(73+1)=1624
+ // out to a (15*(33+1))+3=513 byte redeemScript, 513+1+15*(73+1)+3=1627
// bytes of scriptSig, which we round off to 1650 bytes for some minor
// future-proofing. That's also enough to spend a 20-of-20
// CHECKMULTISIG scriptPubKey, though such a scriptPubKey is not
@@ -583,15 +586,13 @@ bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime)
}
//
-// Check transaction inputs, and make sure any
-// pay-to-script-hash transactions are evaluating IsStandard scripts
+// Check transaction inputs to mitigate two
+// potential denial-of-service attacks:
//
-// Why bother? To avoid denial-of-service attacks; an attacker
-// can submit a standard HASH... OP_EQUAL transaction,
-// which will get accepted into blocks. The redemption
-// script can be anything; an attacker could use a very
-// expensive-to-check-upon-redemption script like:
-// DUP CHECKSIG DROP ... repeated 100 times... OP_1
+// 1. scriptSigs with extra data stuffed into them,
+// not consumed by scriptPubKey (or P2SH script)
+// 2. P2SH scripts with a crazy number of expensive
+// CHECKSIG/CHECKMULTISIG operations
//
bool AreInputsStandard(const CTransaction& tx, CCoinsViewCache& mapInputs)
{
@@ -615,8 +616,9 @@ bool AreInputsStandard(const CTransaction& tx, CCoinsViewCache& mapInputs)
// Transactions with extra stuff in their scriptSigs are
// non-standard. Note that this EvalScript() call will
// be quick, because if there are any operations
- // beside "push data" in the scriptSig the
- // IsStandard() call returns false
+ // beside "push data" in the scriptSig
+ // IsStandard() will have already returned false
+ // and this method isn't called.
vector<vector<unsigned char> > stack;
if (!EvalScript(stack, tx.vin[i].scriptSig, tx, i, false, 0))
return false;
@@ -628,16 +630,20 @@ bool AreInputsStandard(const CTransaction& tx, CCoinsViewCache& mapInputs)
CScript subscript(stack.back().begin(), stack.back().end());
vector<vector<unsigned char> > vSolutions2;
txnouttype whichType2;
- if (!Solver(subscript, whichType2, vSolutions2))
- return false;
- if (whichType2 == TX_SCRIPTHASH)
- return false;
-
- int tmpExpected;
- tmpExpected = ScriptSigArgsExpected(whichType2, vSolutions2);
- if (tmpExpected < 0)
- return false;
- nArgsExpected += tmpExpected;
+ if (Solver(subscript, whichType2, vSolutions2))
+ {
+ int tmpExpected = ScriptSigArgsExpected(whichType2, vSolutions2);
+ if (tmpExpected < 0)
+ return false;
+ nArgsExpected += tmpExpected;
+ }
+ else
+ {
+ // Any other Script with less than 15 sigops OK:
+ unsigned int sigops = subscript.GetSigOpCount(true);
+ // ... extra data left on the stack after execution is OK, too:
+ return (sigops <= MAX_P2SH_SIGOPS);
+ }
}
if (stack.size() != (unsigned int)nArgsExpected)
@@ -3649,7 +3655,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
if (pindex)
pindex = chainActive.Next(pindex);
int nLimit = 500;
- LogPrint("net", "getblocks %d to %s limit %d\n", (pindex ? pindex->nHeight : -1), hashStop.ToString(), nLimit);
+ LogPrint("net", "getblocks %d to %s limit %d\n", (pindex ? pindex->nHeight : -1), hashStop==uint256(0) ? "end" : hashStop.ToString(), nLimit);
for (; pindex; pindex = chainActive.Next(pindex))
{
if (pindex->GetBlockHash() == hashStop)
@@ -4038,6 +4044,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
else
{
// Ignore unknown commands for extensibility
+ LogPrint("net", "Unknown command \"%s\" from peer=%d\n", SanitizeString(strCommand), pfrom->id);
}
diff --git a/src/main.h b/src/main.h
index 9858bcfd69..0332db2163 100644
--- a/src/main.h
+++ b/src/main.h
@@ -43,6 +43,8 @@ static const unsigned int DEFAULT_BLOCK_PRIORITY_SIZE = 50000;
static const unsigned int MAX_STANDARD_TX_SIZE = 100000;
/** The maximum allowed number of signature check operations in a block (network rule) */
static const unsigned int MAX_BLOCK_SIGOPS = MAX_BLOCK_SIZE/50;
+/** Maxiumum number of signature check operations in an IsStandard() P2SH script */
+static const unsigned int MAX_P2SH_SIGOPS = 15;
/** The maximum number of orphan transactions kept in memory */
static const unsigned int MAX_ORPHAN_TRANSACTIONS = MAX_BLOCK_SIZE/100;
/** Default for -maxorphanblocks, maximum number of orphan blocks kept in memory */
diff --git a/src/net.h b/src/net.h
index 41dc618571..2ee798d468 100644
--- a/src/net.h
+++ b/src/net.h
@@ -28,14 +28,13 @@
#include <boost/signals2/signal.hpp>
#include <openssl/rand.h>
-
class CAddrMan;
class CBlockIndex;
class CNode;
namespace boost {
class thread_group;
-}
+} // namespace boost
/** Time between pings automatically sent out for latency probing and keepalive (in seconds). */
static const int PING_INTERVAL = 2 * 60;
diff --git a/src/qt/forms/sendcoinsentry.ui b/src/qt/forms/sendcoinsentry.ui
index e77de0d9b8..9d829970f0 100644
--- a/src/qt/forms/sendcoinsentry.ui
+++ b/src/qt/forms/sendcoinsentry.ui
@@ -51,7 +51,7 @@
<item>
<widget class="QValidatedLineEdit" name="payTo">
<property name="toolTip">
- <string>The address to send the payment to (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</string>
+ <string>The Bitcoin address to send the payment to</string>
</property>
</widget>
</item>
diff --git a/src/qt/forms/signverifymessagedialog.ui b/src/qt/forms/signverifymessagedialog.ui
index aa271b4f2a..53573ec821 100644
--- a/src/qt/forms/signverifymessagedialog.ui
+++ b/src/qt/forms/signverifymessagedialog.ui
@@ -45,7 +45,7 @@
<item>
<widget class="QValidatedLineEdit" name="addressIn_SM">
<property name="toolTip">
- <string>The address to sign the message with (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</string>
+ <string>The Bitcoin address to sign the message with</string>
</property>
</widget>
</item>
@@ -255,7 +255,7 @@
<item>
<widget class="QValidatedLineEdit" name="addressIn_VM">
<property name="toolTip">
- <string>The address the message was signed with (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</string>
+ <string>The Bitcoin address the message was signed with</string>
</property>
</widget>
</item>
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index 4fe98251d9..81b9054252 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -91,7 +91,9 @@ void setupAddressWidget(QValidatedLineEdit *widget, QWidget *parent)
widget->setFont(bitcoinAddressFont());
#if QT_VERSION >= 0x040700
- widget->setPlaceholderText(QObject::tr("Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)"));
+ // We don't want translators to use own addresses in translations
+ // and this is the only place, where this address is supplied.
+ widget->setPlaceholderText(QObject::tr("Enter a Bitcoin address (e.g. %1)").arg("1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L"));
#endif
widget->setValidator(new BitcoinAddressEntryValidator(parent));
widget->setCheckValidator(new BitcoinAddressCheckValidator(parent));
diff --git a/src/qt/signverifymessagedialog.cpp b/src/qt/signverifymessagedialog.cpp
index 3e56412c7c..d4d021e21c 100644
--- a/src/qt/signverifymessagedialog.cpp
+++ b/src/qt/signverifymessagedialog.cpp
@@ -27,7 +27,6 @@ SignVerifyMessageDialog::SignVerifyMessageDialog(QWidget *parent) :
#if QT_VERSION >= 0x040700
ui->signatureOut_SM->setPlaceholderText(tr("Click \"Sign Message\" to generate signature"));
- ui->addressIn_VM->setPlaceholderText(tr("Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)"));
#endif
GUIUtil::setupAddressWidget(ui->addressIn_SM, this);
diff --git a/src/qt/utilitydialog.cpp b/src/qt/utilitydialog.cpp
index eb647d0170..5fb0da145d 100644
--- a/src/qt/utilitydialog.cpp
+++ b/src/qt/utilitydialog.cpp
@@ -117,6 +117,7 @@ void ShutdownWindow::showShutdownWindow(BitcoinGUI *window)
tr("Bitcoin Core is shutting down...") + "<br /><br />" +
tr("Do not shut down the computer until this window disappears.")));
shutdownWindow->setLayout(layout);
+ shutdownWindow->setWindowTitle(window->windowTitle());
// Center shutdown window at where main window was
const QPoint global = window->mapToGlobal(window->rect().center());
diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp
index 580c6bd5ba..a67f266a13 100644
--- a/src/rpcblockchain.cpp
+++ b/src/rpcblockchain.cpp
@@ -66,7 +66,7 @@ Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex)
result.push_back(Pair("tx", txs));
result.push_back(Pair("time", block.GetBlockTime()));
result.push_back(Pair("nonce", (uint64_t)block.nNonce));
- result.push_back(Pair("bits", HexBits(block.nBits)));
+ result.push_back(Pair("bits", strprintf("%08x", block.nBits)));
result.push_back(Pair("difficulty", GetDifficulty(blockindex)));
result.push_back(Pair("chainwork", blockindex->nChainWork.GetHex()));
diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp
index 98caf704ee..db60ef3592 100644
--- a/src/rpcmining.cpp
+++ b/src/rpcmining.cpp
@@ -443,7 +443,7 @@ Value getblocktemplate(const Array& params, bool fHelp)
result.push_back(Pair("sigoplimit", (int64_t)MAX_BLOCK_SIGOPS));
result.push_back(Pair("sizelimit", (int64_t)MAX_BLOCK_SIZE));
result.push_back(Pair("curtime", (int64_t)pblock->nTime));
- result.push_back(Pair("bits", HexBits(pblock->nBits)));
+ result.push_back(Pair("bits", strprintf("%08x", pblock->nBits)));
result.push_back(Pair("height", (int64_t)(pindexPrev->nHeight+1)));
return result;
diff --git a/src/rpcmisc.cpp b/src/rpcmisc.cpp
index a300de2680..5b470516a1 100644
--- a/src/rpcmisc.cpp
+++ b/src/rpcmisc.cpp
@@ -22,10 +22,10 @@
#include "json/json_spirit_utils.h"
#include "json/json_spirit_value.h"
-using namespace std;
using namespace boost;
using namespace boost::assign;
using namespace json_spirit;
+using namespace std;
Value getinfo(const Array& params, bool fHelp)
{
diff --git a/src/rpcprotocol.cpp b/src/rpcprotocol.cpp
index 2718f81783..dd8692e802 100644
--- a/src/rpcprotocol.cpp
+++ b/src/rpcprotocol.cpp
@@ -54,7 +54,19 @@ static string rfc1123Time()
return DateTimeStrFormat("%a, %d %b %Y %H:%M:%S +0000", GetTime());
}
-string HTTPReply(int nStatus, const string& strMsg, bool keepalive)
+static const char *httpStatusDescription(int nStatus)
+{
+ switch (nStatus) {
+ case HTTP_OK: return "OK";
+ case HTTP_BAD_REQUEST: return "Bad Request";
+ case HTTP_FORBIDDEN: return "Forbidden";
+ case HTTP_NOT_FOUND: return "Not Found";
+ case HTTP_INTERNAL_SERVER_ERROR: return "Internal Server Error";
+ default: return "";
+ }
+}
+
+string HTTPError(int nStatus, bool keepalive, bool headersOnly)
{
if (nStatus == HTTP_UNAUTHORIZED)
return strprintf("HTTP/1.0 401 Authorization Required\r\n"
@@ -73,29 +85,32 @@ string HTTPReply(int nStatus, const string& strMsg, bool keepalive)
"</HEAD>\r\n"
"<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
"</HTML>\r\n", rfc1123Time(), FormatFullVersion());
- const char *cStatus;
- if (nStatus == HTTP_OK) cStatus = "OK";
- else if (nStatus == HTTP_BAD_REQUEST) cStatus = "Bad Request";
- else if (nStatus == HTTP_FORBIDDEN) cStatus = "Forbidden";
- else if (nStatus == HTTP_NOT_FOUND) cStatus = "Not Found";
- else if (nStatus == HTTP_INTERNAL_SERVER_ERROR) cStatus = "Internal Server Error";
- else cStatus = "";
+
+ return HTTPReply(nStatus, httpStatusDescription(nStatus), keepalive,
+ headersOnly, "text/plain");
+}
+
+string HTTPReply(int nStatus, const string& strMsg, bool keepalive,
+ bool headersOnly, const char *contentType)
+{
return strprintf(
"HTTP/1.1 %d %s\r\n"
"Date: %s\r\n"
"Connection: %s\r\n"
"Content-Length: %u\r\n"
- "Content-Type: application/json\r\n"
+ "Content-Type: %s\r\n"
"Server: bitcoin-json-rpc/%s\r\n"
"\r\n"
"%s",
nStatus,
- cStatus,
+ httpStatusDescription(nStatus),
rfc1123Time(),
keepalive ? "keep-alive" : "close",
- strMsg.size(),
+ (headersOnly ? 0 : strMsg.size()),
+ contentType,
FormatFullVersion(),
- strMsg);
+ (headersOnly ? "" : strMsg.c_str())
+ );
}
bool ReadHTTPRequestLine(std::basic_istream<char>& stream, int &proto,
diff --git a/src/rpcprotocol.h b/src/rpcprotocol.h
index 11bdd171d9..5627077bfb 100644
--- a/src/rpcprotocol.h
+++ b/src/rpcprotocol.h
@@ -141,7 +141,11 @@ private:
};
std::string HTTPPost(const std::string& strMsg, const std::map<std::string,std::string>& mapRequestHeaders);
-std::string HTTPReply(int nStatus, const std::string& strMsg, bool keepalive);
+std::string HTTPError(int nStatus, bool keepalive,
+ bool headerOnly = false);
+std::string HTTPReply(int nStatus, const std::string& strMsg, bool keepalive,
+ bool headerOnly = false,
+ const char *contentType = "application/json");
bool ReadHTTPRequestLine(std::basic_istream<char>& stream, int &proto,
std::string& http_method, std::string& http_uri);
int ReadHTTPStatus(std::basic_istream<char>& stream, int &proto);
diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp
index 6552de8c49..f47b3385da 100644
--- a/src/rpcserver.cpp
+++ b/src/rpcserver.cpp
@@ -25,10 +25,10 @@
#include <boost/shared_ptr.hpp>
#include "json/json_spirit_writer_template.h"
-using namespace std;
using namespace boost;
using namespace boost::asio;
using namespace json_spirit;
+using namespace std;
static std::string strRPCUserColonPass;
@@ -97,16 +97,6 @@ Value ValueFromAmount(int64_t amount)
return (double)amount / (double)COIN;
}
-std::string HexBits(unsigned int nBits)
-{
- union {
- int32_t nBits;
- char cBits[4];
- } uBits;
- uBits.nBits = htonl((int32_t)nBits);
- return HexStr(BEGIN(uBits.cBits), END(uBits.cBits));
-}
-
uint256 ParseHashV(const Value& v, string strName)
{
string strHex;
@@ -393,16 +383,6 @@ bool ClientAllowed(const boost::asio::ip::address& address)
return false;
}
-class AcceptedConnection
-{
-public:
- virtual ~AcceptedConnection() {}
-
- virtual std::iostream& stream() = 0;
- virtual std::string peer_address_to_string() const = 0;
- virtual void close() = 0;
-};
-
template <typename Protocol>
class AcceptedConnectionImpl : public AcceptedConnection
{
@@ -501,7 +481,7 @@ static void RPCAcceptHandler(boost::shared_ptr< basic_socket_acceptor<Protocol,
{
// Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
if (!fUseSSL)
- conn->stream() << HTTPReply(HTTP_FORBIDDEN, "", false) << std::flush;
+ conn->stream() << HTTPError(HTTP_FORBIDDEN, false) << std::flush;
conn->close();
}
else {
@@ -819,6 +799,71 @@ static string JSONRPCExecBatch(const Array& vReq)
return write_string(Value(ret), false) + "\n";
}
+static bool HTTPReq_JSONRPC(AcceptedConnection *conn,
+ string& strRequest,
+ map<string, string>& mapHeaders,
+ bool fRun)
+{
+ // Check authorization
+ if (mapHeaders.count("authorization") == 0)
+ {
+ conn->stream() << HTTPError(HTTP_UNAUTHORIZED, false) << std::flush;
+ return false;
+ }
+
+ if (!HTTPAuthorized(mapHeaders))
+ {
+ LogPrintf("ThreadRPCServer incorrect password attempt from %s\n", conn->peer_address_to_string());
+ /* Deter brute-forcing short passwords.
+ If this results in a DoS the user really
+ shouldn't have their RPC port exposed. */
+ if (mapArgs["-rpcpassword"].size() < 20)
+ MilliSleep(250);
+
+ conn->stream() << HTTPError(HTTP_UNAUTHORIZED, false) << std::flush;
+ return false;
+ }
+
+ JSONRequest jreq;
+ try
+ {
+ // Parse request
+ Value valRequest;
+ if (!read_string(strRequest, valRequest))
+ throw JSONRPCError(RPC_PARSE_ERROR, "Parse error");
+
+ string strReply;
+
+ // singleton request
+ if (valRequest.type() == obj_type) {
+ jreq.parse(valRequest);
+
+ Value result = tableRPC.execute(jreq.strMethod, jreq.params);
+
+ // Send reply
+ strReply = JSONRPCReply(result, Value::null, jreq.id);
+
+ // array of requests
+ } else if (valRequest.type() == array_type)
+ strReply = JSONRPCExecBatch(valRequest.get_array());
+ else
+ throw JSONRPCError(RPC_PARSE_ERROR, "Top-level object parse error");
+
+ conn->stream() << HTTPReply(HTTP_OK, strReply, fRun) << std::flush;
+ }
+ catch (Object& objError)
+ {
+ ErrorReply(conn->stream(), objError, jreq.id);
+ return false;
+ }
+ catch (std::exception& e)
+ {
+ ErrorReply(conn->stream(), JSONRPCError(RPC_PARSE_ERROR, e.what()), jreq.id);
+ return false;
+ }
+ return true;
+}
+
void ServiceConnection(AcceptedConnection *conn)
{
bool fRun = true;
@@ -835,67 +880,15 @@ void ServiceConnection(AcceptedConnection *conn)
// Read HTTP message headers and body
ReadHTTPMessage(conn->stream(), mapHeaders, strRequest, nProto);
- if (strURI != "/") {
- conn->stream() << HTTPReply(HTTP_NOT_FOUND, "", false) << std::flush;
- break;
- }
-
- // Check authorization
- if (mapHeaders.count("authorization") == 0)
- {
- conn->stream() << HTTPReply(HTTP_UNAUTHORIZED, "", false) << std::flush;
- break;
- }
- if (!HTTPAuthorized(mapHeaders))
- {
- LogPrintf("ThreadRPCServer incorrect password attempt from %s\n", conn->peer_address_to_string());
- /* Deter brute-forcing short passwords.
- If this results in a DoS the user really
- shouldn't have their RPC port exposed. */
- if (mapArgs["-rpcpassword"].size() < 20)
- MilliSleep(250);
-
- conn->stream() << HTTPReply(HTTP_UNAUTHORIZED, "", false) << std::flush;
- break;
- }
+ // HTTP Keep-Alive is false; close connection immediately
if (mapHeaders["connection"] == "close")
fRun = false;
- JSONRequest jreq;
- try
- {
- // Parse request
- Value valRequest;
- if (!read_string(strRequest, valRequest))
- throw JSONRPCError(RPC_PARSE_ERROR, "Parse error");
-
- string strReply;
-
- // singleton request
- if (valRequest.type() == obj_type) {
- jreq.parse(valRequest);
-
- Value result = tableRPC.execute(jreq.strMethod, jreq.params);
-
- // Send reply
- strReply = JSONRPCReply(result, Value::null, jreq.id);
-
- // array of requests
- } else if (valRequest.type() == array_type)
- strReply = JSONRPCExecBatch(valRequest.get_array());
- else
- throw JSONRPCError(RPC_PARSE_ERROR, "Top-level object parse error");
-
- conn->stream() << HTTPReply(HTTP_OK, strReply, fRun) << std::flush;
- }
- catch (Object& objError)
- {
- ErrorReply(conn->stream(), objError, jreq.id);
- break;
- }
- catch (std::exception& e)
- {
- ErrorReply(conn->stream(), JSONRPCError(RPC_PARSE_ERROR, e.what()), jreq.id);
+ if (strURI == "/") {
+ if (!HTTPReq_JSONRPC(conn, strRequest, mapHeaders, fRun))
+ break;
+ } else {
+ conn->stream() << HTTPError(HTTP_NOT_FOUND, false) << std::flush;
break;
}
}
diff --git a/src/rpcserver.h b/src/rpcserver.h
index 1966a65b50..01e77163c4 100644
--- a/src/rpcserver.h
+++ b/src/rpcserver.h
@@ -21,6 +21,16 @@
class CBlockIndex;
class CNetAddr;
+class AcceptedConnection
+{
+public:
+ virtual ~AcceptedConnection() {}
+
+ virtual std::iostream& stream() = 0;
+ virtual std::string peer_address_to_string() const = 0;
+ virtual void close() = 0;
+};
+
/* Start RPC threads */
void StartRPCThreads();
/* Alternative to StartRPCThreads for the GUI, when no server is
@@ -106,7 +116,6 @@ extern int64_t nWalletUnlockTime;
extern int64_t AmountFromValue(const json_spirit::Value& value);
extern json_spirit::Value ValueFromAmount(int64_t amount);
extern double GetDifficulty(const CBlockIndex* blockindex = NULL);
-extern std::string HexBits(unsigned int nBits);
extern std::string HelpRequiringPassphrase();
extern std::string HelpExampleCli(std::string methodname, std::string args);
extern std::string HelpExampleRpc(std::string methodname, std::string args);
diff --git a/src/script.cpp b/src/script.cpp
index bc4705abe7..e1b6985408 100644
--- a/src/script.cpp
+++ b/src/script.cpp
@@ -974,6 +974,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co
namespace {
+
/** Wrapper that serializes like CTransaction, but with the modifications
* required for the signature hash done in-place
*/
@@ -1066,7 +1067,8 @@ public:
::Serialize(s, txTo.nLockTime, nType, nVersion);
}
};
-}
+
+} // anon namespace
uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType)
{
@@ -1092,7 +1094,6 @@ uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsig
return ss.GetHash();
}
-
// Valid signature cache, to avoid doing expensive ECDSA signature checking
// twice for every transaction (once when accepted into memory pool, and
// again when accepted into the block chain)
diff --git a/src/test/script_P2SH_tests.cpp b/src/test/script_P2SH_tests.cpp
index a75593a8b2..6ae2b9cf64 100644
--- a/src/test/script_P2SH_tests.cpp
+++ b/src/test/script_P2SH_tests.cpp
@@ -256,46 +256,61 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
CCoinsView coinsDummy;
CCoinsViewCache coins(coinsDummy);
CBasicKeyStore keystore;
- CKey key[3];
+ CKey key[6];
vector<CPubKey> keys;
- for (int i = 0; i < 3; i++)
+ for (int i = 0; i < 6; i++)
{
key[i].MakeNewKey(true);
keystore.AddKey(key[i]);
- keys.push_back(key[i].GetPubKey());
}
+ for (int i = 0; i < 3; i++)
+ keys.push_back(key[i].GetPubKey());
CMutableTransaction txFrom;
- txFrom.vout.resize(6);
+ txFrom.vout.resize(7);
// First three are standard:
CScript pay1; pay1.SetDestination(key[0].GetPubKey().GetID());
keystore.AddCScript(pay1);
- CScript payScriptHash1; payScriptHash1.SetDestination(pay1.GetID());
CScript pay1of3; pay1of3.SetMultisig(1, keys);
- txFrom.vout[0].scriptPubKey = payScriptHash1;
+ txFrom.vout[0].scriptPubKey.SetDestination(pay1.GetID()); // P2SH (OP_CHECKSIG)
txFrom.vout[0].nValue = 1000;
- txFrom.vout[1].scriptPubKey = pay1;
+ txFrom.vout[1].scriptPubKey = pay1; // ordinary OP_CHECKSIG
txFrom.vout[1].nValue = 2000;
- txFrom.vout[2].scriptPubKey = pay1of3;
+ txFrom.vout[2].scriptPubKey = pay1of3; // ordinary OP_CHECKMULTISIG
txFrom.vout[2].nValue = 3000;
- // Last three non-standard:
- CScript empty;
- keystore.AddCScript(empty);
- txFrom.vout[3].scriptPubKey = empty;
+ // vout[3] is complicated 1-of-3 AND 2-of-3
+ // ... that is OK if wrapped in P2SH:
+ CScript oneAndTwo;
+ oneAndTwo << OP_1 << key[0].GetPubKey() << key[1].GetPubKey() << key[2].GetPubKey();
+ oneAndTwo << OP_3 << OP_CHECKMULTISIGVERIFY;
+ oneAndTwo << OP_2 << key[3].GetPubKey() << key[4].GetPubKey() << key[5].GetPubKey();
+ oneAndTwo << OP_3 << OP_CHECKMULTISIG;
+ keystore.AddCScript(oneAndTwo);
+ txFrom.vout[3].scriptPubKey.SetDestination(oneAndTwo.GetID());
txFrom.vout[3].nValue = 4000;
- // Can't use SetPayToScriptHash, it checks for the empty Script. So:
- txFrom.vout[4].scriptPubKey << OP_HASH160 << Hash160(empty) << OP_EQUAL;
+
+ // vout[4] is max sigops:
+ CScript fifteenSigops; fifteenSigops << OP_1;
+ for (int i = 0; i < MAX_P2SH_SIGOPS; i++)
+ fifteenSigops << key[i%3].GetPubKey();
+ fifteenSigops << OP_15 << OP_CHECKMULTISIG;
+ keystore.AddCScript(fifteenSigops);
+ txFrom.vout[4].scriptPubKey.SetDestination(fifteenSigops.GetID());
txFrom.vout[4].nValue = 5000;
- CScript oneOfEleven;
- oneOfEleven << OP_1;
- for (int i = 0; i < 11; i++)
- oneOfEleven << key[0].GetPubKey();
- oneOfEleven << OP_11 << OP_CHECKMULTISIG;
- txFrom.vout[5].scriptPubKey.SetDestination(oneOfEleven.GetID());
- txFrom.vout[5].nValue = 6000;
+
+ // vout[5/6] are non-standard because they exceed MAX_P2SH_SIGOPS
+ CScript sixteenSigops; sixteenSigops << OP_16 << OP_CHECKMULTISIG;
+ keystore.AddCScript(sixteenSigops);
+ txFrom.vout[5].scriptPubKey.SetDestination(fifteenSigops.GetID());
+ txFrom.vout[5].nValue = 5000;
+ CScript twentySigops; twentySigops << OP_CHECKMULTISIG;
+ keystore.AddCScript(twentySigops);
+ txFrom.vout[6].scriptPubKey.SetDestination(twentySigops.GetID());
+ txFrom.vout[6].nValue = 6000;
+
coins.SetCoins(txFrom.GetHash(), CCoins(txFrom, 0));
@@ -303,19 +318,24 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
txTo.vout.resize(1);
txTo.vout[0].scriptPubKey.SetDestination(key[1].GetPubKey().GetID());
- txTo.vin.resize(3);
- txTo.vin[0].prevout.n = 0;
- txTo.vin[0].prevout.hash = txFrom.GetHash();
+ txTo.vin.resize(5);
+ for (int i = 0; i < 5; i++)
+ {
+ txTo.vin[i].prevout.n = i;
+ txTo.vin[i].prevout.hash = txFrom.GetHash();
+ }
BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 0));
- txTo.vin[1].prevout.n = 1;
- txTo.vin[1].prevout.hash = txFrom.GetHash();
BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 1));
- txTo.vin[2].prevout.n = 2;
- txTo.vin[2].prevout.hash = txFrom.GetHash();
BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 2));
+ // SignSignature doesn't know how to sign these. We're
+ // not testing validating signatures, so just create
+ // dummy signatures that DO include the correct P2SH scripts:
+ txTo.vin[3].scriptSig << OP_11 << OP_11 << static_cast<vector<unsigned char> >(oneAndTwo);
+ txTo.vin[4].scriptSig << static_cast<vector<unsigned char> >(fifteenSigops);
BOOST_CHECK(::AreInputsStandard(txTo, coins));
- BOOST_CHECK_EQUAL(GetP2SHSigOpCount(txTo, coins), 1U);
+ // 22 P2SH sigops for all inputs (1 for vin[0], 6 for vin[3], 15 for vin[4]
+ BOOST_CHECK_EQUAL(GetP2SHSigOpCount(txTo, coins), 22U);
// Make sure adding crap to the scriptSigs makes them non-standard:
for (int i = 0; i < 3; i++)
@@ -326,23 +346,29 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
txTo.vin[i].scriptSig = t;
}
- CMutableTransaction txToNonStd;
- txToNonStd.vout.resize(1);
- txToNonStd.vout[0].scriptPubKey.SetDestination(key[1].GetPubKey().GetID());
- txToNonStd.vout[0].nValue = 1000;
- txToNonStd.vin.resize(2);
- txToNonStd.vin[0].prevout.n = 4;
- txToNonStd.vin[0].prevout.hash = txFrom.GetHash();
- txToNonStd.vin[0].scriptSig << Serialize(empty);
- txToNonStd.vin[1].prevout.n = 5;
- txToNonStd.vin[1].prevout.hash = txFrom.GetHash();
- txToNonStd.vin[1].scriptSig << OP_0 << Serialize(oneOfEleven);
-
- BOOST_CHECK(!::AreInputsStandard(txToNonStd, coins));
- BOOST_CHECK_EQUAL(GetP2SHSigOpCount(txToNonStd, coins), 11U);
-
- txToNonStd.vin[0].scriptSig.clear();
- BOOST_CHECK(!::AreInputsStandard(txToNonStd, coins));
+ CMutableTransaction txToNonStd1;
+ txToNonStd1.vout.resize(1);
+ txToNonStd1.vout[0].scriptPubKey.SetDestination(key[1].GetPubKey().GetID());
+ txToNonStd1.vout[0].nValue = 1000;
+ txToNonStd1.vin.resize(1);
+ txToNonStd1.vin[0].prevout.n = 5;
+ txToNonStd1.vin[0].prevout.hash = txFrom.GetHash();
+ txToNonStd1.vin[0].scriptSig << static_cast<vector<unsigned char> >(sixteenSigops);
+
+ BOOST_CHECK(!::AreInputsStandard(txToNonStd1, coins));
+ BOOST_CHECK_EQUAL(GetP2SHSigOpCount(txToNonStd1, coins), 16U);
+
+ CMutableTransaction txToNonStd2;
+ txToNonStd2.vout.resize(1);
+ txToNonStd2.vout[0].scriptPubKey.SetDestination(key[1].GetPubKey().GetID());
+ txToNonStd2.vout[0].nValue = 1000;
+ txToNonStd2.vin.resize(1);
+ txToNonStd2.vin[0].prevout.n = 6;
+ txToNonStd2.vin[0].prevout.hash = txFrom.GetHash();
+ txToNonStd2.vin[0].scriptSig << static_cast<vector<unsigned char> >(twentySigops);
+
+ BOOST_CHECK(!::AreInputsStandard(txToNonStd2, coins));
+ BOOST_CHECK_EQUAL(GetP2SHSigOpCount(txToNonStd2, coins), 20U);
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/util.cpp b/src/util.cpp
index e67c0dfd8a..5a8f85ade7 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -77,11 +77,12 @@
// See also: http://stackoverflow.com/questions/10020179/compilation-fail-in-boost-librairies-program-options
// http://clang.debian.net/status.php?version=3.0&key=CANNOT_FIND_FUNCTION
namespace boost {
+
namespace program_options {
std::string to_internal(const std::string&);
}
-}
+} // namespace boost
using namespace std;