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

fix(202-tariscript): add missing OP_CHECKMULTISIG/VERIFY and update error codes #15

Merged
merged 2 commits into from
Oct 13, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 62 additions & 31 deletions src/RFC-0202_TariScriptOpcodes.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ The same as [`CheckHeightVerify`](#checkheightverifyheight), except that the hei
it to the current block height.

* Fails with `INVALID_INPUT` if there is not a valid integer value on top of the stack.
* Fails with `EMPTY_STACK` if the stack is empty.
* Fails with `STACK_UNDERFLOW` if the stack is empty.
* Fails with `VERIFY_FAILED` if the block height < `height`.


Expand All @@ -154,7 +154,7 @@ Pops the top of the stack as `height`, then pushes the value of (`height` - the
In other words, this opcode replaces the top of the stack with the difference between that value and the current height.

* Fails with `INVALID_INPUT` if there is not a valid integer value on top of the stack.
* Fails with `EMPTY_STACK` if the stack is empty.
* Fails with `STACK_UNDERFLOW` if the stack is empty.

### Stack manipulation

Expand Down Expand Up @@ -201,77 +201,77 @@ Push the associated 32-byte value onto the stack. It will be interpreted as a pu

Drops the top stack item.

* Fails with `EMPTY_STACK` if the stack is empty.
* Fails with `STACK_UNDERFLOW` if the stack is empty.

##### Dup

Duplicates the top stack item.

* Fails with `EMPTY_STACK` if the stack is empty.
* Fails with `STACK_UNDERFLOW` if the stack is empty.
* Fails with `STACK_OVERFLOW` if the stack would exceed the max stack height.

##### RevRot

Reverse rotation. The top stack item moves into 3rd place, e.g. `abc => bca`.

* Fails with `EMPTY_STACK` if the stack has fewer than three items.
* Fails with `STACK_UNDERFLOW` if the stack has fewer than three items.

### Math operations

#### GeZero

Pops the top stack element as `val`. If `val` is greater than or equal to zero, push a 1 to the stack, otherwise push 0.

* Fails with `EMPTY_STACK` if the stack is empty.
* Fails with `STACK_UNDERFLOW` if the stack is empty.
* Fails with `INVALID_INPUT` if `val` is not an integer.

#### GtZero

Pops the top stack element as `val`. If `val` is strictly greater than zero, push a 1 to the stack, otherwise push 0.

* Fails with `EMPTY_STACK` if the stack is empty.
* Fails with `STACK_UNDERFLOW` if the stack is empty.
* Fails with `INVALID_INPUT` if the item is not an integer.

#### LeZero

Pops the top stack element as `val`. If `val` is less than or equal to zero, push a 1 to the stack, otherwise push 0.

* Fails with `EMPTY_STACK` if the stack is empty.
* Fails with `STACK_UNDERFLOW` if the stack is empty.
* Fails with `INVALID_INPUT` if the item is not an integer.

#### LtZero

Pops the top stack element as `val`. If `val` is strictly less than zero, push a 1 to the stack, otherwise push 0.

* Fails with `EMPTY_STACK` if the stack is empty.
* Fails with `STACK_UNDERFLOW` if the stack is empty.
* Fails with `INVALID_INPUT` if the items is not an integer.

##### Add

Pop two items and push their sum

* Fails with `EMPTY_STACK` if the stack has fewer than two items.
* Fails with `STACK_UNDERFLOW` if the stack has fewer than two items.
* Fails with `INVALID_INPUT` if the items cannot be added to each other (e.g. an integer and public key).

##### Sub

Pop two items and push the second minus the top

* Fails with `EMPTY_STACK` if the stack has fewer than two items.
* Fails with `STACK_UNDERFLOW` if the stack has fewer than two items.
* Fails with `INVALID_INPUT` if the items cannot be subtracted from each other (e.g. an integer and public key).

##### Equal

Pops the top two items, and pushes 1 to the stack if the inputs are exactly equal, 0 otherwise. 0 is also pushed if the
values cannot be compared (e.g. integer and pubkey).

* Fails with `EMPTY_STACK` if the stack has fewer than two items.
* Fails with `STACK_UNDERFLOW` if the stack has fewer than two items.

##### EqualVerify

Pops the top two items, and compares their values.

* Fails with `EMPTY_STACK` if the stack has fewer than two items.
* Fails with `STACK_UNDERFLOW` if the stack has fewer than two items.
* Fails with `VERIFY_FAILED` if the top two stack elements are not equal.

### Boolean logic
Expand All @@ -281,42 +281,42 @@ Pops the top two items, and compares their values.
`n` + 1 items are popped from the stack. If the last item popped matches at least one of the first `n` items popped,
push 1 onto the stack. Push 0 otherwise.

* Fails with `EMPTY_STACK` if the stack has fewer than `n` + 1 items.
* Fails with `STACK_UNDERFLOW` if the stack has fewer than `n` + 1 items.

#### OrVerify(n)

`n` + 1 items are popped from the stack. If the last item popped matches at least one of the first `n` items popped,
continue. Fail with `VERIFY_FAILED` otherwise.

* Fails with `EMPTY_STACK` if the stack has fewer than `n` + 1 items.
* Fails with `STACK_UNDERFLOW` if the stack has fewer than `n` + 1 items.

### Cryptographic operations

##### HashBlake256

Pop the top element, hash it with the Blake256 hash function and push the result to the stack.

* Fails with `EMPTY_STACK` if the stack is empty.
* Fails with `STACK_UNDERFLOW` if the stack is empty.

##### HashSha256

Pop the top element, hash it with the SHA256 hash function and push the result to the stack.

* Fails with `EMPTY_STACK` if the stack is empty.
* Fails with `STACK_UNDERFLOW` if the stack is empty.

##### HashSha3

Pop the top element, hash it with the SHA-3 hash function and push the result to the stack.

* Fails with `EMPTY_STACK` if the stack is empty.
* Fails with `STACK_UNDERFLOW` if the stack is empty.

##### CheckSig(Msg)

Pop the public key and then the signature. If the signature signs the 32-byte message, push 1 to the stack, otherwise
push 0.

* Fails with `INVALID_SCRIPT_DATA` if the `Msg` is not a valid 32-byte value.
* Fails with `EMPTY_STACK` if the stack has fewer than 2 items.
* Fails with `STACK_UNDERFLOW` if the stack has fewer than 2 items.
* Fails with `INVALID_INPUT` if the top stack element is not a PublicKey or Commitment
* Fails with `INVALID_INPUT` if the second stack element is not a Signature

Expand All @@ -325,11 +325,28 @@ push 0.
Identical to [`CheckSig`](#checksigmsg), except that nothing is pushed to the stack if the signature is valid, and the
operation fails with `VERIFY_FAILED` if the signature is invalid.

##### CheckMultiSig(Msg)

Pop $m$ signatures from the stack. If $m$ signatures out of the provided $n$ public keys sign the 32-byte message,
push 1 to the stack, otherwise push 0.

* Fails with `INVALID_SCRIPT_DATA` if the `Msg` is not a valid 32-byte value.
* Fails with `INVALID_SCRIPT_DATA` if $m$ or $n$ are zero.
* Fails with `INVALID_SCRIPT_DATA` if $m$ or $n$ are greater than `MAX_MULTISIG_LIMIT (32)`.
* Fails with `INVALID_SCRIPT_DATA` if $m > n$
* Fails with `STACK_UNDERFLOW` if the stack has fewer than $m$ items.
* Fails with `INVALID_INPUT` if $m$ stack elements are not a `Signature`.

##### CheckMultiSigVerify(Msg),

Identical to [`CheckMultiSig`](#checkmultisigmsg), except that nothing is pushed to the stack if the signatures are valid, and the
operation fails with `VERIFY_FAILED` if the signatures are invalid.

##### ToRistrettoPoint,

Pops the top element which must be a valid Ristretto scalar, calculates the corresponding Ristretto point, and pushes this to the stack.

* Fails with `EMPTY_STACK` if the stack is empty.
* Fails with `STACK_UNDERFLOW` if the stack is empty.
* Fails with `INVALID_INPUT` if the top stack element is not a scalar.

### Miscellaneous
Expand All @@ -349,7 +366,7 @@ If `pred` is 0, instructions are popped until `ELSE` or `ENDIF` is encountered.
If `ELSE` is encountered, instructions are executed until `ENDIF` is reached.
`ENDIF` is a marker opcode and a no-op.

* Fails with `EMPTY_STACK` if the stack is empty.
* Fails with `STACK_UNDERFLOW` if the stack is empty.
* If `pred` is anything other than 0 or 1, the script fails with `INVALID_INPUT`.
* If any instruction during execution of the clause causes a failure, the script fails with that failure code.

Expand Down Expand Up @@ -563,20 +580,34 @@ or Bob can spend the output.

### Error codes

| Code | Description |
|:----------------------------|:---------------------------------------------------------------------------------|
| `SCRIPT_TOO_LONG` | The serialised script exceeds 1024 bytes. |
| `SCRIPT_INPUT_TOO_LONG` | The serialised script input exceeds 1024 bytes. |
| `STACK_OVERFLOW` | The stack exceeded 255 elements during script execution |
| `EMPTY_STACK` | There was an attempt to pop an item off an empty stack |
| `INVALID_OPCODE` | The script cannot be deserialised due to an invalid opcode |
| `INVALID_SCRIPT_DATA` | An opcode parameter is invalid or of the wrong type |
| `INVALID_INPUT` | Invalid or incompatible data was popped off the stack as input into an operation |
| `VERIFY_FAILED` | A script condition (typically a `nnnVerify` opcode) failed |
| Code | Description |
|:------------------------|:---------------------------------------------------------------------------------|
| `RETURN` | The serialised script exceeds 1024 bytes. |
| `STACK_OVERFLOW` | The stack exceeded 255 elements during script execution |
| `STACK_UNDERFLOW` | Attempt to pop more items than remain on the stack during script execution |
| `NON_UNIT_LENGTH_STACK` | The stack did not exactly 1 element after script execution |
| `INCOMPATIBLE_TYPES` | An operand was applied to incompatible types |
| `VALUE_EXCEEDS_BOUNDS` | A script opcode resulted in a value that exceeded the maximum or minimum value |
| `INVALID_OPCODE` | The script cannot be deserialised due to an invalid opcode |
| `MISSING_OPCODE` | The script is missing closing opcodes (Else or EndIf) |
| `INVALID_SIGNATURE` | The script contained an invalid signature |
| `INVALID_INPUT` | Invalid or incompatible data was popped off the stack as input into an operation |
| `INVALID_SCRIPT_DATA` | An opcode parameter is invalid or of the wrong type |
| `VERIFY_FAILED` | A script condition (typically a `nnnVerify` opcode) failed |

### Credits

Thanks to [@philipr-za](https://github.com/philipr-za) and [@SWvheerden](https://github.com/SWvheerden) for their input
and contributions to this RFC.


# Change Log

| Date | Change | Author |
|:-------------|:---------------------------------------|:----------|
| 17 Aug 2020 | First draft | CjS77 |
| 8 Mar 2021 | Minor update | philip-za |
| 28 Sep 2022 | Minor update to reflect implementation | sdbondi |


[TariScript]: Glossary.md#tariscript