Skip to content
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

OP_REVERSE #358

Closed
wants to merge 5 commits into from

Conversation

Projects
None yet
5 participants
@EyeOfPython
Copy link

commented May 29, 2019

A proposal to add OP_REVERSE to Script

EyeOfPython added some commits May 29, 2019

@markblundeberg

This comment has been minimized.

Copy link
Collaborator

commented May 29, 2019

This is a great idea! Though of course, whether it comes in November will depend a lot if there is the dev bandwidth to actually make this consensus change. (Though the change itself is almost trivial, it requires activation logic + lots of testing.)

Show resolved Hide resolved spec/op_reverse.md Outdated
@dskloet

This comment has been minimized.

Copy link

commented May 29, 2019

Why doesn't SLP use little endian instead?


* Covenants and looping scripts usually take the script code of the preimage [9] as input, which means every operation counts twice: Once for the stack item containing the script code, and once for the P2SH script stack item [10]. In the example above, this would save 32 bytes per conversion, and if there's, say, three of those conversions in a script, it would already amount to 96 bytes - a non-trivial amount of bytes for a transaction.
* The cognitive load of developing scripts using the larger snippet above is increased unnecessarily. Developing scripts, by hand or by using tools such as macros or Spedn, already puts a lot of cognitive load on developers, and errors can be devastating to the community. A prominent example of such a failure is the contentious hard-fork on the Ethereum blockchain that was caused by a bug in The DAO smart contract.
* The first version assumes that Script uses 32-byte numbers, however, once 64-bit numbers are implemented, the script fails when numbers that do not fit in 32-bits are used [11], and has to be updated. The second version will work with up to 64-bit numbers.

This comment has been minimized.

Copy link
@BigBlockIfTrue

BigBlockIfTrue May 29, 2019

Suggested change
* The first version assumes that Script uses 32-byte numbers, however, once 64-bit numbers are implemented, the script fails when numbers that do not fit in 32-bits are used [11], and has to be updated. The second version will work with up to 64-bit numbers.
* The first version assumes that Script uses 32-byte numbers, however, once 64-bit numbers are implemented, the script fails when numbers that do not fit in 32-bits are used [11], and has to be updated. The second version will work with up to 64-bit numbers. OP_REVERSE itself has no limit on the length of the byte vector it reverses.

Clarification.

This comment has been minimized.

Copy link
@EyeOfPython

EyeOfPython May 29, 2019

Author

I've rewritten the rationale to be less SLP-centered, do you think we could add this clarification somewhere else?

* The cognitive load of developing scripts using the larger snippet above is increased unnecessarily. Developing scripts, by hand or by using tools such as macros or Spedn, already puts a lot of cognitive load on developers, and errors can be devastating to the community. A prominent example of such a failure is the contentious hard-fork on the Ethereum blockchain that was caused by a bug in The DAO smart contract.
* The first version assumes that Script uses 32-byte numbers, however, once 64-bit numbers are implemented, the script fails when numbers that do not fit in 32-bits are used [11], and has to be updated. The second version will work with up to 64-bit numbers.

Further, there's likely many additional use cases beside encoding SLP values, as many protocols outside of Bitcoin use big endian numbers, and all of them would benefit from this opcode. Also, it can be used to check palindromes.

This comment has been minimized.

Copy link
@BigBlockIfTrue

BigBlockIfTrue May 29, 2019

Suggested change
Further, there's likely many additional use cases beside encoding SLP values, as many protocols outside of Bitcoin use big endian numbers, and all of them would benefit from this opcode. Also, it can be used to check palindromes.
Further, there's likely many additional use cases beside encoding SLP values, as many protocols outside of Bitcoin use big endian numbers, and all of them would benefit from this opcode. It can also be used to check palindromes. Besides number encoding, OP_REVERSE may be useful for manipulation of non-numeric data.
@BigBlockIfTrue
Copy link

left a comment

Nice work. I included some suggestions for minor changes.

@markblundeberg

This comment has been minimized.

Copy link
Collaborator

commented May 29, 2019

I posted off-github:

Can you emphasize more on this point — "Further, there's likely many additional use cases beside encoding SLP values, as many protocols outside of Bitcoin use big endian numbers, and all of them would benefit from this opcode.".
Complex SLP covenants on their own don't seem like sufficient justification and the way you write the document seems very single-purpose to that one goal."

@dskloet

This comment has been minimized.

Copy link

commented May 29, 2019

Specifically: why wouldn't the big-endian to little-endian conversion when interacting with "protocols outside of Bitcoin" happen off-chain?

@EyeOfPython

This comment has been minimized.

Copy link
Author

commented May 29, 2019

I posted off-github:

Can you emphasize more on this point — "Further, there's likely many additional use cases beside encoding SLP values, as many protocols outside of Bitcoin use big endian numbers, and all of them would benefit from this opcode.".
Complex SLP covenants on their own don't seem like sufficient justification and the way you write the document seems very single-purpose to that one goal."

I've rewritten the rationale to be non-SLP specific. It now focuses mostly on why encoding numbers in big-endian is desireable.

Added and clarified unittests
* Adds more basic unit tests
* Adds unit test checking whether reversing twice returns the original value.
* Covers both even and odd lengths of the byte vector.

Co-Authored-By: BigBlockIfTrue <32314686+BigBlockIfTrue@users.noreply.github.com>
@EyeOfPython

This comment has been minimized.

Copy link
Author

commented May 31, 2019

@markblundeberg Thoughts on the updated version? c26607c

@markblundeberg

This comment has been minimized.

Copy link
Collaborator

commented Jun 1, 2019

Hmm interesting, though it still feels like most protocols can just adapt and provide little endian numbers. Do you see any use case besides endianness conversions?

@EyeOfPython

This comment has been minimized.

Copy link
Author

commented Jun 1, 2019

Do you see any use case besides endianness conversions?

There aren't many; but given the crazy things some C developers came up with for optimizing their code (like fast inverse square root), there's probably some real-life function that corresponds to reversing the bytes of an integer.

Otherwise, on the top of my head, I came up with these additional use cases, which are just versions of already possible things, but requiring less fewer bytes:

Simple proof-of-work check:

Without OP_REVERSE:

<proof-of-work>
<target bytes>
OP_SPLIT
0
<target bytes>
OP_NUM2BIN
OP_EQUALVERIFY

6 bytes, checks number of leading zeros.

With OP_REVERSE:

<proof-of-work>
<target bytes>
OP_SPLIT
OP_DUP
OP_REVERSE
OP_EQUALVERIFY

5 bytes, checks whether the N leading bytes are a palindrome (<target bytes> must be twice as large as in the previous script for the same difficulty).

Pushing a large number (only relevant once we've got 64-bit or higher numbers):

Without OP_REVERSE:

0x00 00 00 00  00 00 00 01 (=72057594037927936)

8 bytes

With OP_REVERSE:

1
8
OP_NUM2BIN
OP_REVERSE

4 bytes

With 256-bit numbers, the first one would take 32 bytes whereas the second one would take 5 bytes.

I know, the benefit is either niche or not really significant, but it is a possible use case.

@EyeOfPython

This comment has been minimized.

Copy link
Author

commented Jun 1, 2019

most protocols can just adapt and provide little endian numbers

That's true, but not all protocols can just adapt, which is not possible for SLP tokens.

One more point on endianness:

Most services (explorer.bitcoin.com/rest.bitcoin.com, Bitdb, etc.) and protocols (most notably, SLP tokens) encode hashes (e.g. transaction hashes) in big endian. However, OP_SHA256 and OP_HASH256 encode hashes in little endian. If a script would calculate the hash of some external transaction and compare it to an input, or match the input against the outpoint, that input would have to be encoded in a little endian hash, making interaction with e.g. bitcoin.com's REST API and Bitdb very cumbersome.

Of course, it's possible to add a switch/function to those services, but that will make interaction unnecessarily confusing and increase the congnitive load needlessly.

At the end, it's mostly a question of goals: Should things be easy to do or is it already sufficient if they're just possible? For example, should we re-enable OP_MUL? As far as I'm able to tell, developers can just rearrange the terms of the formula and push products as inputs instead of factors.

Similar with the already re-enabled OP_NUM2BIN and OP_BIN2NUM: developers could just push numbers in the required format (minimal encoding/N-byte encoding), and if conversion is necessary, they could just use OP_SPLIT and OP_CAT.

However, it seems many would eventually like to see OP_MUL re-enabled, and OP_NUM2BIN and OP_BIN2NUM already has been, not because it offers new functionality, but because it makes interaction with Bitcoin Cash and Script easier, more approachable and, especially, safer. The same holds for OP_REVERSE: While technically many protocols can adapt (even the SLP protocol could be changed to support both big-endian and little-endian), it would require, at best (e.g. for a price oracle), just switching out a function call, worse (e.g. for interacting with Bitdb/rest.bitcoin.com) complicated switches/functions, or at worst (like for the SLP token) an immense effort to upgrade all participants to a new protocol.

@EyeOfPython

This comment has been minimized.

Copy link
Author

commented Jun 8, 2019

I think there's better ways to do something like OP_REVERSE, so I'm closing the PR.

@EyeOfPython EyeOfPython closed this Jun 8, 2019

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.