Skip to content

Conversation

petertodd
Copy link
Contributor

Previously only one PUSHDATA was allowed, needlessly limiting applications such as matching OP_RETURN contents with bloom filters that operate on a per-PUSHDATA level. Now any combination that passes IsPushOnly() is allowed, so long as the total size of the scriptPubKey is less than 42 bytes. (unchanged modulo non-minimal PUSHDATA encodings)

Also, this fixes the odd bug where previously the PUSHDATA could be replaced by any single opcode, even sigops consuming opcodes such as CHECKMULTISIG. (20 sigops!)

Finally, fix a weird corner-case bug is also fixed for TX_SCRIPTHASH outputs.

// script.
size_t nMaxOpReturnRelay = GetBoolArg("-datacarrier", true) ? MAX_OP_RETURN_RELAY : 1;
if (scriptPubKey.IsUnspendable() && 1 <= scriptPubKey.size() // protect the begin() + 1 below
&& scriptPubKey.size() <= nMaxOpReturnRelay)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This conditional could be written much more clearly. It is not clear that IsUnspendable() is actually checking for OP_RETURN at the beginning.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

@TheBlueMatt
Copy link
Contributor

Aside from that one thing, utACK.

@petertodd petertodd force-pushed the op-return-accept-multiple-pushdatas branch from 8d67967 to ba78c76 Compare October 14, 2014 11:20
// byte passes the IsPushOnly() test we don't care what exactly is in the
// script.
size_t nMaxOpReturnRelay = GetBoolArg("-datacarrier", true) ? MAX_OP_RETURN_RELAY : 1;
if (1 <= scriptPubKey.size() && scriptPubKey[0] == OP_RETURN
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 smaller than scriptPubKey.size, it is. Can we avoid yoda conditionals?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is scriptPubKey.IsUnspendable(), btw

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@theuni Lol, that's what the code was prior to @TheBlueMatt asking me to change it to something explicit. :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@TheBlueMatt I've got no strong feelings about Star Wars, so yoda removed.

@TheBlueMatt
Copy link
Contributor

WIth or without yodaspeak, utACK.

if (1 <= scriptPubKey.size() && scriptPubKey[0] == OP_RETURN
&& scriptPubKey.size() <= nMaxOpReturnRelay)
{
CScript scriptData(scriptPubKey.begin() + 1, scriptPubKey.end());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Making a full copy (apart from one byte) of every script in every transaction being relayed seems wasteful. Why is there a requirement that it's push only?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sigops are counted even in scriptPubKeys, so accepting a transaction with an OP_RETURN output containing a bunch of CHECKMULTISIGS - for instance - would use up a lot of your per-block sigop quota.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could easily adapt IsPushOnly() to be IsPushOnly(int startingAt), or even an iterator.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@TheBlueMatt Any ideas on the best way of doing that?

@petertodd petertodd force-pushed the op-return-accept-multiple-pushdatas branch from ba78c76 to f386100 Compare October 14, 2014 20:31
@devrandom
Copy link

You could add a IsPushOnly with an arg as follows:

bool CScript::IsPushOnly() const
{
  return this->IsPushOnly(begin());
}

bool CScript::IsPushOnly(const_iterator pc) const
{
...

and then call it with begin()+1 in the OP_RETURN flow.

Also add the new definition in script.h

@sipa
Copy link
Member

sipa commented Oct 15, 2014

Sounds like a good suggestion, @devrandom.

@petertodd petertodd force-pushed the op-return-accept-multiple-pushdatas branch from f386100 to 6865d23 Compare November 4, 2014 17:44
@petertodd
Copy link
Contributor Author

@devrandom I implemented your suggestion re: IsPushOnly() and rebased.

@devrandom
Copy link

+1

@Flavien
Copy link
Contributor

Flavien commented Nov 13, 2014

Since the OP_RETURN doomsday some had predicted did not happen, could we also increase the space in the OP_RETURN? 20 bytes would already go a long way.

@luke-jr
Copy link
Member

luke-jr commented Nov 13, 2014

@Flavien 0.10 is adding a -datacarriersize option to make configuring the size easy. Changing the default value is IMO outside the scope of this PR and should be proposed independently.

Previously unlike other transaction types the TX_SCRIPTHASH would not
clear vSolutionsRet, which means that unlike other transaction types if
it was called twice in a row you would get the result of the previous
invocation as well.
Allows IsPushOnly() to be applied to just part of the script for
OP_RETURN outputs.
@petertodd petertodd force-pushed the op-return-accept-multiple-pushdatas branch from 6865d23 to c263701 Compare November 13, 2014 21:09
@petertodd
Copy link
Contributor Author

Rebased

Previously only one PUSHDATA was allowed, needlessly limiting
applications such as matching OP_RETURN contents with bloom filters that
operate on a per-PUSHDATA level. Now any combination that passes
IsPushOnly() is allowed, so long as the total size of the scriptPubKey
is less than 42 bytes. (unchanged modulo non-minimal PUSHDATA encodings)

Also, this fixes the odd bug where previously the PUSHDATA could be
replaced by any single opcode, even sigops consuming opcodes such as
CHECKMULTISIG. (20 sigops!)
@petertodd
Copy link
Contributor Author

@Flavien Yeah, that belongs in a separate pull-req. Also, if you want this merged, do please test it and ACK...

@devrandom
Copy link

tested ACK

@maraoz
Copy link
Contributor

maraoz commented Apr 8, 2015

concept ACK

@jtimon
Copy link
Contributor

jtimon commented Apr 27, 2015

If this was rebased today, it wouldn't pass the tests. I rebased and fixed that.
You were adding 2 for the op_return and the op_pushdata, but you also have to add the number expressing the size and the size of that number itself depends on the pushdata type used. So replacing 2 with 3 to fix the tests is not a very convincing option IMO. I would prefer to change the default from 80 to 83 and say that it also counds the op_return and whatever pushdata ops you need.

You were also altering the behaviour of the -datacarrier option and I fixed that too.
Ultimately I think we could get rid of that option since users can just express the same desire using -datacarriersize=0.

Also since you are touching this part of the code already, it is trivial to move the nMaxDatacarrierBytes checks from Solver to IsStandard where it belongs (to be moved with #6068 to policy/policy).

You can read and get my suggestions (diff only from what you already had, which had a clean rebase) here: jtimon/bitcoin@pr_5079_rebased...jtimon:pr_5079

Apart from that, utACK.

@petertodd
Copy link
Contributor Author

@jtimon I disagree with some of the things you say above in minor ways, but the big picture is that you're version looks fine to me. How about you submit it as a separate pull-req and I'll close this one?

@jtimon
Copy link
Contributor

jtimon commented May 7, 2015

Care to be more specific about where you disagree?
Sure, I could replace this PR. But if I do that, I would only do it after #6068 (was #5595) if that ever gets merged.

@petertodd
Copy link
Contributor Author

Oh, actually re-reeading it I think it's all fine.

Well, it's up to you, but I'd see this as separate to #6068, in the sense that it doesn't need to be a blocker.

@dexX7
Copy link
Contributor

dexX7 commented Jun 4, 2015

matching OP_RETURN contents with bloom filters that operate on a per-PUSHDATA level

This seems very useful in my opinon.

@dexX7
Copy link
Contributor

dexX7 commented Jun 13, 2015

@jtimon: jtimon/bitcoin@pr_5079_rebased...jtimon:pr_5079

If the size check is removed from Solver(), then there are a few consequences.

The solver is still successful, even if payloads are larger than nMaxDatacarrierBytes. On the first glimpse this has no negative effect, but since typeRet is set TX_NULL_DATA in these cases, too, then it also affects ExtractDestinations(), and ultimately ScriptPubKeyToJSON() plus friends.

The RPC calls "getrawtransaction", "decoderawtransaction" and "decodescript" then no longer return "type" : "nonstandard", but "nulldata".

Nevertheless, I think this is the right thing to do, and it would be in line with the behavior related to non-standard m-of-n multisig scripts.

if (scriptPubKey.size() >= 1 && scriptPubKey[0] == OP_RETURN
&& scriptPubKey.size() <= nMaxDatacarrierBytes+2) // to account for the pushdata opcodes
{
if (scriptPubKey.IsPushOnly(scriptPubKey.begin()+1))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be incorporated to the previous if, just another &&. What makes this condition different from the others?

@jtimon
Copy link
Contributor

jtimon commented Jul 12, 2015

Please, rebase. Even if it's not strictly necessary, MAX_OP_RETURN_RELAY has changed its value and IsStandard() has moved to policy/policy. It will also become easier to compare with #6424, which I just opened (it's a rebased version of this with my nits on top, ready to be squashed).

@laanwj
Copy link
Member

laanwj commented Jul 21, 2015

What still needs to happen here?
Edit: re-triggered travis to see the test failures.

@jtimon
Copy link
Contributor

jtimon commented Jul 21, 2015

@laanwj just merge #6424 instead? Well, after I get some more review and I remove the last "fixup?" commit.

@dexX7

The RPC calls "getrawtransaction", "decoderawtransaction" and "decodescript" then no longer return "type" : "nonstandard", but "nulldata".

Yes, and there's no problem with that.

Nevertheless, I think this is the right thing to do, and it would be in line with the behavior related to non-standard m-of-n multisig scripts.

So do you agree or not, I'm confused...

@dexX7
Copy link
Contributor

dexX7 commented Jul 21, 2015

@jtimon: So do you agree or not, I'm confused...

With #5079 (comment) I was just pointing out that your change has an impact on how the scripts are labeled via RPC, but I think it's fine, and I agree with:

@jtimon: Yes, and there's no problem with that.

@jtimon
Copy link
Contributor

jtimon commented Jul 21, 2015

@dexX7 Oh, I see, it was just to inform. Thanks.

@jgarzik
Copy link
Contributor

jgarzik commented Sep 15, 2015

ut ACK as-is

Suggested improvement:

  • first "if" checks only for OP_RETURN
  • second "if" detects TX_NULL_DATA
  • otherwise no need to scan templates - it is an OP_RETURN - we know it is "unspendable+garbage" and therefore TX_NONSTANDARD

@dcousens
Copy link
Contributor

concept / utACK, though waiting on @jtimon's comments to be addressed. +1 on @jgarzik's suggestions.

@jtimon
Copy link
Contributor

jtimon commented Sep 19, 2015

Was this rebased? There was already a rebased version (with my nits fixed) in #6424 ...

@laanwj
Copy link
Member

laanwj commented Oct 1, 2015

Closing in favor of @jtimon's #6424

@laanwj laanwj closed this Oct 1, 2015
@bitcoin bitcoin locked as resolved and limited conversation to collaborators Sep 8, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.