Browse Source

Add HasCanonicalPushes(), and use it in IsStandardTx

0.10
Pieter Wuille 11 years ago committed by Pieter Wuille
parent
commit
87fe71e1fc
  1. 4
      src/main.cpp
  2. 27
      src/script.cpp
  3. 5
      src/script.h
  4. 18
      src/test/script_tests.cpp

4
src/main.cpp

@ -442,6 +442,10 @@ bool IsStandardTx(const CTransaction& tx, string& reason)
reason = "scriptsig-not-pushonly"; reason = "scriptsig-not-pushonly";
return false; return false;
} }
if (!txin.scriptSig.HasCanonicalPushes()) {
reason = "non-canonical-push";
return false;
}
} }
unsigned int nDataOut = 0; unsigned int nDataOut = 0;

27
src/script.cpp

@ -1881,6 +1881,33 @@ bool CScript::IsPushOnly() const
return true; return true;
} }
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> class CScriptVisitor : public boost::static_visitor<bool>
{ {
private: private:

5
src/script.h

@ -541,9 +541,12 @@ public:
bool IsPayToScriptHash() const; bool IsPayToScriptHash() const;
// Called by IsStandardTx // Called by IsStandardTx and P2SH VerifyScript (which makes it consensus-critical).
bool IsPushOnly() const; bool IsPushOnly() const;
// Called by IsStandardTx.
bool HasCanonicalPushes() const;
// Returns whether the script is guaranteed to fail at execution, // Returns whether the script is guaranteed to fail at execution,
// regardless of the initial stack. This allows outputs to be pruned // regardless of the initial stack. This allows outputs to be pruned
// instantly when entering the UTXO set. // instantly when entering the UTXO set.

18
src/test/script_tests.cpp

@ -438,4 +438,22 @@ BOOST_AUTO_TEST_CASE(script_combineSigs)
BOOST_CHECK(combined == partial3c); BOOST_CHECK(combined == partial3c);
} }
BOOST_AUTO_TEST_CASE(script_standard_push)
{
for (int i=0; i<1000; i++) {
CScript script;
script << i;
BOOST_CHECK_MESSAGE(script.IsPushOnly(), "Number " << i << " is not pure push.");
BOOST_CHECK_MESSAGE(script.HasCanonicalPushes(), "Number " << i << " push is not canonical.");
}
for (int i=0; i<1000; i++) {
std::vector<unsigned char> data(i, '\111');
CScript script;
script << data;
BOOST_CHECK_MESSAGE(script.IsPushOnly(), "Length " << i << " is not pure push.");
BOOST_CHECK_MESSAGE(script.HasCanonicalPushes(), "Length " << i << " push is not canonical.");
}
}
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()

Loading…
Cancel
Save