Merge pull request #2738 from jgarzik/op_return
Relay OP_RETURN data TxOut as standard transaction type.
This commit is contained in:
commit
be484db274
5 changed files with 56 additions and 10 deletions
15
src/main.cpp
15
src/main.cpp
|
@ -469,17 +469,28 @@ bool IsStandardTx(const CTransaction& tx, string& reason)
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int nDataOut = 0;
|
||||
txnouttype whichType;
|
||||
BOOST_FOREACH(const CTxOut& txout, tx.vout) {
|
||||
if (!::IsStandard(txout.scriptPubKey)) {
|
||||
if (!::IsStandard(txout.scriptPubKey, whichType)) {
|
||||
reason = "scriptpubkey";
|
||||
return false;
|
||||
}
|
||||
if (txout.IsDust(CTransaction::nMinRelayTxFee)) {
|
||||
if (whichType == TX_NULL_DATA)
|
||||
nDataOut++;
|
||||
else if (txout.IsDust(CTransaction::nMinRelayTxFee)) {
|
||||
reason = "dust";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// only one OP_RETURN txout is permitted
|
||||
if (nDataOut > 1) {
|
||||
reason = "mucho-data";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -79,6 +79,7 @@ const char* GetTxnOutputType(txnouttype t)
|
|||
case TX_PUBKEYHASH: return "pubkeyhash";
|
||||
case TX_SCRIPTHASH: return "scripthash";
|
||||
case TX_MULTISIG: return "multisig";
|
||||
case TX_NULL_DATA: return "nulldata";
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
@ -220,6 +221,7 @@ const char* GetOpName(opcodetype opcode)
|
|||
// template matching params
|
||||
case OP_PUBKEYHASH : return "OP_PUBKEYHASH";
|
||||
case OP_PUBKEY : return "OP_PUBKEY";
|
||||
case OP_SMALLDATA : return "OP_SMALLDATA";
|
||||
|
||||
case OP_INVALIDOPCODE : return "OP_INVALIDOPCODE";
|
||||
default:
|
||||
|
@ -1204,6 +1206,9 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsi
|
|||
|
||||
// Sender provides N pubkeys, receivers provides M signatures
|
||||
mTemplates.insert(make_pair(TX_MULTISIG, CScript() << OP_SMALLINTEGER << OP_PUBKEYS << OP_SMALLINTEGER << OP_CHECKMULTISIG));
|
||||
|
||||
// Empty, provably prunable, data-carrying output
|
||||
mTemplates.insert(make_pair(TX_NULL_DATA, CScript() << OP_RETURN << OP_SMALLDATA));
|
||||
}
|
||||
|
||||
// Shortcut for pay-to-script-hash, which are more constrained than the other types:
|
||||
|
@ -1288,6 +1293,12 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsi
|
|||
else
|
||||
break;
|
||||
}
|
||||
else if (opcode2 == OP_SMALLDATA)
|
||||
{
|
||||
// small pushdata, <= 80 bytes
|
||||
if (vch1.size() > 80)
|
||||
break;
|
||||
}
|
||||
else if (opcode1 != opcode2 || vch1 != vch2)
|
||||
{
|
||||
// Others must match exactly
|
||||
|
@ -1350,6 +1361,7 @@ bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, uint256 hash
|
|||
switch (whichTypeRet)
|
||||
{
|
||||
case TX_NONSTANDARD:
|
||||
case TX_NULL_DATA:
|
||||
return false;
|
||||
case TX_PUBKEY:
|
||||
keyID = CPubKey(vSolutions[0]).GetID();
|
||||
|
@ -1381,6 +1393,8 @@ int ScriptSigArgsExpected(txnouttype t, const std::vector<std::vector<unsigned c
|
|||
{
|
||||
case TX_NONSTANDARD:
|
||||
return -1;
|
||||
case TX_NULL_DATA:
|
||||
return 1;
|
||||
case TX_PUBKEY:
|
||||
return 1;
|
||||
case TX_PUBKEYHASH:
|
||||
|
@ -1395,10 +1409,9 @@ int ScriptSigArgsExpected(txnouttype t, const std::vector<std::vector<unsigned c
|
|||
return -1;
|
||||
}
|
||||
|
||||
bool IsStandard(const CScript& scriptPubKey)
|
||||
bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType)
|
||||
{
|
||||
vector<valtype> vSolutions;
|
||||
txnouttype whichType;
|
||||
if (!Solver(scriptPubKey, whichType, vSolutions))
|
||||
return false;
|
||||
|
||||
|
@ -1457,6 +1470,7 @@ bool IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
|
|||
switch (whichType)
|
||||
{
|
||||
case TX_NONSTANDARD:
|
||||
case TX_NULL_DATA:
|
||||
return false;
|
||||
case TX_PUBKEY:
|
||||
keyID = CPubKey(vSolutions[0]).GetID();
|
||||
|
@ -1518,6 +1532,8 @@ bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, vecto
|
|||
vector<valtype> vSolutions;
|
||||
if (!Solver(scriptPubKey, typeRet, vSolutions))
|
||||
return false;
|
||||
if (typeRet == TX_NULL_DATA)
|
||||
return true;
|
||||
|
||||
if (typeRet == TX_MULTISIG)
|
||||
{
|
||||
|
@ -1733,6 +1749,7 @@ static CScript CombineSignatures(CScript scriptPubKey, const CTransaction& txTo,
|
|||
switch (txType)
|
||||
{
|
||||
case TX_NONSTANDARD:
|
||||
case TX_NULL_DATA:
|
||||
// Don't know anything about this, assume bigger one is correct:
|
||||
if (sigs1.size() >= sigs2.size())
|
||||
return PushAll(sigs1);
|
||||
|
|
|
@ -46,6 +46,7 @@ enum txnouttype
|
|||
TX_PUBKEYHASH,
|
||||
TX_SCRIPTHASH,
|
||||
TX_MULTISIG,
|
||||
TX_NULL_DATA,
|
||||
};
|
||||
|
||||
class CNoDestination {
|
||||
|
@ -202,6 +203,7 @@ enum opcodetype
|
|||
|
||||
|
||||
// template matching params
|
||||
OP_SMALLDATA = 0xf9,
|
||||
OP_SMALLINTEGER = 0xfa,
|
||||
OP_PUBKEYS = 0xfb,
|
||||
OP_PUBKEYHASH = 0xfd,
|
||||
|
@ -683,7 +685,7 @@ bool IsCanonicalSignature(const std::vector<unsigned char> &vchSig, unsigned int
|
|||
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType);
|
||||
bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::vector<unsigned char> >& vSolutionsRet);
|
||||
int ScriptSigArgsExpected(txnouttype t, const std::vector<std::vector<unsigned char> >& vSolutions);
|
||||
bool IsStandard(const CScript& scriptPubKey);
|
||||
bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType);
|
||||
bool IsMine(const CKeyStore& keystore, const CScript& scriptPubKey);
|
||||
bool IsMine(const CKeyStore& keystore, const CTxDestination &dest);
|
||||
void ExtractAffectedKeys(const CKeyStore &keystore, const CScript& scriptPubKey, std::vector<CKeyID> &vKeys);
|
||||
|
|
|
@ -133,21 +133,23 @@ BOOST_AUTO_TEST_CASE(multisig_IsStandard)
|
|||
for (int i = 0; i < 4; i++)
|
||||
key[i].MakeNewKey(true);
|
||||
|
||||
txnouttype whichType;
|
||||
|
||||
CScript a_and_b;
|
||||
a_and_b << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG;
|
||||
BOOST_CHECK(::IsStandard(a_and_b));
|
||||
BOOST_CHECK(::IsStandard(a_and_b, whichType));
|
||||
|
||||
CScript a_or_b;
|
||||
a_or_b << OP_1 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG;
|
||||
BOOST_CHECK(::IsStandard(a_or_b));
|
||||
BOOST_CHECK(::IsStandard(a_or_b, whichType));
|
||||
|
||||
CScript escrow;
|
||||
escrow << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << key[2].GetPubKey() << OP_3 << OP_CHECKMULTISIG;
|
||||
BOOST_CHECK(::IsStandard(escrow));
|
||||
BOOST_CHECK(::IsStandard(escrow, whichType));
|
||||
|
||||
CScript one_of_four;
|
||||
one_of_four << OP_1 << key[0].GetPubKey() << key[1].GetPubKey() << key[2].GetPubKey() << key[3].GetPubKey() << OP_4 << OP_CHECKMULTISIG;
|
||||
BOOST_CHECK(!::IsStandard(one_of_four));
|
||||
BOOST_CHECK(!::IsStandard(one_of_four, whichType));
|
||||
|
||||
CScript malformed[6];
|
||||
malformed[0] << OP_3 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG;
|
||||
|
@ -158,7 +160,7 @@ BOOST_AUTO_TEST_CASE(multisig_IsStandard)
|
|||
malformed[5] << OP_1 << key[0].GetPubKey() << key[1].GetPubKey();
|
||||
|
||||
for (int i = 0; i < 6; i++)
|
||||
BOOST_CHECK(!::IsStandard(malformed[i]));
|
||||
BOOST_CHECK(!::IsStandard(malformed[i], whichType));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(multisig_Solver1)
|
||||
|
|
|
@ -273,6 +273,20 @@ BOOST_AUTO_TEST_CASE(test_IsStandard)
|
|||
|
||||
t.vout[0].scriptPubKey = CScript() << OP_1;
|
||||
BOOST_CHECK(!IsStandardTx(t, reason));
|
||||
|
||||
// 80-byte TX_NULL_DATA (standard)
|
||||
t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38");
|
||||
BOOST_CHECK(IsStandardTx(t, reason));
|
||||
|
||||
// 81-byte TX_NULL_DATA (non-standard)
|
||||
t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3800");
|
||||
BOOST_CHECK(!IsStandardTx(t, reason));
|
||||
|
||||
// Only one TX_NULL_DATA permitted
|
||||
t.vout.resize(2);
|
||||
t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38");
|
||||
t.vout[1].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38");
|
||||
BOOST_CHECK(!IsStandardTx(t, reason));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
|
Loading…
Reference in a new issue