-
Notifications
You must be signed in to change notification settings - Fork 38.7k
Unify and simplify CScript push methods #5091
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
sipa
commented
Oct 16, 2014
- Make CScript::operator<<(const std::vector&) cover all push operations (including OP_0, OP_1..OP_16 and OP_1NEGATE), and make the push for numbers use that.
- Convert the uint256, uint160 and CPubKey into a single templated one using the vector push code.
- Get rid of the int64_t operator<<; better be explicit about what needs pushing, so change all number pushes to use CScriptNum (which, due to the generic vector push now also correctly uses OP_n).
- Get rid of some unused methods and constructors as a result.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because the number push operator doesn't work anymore - it uses OP_4 intead of 1-byte push of 0x04. As this is one of the very few cases where you need the byte-level ability, I figured it's just shorter to turn it into a single byte sequence here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ugh, ok then...maybe put in a comment of the old code?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does the old code matter? The coinbase input is just a byte array.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suppose for historical nostalgia? In any case, it matters not.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
06d2bca to
4ad85ab
Compare
|
utACK...hope no one ever writes a class with unsigned char* begin() and unsigned char* end() |
Why not? That would still be transparently converted to a std::vector, right? |
|
OK, hope no one ever writes a class with unsigned char* begin() and On 10/16/14 06:46, Wladimir J. van der Laan wrote:
|
|
Rebased on top of #4981. |
|
Also added a move-only commit to move a lot of the larger script methods to the .cpp file. |
|
|
I'm not sure this makes things any clearer. I'll delay judgement until giving it a re-read this weekend. |
|
It makes it marginally clearer, and the move to the .cpp is nice. |
|
I should probably clarify a bit why I think this is nicer. Previously, there were some different ways of pushing vectors/numbers:
So the logic for number conversion and vector-to-opcode conversion was being done in several places, and pushing a vector or scriptnum would never result in using OP_1..OP_16 or OP_1NEGATE, even if that was the shortest way of doing it (which would violate BIP62). This pull request moves all number-to-vector logic to CScriptNum, and all vector-to-opcode logic to operator<<(vector), and makes the rest wrappers around it. Also, it removes a bunch of unnecessary methods. |
|
Rebased. @theuni Do you understand my motivation now for this? |
|
@sipa Yes, It's fine by me. My iffyness stemmed from the fact that this changes behavior somewhat from "I'll blindly add whatever you tell me to" to "just tell me what you want and I'll clean it up". I'd usually prefer to allow people to shoot themselves in the foot if they're really trying, but this really isn't the place for that. Fwiw, I really meant for the ScriptBinaryData change (what eventually turned into the ToByteVector() function) to be used for this. I had hoped to leave a method around for adding exact data to a script. That would've made the chainparams change a good bit cleaner. But I suppose it's possible there aren't enough of those cases to justify easy the foot-shooting. |
|
@laanwj comments? |
|
utACK |
|
Rebased. |
* Make CScript::operator<<(const std::vector<unsigned char>&) cover all push operations (including OP_0, OP_1..OP_16 and OP_1NEGATE), and make the push for numbers use that. * Convert the uint256, uint160 and CPubKey into a single templated one using the vector push code. * Get rid of the int64_t operator<<; better be explicit about what needs pushing, so change all number pushes to use CScriptNum (which, due to the generic vector push now also correctly uses OP_n). * Get rid of some unused methods and constructors as a result.
|
Rebased. |
|
Untested ACK |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@petertodd I think this would actually be a consensus change...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep! Well, maybe, probably not. I think this may only matter in the case of a valid signature, so you'd need a valid signature that is representable by a non-push opcode.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@TheBlueMatt If STRICTENC was written such that it caused the script to immediately fail, this could matter as CHECKMULTISIG evaluation exits early; the fork would be the difference between a passing CHECKMULTISIG NOT and a failed script.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
True, though I think its rather orthogonal to this issue...and we knew (its in the src!) that STRICTENC was not a softfork.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's not the point. It's an example of how a very subtle change could have lead to a fork because of a known consensus-critical dependency. Just because you don't know how to exploit it right now doesn't mean you can't.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Huh? My point was that STRICTENC is already a hardfork, and while I agree 100% with everything you said in your last statement, its again not connected to the previous discussion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, you're comment gives the impression that you're arguing this change is ok, on the basis that it can't be exploited right now. I'm arguing this change isn't ok, because we have solid evidence that it changes behavior that could be used for an exploit. I'm not sure how, and maybe it isn't possible, but it's obviously a risky change.
Adding a separate method to serialize a unsigned char vector to a PUSHDATA and nothing else, and changing FindAndDelete() calls to use that method, may be one way to mitigate the risk.
Note how all of the above also suggests that conversions of data to CScripts() is something that should ideally be kept separate of the consensus-critical code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is also a good argument for incorporating hashed instruction-by-instruction execution traces into any future OP_EVAL proposal, where failure to match the trace hash exactly fails immediately. Merkelized abstract syntax tree ideas lend themselves naturally to this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My point was not that this is OK, but that arguing based on STRICTENC is a completely invalid argument. In any case, we clearly agree, so...whatever.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's nothing invalid about arguing that we had a close call. We should follow development practices that prevent close calls, given it's only a matter of time before one of those close calls turns into an actual exploit.
|
Too risky. Closing. |
|
Maybe we can push a subset of the changes that is not risky? |