Relay OP_RETURN data TxOut as standard transaction type. #2738
Merged
15
src/main.cpp
| @@ -497,17 +497,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"; | ||
jgarzik
Member
|
||
| + 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: | ||
| @@ -1148,6 +1150,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: | ||
| @@ -1232,6 +1237,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) | ||
petertodd
Member
|
||
| + break; | ||
| + } | ||
| else if (opcode1 != opcode2 || vch1 != vch2) | ||
| { | ||
| // Others must match exactly | ||
| @@ -1294,6 +1305,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(); | ||
| @@ -1325,6 +1337,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: | ||
| @@ -1339,10 +1353,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; | ||
| @@ -1401,6 +1414,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(); | ||
| @@ -1462,6 +1476,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) | ||
| { | ||
| @@ -1677,6 +1693,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); | ||
"mucho-data" ? You trolling to see if we're paying attention?
"multi-op-return" would be better for non-Spanglish speakers.