Skip to content

Commit da894ab

Browse files
petertoddjtimon
authored andcommitted
Accept any sequence of PUSHDATAs in OP_RETURN outputs
Previously only one PUSHDATA was allowed, needlessly limiting applications such as matching OP_RETURN contents with bloom filters that operate on a per-PUSHDATA level. Now any combination that passes IsPushOnly() is allowed, so long as the total size of the scriptPubKey is less than 42 bytes. (unchanged modulo non-minimal PUSHDATA encodings) Also, this fixes the odd bug where previously the PUSHDATA could be replaced by any single opcode, even sigops consuming opcodes such as CHECKMULTISIG. (20 sigops!)
1 parent 5d8709c commit da894ab

File tree

6 files changed

+34
-17
lines changed

6 files changed

+34
-17
lines changed

src/policy/policy.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,9 @@ bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType)
4949
return false;
5050
if (m < 1 || m > n)
5151
return false;
52-
}
52+
} else if (whichType == TX_NULL_DATA &&
53+
(!GetBoolArg("-datacarrier", true) || scriptPubKey.size() > nMaxDatacarrierBytes))
54+
return false;
5355

5456
return whichType != TX_NONSTANDARD;
5557
}

src/script/script.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ const char* GetOpName(opcodetype opcode)
144144
case OP_INVALIDOPCODE : return "OP_INVALIDOPCODE";
145145

146146
// Note:
147-
// The template matching params OP_SMALLDATA/etc are defined in opcodetype enum
147+
// The template matching params OP_SMALLINTEGER/etc are defined in opcodetype enum
148148
// as kind of implementation hack, they are *NOT* real opcodes. If found in real
149149
// Script, just let the default: case deal with them.
150150

src/script/script.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,6 @@ enum opcodetype
167167

168168

169169
// template matching params
170-
OP_SMALLDATA = 0xf9,
171170
OP_SMALLINTEGER = 0xfa,
172171
OP_PUBKEYS = 0xfb,
173172
OP_PUBKEYHASH = 0xfd,

src/script/standard.cpp

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,6 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsi
5151

5252
// Sender provides N pubkeys, receivers provides M signatures
5353
mTemplates.insert(make_pair(TX_MULTISIG, CScript() << OP_SMALLINTEGER << OP_PUBKEYS << OP_SMALLINTEGER << OP_CHECKMULTISIG));
54-
55-
// Empty, provably prunable, data-carrying output
56-
if (GetBoolArg("-datacarrier", true))
57-
mTemplates.insert(make_pair(TX_NULL_DATA, CScript() << OP_RETURN << OP_SMALLDATA));
58-
mTemplates.insert(make_pair(TX_NULL_DATA, CScript() << OP_RETURN));
5954
}
6055

6156
vSolutionsRet.clear();
@@ -70,6 +65,16 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsi
7065
return true;
7166
}
7267

68+
// Provably prunable, data-carrying output
69+
//
70+
// So long as script passes the IsUnspendable() test and all but the first
71+
// byte passes the IsPushOnly() test we don't care what exactly is in the
72+
// script.
73+
if (scriptPubKey.size() >= 1 && scriptPubKey[0] == OP_RETURN && scriptPubKey.IsPushOnly(scriptPubKey.begin()+1)) {
74+
typeRet = TX_NULL_DATA;
75+
return true;
76+
}
77+
7378
// Scan templates
7479
const CScript& script1 = scriptPubKey;
7580
BOOST_FOREACH(const PAIRTYPE(txnouttype, CScript)& tplate, mTemplates)
@@ -142,12 +147,6 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsi
142147
else
143148
break;
144149
}
145-
else if (opcode2 == OP_SMALLDATA)
146-
{
147-
// small pushdata, <= nMaxDatacarrierBytes
148-
if (vch1.size() > nMaxDatacarrierBytes)
149-
break;
150-
}
151150
else if (opcode1 != opcode2 || vch1 != vch2)
152151
{
153152
// Others must match exactly

src/script/standard.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class CScriptID : public uint160
2525
CScriptID(const uint160& in) : uint160(in) {}
2626
};
2727

28-
static const unsigned int MAX_OP_RETURN_RELAY = 80; //! bytes
28+
static const unsigned int MAX_OP_RETURN_RELAY = 83; //! bytes (+1 for OP_RETURN, +2 for the pushdata opcodes)
2929
extern unsigned nMaxDatacarrierBytes;
3030

3131
/**

src/test/transaction_tests.cpp

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -351,12 +351,29 @@ BOOST_AUTO_TEST_CASE(test_IsStandard)
351351
t.vout[0].scriptPubKey = CScript() << OP_1;
352352
BOOST_CHECK(!IsStandardTx(t, reason));
353353

354-
// 80-byte TX_NULL_DATA (standard)
354+
// MAX_OP_RETURN_RELAY-byte TX_NULL_DATA (standard)
355355
t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38");
356+
BOOST_CHECK_EQUAL(MAX_OP_RETURN_RELAY, t.vout[0].scriptPubKey.size());
356357
BOOST_CHECK(IsStandardTx(t, reason));
357358

358-
// 81-byte TX_NULL_DATA (non-standard)
359+
// MAX_OP_RETURN_RELAY+1-byte TX_NULL_DATA (non-standard)
359360
t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3800");
361+
BOOST_CHECK_EQUAL(MAX_OP_RETURN_RELAY + 1, t.vout[0].scriptPubKey.size());
362+
BOOST_CHECK(!IsStandardTx(t, reason));
363+
364+
// Data payload can be encoded in any way...
365+
t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("");
366+
BOOST_CHECK(IsStandardTx(t, reason));
367+
t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("00") << ParseHex("01");
368+
BOOST_CHECK(IsStandardTx(t, reason));
369+
// OP_RESERVED *is* considered to be a PUSHDATA type opcode by IsPushOnly()!
370+
t.vout[0].scriptPubKey = CScript() << OP_RETURN << OP_RESERVED << -1 << 0 << ParseHex("01") << 2 << 3 << 4 << 5 << 6 << 7 << 8 << 9 << 10 << 11 << 12 << 13 << 14 << 15 << 16;
371+
BOOST_CHECK(IsStandardTx(t, reason));
372+
t.vout[0].scriptPubKey = CScript() << OP_RETURN << 0 << ParseHex("01") << 2 << ParseHex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
373+
BOOST_CHECK(IsStandardTx(t, reason));
374+
375+
// ...so long as it only contains PUSHDATA's
376+
t.vout[0].scriptPubKey = CScript() << OP_RETURN << OP_RETURN;
360377
BOOST_CHECK(!IsStandardTx(t, reason));
361378

362379
// TX_NULL_DATA w/o PUSHDATA

0 commit comments

Comments
 (0)