Skip to content

Commit

Permalink
Relay OP_RETURN data TxOut as standard transaction type
Browse files Browse the repository at this point in the history
Backport bitcoin commit a793424
(cherry picked from bitcoin a793424)

Conflicts:

	src/main.cpp
	src/test/transaction_tests.cpp
  • Loading branch information
Jeff Garzik authored and sunnyking committed Apr 22, 2015
1 parent d50b306 commit ac8be96
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 12 deletions.
17 changes: 15 additions & 2 deletions src/main.cpp
Expand Up @@ -305,9 +305,22 @@ bool CTransaction::IsStandard() const
if (!txin.scriptSig.IsPushOnly())
return false;
}
BOOST_FOREACH(const CTxOut& txout, vout)
if (!::IsStandard(txout.scriptPubKey))

unsigned int nDataOut = 0;
txnouttype whichType;
BOOST_FOREACH(const CTxOut& txout, vout) {
if (!::IsStandard(txout.scriptPubKey, whichType)) {
return false;
}
if (whichType == TX_NULL_DATA)
nDataOut++;
}

// only one OP_RETURN txout is permitted
if (nDataOut > 1) {
return false;
}

return true;
}

Expand Down
21 changes: 19 additions & 2 deletions src/script.cpp
Expand Up @@ -87,6 +87,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;
}
Expand Down Expand Up @@ -228,6 +229,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:
Expand Down Expand Up @@ -1213,6 +1215,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:
Expand Down Expand Up @@ -1297,6 +1302,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
Expand Down Expand Up @@ -1362,6 +1373,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();
Expand Down Expand Up @@ -1393,6 +1405,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:
Expand All @@ -1407,10 +1421,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;

Expand Down Expand Up @@ -1469,6 +1482,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();
Expand Down Expand Up @@ -1530,6 +1544,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)
{
Expand Down Expand Up @@ -1721,6 +1737,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);
Expand Down
4 changes: 3 additions & 1 deletion src/script.h
Expand Up @@ -37,6 +37,7 @@ enum txnouttype
TX_PUBKEYHASH,
TX_SCRIPTHASH,
TX_MULTISIG,
TX_NULL_DATA,
};

class CNoDestination {
Expand Down Expand Up @@ -193,6 +194,7 @@ enum opcodetype


// template matching params
OP_SMALLDATA = 0xf9,
OP_SMALLINTEGER = 0xfa,
OP_PUBKEYS = 0xfb,
OP_PUBKEYHASH = 0xfd,
Expand Down Expand Up @@ -589,7 +591,7 @@ class CScript : public std::vector<unsigned char>
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, 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);
bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet);
Expand Down
12 changes: 7 additions & 5 deletions src/test/multisig_tests.cpp
Expand Up @@ -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;
Expand All @@ -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)
Expand Down
18 changes: 16 additions & 2 deletions src/test/transaction_tests.cpp
Expand Up @@ -113,8 +113,22 @@ BOOST_AUTO_TEST_CASE(test_GetThrow)
t1.vout[0].nValue = 90*CENT;
t1.vout[0].scriptPubKey << OP_1;

BOOST_CHECK_THROW(t1.AreInputsStandard(missingInputs), runtime_error);
BOOST_CHECK_THROW(t1.GetValueIn(missingInputs), runtime_error);
t.vout[0].scriptPubKey = CScript() << OP_1;
BOOST_CHECK(t.IsStandard());

// 80-byte TX_NULL_DATA (standard)
t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38");
BOOST_CHECK(t.IsStandard());

// 81-byte TX_NULL_DATA (non-standard)
t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3800");
BOOST_CHECK(!t.IsStandard());

// 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(!t.IsStandard());
}

BOOST_AUTO_TEST_SUITE_END()

0 comments on commit ac8be96

Please sign in to comment.