From 0c80f9494715c7dacd6c74a6a56092b416a4d60d Mon Sep 17 00:00:00 2001 From: MASM fan Date: Wed, 12 Feb 2014 08:58:27 +0400 Subject: [PATCH] Add -enforcecanonical option Allows user enforce transaction scripts to use canonical PUSH operators, enabled by default. --- src/init.cpp | 3 +++ src/main.cpp | 6 ++++++ src/main.h | 2 ++ src/script.cpp | 27 +++++++++++++++++++++++++++ src/script.h | 4 +++- 5 files changed, 41 insertions(+), 1 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 66ffda6..36c4a3a 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -30,6 +30,7 @@ CWallet* pwalletMain; CClientUIInterface uiInterface; std::string strWalletFileName; bool fConfChange; +bool fEnforceCanonical; unsigned int nNodeLifespan; unsigned int nDerivationMethodIndex; unsigned int nMinerSleep; @@ -291,6 +292,7 @@ std::string HelpMessage() " -blocknotify= " + _("Execute command when the best block changes (%s in cmd is replaced by block hash)") + "\n" + " -walletnotify= " + _("Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)") + "\n" + " -confchange " + _("Require a confirmations for change (default: 0)") + "\n" + + " -enforcecanonical " + _("Enforce transaction scripts to use canonical PUSH operators (default: 1)") + "\n" + " -upgradewallet " + _("Upgrade wallet to latest format") + "\n" + " -keypool= " + _("Set key pool size to (default: 100)") + "\n" + " -rescan " + _("Rescan the block chain for missing wallet transactions") + "\n" + @@ -472,6 +474,7 @@ bool AppInit2() } fConfChange = GetBoolArg("-confchange", false); + fEnforceCanonical = GetBoolArg("-enforcecanonical", true); if (mapArgs.count("-mininput")) { diff --git a/src/main.cpp b/src/main.cpp index 6e7d2a4..c4f3d17 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -309,12 +309,18 @@ bool CTransaction::IsStandard() const return false; if (!txin.scriptSig.IsPushOnly()) return false; + if (fEnforceCanonical && !txin.scriptSig.HasCanonicalPushes()) { + return false; + } } BOOST_FOREACH(const CTxOut& txout, vout) { if (!::IsStandard(txout.scriptPubKey)) return false; if (txout.nValue == 0) return false; + if (fEnforceCanonical && !txout.scriptPubKey.HasCanonicalPushes()) { + return false; + } } return true; } diff --git a/src/main.h b/src/main.h index 58ec9fa..fe64412 100644 --- a/src/main.h +++ b/src/main.h @@ -93,6 +93,8 @@ extern int64 nMinimumInputValue; extern bool fUseFastIndex; extern unsigned int nDerivationMethodIndex; +extern bool fEnforceCanonical; + // Minimum disk space required - used in CheckDiskSpace() static const uint64 nMinDiskSpace = 52428800; diff --git a/src/script.cpp b/src/script.cpp index 34c02cf..2bf2cbf 100644 --- a/src/script.cpp +++ b/src/script.cpp @@ -1881,6 +1881,33 @@ bool CScript::IsPayToScriptHash() const this->at(22) == OP_EQUAL); } +bool CScript::HasCanonicalPushes() const +{ + const_iterator pc = begin(); + while (pc < end()) + { + opcodetype opcode; + std::vector data; + if (!GetOp(pc, opcode, data)) + return false; + if (opcode > OP_16) + continue; + if (opcode < OP_PUSHDATA1 && opcode > OP_0 && (data.size() == 1 && data[0] <= 16)) + // Could have used an OP_n code, rather than a 1-byte push. + return false; + if (opcode == OP_PUSHDATA1 && data.size() < OP_PUSHDATA1) + // Could have used a normal n-byte push, rather than OP_PUSHDATA1. + return false; + if (opcode == OP_PUSHDATA2 && data.size() <= 0xFF) + // Could have used an OP_PUSHDATA1. + return false; + if (opcode == OP_PUSHDATA4 && data.size() <= 0xFFFF) + // Could have used an OP_PUSHDATA2. + return false; + } + return true; +} + class CScriptVisitor : public boost::static_visitor { private: diff --git a/src/script.h b/src/script.h index 711b03c..577e80c 100644 --- a/src/script.h +++ b/src/script.h @@ -522,7 +522,7 @@ public: bool IsPayToScriptHash() const; - // Called by CTransaction::IsStandard + // Called by CTransaction::IsStandard and P2SH VerifyScript (which makes it consensus-critical). bool IsPushOnly() const { const_iterator pc = begin(); @@ -537,6 +537,8 @@ public: return true; } + // Called by CTransaction::IsStandard. + bool HasCanonicalPushes() const; void SetDestination(const CTxDestination& address); void SetMultisig(int nRequired, const std::vector& keys); -- 1.7.1