Skip to content

Commit be484db

Browse files
committed
Merge pull request #2738 from jgarzik/op_return
Relay OP_RETURN data TxOut as standard transaction type.
2 parents 10dc3c7 + a793424 commit be484db

File tree

5 files changed

+56
-10
lines changed

5 files changed

+56
-10
lines changed

src/main.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -469,17 +469,28 @@ bool IsStandardTx(const CTransaction& tx, string& reason)
469469
return false;
470470
}
471471
}
472+
473+
unsigned int nDataOut = 0;
474+
txnouttype whichType;
472475
BOOST_FOREACH(const CTxOut& txout, tx.vout) {
473-
if (!::IsStandard(txout.scriptPubKey)) {
476+
if (!::IsStandard(txout.scriptPubKey, whichType)) {
474477
reason = "scriptpubkey";
475478
return false;
476479
}
477-
if (txout.IsDust(CTransaction::nMinRelayTxFee)) {
480+
if (whichType == TX_NULL_DATA)
481+
nDataOut++;
482+
else if (txout.IsDust(CTransaction::nMinRelayTxFee)) {
478483
reason = "dust";
479484
return false;
480485
}
481486
}
482487

488+
// only one OP_RETURN txout is permitted
489+
if (nDataOut > 1) {
490+
reason = "mucho-data";
491+
return false;
492+
}
493+
483494
return true;
484495
}
485496

src/script.cpp

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ const char* GetTxnOutputType(txnouttype t)
7979
case TX_PUBKEYHASH: return "pubkeyhash";
8080
case TX_SCRIPTHASH: return "scripthash";
8181
case TX_MULTISIG: return "multisig";
82+
case TX_NULL_DATA: return "nulldata";
8283
}
8384
return NULL;
8485
}
@@ -220,6 +221,7 @@ const char* GetOpName(opcodetype opcode)
220221
// template matching params
221222
case OP_PUBKEYHASH : return "OP_PUBKEYHASH";
222223
case OP_PUBKEY : return "OP_PUBKEY";
224+
case OP_SMALLDATA : return "OP_SMALLDATA";
223225

224226
case OP_INVALIDOPCODE : return "OP_INVALIDOPCODE";
225227
default:
@@ -1204,6 +1206,9 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsi
12041206

12051207
// Sender provides N pubkeys, receivers provides M signatures
12061208
mTemplates.insert(make_pair(TX_MULTISIG, CScript() << OP_SMALLINTEGER << OP_PUBKEYS << OP_SMALLINTEGER << OP_CHECKMULTISIG));
1209+
1210+
// Empty, provably prunable, data-carrying output
1211+
mTemplates.insert(make_pair(TX_NULL_DATA, CScript() << OP_RETURN << OP_SMALLDATA));
12071212
}
12081213

12091214
// 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
12881293
else
12891294
break;
12901295
}
1296+
else if (opcode2 == OP_SMALLDATA)
1297+
{
1298+
// small pushdata, <= 80 bytes
1299+
if (vch1.size() > 80)
1300+
break;
1301+
}
12911302
else if (opcode1 != opcode2 || vch1 != vch2)
12921303
{
12931304
// Others must match exactly
@@ -1350,6 +1361,7 @@ bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, uint256 hash
13501361
switch (whichTypeRet)
13511362
{
13521363
case TX_NONSTANDARD:
1364+
case TX_NULL_DATA:
13531365
return false;
13541366
case TX_PUBKEY:
13551367
keyID = CPubKey(vSolutions[0]).GetID();
@@ -1381,6 +1393,8 @@ int ScriptSigArgsExpected(txnouttype t, const std::vector<std::vector<unsigned c
13811393
{
13821394
case TX_NONSTANDARD:
13831395
return -1;
1396+
case TX_NULL_DATA:
1397+
return 1;
13841398
case TX_PUBKEY:
13851399
return 1;
13861400
case TX_PUBKEYHASH:
@@ -1395,10 +1409,9 @@ int ScriptSigArgsExpected(txnouttype t, const std::vector<std::vector<unsigned c
13951409
return -1;
13961410
}
13971411

1398-
bool IsStandard(const CScript& scriptPubKey)
1412+
bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType)
13991413
{
14001414
vector<valtype> vSolutions;
1401-
txnouttype whichType;
14021415
if (!Solver(scriptPubKey, whichType, vSolutions))
14031416
return false;
14041417

@@ -1457,6 +1470,7 @@ bool IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
14571470
switch (whichType)
14581471
{
14591472
case TX_NONSTANDARD:
1473+
case TX_NULL_DATA:
14601474
return false;
14611475
case TX_PUBKEY:
14621476
keyID = CPubKey(vSolutions[0]).GetID();
@@ -1518,6 +1532,8 @@ bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, vecto
15181532
vector<valtype> vSolutions;
15191533
if (!Solver(scriptPubKey, typeRet, vSolutions))
15201534
return false;
1535+
if (typeRet == TX_NULL_DATA)
1536+
return true;
15211537

15221538
if (typeRet == TX_MULTISIG)
15231539
{
@@ -1733,6 +1749,7 @@ static CScript CombineSignatures(CScript scriptPubKey, const CTransaction& txTo,
17331749
switch (txType)
17341750
{
17351751
case TX_NONSTANDARD:
1752+
case TX_NULL_DATA:
17361753
// Don't know anything about this, assume bigger one is correct:
17371754
if (sigs1.size() >= sigs2.size())
17381755
return PushAll(sigs1);

src/script.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ enum txnouttype
4646
TX_PUBKEYHASH,
4747
TX_SCRIPTHASH,
4848
TX_MULTISIG,
49+
TX_NULL_DATA,
4950
};
5051

5152
class CNoDestination {
@@ -202,6 +203,7 @@ enum opcodetype
202203

203204

204205
// template matching params
206+
OP_SMALLDATA = 0xf9,
205207
OP_SMALLINTEGER = 0xfa,
206208
OP_PUBKEYS = 0xfb,
207209
OP_PUBKEYHASH = 0xfd,
@@ -683,7 +685,7 @@ bool IsCanonicalSignature(const std::vector<unsigned char> &vchSig, unsigned int
683685
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType);
684686
bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::vector<unsigned char> >& vSolutionsRet);
685687
int ScriptSigArgsExpected(txnouttype t, const std::vector<std::vector<unsigned char> >& vSolutions);
686-
bool IsStandard(const CScript& scriptPubKey);
688+
bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType);
687689
bool IsMine(const CKeyStore& keystore, const CScript& scriptPubKey);
688690
bool IsMine(const CKeyStore& keystore, const CTxDestination &dest);
689691
void ExtractAffectedKeys(const CKeyStore &keystore, const CScript& scriptPubKey, std::vector<CKeyID> &vKeys);

src/test/multisig_tests.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -133,21 +133,23 @@ BOOST_AUTO_TEST_CASE(multisig_IsStandard)
133133
for (int i = 0; i < 4; i++)
134134
key[i].MakeNewKey(true);
135135

136+
txnouttype whichType;
137+
136138
CScript a_and_b;
137139
a_and_b << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG;
138-
BOOST_CHECK(::IsStandard(a_and_b));
140+
BOOST_CHECK(::IsStandard(a_and_b, whichType));
139141

140142
CScript a_or_b;
141143
a_or_b << OP_1 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG;
142-
BOOST_CHECK(::IsStandard(a_or_b));
144+
BOOST_CHECK(::IsStandard(a_or_b, whichType));
143145

144146
CScript escrow;
145147
escrow << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << key[2].GetPubKey() << OP_3 << OP_CHECKMULTISIG;
146-
BOOST_CHECK(::IsStandard(escrow));
148+
BOOST_CHECK(::IsStandard(escrow, whichType));
147149

148150
CScript one_of_four;
149151
one_of_four << OP_1 << key[0].GetPubKey() << key[1].GetPubKey() << key[2].GetPubKey() << key[3].GetPubKey() << OP_4 << OP_CHECKMULTISIG;
150-
BOOST_CHECK(!::IsStandard(one_of_four));
152+
BOOST_CHECK(!::IsStandard(one_of_four, whichType));
151153

152154
CScript malformed[6];
153155
malformed[0] << OP_3 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG;
@@ -158,7 +160,7 @@ BOOST_AUTO_TEST_CASE(multisig_IsStandard)
158160
malformed[5] << OP_1 << key[0].GetPubKey() << key[1].GetPubKey();
159161

160162
for (int i = 0; i < 6; i++)
161-
BOOST_CHECK(!::IsStandard(malformed[i]));
163+
BOOST_CHECK(!::IsStandard(malformed[i], whichType));
162164
}
163165

164166
BOOST_AUTO_TEST_CASE(multisig_Solver1)

src/test/transaction_tests.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,20 @@ BOOST_AUTO_TEST_CASE(test_IsStandard)
273273

274274
t.vout[0].scriptPubKey = CScript() << OP_1;
275275
BOOST_CHECK(!IsStandardTx(t, reason));
276+
277+
// 80-byte TX_NULL_DATA (standard)
278+
t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38");
279+
BOOST_CHECK(IsStandardTx(t, reason));
280+
281+
// 81-byte TX_NULL_DATA (non-standard)
282+
t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3800");
283+
BOOST_CHECK(!IsStandardTx(t, reason));
284+
285+
// Only one TX_NULL_DATA permitted
286+
t.vout.resize(2);
287+
t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38");
288+
t.vout[1].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38");
289+
BOOST_CHECK(!IsStandardTx(t, reason));
276290
}
277291

278292
BOOST_AUTO_TEST_SUITE_END()

0 commit comments

Comments
 (0)