Skip to content

Commit 87fe71e

Browse files
committed
Add HasCanonicalPushes(), and use it in IsStandardTx
1 parent 9aea601 commit 87fe71e

File tree

4 files changed

+53
-1
lines changed

4 files changed

+53
-1
lines changed

src/main.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,10 @@ bool IsStandardTx(const CTransaction& tx, string& reason)
442442
reason = "scriptsig-not-pushonly";
443443
return false;
444444
}
445+
if (!txin.scriptSig.HasCanonicalPushes()) {
446+
reason = "non-canonical-push";
447+
return false;
448+
}
445449
}
446450

447451
unsigned int nDataOut = 0;

src/script.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1881,6 +1881,33 @@ bool CScript::IsPushOnly() const
18811881
return true;
18821882
}
18831883

1884+
bool CScript::HasCanonicalPushes() const
1885+
{
1886+
const_iterator pc = begin();
1887+
while (pc < end())
1888+
{
1889+
opcodetype opcode;
1890+
std::vector<unsigned char> data;
1891+
if (!GetOp(pc, opcode, data))
1892+
return false;
1893+
if (opcode > OP_16)
1894+
continue;
1895+
if (opcode < OP_PUSHDATA1 && opcode > OP_0 && (data.size() == 1 && data[0] <= 16))
1896+
// Could have used an OP_n code, rather than a 1-byte push.
1897+
return false;
1898+
if (opcode == OP_PUSHDATA1 && data.size() < OP_PUSHDATA1)
1899+
// Could have used a normal n-byte push, rather than OP_PUSHDATA1.
1900+
return false;
1901+
if (opcode == OP_PUSHDATA2 && data.size() <= 0xFF)
1902+
// Could have used an OP_PUSHDATA1.
1903+
return false;
1904+
if (opcode == OP_PUSHDATA4 && data.size() <= 0xFFFF)
1905+
// Could have used an OP_PUSHDATA2.
1906+
return false;
1907+
}
1908+
return true;
1909+
}
1910+
18841911
class CScriptVisitor : public boost::static_visitor<bool>
18851912
{
18861913
private:

src/script.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -541,9 +541,12 @@ class CScript : public std::vector<unsigned char>
541541

542542
bool IsPayToScriptHash() const;
543543

544-
// Called by IsStandardTx
544+
// Called by IsStandardTx and P2SH VerifyScript (which makes it consensus-critical).
545545
bool IsPushOnly() const;
546546

547+
// Called by IsStandardTx.
548+
bool HasCanonicalPushes() const;
549+
547550
// Returns whether the script is guaranteed to fail at execution,
548551
// regardless of the initial stack. This allows outputs to be pruned
549552
// instantly when entering the UTXO set.

src/test/script_tests.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -438,4 +438,22 @@ BOOST_AUTO_TEST_CASE(script_combineSigs)
438438
BOOST_CHECK(combined == partial3c);
439439
}
440440

441+
BOOST_AUTO_TEST_CASE(script_standard_push)
442+
{
443+
for (int i=0; i<1000; i++) {
444+
CScript script;
445+
script << i;
446+
BOOST_CHECK_MESSAGE(script.IsPushOnly(), "Number " << i << " is not pure push.");
447+
BOOST_CHECK_MESSAGE(script.HasCanonicalPushes(), "Number " << i << " push is not canonical.");
448+
}
449+
450+
for (int i=0; i<1000; i++) {
451+
std::vector<unsigned char> data(i, '\111');
452+
CScript script;
453+
script << data;
454+
BOOST_CHECK_MESSAGE(script.IsPushOnly(), "Length " << i << " is not pure push.");
455+
BOOST_CHECK_MESSAGE(script.HasCanonicalPushes(), "Length " << i << " push is not canonical.");
456+
}
457+
}
458+
441459
BOOST_AUTO_TEST_SUITE_END()

0 commit comments

Comments
 (0)