Merge pull request #6424
da894ab
Accept any sequence of PUSHDATAs in OP_RETURN outputs (Peter Todd)5d8709c
Add IsPushOnly(const_iterator pc) (Peter Todd)6a07eb6
Make TX_SCRIPTHASH clear vSolutionsRet first (Peter Todd)
This commit is contained in:
commit
cd78c2a421
@ -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.
|
||||||
|
|
||||||
@ -210,9 +210,8 @@ bool CScript::IsPayToScriptHash() const
|
|||||||
this->at(22) == OP_EQUAL);
|
this->at(22) == OP_EQUAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CScript::IsPushOnly() const
|
bool CScript::IsPushOnly(const_iterator pc) const
|
||||||
{
|
{
|
||||||
const_iterator pc = begin();
|
|
||||||
while (pc < end())
|
while (pc < end())
|
||||||
{
|
{
|
||||||
opcodetype opcode;
|
opcodetype opcode;
|
||||||
@ -227,3 +226,8 @@ bool CScript::IsPushOnly() const
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CScript::IsPushOnly() const
|
||||||
|
{
|
||||||
|
return this->IsPushOnly(begin());
|
||||||
|
}
|
||||||
|
@ -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,
|
||||||
@ -589,6 +588,7 @@ public:
|
|||||||
bool IsPayToScriptHash() const;
|
bool IsPayToScriptHash() const;
|
||||||
|
|
||||||
/** Called by IsStandardTx and P2SH/BIP62 VerifyScript (which makes it consensus-critical). */
|
/** Called by IsStandardTx and P2SH/BIP62 VerifyScript (which makes it consensus-critical). */
|
||||||
|
bool IsPushOnly(const_iterator pc) const;
|
||||||
bool IsPushOnly() const;
|
bool IsPushOnly() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -51,13 +51,10 @@ 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();
|
||||||
|
|
||||||
// Shortcut for pay-to-script-hash, which are more constrained than the other types:
|
// Shortcut for pay-to-script-hash, which are more constrained than the other types:
|
||||||
// it is always OP_HASH160 20 [20 byte hash] OP_EQUAL
|
// it is always OP_HASH160 20 [20 byte hash] OP_EQUAL
|
||||||
if (scriptPubKey.IsPayToScriptHash())
|
if (scriptPubKey.IsPayToScriptHash())
|
||||||
@ -68,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)
|
||||||
@ -140,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