Allows user enforce transaction scripts to use canonical PUSH operators, enabled by default.
CClientUIInterface uiInterface;
std::string strWalletFileName;
bool fConfChange;
+bool fEnforceCanonical;
unsigned int nNodeLifespan;
unsigned int nDerivationMethodIndex;
unsigned int nMinerSleep;
" -blocknotify=<cmd> " + _("Execute command when the best block changes (%s in cmd is replaced by block hash)") + "\n" +
" -walletnotify=<cmd> " + _("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=<n> " + _("Set key pool size to <n> (default: 100)") + "\n" +
" -rescan " + _("Rescan the block chain for missing wallet transactions") + "\n" +
}
fConfChange = GetBoolArg("-confchange", false);
+ fEnforceCanonical = GetBoolArg("-enforcecanonical", true);
if (mapArgs.count("-mininput"))
{
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;
}
extern bool fUseFastIndex;
extern unsigned int nDerivationMethodIndex;
+extern bool fEnforceCanonical;
+
// Minimum disk space required - used in CheckDiskSpace()
static const uint64 nMinDiskSpace = 52428800;
this->at(22) == OP_EQUAL);
}
+bool CScript::HasCanonicalPushes() const
+{
+ const_iterator pc = begin();
+ while (pc < end())
+ {
+ opcodetype opcode;
+ std::vector<unsigned char> 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<bool>
{
private:
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();
return true;
}
+ // Called by CTransaction::IsStandard.
+ bool HasCanonicalPushes() const;
void SetDestination(const CTxDestination& address);
void SetMultisig(int nRequired, const std::vector<CKey>& keys);