While implementing the sample code for reusable addresses, I had to implement this line:
stealthTx.Vout.Add(TxOut.OpReturn(P));
Generally the OP_RETURN support is talked about as "OP_RETURN " but sometimes it's also described as OP_RETURN followed by anything.
So my question was whether or not you have to pack the data inside an OP_PUSHDATA, e.g.
public static TxOut OpReturn(byte[] data)
{
byte[] scriptRaw = new byte[data.Length + 1];
scriptRaw[0] = (byte)Script.OpCode.OP_RETURN;
scriptRaw[1] = (byte)Script.OpCode.OP_PUSHDATA1;
scriptRaw[2] = (byte)data.Length;
Array.Copy(data, 0, scriptRaw, 3, data.Length);
return new TxOut()
{
Value = 0L,
ScriptPubKey = Script.Parse(scriptRaw)
};
}
Note, I could save a byte there if data was between 1 and 75 bytes... and the function as written assumes data is less than 255 bytes, but I'm trying to keep the example simple.
In practice, if I did *not* pack the data, then I get something like this from 'decoderawtransaction':
{
"value" : 0.00000000,
"n" : 1,
"scriptPubKey" : {
"asm" : "OP_RETURN -30205 OP_UNKNOWN OP_UNKNOWN OP_NOP6 OP_UNKNOWN [error]",
"hex" : "6a02fdf5c5e6b5d3419e42cc0e12a53b3bd42795a2bdd937739e5eb6eca5cf542206",
"type" : "nonstandard"
}
And so in the test transactions I sent, I did pack the data inside OP_PUSHDATA1.
I did find an Issue #3313 - 'OP_RETURN is now standard':
https://github.com/bitcoin/bitcoin/issues/3313
Reading the discussion it still wasn't really clear to me, no one really seems to come out and say that actually the code as-is does NOT allow ....
Looking at the actual Solver() code...
mTemplates.insert(make_pair(TX_NULL_DATA, CScript() << OP_RETURN << OP_SMALLDATA));
It eventually becomes clear that OP_SMALLDATA (not really an OP) will allow a single block of data appropriately wrapped in a PUSHDATA (not necessarily PUSHDATA1, I don't think we force 'most efficient' encoding yet).
And so the following code in Solver()...
else if (opcode2 == OP_SMALLDATA)
{
// small pushdata, <= 80 bytes
if (vch1.size() > 80)
break;
}
}
I think that allows up to 78 bytes of actual data payload in an OP_RETURN output.
Since you can PUSH up to 75 bytes with a single OP code, and pushing 76-78 bytes requires OP_PUSHDATA1 . Making the cutoff 80 bytes seems like a funny number, I would have gone with a cutoff at 77 -- which would discourage OP_PUSHDATA1/2/4.
Or to be even more explicit... require OP_RETURN (0x6a) followed by either nothing, or followed by a single byte 1 - 75 (0x01 - 0x4b) indicating length and the specified amount of data.