mirror of
https://github.com/dashpay/dash.git
synced 2024-12-27 21:12:48 +01:00
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!)
This commit is contained in:
parent
5d8709c3b7
commit
da894ab5da
@ -49,7 +49,9 @@ bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType)
|
|||||||
return false;
|
return false;
|
||||||
if (m < 1 || m > n)
|
if (m < 1 || m > n)
|
||||||
return false;
|
return false;
|
||||||
}
|
} else if (whichType == TX_NULL_DATA &&
|
||||||
|
(!GetBoolArg("-datacarrier", true) || scriptPubKey.size() > nMaxDatacarrierBytes))
|
||||||
|
return false;
|
||||||
|
|
||||||
return whichType != TX_NONSTANDARD;
|
return whichType != TX_NONSTANDARD;
|
||||||
}
|
}
|
||||||
|
@ -144,7 +144,7 @@ const char* GetOpName(opcodetype opcode)
|
|||||||
case OP_INVALIDOPCODE : return "OP_INVALIDOPCODE";
|
case OP_INVALIDOPCODE : return "OP_INVALIDOPCODE";
|
||||||
|
|
||||||
// Note:
|
// Note:
|
||||||
// The template matching params OP_SMALLDATA/etc are defined in opcodetype enum
|
// The template matching params OP_SMALLINTEGER/etc are defined in opcodetype enum
|
||||||
// as kind of implementation hack, they are *NOT* real opcodes. If found in real
|
// as kind of implementation hack, they are *NOT* real opcodes. If found in real
|
||||||
// Script, just let the default: case deal with them.
|
// Script, just let the default: case deal with them.
|
||||||
|
|
||||||
|
@ -167,7 +167,6 @@ enum opcodetype
|
|||||||
|
|
||||||
|
|
||||||
// template matching params
|
// template matching params
|
||||||
OP_SMALLDATA = 0xf9,
|
|
||||||
OP_SMALLINTEGER = 0xfa,
|
OP_SMALLINTEGER = 0xfa,
|
||||||
OP_PUBKEYS = 0xfb,
|
OP_PUBKEYS = 0xfb,
|
||||||
OP_PUBKEYHASH = 0xfd,
|
OP_PUBKEYHASH = 0xfd,
|
||||||
|
@ -51,11 +51,6 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsi
|
|||||||
|
|
||||||
// Sender provides N pubkeys, receivers provides M signatures
|
// Sender provides N pubkeys, receivers provides M signatures
|
||||||
mTemplates.insert(make_pair(TX_MULTISIG, CScript() << OP_SMALLINTEGER << OP_PUBKEYS << OP_SMALLINTEGER << OP_CHECKMULTISIG));
|
mTemplates.insert(make_pair(TX_MULTISIG, CScript() << OP_SMALLINTEGER << OP_PUBKEYS << OP_SMALLINTEGER << OP_CHECKMULTISIG));
|
||||||
|
|
||||||
// Empty, provably prunable, data-carrying output
|
|
||||||
if (GetBoolArg("-datacarrier", true))
|
|
||||||
mTemplates.insert(make_pair(TX_NULL_DATA, CScript() << OP_RETURN << OP_SMALLDATA));
|
|
||||||
mTemplates.insert(make_pair(TX_NULL_DATA, CScript() << OP_RETURN));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
vSolutionsRet.clear();
|
vSolutionsRet.clear();
|
||||||
@ -70,6 +65,16 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsi
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Provably prunable, data-carrying output
|
||||||
|
//
|
||||||
|
// So long as script passes the IsUnspendable() test and all but the first
|
||||||
|
// byte passes the IsPushOnly() test we don't care what exactly is in the
|
||||||
|
// script.
|
||||||
|
if (scriptPubKey.size() >= 1 && scriptPubKey[0] == OP_RETURN && scriptPubKey.IsPushOnly(scriptPubKey.begin()+1)) {
|
||||||
|
typeRet = TX_NULL_DATA;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Scan templates
|
// Scan templates
|
||||||
const CScript& script1 = scriptPubKey;
|
const CScript& script1 = scriptPubKey;
|
||||||
BOOST_FOREACH(const PAIRTYPE(txnouttype, CScript)& tplate, mTemplates)
|
BOOST_FOREACH(const PAIRTYPE(txnouttype, CScript)& tplate, mTemplates)
|
||||||
@ -142,12 +147,6 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsi
|
|||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else if (opcode2 == OP_SMALLDATA)
|
|
||||||
{
|
|
||||||
// small pushdata, <= nMaxDatacarrierBytes
|
|
||||||
if (vch1.size() > nMaxDatacarrierBytes)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if (opcode1 != opcode2 || vch1 != vch2)
|
else if (opcode1 != opcode2 || vch1 != vch2)
|
||||||
{
|
{
|
||||||
// Others must match exactly
|
// Others must match exactly
|
||||||
|
@ -25,7 +25,7 @@ public:
|
|||||||
CScriptID(const uint160& in) : uint160(in) {}
|
CScriptID(const uint160& in) : uint160(in) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
static const unsigned int MAX_OP_RETURN_RELAY = 80; //! bytes
|
static const unsigned int MAX_OP_RETURN_RELAY = 83; //! bytes (+1 for OP_RETURN, +2 for the pushdata opcodes)
|
||||||
extern unsigned nMaxDatacarrierBytes;
|
extern unsigned nMaxDatacarrierBytes;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -351,12 +351,29 @@ BOOST_AUTO_TEST_CASE(test_IsStandard)
|
|||||||
t.vout[0].scriptPubKey = CScript() << OP_1;
|
t.vout[0].scriptPubKey = CScript() << OP_1;
|
||||||
BOOST_CHECK(!IsStandardTx(t, reason));
|
BOOST_CHECK(!IsStandardTx(t, reason));
|
||||||
|
|
||||||
// 80-byte TX_NULL_DATA (standard)
|
// MAX_OP_RETURN_RELAY-byte TX_NULL_DATA (standard)
|
||||||
t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38");
|
t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38");
|
||||||
|
BOOST_CHECK_EQUAL(MAX_OP_RETURN_RELAY, t.vout[0].scriptPubKey.size());
|
||||||
BOOST_CHECK(IsStandardTx(t, reason));
|
BOOST_CHECK(IsStandardTx(t, reason));
|
||||||
|
|
||||||
// 81-byte TX_NULL_DATA (non-standard)
|
// MAX_OP_RETURN_RELAY+1-byte TX_NULL_DATA (non-standard)
|
||||||
t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3800");
|
t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3800");
|
||||||
|
BOOST_CHECK_EQUAL(MAX_OP_RETURN_RELAY + 1, t.vout[0].scriptPubKey.size());
|
||||||
|
BOOST_CHECK(!IsStandardTx(t, reason));
|
||||||
|
|
||||||
|
// Data payload can be encoded in any way...
|
||||||
|
t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("");
|
||||||
|
BOOST_CHECK(IsStandardTx(t, reason));
|
||||||
|
t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("00") << ParseHex("01");
|
||||||
|
BOOST_CHECK(IsStandardTx(t, reason));
|
||||||
|
// OP_RESERVED *is* considered to be a PUSHDATA type opcode by IsPushOnly()!
|
||||||
|
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;
|
||||||
|
BOOST_CHECK(IsStandardTx(t, reason));
|
||||||
|
t.vout[0].scriptPubKey = CScript() << OP_RETURN << 0 << ParseHex("01") << 2 << ParseHex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
|
||||||
|
BOOST_CHECK(IsStandardTx(t, reason));
|
||||||
|
|
||||||
|
// ...so long as it only contains PUSHDATA's
|
||||||
|
t.vout[0].scriptPubKey = CScript() << OP_RETURN << OP_RETURN;
|
||||||
BOOST_CHECK(!IsStandardTx(t, reason));
|
BOOST_CHECK(!IsStandardTx(t, reason));
|
||||||
|
|
||||||
// TX_NULL_DATA w/o PUSHDATA
|
// TX_NULL_DATA w/o PUSHDATA
|
||||||
|
Loading…
Reference in New Issue
Block a user