mirror of
https://github.com/FlipsideCrypto/dcrd.git
synced 2026-02-06 19:06:51 +00:00
This commit is the first stage of several that are planned to convert
the blockchain package into a concurrent safe package that will
ultimately allow support for multi-peer download and concurrent chain
processing. The goal is to update btcd proper after each step so it can
take advantage of the enhancements as they are developed.
In addition to the aforementioned benefit, this staged approach has been
chosen since it is absolutely critical to maintain consensus.
Separating the changes into several stages makes it easier for reviewers
to logically follow what is happening and therefore helps prevent
consensus bugs. Naturally there are significant automated tests to help
prevent consensus issues as well.
The main focus of this stage is to convert the blockchain package to use
the new database interface and implement the chain-related functionality
which it no longer handles. It also aims to improve efficiency in
various areas by making use of the new database and chain capabilities.
The following is an overview of the chain changes:
- Update to use the new database interface
- Add chain-related functionality that the old database used to handle
- Main chain structure and state
- Transaction spend tracking
- Implement a new pruned unspent transaction output (utxo) set
- Provides efficient direct access to the unspent transaction outputs
- Uses a domain specific compression algorithm that understands the
standard transaction scripts in order to significantly compress them
- Removes reliance on the transaction index and paves the way toward
eventually enabling block pruning
- Modify the New function to accept a Config struct instead of
inidividual parameters
- Replace the old TxStore type with a new UtxoViewpoint type that makes
use of the new pruned utxo set
- Convert code to treat the new UtxoViewpoint as a rolling view that is
used between connects and disconnects to improve efficiency
- Make best chain state always set when the chain instance is created
- Remove now unnecessary logic for dealing with unset best state
- Make all exported functions concurrent safe
- Currently using a single chain state lock as it provides a straight
forward and easy to review path forward however this can be improved
with more fine grained locking
- Optimize various cases where full blocks were being loaded when only
the header is needed to help reduce the I/O load
- Add the ability for callers to get a snapshot of the current best
chain stats in a concurrent safe fashion
- Does not block callers while new blocks are being processed
- Make error messages that reference transaction outputs consistently
use <transaction hash>:<output index>
- Introduce a new AssertError type an convert internal consistency
checks to use it
- Update tests and examples to reflect the changes
- Add a full suite of tests to ensure correct functionality of the new
code
The following is an overview of the btcd changes:
- Update to use the new database and chain interfaces
- Temporarily remove all code related to the transaction index
- Temporarily remove all code related to the address index
- Convert all code that uses transaction stores to use the new utxo
view
- Rework several calls that required the block manager for safe
concurrency to use the chain package directly now that it is
concurrent safe
- Change all calls to obtain the best hash to use the new best state
snapshot capability from the chain package
- Remove workaround for limits on fetching height ranges since the new
database interface no longer imposes them
- Correct the gettxout RPC handler to return the best chain hash as
opposed the hash the txout was found in
- Optimize various RPC handlers:
- Change several of the RPC handlers to use the new chain snapshot
capability to avoid needlessly loading data
- Update several handlers to use new functionality to avoid accessing
the block manager so they are able to return the data without
blocking when the server is busy processing blocks
- Update non-verbose getblock to avoid deserialization and
serialization overhead
- Update getblockheader to request the block height directly from
chain and only load the header
- Update getdifficulty to use the new cached data from chain
- Update getmininginfo to use the new cached data from chain
- Update non-verbose getrawtransaction to avoid deserialization and
serialization overhead
- Update gettxout to use the new utxo store versus loading
full transactions using the transaction index
The following is an overview of the utility changes:
- Update addblock to use the new database and chain interfaces
- Update findcheckpoint to use the new database and chain interfaces
- Remove the dropafter utility which is no longer supported
NOTE: The transaction index and address index will be reimplemented in
another commit.
2863 lines
91 KiB
Go
2863 lines
91 KiB
Go
// Copyright (c) 2013-2015 The btcsuite developers
|
|
// Copyright (c) 2015-2016 The Decred developers
|
|
// Use of this source code is governed by an ISC
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package txscript
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/sha1"
|
|
"encoding/binary"
|
|
"errors"
|
|
"fmt"
|
|
"hash"
|
|
|
|
"github.com/btcsuite/golangcrypto/ripemd160"
|
|
|
|
"github.com/decred/dcrd/chaincfg"
|
|
"github.com/decred/dcrd/chaincfg/chainec"
|
|
"github.com/decred/dcrd/chaincfg/chainhash"
|
|
"github.com/decred/dcrd/wire"
|
|
)
|
|
|
|
var optimizeSigVerification = chaincfg.SigHashOptimization
|
|
|
|
// An opcode defines the information related to a txscript opcode. opfunc, if
|
|
// present, is the function to call to perform the opcode on the script. The
|
|
// current script is passed in as a slice with the first member being the opcode
|
|
// itself.
|
|
type opcode struct {
|
|
value byte
|
|
name string
|
|
length int
|
|
opfunc func(*parsedOpcode, *Engine) error
|
|
}
|
|
|
|
// These constants are the values of the official opcodes used on the btc wiki,
|
|
// in bitcoin core and in most if not all other references and software related
|
|
// to handling DCR scripts.
|
|
const (
|
|
OP_0 = 0x00 // 0
|
|
OP_FALSE = 0x00 // 0 - AKA OP_0
|
|
OP_DATA_1 = 0x01 // 1
|
|
OP_DATA_2 = 0x02 // 2
|
|
OP_DATA_3 = 0x03 // 3
|
|
OP_DATA_4 = 0x04 // 4
|
|
OP_DATA_5 = 0x05 // 5
|
|
OP_DATA_6 = 0x06 // 6
|
|
OP_DATA_7 = 0x07 // 7
|
|
OP_DATA_8 = 0x08 // 8
|
|
OP_DATA_9 = 0x09 // 9
|
|
OP_DATA_10 = 0x0a // 10
|
|
OP_DATA_11 = 0x0b // 11
|
|
OP_DATA_12 = 0x0c // 12
|
|
OP_DATA_13 = 0x0d // 13
|
|
OP_DATA_14 = 0x0e // 14
|
|
OP_DATA_15 = 0x0f // 15
|
|
OP_DATA_16 = 0x10 // 16
|
|
OP_DATA_17 = 0x11 // 17
|
|
OP_DATA_18 = 0x12 // 18
|
|
OP_DATA_19 = 0x13 // 19
|
|
OP_DATA_20 = 0x14 // 20
|
|
OP_DATA_21 = 0x15 // 21
|
|
OP_DATA_22 = 0x16 // 22
|
|
OP_DATA_23 = 0x17 // 23
|
|
OP_DATA_24 = 0x18 // 24
|
|
OP_DATA_25 = 0x19 // 25
|
|
OP_DATA_26 = 0x1a // 26
|
|
OP_DATA_27 = 0x1b // 27
|
|
OP_DATA_28 = 0x1c // 28
|
|
OP_DATA_29 = 0x1d // 29
|
|
OP_DATA_30 = 0x1e // 30
|
|
OP_DATA_31 = 0x1f // 31
|
|
OP_DATA_32 = 0x20 // 32
|
|
OP_DATA_33 = 0x21 // 33
|
|
OP_DATA_34 = 0x22 // 34
|
|
OP_DATA_35 = 0x23 // 35
|
|
OP_DATA_36 = 0x24 // 36
|
|
OP_DATA_37 = 0x25 // 37
|
|
OP_DATA_38 = 0x26 // 38
|
|
OP_DATA_39 = 0x27 // 39
|
|
OP_DATA_40 = 0x28 // 40
|
|
OP_DATA_41 = 0x29 // 41
|
|
OP_DATA_42 = 0x2a // 42
|
|
OP_DATA_43 = 0x2b // 43
|
|
OP_DATA_44 = 0x2c // 44
|
|
OP_DATA_45 = 0x2d // 45
|
|
OP_DATA_46 = 0x2e // 46
|
|
OP_DATA_47 = 0x2f // 47
|
|
OP_DATA_48 = 0x30 // 48
|
|
OP_DATA_49 = 0x31 // 49
|
|
OP_DATA_50 = 0x32 // 50
|
|
OP_DATA_51 = 0x33 // 51
|
|
OP_DATA_52 = 0x34 // 52
|
|
OP_DATA_53 = 0x35 // 53
|
|
OP_DATA_54 = 0x36 // 54
|
|
OP_DATA_55 = 0x37 // 55
|
|
OP_DATA_56 = 0x38 // 56
|
|
OP_DATA_57 = 0x39 // 57
|
|
OP_DATA_58 = 0x3a // 58
|
|
OP_DATA_59 = 0x3b // 59
|
|
OP_DATA_60 = 0x3c // 60
|
|
OP_DATA_61 = 0x3d // 61
|
|
OP_DATA_62 = 0x3e // 62
|
|
OP_DATA_63 = 0x3f // 63
|
|
OP_DATA_64 = 0x40 // 64
|
|
OP_DATA_65 = 0x41 // 65
|
|
OP_DATA_66 = 0x42 // 66
|
|
OP_DATA_67 = 0x43 // 67
|
|
OP_DATA_68 = 0x44 // 68
|
|
OP_DATA_69 = 0x45 // 69
|
|
OP_DATA_70 = 0x46 // 70
|
|
OP_DATA_71 = 0x47 // 71
|
|
OP_DATA_72 = 0x48 // 72
|
|
OP_DATA_73 = 0x49 // 73
|
|
OP_DATA_74 = 0x4a // 74
|
|
OP_DATA_75 = 0x4b // 75
|
|
OP_PUSHDATA1 = 0x4c // 76
|
|
OP_PUSHDATA2 = 0x4d // 77
|
|
OP_PUSHDATA4 = 0x4e // 78
|
|
OP_1NEGATE = 0x4f // 79
|
|
OP_RESERVED = 0x50 // 80
|
|
OP_1 = 0x51 // 81 - AKA OP_TRUE
|
|
OP_TRUE = 0x51 // 81
|
|
OP_2 = 0x52 // 82
|
|
OP_3 = 0x53 // 83
|
|
OP_4 = 0x54 // 84
|
|
OP_5 = 0x55 // 85
|
|
OP_6 = 0x56 // 86
|
|
OP_7 = 0x57 // 87
|
|
OP_8 = 0x58 // 88
|
|
OP_9 = 0x59 // 89
|
|
OP_10 = 0x5a // 90
|
|
OP_11 = 0x5b // 91
|
|
OP_12 = 0x5c // 92
|
|
OP_13 = 0x5d // 93
|
|
OP_14 = 0x5e // 94
|
|
OP_15 = 0x5f // 95
|
|
OP_16 = 0x60 // 96
|
|
OP_NOP = 0x61 // 97
|
|
OP_VER = 0x62 // 98
|
|
OP_IF = 0x63 // 99
|
|
OP_NOTIF = 0x64 // 100
|
|
OP_VERIF = 0x65 // 101
|
|
OP_VERNOTIF = 0x66 // 102
|
|
OP_ELSE = 0x67 // 103
|
|
OP_ENDIF = 0x68 // 104
|
|
OP_VERIFY = 0x69 // 105
|
|
OP_RETURN = 0x6a // 106
|
|
OP_TOALTSTACK = 0x6b // 107
|
|
OP_FROMALTSTACK = 0x6c // 108
|
|
OP_2DROP = 0x6d // 109
|
|
OP_2DUP = 0x6e // 110
|
|
OP_3DUP = 0x6f // 111
|
|
OP_2OVER = 0x70 // 112
|
|
OP_2ROT = 0x71 // 113
|
|
OP_2SWAP = 0x72 // 114
|
|
OP_IFDUP = 0x73 // 115
|
|
OP_DEPTH = 0x74 // 116
|
|
OP_DROP = 0x75 // 117
|
|
OP_DUP = 0x76 // 118
|
|
OP_NIP = 0x77 // 119
|
|
OP_OVER = 0x78 // 120
|
|
OP_PICK = 0x79 // 121
|
|
OP_ROLL = 0x7a // 122
|
|
OP_ROT = 0x7b // 123
|
|
OP_SWAP = 0x7c // 124
|
|
OP_TUCK = 0x7d // 125
|
|
OP_CAT = 0x7e // 126
|
|
OP_SUBSTR = 0x7f // 127
|
|
OP_LEFT = 0x80 // 128
|
|
OP_RIGHT = 0x81 // 129
|
|
OP_SIZE = 0x82 // 130
|
|
OP_INVERT = 0x83 // 131
|
|
OP_AND = 0x84 // 132
|
|
OP_OR = 0x85 // 133
|
|
OP_XOR = 0x86 // 134
|
|
OP_EQUAL = 0x87 // 135
|
|
OP_EQUALVERIFY = 0x88 // 136
|
|
OP_ROTR = 0x89 // 137
|
|
OP_ROTL = 0x8a // 138
|
|
OP_1ADD = 0x8b // 139
|
|
OP_1SUB = 0x8c // 140
|
|
OP_2MUL = 0x8d // 141
|
|
OP_2DIV = 0x8e // 142
|
|
OP_NEGATE = 0x8f // 143
|
|
OP_ABS = 0x90 // 144
|
|
OP_NOT = 0x91 // 145
|
|
OP_0NOTEQUAL = 0x92 // 146
|
|
OP_ADD = 0x93 // 147
|
|
OP_SUB = 0x94 // 148
|
|
OP_MUL = 0x95 // 149
|
|
OP_DIV = 0x96 // 150
|
|
OP_MOD = 0x97 // 151
|
|
OP_LSHIFT = 0x98 // 152
|
|
OP_RSHIFT = 0x99 // 153
|
|
OP_BOOLAND = 0x9a // 154
|
|
OP_BOOLOR = 0x9b // 155
|
|
OP_NUMEQUAL = 0x9c // 156
|
|
OP_NUMEQUALVERIFY = 0x9d // 157
|
|
OP_NUMNOTEQUAL = 0x9e // 158
|
|
OP_LESSTHAN = 0x9f // 159
|
|
OP_GREATERTHAN = 0xa0 // 160
|
|
OP_LESSTHANOREQUAL = 0xa1 // 161
|
|
OP_GREATERTHANOREQUAL = 0xa2 // 162
|
|
OP_MIN = 0xa3 // 163
|
|
OP_MAX = 0xa4 // 164
|
|
OP_WITHIN = 0xa5 // 165
|
|
OP_RIPEMD160 = 0xa6 // 166
|
|
OP_SHA1 = 0xa7 // 167
|
|
OP_SHA256 = 0xa8 // 168
|
|
OP_HASH160 = 0xa9 // 169
|
|
OP_HASH256 = 0xaa // 170
|
|
OP_CODESEPARATOR = 0xab // 171
|
|
OP_CHECKSIG = 0xac // 172
|
|
OP_CHECKSIGVERIFY = 0xad // 173
|
|
OP_CHECKMULTISIG = 0xae // 174
|
|
OP_CHECKMULTISIGVERIFY = 0xaf // 175
|
|
OP_NOP1 = 0xb0 // 176
|
|
OP_NOP2 = 0xb1 // 177
|
|
OP_CHECKLOCKTIMEVERIFY = 0xb1 // 177 - AKA OP_NOP2
|
|
OP_NOP3 = 0xb2 // 178
|
|
OP_NOP4 = 0xb3 // 179
|
|
OP_NOP5 = 0xb4 // 180
|
|
OP_NOP6 = 0xb5 // 181
|
|
OP_NOP7 = 0xb6 // 182
|
|
OP_NOP8 = 0xb7 // 183
|
|
OP_NOP9 = 0xb8 // 184
|
|
OP_NOP10 = 0xb9 // 185
|
|
OP_SSTX = 0xba // 186 DECRED
|
|
OP_SSGEN = 0xbb // 187 DECRED
|
|
OP_SSRTX = 0xbc // 188 DECRED
|
|
OP_SSTXCHANGE = 0xbd // 189 DECRED
|
|
OP_CHECKSIGALT = 0xbe // 190 DECRED
|
|
OP_CHECKSIGALTVERIFY = 0xbf // 191 DECRED
|
|
OP_UNKNOWN192 = 0xc0 // 192
|
|
OP_UNKNOWN193 = 0xc1 // 193
|
|
OP_UNKNOWN194 = 0xc2 // 194
|
|
OP_UNKNOWN195 = 0xc3 // 195
|
|
OP_UNKNOWN196 = 0xc4 // 196
|
|
OP_UNKNOWN197 = 0xc5 // 197
|
|
OP_UNKNOWN198 = 0xc6 // 198
|
|
OP_UNKNOWN199 = 0xc7 // 199
|
|
OP_UNKNOWN200 = 0xc8 // 200
|
|
OP_UNKNOWN201 = 0xc9 // 201
|
|
OP_UNKNOWN202 = 0xca // 202
|
|
OP_UNKNOWN203 = 0xcb // 203
|
|
OP_UNKNOWN204 = 0xcc // 204
|
|
OP_UNKNOWN205 = 0xcd // 205
|
|
OP_UNKNOWN206 = 0xce // 206
|
|
OP_UNKNOWN207 = 0xcf // 207
|
|
OP_UNKNOWN208 = 0xd0 // 208
|
|
OP_UNKNOWN209 = 0xd1 // 209
|
|
OP_UNKNOWN210 = 0xd2 // 210
|
|
OP_UNKNOWN211 = 0xd3 // 211
|
|
OP_UNKNOWN212 = 0xd4 // 212
|
|
OP_UNKNOWN213 = 0xd5 // 213
|
|
OP_UNKNOWN214 = 0xd6 // 214
|
|
OP_UNKNOWN215 = 0xd7 // 215
|
|
OP_UNKNOWN216 = 0xd8 // 216
|
|
OP_UNKNOWN217 = 0xd9 // 217
|
|
OP_UNKNOWN218 = 0xda // 218
|
|
OP_UNKNOWN219 = 0xdb // 219
|
|
OP_UNKNOWN220 = 0xdc // 220
|
|
OP_UNKNOWN221 = 0xdd // 221
|
|
OP_UNKNOWN222 = 0xde // 222
|
|
OP_UNKNOWN223 = 0xdf // 223
|
|
OP_UNKNOWN224 = 0xe0 // 224
|
|
OP_UNKNOWN225 = 0xe1 // 225
|
|
OP_UNKNOWN226 = 0xe2 // 226
|
|
OP_UNKNOWN227 = 0xe3 // 227
|
|
OP_UNKNOWN228 = 0xe4 // 228
|
|
OP_UNKNOWN229 = 0xe5 // 229
|
|
OP_UNKNOWN230 = 0xe6 // 230
|
|
OP_UNKNOWN231 = 0xe7 // 231
|
|
OP_UNKNOWN232 = 0xe8 // 232
|
|
OP_UNKNOWN233 = 0xe9 // 233
|
|
OP_UNKNOWN234 = 0xea // 234
|
|
OP_UNKNOWN235 = 0xeb // 235
|
|
OP_UNKNOWN236 = 0xec // 236
|
|
OP_UNKNOWN237 = 0xed // 237
|
|
OP_UNKNOWN238 = 0xee // 238
|
|
OP_UNKNOWN239 = 0xef // 239
|
|
OP_UNKNOWN240 = 0xf0 // 240
|
|
OP_UNKNOWN241 = 0xf1 // 241
|
|
OP_UNKNOWN242 = 0xf2 // 242
|
|
OP_UNKNOWN243 = 0xf3 // 243
|
|
OP_UNKNOWN244 = 0xf4 // 244
|
|
OP_UNKNOWN245 = 0xf5 // 245
|
|
OP_UNKNOWN246 = 0xf6 // 246
|
|
OP_UNKNOWN247 = 0xf7 // 247
|
|
OP_UNKNOWN248 = 0xf8 // 248
|
|
OP_SMALLDATA = 0xf9 // 249 - bitcoin core internal
|
|
OP_SMALLINTEGER = 0xfa // 250 - bitcoin core internal
|
|
OP_PUBKEYS = 0xfb // 251 - bitcoin core internal
|
|
OP_UNKNOWN252 = 0xfc // 252
|
|
OP_PUBKEYHASH = 0xfd // 253 - bitcoin core internal
|
|
OP_PUBKEY = 0xfe // 254 - bitcoin core internal
|
|
OP_INVALIDOPCODE = 0xff // 255 - bitcoin core internal
|
|
)
|
|
|
|
// Conditional execution constants.
|
|
const (
|
|
OpCondFalse = 0
|
|
OpCondTrue = 1
|
|
OpCondSkip = 2
|
|
)
|
|
|
|
// opcodeArray holds details about all possible opcodes such as how many bytes
|
|
// the opcode and any associated data should take, its human-readable name, and
|
|
// the handler function.
|
|
var opcodeArray = [256]opcode{
|
|
// Data push opcodes.
|
|
OP_FALSE: {OP_FALSE, "OP_0", 1, opcodeFalse},
|
|
OP_DATA_1: {OP_DATA_1, "OP_DATA_1", 2, opcodePushData},
|
|
OP_DATA_2: {OP_DATA_2, "OP_DATA_2", 3, opcodePushData},
|
|
OP_DATA_3: {OP_DATA_3, "OP_DATA_3", 4, opcodePushData},
|
|
OP_DATA_4: {OP_DATA_4, "OP_DATA_4", 5, opcodePushData},
|
|
OP_DATA_5: {OP_DATA_5, "OP_DATA_5", 6, opcodePushData},
|
|
OP_DATA_6: {OP_DATA_6, "OP_DATA_6", 7, opcodePushData},
|
|
OP_DATA_7: {OP_DATA_7, "OP_DATA_7", 8, opcodePushData},
|
|
OP_DATA_8: {OP_DATA_8, "OP_DATA_8", 9, opcodePushData},
|
|
OP_DATA_9: {OP_DATA_9, "OP_DATA_9", 10, opcodePushData},
|
|
OP_DATA_10: {OP_DATA_10, "OP_DATA_10", 11, opcodePushData},
|
|
OP_DATA_11: {OP_DATA_11, "OP_DATA_11", 12, opcodePushData},
|
|
OP_DATA_12: {OP_DATA_12, "OP_DATA_12", 13, opcodePushData},
|
|
OP_DATA_13: {OP_DATA_13, "OP_DATA_13", 14, opcodePushData},
|
|
OP_DATA_14: {OP_DATA_14, "OP_DATA_14", 15, opcodePushData},
|
|
OP_DATA_15: {OP_DATA_15, "OP_DATA_15", 16, opcodePushData},
|
|
OP_DATA_16: {OP_DATA_16, "OP_DATA_16", 17, opcodePushData},
|
|
OP_DATA_17: {OP_DATA_17, "OP_DATA_17", 18, opcodePushData},
|
|
OP_DATA_18: {OP_DATA_18, "OP_DATA_18", 19, opcodePushData},
|
|
OP_DATA_19: {OP_DATA_19, "OP_DATA_19", 20, opcodePushData},
|
|
OP_DATA_20: {OP_DATA_20, "OP_DATA_20", 21, opcodePushData},
|
|
OP_DATA_21: {OP_DATA_21, "OP_DATA_21", 22, opcodePushData},
|
|
OP_DATA_22: {OP_DATA_22, "OP_DATA_22", 23, opcodePushData},
|
|
OP_DATA_23: {OP_DATA_23, "OP_DATA_23", 24, opcodePushData},
|
|
OP_DATA_24: {OP_DATA_24, "OP_DATA_24", 25, opcodePushData},
|
|
OP_DATA_25: {OP_DATA_25, "OP_DATA_25", 26, opcodePushData},
|
|
OP_DATA_26: {OP_DATA_26, "OP_DATA_26", 27, opcodePushData},
|
|
OP_DATA_27: {OP_DATA_27, "OP_DATA_27", 28, opcodePushData},
|
|
OP_DATA_28: {OP_DATA_28, "OP_DATA_28", 29, opcodePushData},
|
|
OP_DATA_29: {OP_DATA_29, "OP_DATA_29", 30, opcodePushData},
|
|
OP_DATA_30: {OP_DATA_30, "OP_DATA_30", 31, opcodePushData},
|
|
OP_DATA_31: {OP_DATA_31, "OP_DATA_31", 32, opcodePushData},
|
|
OP_DATA_32: {OP_DATA_32, "OP_DATA_32", 33, opcodePushData},
|
|
OP_DATA_33: {OP_DATA_33, "OP_DATA_33", 34, opcodePushData},
|
|
OP_DATA_34: {OP_DATA_34, "OP_DATA_34", 35, opcodePushData},
|
|
OP_DATA_35: {OP_DATA_35, "OP_DATA_35", 36, opcodePushData},
|
|
OP_DATA_36: {OP_DATA_36, "OP_DATA_36", 37, opcodePushData},
|
|
OP_DATA_37: {OP_DATA_37, "OP_DATA_37", 38, opcodePushData},
|
|
OP_DATA_38: {OP_DATA_38, "OP_DATA_38", 39, opcodePushData},
|
|
OP_DATA_39: {OP_DATA_39, "OP_DATA_39", 40, opcodePushData},
|
|
OP_DATA_40: {OP_DATA_40, "OP_DATA_40", 41, opcodePushData},
|
|
OP_DATA_41: {OP_DATA_41, "OP_DATA_41", 42, opcodePushData},
|
|
OP_DATA_42: {OP_DATA_42, "OP_DATA_42", 43, opcodePushData},
|
|
OP_DATA_43: {OP_DATA_43, "OP_DATA_43", 44, opcodePushData},
|
|
OP_DATA_44: {OP_DATA_44, "OP_DATA_44", 45, opcodePushData},
|
|
OP_DATA_45: {OP_DATA_45, "OP_DATA_45", 46, opcodePushData},
|
|
OP_DATA_46: {OP_DATA_46, "OP_DATA_46", 47, opcodePushData},
|
|
OP_DATA_47: {OP_DATA_47, "OP_DATA_47", 48, opcodePushData},
|
|
OP_DATA_48: {OP_DATA_48, "OP_DATA_48", 49, opcodePushData},
|
|
OP_DATA_49: {OP_DATA_49, "OP_DATA_49", 50, opcodePushData},
|
|
OP_DATA_50: {OP_DATA_50, "OP_DATA_50", 51, opcodePushData},
|
|
OP_DATA_51: {OP_DATA_51, "OP_DATA_51", 52, opcodePushData},
|
|
OP_DATA_52: {OP_DATA_52, "OP_DATA_52", 53, opcodePushData},
|
|
OP_DATA_53: {OP_DATA_53, "OP_DATA_53", 54, opcodePushData},
|
|
OP_DATA_54: {OP_DATA_54, "OP_DATA_54", 55, opcodePushData},
|
|
OP_DATA_55: {OP_DATA_55, "OP_DATA_55", 56, opcodePushData},
|
|
OP_DATA_56: {OP_DATA_56, "OP_DATA_56", 57, opcodePushData},
|
|
OP_DATA_57: {OP_DATA_57, "OP_DATA_57", 58, opcodePushData},
|
|
OP_DATA_58: {OP_DATA_58, "OP_DATA_58", 59, opcodePushData},
|
|
OP_DATA_59: {OP_DATA_59, "OP_DATA_59", 60, opcodePushData},
|
|
OP_DATA_60: {OP_DATA_60, "OP_DATA_60", 61, opcodePushData},
|
|
OP_DATA_61: {OP_DATA_61, "OP_DATA_61", 62, opcodePushData},
|
|
OP_DATA_62: {OP_DATA_62, "OP_DATA_62", 63, opcodePushData},
|
|
OP_DATA_63: {OP_DATA_63, "OP_DATA_63", 64, opcodePushData},
|
|
OP_DATA_64: {OP_DATA_64, "OP_DATA_64", 65, opcodePushData},
|
|
OP_DATA_65: {OP_DATA_65, "OP_DATA_65", 66, opcodePushData},
|
|
OP_DATA_66: {OP_DATA_66, "OP_DATA_66", 67, opcodePushData},
|
|
OP_DATA_67: {OP_DATA_67, "OP_DATA_67", 68, opcodePushData},
|
|
OP_DATA_68: {OP_DATA_68, "OP_DATA_68", 69, opcodePushData},
|
|
OP_DATA_69: {OP_DATA_69, "OP_DATA_69", 70, opcodePushData},
|
|
OP_DATA_70: {OP_DATA_70, "OP_DATA_70", 71, opcodePushData},
|
|
OP_DATA_71: {OP_DATA_71, "OP_DATA_71", 72, opcodePushData},
|
|
OP_DATA_72: {OP_DATA_72, "OP_DATA_72", 73, opcodePushData},
|
|
OP_DATA_73: {OP_DATA_73, "OP_DATA_73", 74, opcodePushData},
|
|
OP_DATA_74: {OP_DATA_74, "OP_DATA_74", 75, opcodePushData},
|
|
OP_DATA_75: {OP_DATA_75, "OP_DATA_75", 76, opcodePushData},
|
|
OP_PUSHDATA1: {OP_PUSHDATA1, "OP_PUSHDATA1", -1, opcodePushData},
|
|
OP_PUSHDATA2: {OP_PUSHDATA2, "OP_PUSHDATA2", -2, opcodePushData},
|
|
OP_PUSHDATA4: {OP_PUSHDATA4, "OP_PUSHDATA4", -4, opcodePushData},
|
|
OP_1NEGATE: {OP_1NEGATE, "OP_1NEGATE", 1, opcode1Negate},
|
|
OP_RESERVED: {OP_RESERVED, "OP_RESERVED", 1, opcodeReserved},
|
|
OP_TRUE: {OP_TRUE, "OP_1", 1, opcodeN},
|
|
OP_2: {OP_2, "OP_2", 1, opcodeN},
|
|
OP_3: {OP_3, "OP_3", 1, opcodeN},
|
|
OP_4: {OP_4, "OP_4", 1, opcodeN},
|
|
OP_5: {OP_5, "OP_5", 1, opcodeN},
|
|
OP_6: {OP_6, "OP_6", 1, opcodeN},
|
|
OP_7: {OP_7, "OP_7", 1, opcodeN},
|
|
OP_8: {OP_8, "OP_8", 1, opcodeN},
|
|
OP_9: {OP_9, "OP_9", 1, opcodeN},
|
|
OP_10: {OP_10, "OP_10", 1, opcodeN},
|
|
OP_11: {OP_11, "OP_11", 1, opcodeN},
|
|
OP_12: {OP_12, "OP_12", 1, opcodeN},
|
|
OP_13: {OP_13, "OP_13", 1, opcodeN},
|
|
OP_14: {OP_14, "OP_14", 1, opcodeN},
|
|
OP_15: {OP_15, "OP_15", 1, opcodeN},
|
|
OP_16: {OP_16, "OP_16", 1, opcodeN},
|
|
|
|
// Control opcodes.
|
|
OP_NOP: {OP_NOP, "OP_NOP", 1, opcodeNop},
|
|
OP_VER: {OP_VER, "OP_VER", 1, opcodeReserved},
|
|
OP_IF: {OP_IF, "OP_IF", 1, opcodeIf},
|
|
OP_NOTIF: {OP_NOTIF, "OP_NOTIF", 1, opcodeNotIf},
|
|
OP_VERIF: {OP_VERIF, "OP_VERIF", 1, opcodeReserved},
|
|
OP_VERNOTIF: {OP_VERNOTIF, "OP_VERNOTIF", 1, opcodeReserved},
|
|
OP_ELSE: {OP_ELSE, "OP_ELSE", 1, opcodeElse},
|
|
OP_ENDIF: {OP_ENDIF, "OP_ENDIF", 1, opcodeEndif},
|
|
OP_VERIFY: {OP_VERIFY, "OP_VERIFY", 1, opcodeVerify},
|
|
OP_RETURN: {OP_RETURN, "OP_RETURN", 1, opcodeReturn},
|
|
OP_CHECKLOCKTIMEVERIFY: {OP_CHECKLOCKTIMEVERIFY, "OP_CHECKLOCKTIMEVERIFY", 1, opcodeCheckLockTimeVerify},
|
|
|
|
// Stack opcodes.
|
|
OP_TOALTSTACK: {OP_TOALTSTACK, "OP_TOALTSTACK", 1, opcodeToAltStack},
|
|
OP_FROMALTSTACK: {OP_FROMALTSTACK, "OP_FROMALTSTACK", 1, opcodeFromAltStack},
|
|
OP_2DROP: {OP_2DROP, "OP_2DROP", 1, opcode2Drop},
|
|
OP_2DUP: {OP_2DUP, "OP_2DUP", 1, opcode2Dup},
|
|
OP_3DUP: {OP_3DUP, "OP_3DUP", 1, opcode3Dup},
|
|
OP_2OVER: {OP_2OVER, "OP_2OVER", 1, opcode2Over},
|
|
OP_2ROT: {OP_2ROT, "OP_2ROT", 1, opcode2Rot},
|
|
OP_2SWAP: {OP_2SWAP, "OP_2SWAP", 1, opcode2Swap},
|
|
OP_IFDUP: {OP_IFDUP, "OP_IFDUP", 1, opcodeIfDup},
|
|
OP_DEPTH: {OP_DEPTH, "OP_DEPTH", 1, opcodeDepth},
|
|
OP_DROP: {OP_DROP, "OP_DROP", 1, opcodeDrop},
|
|
OP_DUP: {OP_DUP, "OP_DUP", 1, opcodeDup},
|
|
OP_NIP: {OP_NIP, "OP_NIP", 1, opcodeNip},
|
|
OP_OVER: {OP_OVER, "OP_OVER", 1, opcodeOver},
|
|
OP_PICK: {OP_PICK, "OP_PICK", 1, opcodePick},
|
|
OP_ROLL: {OP_ROLL, "OP_ROLL", 1, opcodeRoll},
|
|
OP_ROT: {OP_ROT, "OP_ROT", 1, opcodeRot},
|
|
OP_SWAP: {OP_SWAP, "OP_SWAP", 1, opcodeSwap},
|
|
OP_TUCK: {OP_TUCK, "OP_TUCK", 1, opcodeTuck},
|
|
|
|
// Splice opcodes.
|
|
OP_CAT: {OP_CAT, "OP_CAT", 1, opcodeCat},
|
|
OP_SUBSTR: {OP_SUBSTR, "OP_SUBSTR", 1, opcodeSubstr},
|
|
OP_LEFT: {OP_LEFT, "OP_LEFT", 1, opcodeLeft},
|
|
OP_RIGHT: {OP_RIGHT, "OP_RIGHT", 1, opcodeRight},
|
|
OP_SIZE: {OP_SIZE, "OP_SIZE", 1, opcodeSize},
|
|
|
|
// Bitwise logic opcodes for int32 registers derived from the stack.
|
|
OP_INVERT: {OP_INVERT, "OP_INVERT", 1, opcodeInvert},
|
|
OP_AND: {OP_AND, "OP_AND", 1, opcodeAnd},
|
|
OP_OR: {OP_OR, "OP_OR", 1, opcodeOr},
|
|
OP_XOR: {OP_XOR, "OP_XOR", 1, opcodeXor},
|
|
|
|
// Bytewise comparison function opcodes for byte strings.
|
|
OP_EQUAL: {OP_EQUAL, "OP_EQUAL", 1, opcodeEqual},
|
|
OP_EQUALVERIFY: {OP_EQUALVERIFY, "OP_EQUALVERIFY", 1, opcodeEqualVerify},
|
|
|
|
// Bitwise rotation opcodes for an int32 register derived from the stack.
|
|
OP_ROTR: {OP_ROTR, "OP_ROTR", 1, opcodeRotr},
|
|
OP_ROTL: {OP_ROTL, "OP_ROTL", 1, opcodeRotl},
|
|
|
|
// Numeric related opcodes.
|
|
OP_1ADD: {OP_1ADD, "OP_1ADD", 1, opcode1Add},
|
|
OP_1SUB: {OP_1SUB, "OP_1SUB", 1, opcode1Sub},
|
|
OP_2MUL: {OP_2MUL, "OP_2MUL", 1, opcodeNop},
|
|
OP_2DIV: {OP_2DIV, "OP_2DIV", 1, opcodeNop},
|
|
OP_NEGATE: {OP_NEGATE, "OP_NEGATE", 1, opcodeNegate},
|
|
OP_ABS: {OP_ABS, "OP_ABS", 1, opcodeAbs},
|
|
OP_NOT: {OP_NOT, "OP_NOT", 1, opcodeNot},
|
|
OP_0NOTEQUAL: {OP_0NOTEQUAL, "OP_0NOTEQUAL", 1, opcode0NotEqual},
|
|
OP_ADD: {OP_ADD, "OP_ADD", 1, opcodeAdd},
|
|
OP_SUB: {OP_SUB, "OP_SUB", 1, opcodeSub},
|
|
OP_MUL: {OP_MUL, "OP_MUL", 1, opcodeMul},
|
|
OP_DIV: {OP_DIV, "OP_DIV", 1, opcodeDiv},
|
|
OP_MOD: {OP_MOD, "OP_MOD", 1, opcodeMod},
|
|
OP_LSHIFT: {OP_LSHIFT, "OP_LSHIFT", 1, opcodeLShift},
|
|
OP_RSHIFT: {OP_RSHIFT, "OP_RSHIFT", 1, opcodeRShift},
|
|
OP_BOOLAND: {OP_BOOLAND, "OP_BOOLAND", 1, opcodeBoolAnd},
|
|
OP_BOOLOR: {OP_BOOLOR, "OP_BOOLOR", 1, opcodeBoolOr},
|
|
OP_NUMEQUAL: {OP_NUMEQUAL, "OP_NUMEQUAL", 1, opcodeNumEqual},
|
|
OP_NUMEQUALVERIFY: {OP_NUMEQUALVERIFY, "OP_NUMEQUALVERIFY", 1, opcodeNumEqualVerify},
|
|
OP_NUMNOTEQUAL: {OP_NUMNOTEQUAL, "OP_NUMNOTEQUAL", 1, opcodeNumNotEqual},
|
|
OP_LESSTHAN: {OP_LESSTHAN, "OP_LESSTHAN", 1, opcodeLessThan},
|
|
OP_GREATERTHAN: {OP_GREATERTHAN, "OP_GREATERTHAN", 1, opcodeGreaterThan},
|
|
OP_LESSTHANOREQUAL: {OP_LESSTHANOREQUAL, "OP_LESSTHANOREQUAL", 1, opcodeLessThanOrEqual},
|
|
OP_GREATERTHANOREQUAL: {OP_GREATERTHANOREQUAL, "OP_GREATERTHANOREQUAL", 1, opcodeGreaterThanOrEqual},
|
|
OP_MIN: {OP_MIN, "OP_MIN", 1, opcodeMin},
|
|
OP_MAX: {OP_MAX, "OP_MAX", 1, opcodeMax},
|
|
OP_WITHIN: {OP_WITHIN, "OP_WITHIN", 1, opcodeWithin},
|
|
|
|
// Crypto opcodes.
|
|
OP_RIPEMD160: {OP_RIPEMD160, "OP_RIPEMD160", 1, opcodeRipemd160},
|
|
OP_SHA1: {OP_SHA1, "OP_SHA1", 1, opcodeSha1},
|
|
OP_SHA256: {OP_SHA256, "OP_SHA256", 1, opcodeSha256},
|
|
OP_HASH160: {OP_HASH160, "OP_HASH160", 1, opcodeHash160},
|
|
OP_HASH256: {OP_HASH256, "OP_HASH256", 1, opcodeHash256},
|
|
OP_CODESEPARATOR: {OP_CODESEPARATOR, "OP_CODESEPARATOR", 1, opcodeDisabled}, // Disabled
|
|
OP_CHECKSIG: {OP_CHECKSIG, "OP_CHECKSIG", 1, opcodeCheckSig},
|
|
OP_CHECKSIGVERIFY: {OP_CHECKSIGVERIFY, "OP_CHECKSIGVERIFY", 1, opcodeCheckSigVerify},
|
|
OP_CHECKMULTISIG: {OP_CHECKMULTISIG, "OP_CHECKMULTISIG", 1, opcodeCheckMultiSig},
|
|
OP_CHECKMULTISIGVERIFY: {OP_CHECKMULTISIGVERIFY, "OP_CHECKMULTISIGVERIFY", 1, opcodeCheckMultiSigVerify},
|
|
|
|
// Reserved opcodes.
|
|
OP_NOP1: {OP_NOP1, "OP_NOP1", 1, opcodeNop},
|
|
OP_NOP3: {OP_NOP3, "OP_NOP3", 1, opcodeNop},
|
|
OP_NOP4: {OP_NOP4, "OP_NOP4", 1, opcodeNop},
|
|
OP_NOP5: {OP_NOP5, "OP_NOP5", 1, opcodeNop},
|
|
OP_NOP6: {OP_NOP6, "OP_NOP6", 1, opcodeNop},
|
|
OP_NOP7: {OP_NOP7, "OP_NOP7", 1, opcodeNop},
|
|
OP_NOP8: {OP_NOP8, "OP_NOP8", 1, opcodeNop},
|
|
OP_NOP9: {OP_NOP9, "OP_NOP9", 1, opcodeNop},
|
|
OP_NOP10: {OP_NOP10, "OP_NOP10", 1, opcodeNop},
|
|
|
|
// SS* opcodes.
|
|
OP_SSTX: {OP_SSTX, "OP_SSTX", 1, opcodeNop},
|
|
OP_SSGEN: {OP_SSGEN, "OP_SSGEN", 1, opcodeNop},
|
|
OP_SSRTX: {OP_SSRTX, "OP_SSRTX", 1, opcodeNop},
|
|
OP_SSTXCHANGE: {OP_SSTXCHANGE, "OP_SSTXCHANGE", 1, opcodeNop},
|
|
|
|
// Alternative checksig opcode.
|
|
OP_CHECKSIGALT: {OP_CHECKSIGALT, "OP_CHECKSIGALT", 1, opcodeCheckSigAlt},
|
|
OP_CHECKSIGALTVERIFY: {OP_CHECKSIGALTVERIFY, "OP_CHECKSIGALTVERIFY", 1, opcodeCheckSigAltVerify},
|
|
|
|
// Undefined opcodes.
|
|
OP_UNKNOWN192: {OP_UNKNOWN192, "OP_UNKNOWN192", 1, opcodeNop},
|
|
OP_UNKNOWN193: {OP_UNKNOWN193, "OP_UNKNOWN193", 1, opcodeNop},
|
|
OP_UNKNOWN194: {OP_UNKNOWN194, "OP_UNKNOWN194", 1, opcodeNop},
|
|
OP_UNKNOWN195: {OP_UNKNOWN195, "OP_UNKNOWN195", 1, opcodeNop},
|
|
OP_UNKNOWN196: {OP_UNKNOWN196, "OP_UNKNOWN196", 1, opcodeNop},
|
|
OP_UNKNOWN197: {OP_UNKNOWN197, "OP_UNKNOWN197", 1, opcodeNop},
|
|
OP_UNKNOWN198: {OP_UNKNOWN198, "OP_UNKNOWN198", 1, opcodeNop},
|
|
OP_UNKNOWN199: {OP_UNKNOWN199, "OP_UNKNOWN199", 1, opcodeNop},
|
|
OP_UNKNOWN200: {OP_UNKNOWN200, "OP_UNKNOWN200", 1, opcodeNop},
|
|
OP_UNKNOWN201: {OP_UNKNOWN201, "OP_UNKNOWN201", 1, opcodeNop},
|
|
OP_UNKNOWN202: {OP_UNKNOWN202, "OP_UNKNOWN202", 1, opcodeNop},
|
|
OP_UNKNOWN203: {OP_UNKNOWN203, "OP_UNKNOWN203", 1, opcodeNop},
|
|
OP_UNKNOWN204: {OP_UNKNOWN204, "OP_UNKNOWN204", 1, opcodeNop},
|
|
OP_UNKNOWN205: {OP_UNKNOWN205, "OP_UNKNOWN205", 1, opcodeNop},
|
|
OP_UNKNOWN206: {OP_UNKNOWN206, "OP_UNKNOWN206", 1, opcodeNop},
|
|
OP_UNKNOWN207: {OP_UNKNOWN207, "OP_UNKNOWN207", 1, opcodeNop},
|
|
OP_UNKNOWN208: {OP_UNKNOWN208, "OP_UNKNOWN208", 1, opcodeNop},
|
|
OP_UNKNOWN209: {OP_UNKNOWN209, "OP_UNKNOWN209", 1, opcodeNop},
|
|
OP_UNKNOWN210: {OP_UNKNOWN210, "OP_UNKNOWN210", 1, opcodeNop},
|
|
OP_UNKNOWN211: {OP_UNKNOWN211, "OP_UNKNOWN211", 1, opcodeNop},
|
|
OP_UNKNOWN212: {OP_UNKNOWN212, "OP_UNKNOWN212", 1, opcodeNop},
|
|
OP_UNKNOWN213: {OP_UNKNOWN213, "OP_UNKNOWN213", 1, opcodeNop},
|
|
OP_UNKNOWN214: {OP_UNKNOWN214, "OP_UNKNOWN214", 1, opcodeNop},
|
|
OP_UNKNOWN215: {OP_UNKNOWN215, "OP_UNKNOWN215", 1, opcodeNop},
|
|
OP_UNKNOWN216: {OP_UNKNOWN216, "OP_UNKNOWN216", 1, opcodeNop},
|
|
OP_UNKNOWN217: {OP_UNKNOWN217, "OP_UNKNOWN217", 1, opcodeNop},
|
|
OP_UNKNOWN218: {OP_UNKNOWN218, "OP_UNKNOWN218", 1, opcodeNop},
|
|
OP_UNKNOWN219: {OP_UNKNOWN219, "OP_UNKNOWN219", 1, opcodeNop},
|
|
OP_UNKNOWN220: {OP_UNKNOWN220, "OP_UNKNOWN220", 1, opcodeNop},
|
|
OP_UNKNOWN221: {OP_UNKNOWN221, "OP_UNKNOWN221", 1, opcodeNop},
|
|
OP_UNKNOWN222: {OP_UNKNOWN222, "OP_UNKNOWN222", 1, opcodeNop},
|
|
OP_UNKNOWN223: {OP_UNKNOWN223, "OP_UNKNOWN223", 1, opcodeNop},
|
|
OP_UNKNOWN224: {OP_UNKNOWN224, "OP_UNKNOWN224", 1, opcodeNop},
|
|
OP_UNKNOWN225: {OP_UNKNOWN225, "OP_UNKNOWN225", 1, opcodeNop},
|
|
OP_UNKNOWN226: {OP_UNKNOWN226, "OP_UNKNOWN226", 1, opcodeNop},
|
|
OP_UNKNOWN227: {OP_UNKNOWN227, "OP_UNKNOWN227", 1, opcodeNop},
|
|
OP_UNKNOWN228: {OP_UNKNOWN228, "OP_UNKNOWN228", 1, opcodeNop},
|
|
OP_UNKNOWN229: {OP_UNKNOWN229, "OP_UNKNOWN229", 1, opcodeNop},
|
|
OP_UNKNOWN230: {OP_UNKNOWN230, "OP_UNKNOWN230", 1, opcodeNop},
|
|
OP_UNKNOWN231: {OP_UNKNOWN231, "OP_UNKNOWN231", 1, opcodeNop},
|
|
OP_UNKNOWN232: {OP_UNKNOWN232, "OP_UNKNOWN232", 1, opcodeNop},
|
|
OP_UNKNOWN233: {OP_UNKNOWN233, "OP_UNKNOWN233", 1, opcodeNop},
|
|
OP_UNKNOWN234: {OP_UNKNOWN234, "OP_UNKNOWN234", 1, opcodeNop},
|
|
OP_UNKNOWN235: {OP_UNKNOWN235, "OP_UNKNOWN235", 1, opcodeNop},
|
|
OP_UNKNOWN236: {OP_UNKNOWN236, "OP_UNKNOWN236", 1, opcodeNop},
|
|
OP_UNKNOWN237: {OP_UNKNOWN237, "OP_UNKNOWN237", 1, opcodeNop},
|
|
OP_UNKNOWN238: {OP_UNKNOWN238, "OP_UNKNOWN238", 1, opcodeNop},
|
|
OP_UNKNOWN239: {OP_UNKNOWN239, "OP_UNKNOWN239", 1, opcodeNop},
|
|
OP_UNKNOWN240: {OP_UNKNOWN240, "OP_UNKNOWN240", 1, opcodeNop},
|
|
OP_UNKNOWN241: {OP_UNKNOWN241, "OP_UNKNOWN241", 1, opcodeNop},
|
|
OP_UNKNOWN242: {OP_UNKNOWN242, "OP_UNKNOWN242", 1, opcodeNop},
|
|
OP_UNKNOWN243: {OP_UNKNOWN243, "OP_UNKNOWN243", 1, opcodeNop},
|
|
OP_UNKNOWN244: {OP_UNKNOWN244, "OP_UNKNOWN244", 1, opcodeNop},
|
|
OP_UNKNOWN245: {OP_UNKNOWN245, "OP_UNKNOWN245", 1, opcodeNop},
|
|
OP_UNKNOWN246: {OP_UNKNOWN246, "OP_UNKNOWN246", 1, opcodeNop},
|
|
OP_UNKNOWN247: {OP_UNKNOWN247, "OP_UNKNOWN247", 1, opcodeNop},
|
|
OP_UNKNOWN248: {OP_UNKNOWN248, "OP_UNKNOWN248", 1, opcodeNop},
|
|
|
|
// Bitcoin Core internal use opcode. Defined here for completeness.
|
|
OP_SMALLDATA: {OP_SMALLDATA, "OP_SMALLDATA", 1, opcodeInvalid},
|
|
OP_SMALLINTEGER: {OP_SMALLINTEGER, "OP_SMALLINTEGER", 1, opcodeInvalid},
|
|
OP_PUBKEYS: {OP_PUBKEYS, "OP_PUBKEYS", 1, opcodeInvalid},
|
|
OP_UNKNOWN252: {OP_UNKNOWN252, "OP_UNKNOWN252", 1, opcodeInvalid},
|
|
OP_PUBKEYHASH: {OP_PUBKEYHASH, "OP_PUBKEYHASH", 1, opcodeInvalid},
|
|
OP_PUBKEY: {OP_PUBKEY, "OP_PUBKEY", 1, opcodeInvalid},
|
|
|
|
OP_INVALIDOPCODE: {OP_INVALIDOPCODE, "OP_INVALIDOPCODE", 1, opcodeInvalid},
|
|
}
|
|
|
|
// opcodeOnelineRepls defines opcode names which are replaced when doing a
|
|
// one-line disassembly. This is done to match the output of the reference
|
|
// implementation while not changing the opcode names in the nicer full
|
|
// disassembly.
|
|
var opcodeOnelineRepls = map[string]string{
|
|
"OP_1NEGATE": "-1",
|
|
"OP_0": "0",
|
|
"OP_1": "1",
|
|
"OP_2": "2",
|
|
"OP_3": "3",
|
|
"OP_4": "4",
|
|
"OP_5": "5",
|
|
"OP_6": "6",
|
|
"OP_7": "7",
|
|
"OP_8": "8",
|
|
"OP_9": "9",
|
|
"OP_10": "10",
|
|
"OP_11": "11",
|
|
"OP_12": "12",
|
|
"OP_13": "13",
|
|
"OP_14": "14",
|
|
"OP_15": "15",
|
|
"OP_16": "16",
|
|
}
|
|
|
|
// parsedOpcode represents an opcode that has been parsed and includes any
|
|
// potential data associated with it.
|
|
type parsedOpcode struct {
|
|
opcode *opcode
|
|
data []byte
|
|
}
|
|
|
|
// isDisabled returns whether or not the opcode is disabled and thus is always
|
|
// bad to see in the instruction stream (even if turned off by a conditional).
|
|
func (pop *parsedOpcode) isDisabled() bool {
|
|
switch pop.opcode.value {
|
|
case OP_CODESEPARATOR:
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
// alwaysIllegal returns whether or not the opcode is always illegal when passed
|
|
// over by the program counter even if in a non-executed branch (it isn't a
|
|
// coincidence that they are conditionals).
|
|
func (pop *parsedOpcode) alwaysIllegal() bool {
|
|
switch pop.opcode.value {
|
|
case OP_VERIF:
|
|
return true
|
|
case OP_VERNOTIF:
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
// isConditional returns whether or not the opcode is a conditional opcode which
|
|
// changes the conditional execution stack when executed.
|
|
func (pop *parsedOpcode) isConditional() bool {
|
|
switch pop.opcode.value {
|
|
case OP_IF:
|
|
return true
|
|
case OP_NOTIF:
|
|
return true
|
|
case OP_ELSE:
|
|
return true
|
|
case OP_ENDIF:
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
// checkMinimalDataPush returns whether or not the current data push uses the
|
|
// smallest possible opcode to represent it. For example, the value 15 could
|
|
// be pushed with OP_DATA_1 15 (among other variations); however, OP_15 is a
|
|
// single opcode that represents the same value and is only a single byte versus
|
|
// two bytes.
|
|
func (pop *parsedOpcode) checkMinimalDataPush() error {
|
|
data := pop.data
|
|
dataLen := len(data)
|
|
opcode := pop.opcode.value
|
|
|
|
if dataLen == 0 && opcode != OP_0 {
|
|
return ErrStackMinimalData
|
|
} else if dataLen == 1 && data[0] >= 1 && data[0] <= 16 {
|
|
if opcode != OP_1+data[0]-1 {
|
|
// Should have used OP_1 .. OP_16
|
|
return ErrStackMinimalData
|
|
}
|
|
} else if dataLen == 1 && data[0] == 0x81 {
|
|
if opcode != OP_1NEGATE {
|
|
return ErrStackMinimalData
|
|
}
|
|
} else if dataLen <= 75 {
|
|
if int(opcode) != dataLen {
|
|
// Should have used a direct push
|
|
return ErrStackMinimalData
|
|
}
|
|
} else if dataLen <= 255 {
|
|
if opcode != OP_PUSHDATA1 {
|
|
return ErrStackMinimalData
|
|
}
|
|
} else if dataLen <= 65535 {
|
|
if opcode != OP_PUSHDATA2 {
|
|
return ErrStackMinimalData
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// print returns a human-readable string representation of the opcode for use
|
|
// in script disassembly.
|
|
func (pop *parsedOpcode) print(oneline bool) string {
|
|
// The reference implementation one-line disassembly replaces opcodes
|
|
// which represent values (e.g. OP_0 through OP_16 and OP_1NEGATE)
|
|
// with the raw value. However, when not doing a one-line dissassembly,
|
|
// we prefer to show the actual opcode names. Thus, only replace the
|
|
// opcodes in question when the oneline flag is set.
|
|
opcodeName := pop.opcode.name
|
|
if oneline {
|
|
if replName, ok := opcodeOnelineRepls[opcodeName]; ok {
|
|
opcodeName = replName
|
|
}
|
|
|
|
// Nothing more to do for non-data push opcodes.
|
|
if pop.opcode.length == 1 {
|
|
return opcodeName
|
|
}
|
|
|
|
return fmt.Sprintf("%x", pop.data)
|
|
}
|
|
|
|
// Nothing more to do for non-data push opcodes.
|
|
if pop.opcode.length == 1 {
|
|
return opcodeName
|
|
}
|
|
|
|
// Add length for the OP_PUSHDATA# opcodes.
|
|
retString := opcodeName
|
|
switch pop.opcode.length {
|
|
case -1:
|
|
retString += fmt.Sprintf(" 0x%02x", len(pop.data))
|
|
case -2:
|
|
retString += fmt.Sprintf(" 0x%04x", len(pop.data))
|
|
case -4:
|
|
retString += fmt.Sprintf(" 0x%08x", len(pop.data))
|
|
}
|
|
|
|
return fmt.Sprintf("%s 0x%02x", retString, pop.data)
|
|
}
|
|
|
|
// bytes returns any data associated with the opcode encoded as it would be in
|
|
// a script. This is used for unparsing scripts from parsed opcodes.
|
|
func (pop *parsedOpcode) bytes() ([]byte, error) {
|
|
var retbytes []byte
|
|
if pop.opcode.length > 0 {
|
|
retbytes = make([]byte, 1, pop.opcode.length)
|
|
} else {
|
|
retbytes = make([]byte, 1, 1+len(pop.data)-
|
|
pop.opcode.length)
|
|
}
|
|
|
|
retbytes[0] = pop.opcode.value
|
|
if pop.opcode.length == 1 {
|
|
if len(pop.data) != 0 {
|
|
return nil, ErrStackInvalidOpcode
|
|
}
|
|
return retbytes, nil
|
|
}
|
|
nbytes := pop.opcode.length
|
|
if pop.opcode.length < 0 {
|
|
l := len(pop.data)
|
|
// tempting just to hardcode to avoid the complexity here.
|
|
switch pop.opcode.length {
|
|
case -1:
|
|
retbytes = append(retbytes, byte(l))
|
|
nbytes = int(retbytes[1]) + len(retbytes)
|
|
case -2:
|
|
retbytes = append(retbytes, byte(l&0xff),
|
|
byte(l>>8&0xff))
|
|
nbytes = int(binary.LittleEndian.Uint16(retbytes[1:])) +
|
|
len(retbytes)
|
|
case -4:
|
|
retbytes = append(retbytes, byte(l&0xff),
|
|
byte((l>>8)&0xff), byte((l>>16)&0xff),
|
|
byte((l>>24)&0xff))
|
|
nbytes = int(binary.LittleEndian.Uint32(retbytes[1:])) +
|
|
len(retbytes)
|
|
}
|
|
}
|
|
|
|
retbytes = append(retbytes, pop.data...)
|
|
|
|
if len(retbytes) != nbytes {
|
|
return nil, ErrStackInvalidOpcode
|
|
}
|
|
|
|
return retbytes, nil
|
|
}
|
|
|
|
// *******************************************
|
|
// Opcode implementation functions start here.
|
|
// *******************************************
|
|
|
|
// opcodeDisabled is a common handler for disabled opcodes. It returns an
|
|
// appropriate error indicating the opcode is disabled. While it would
|
|
// ordinarily make more sense to detect if the script contains any disabled
|
|
// opcodes before executing in an initial parse step, the consensus rules
|
|
// dictate the script doesn't fail until the program counter passes over a
|
|
// disabled opcode (even when they appear in a branch that is not executed).
|
|
func opcodeDisabled(op *parsedOpcode, vm *Engine) error {
|
|
return ErrStackOpDisabled
|
|
}
|
|
|
|
// opcodeReserved is a common handler for all reserved opcodes. It returns an
|
|
// appropriate error indicating the opcode is reserved.
|
|
func opcodeReserved(op *parsedOpcode, vm *Engine) error {
|
|
return ErrStackReservedOpcode
|
|
}
|
|
|
|
// opcodeInvalid is a common handler for all invalid opcodes. It returns an
|
|
// appropriate error indicating the opcode is invalid.
|
|
func opcodeInvalid(op *parsedOpcode, vm *Engine) error {
|
|
return ErrStackInvalidOpcode
|
|
}
|
|
|
|
// opcodeFalse pushes an empty array to the data stack to represent false. Note
|
|
// that 0, when encoded as a number according to the numeric encoding consensus
|
|
// rules, is an empty array.
|
|
func opcodeFalse(op *parsedOpcode, vm *Engine) error {
|
|
vm.dstack.PushByteArray(nil)
|
|
return nil
|
|
}
|
|
|
|
// opcodePushData is a common handler for the vast majority of opcodes that push
|
|
// raw data (bytes) to the data stack.
|
|
func opcodePushData(op *parsedOpcode, vm *Engine) error {
|
|
vm.dstack.PushByteArray(op.data)
|
|
return nil
|
|
}
|
|
|
|
// opcode1Negate pushes -1, encoded as a number, to the data stack.
|
|
func opcode1Negate(op *parsedOpcode, vm *Engine) error {
|
|
vm.dstack.PushInt(scriptNum(-1))
|
|
return nil
|
|
}
|
|
|
|
// opcodeN is a common handler for the small integer data push opcodes. It
|
|
// pushes the numeric value the opcode represents (which will be from 1 to 16)
|
|
// onto the data stack.
|
|
func opcodeN(op *parsedOpcode, vm *Engine) error {
|
|
// The opcodes are all defined consecutively, so the numeric value is
|
|
// the difference.
|
|
vm.dstack.PushInt(scriptNum((op.opcode.value - (OP_1 - 1))))
|
|
return nil
|
|
}
|
|
|
|
// opcodeNop is a common handler for the NOP family of opcodes. As the name
|
|
// implies it generally does nothing, however, it will return an error when
|
|
// the flag to discourage use of NOPs is set for select opcodes.
|
|
func opcodeNop(op *parsedOpcode, vm *Engine) error {
|
|
switch op.opcode.value {
|
|
case OP_NOP1, OP_NOP3, OP_NOP4, OP_NOP5,
|
|
OP_NOP6, OP_NOP7, OP_NOP8, OP_NOP9, OP_NOP10,
|
|
OP_UNKNOWN192, OP_UNKNOWN193,
|
|
OP_UNKNOWN194, OP_UNKNOWN195,
|
|
OP_UNKNOWN196, OP_UNKNOWN197,
|
|
OP_UNKNOWN198, OP_UNKNOWN199,
|
|
OP_UNKNOWN200, OP_UNKNOWN201,
|
|
OP_UNKNOWN202, OP_UNKNOWN203,
|
|
OP_UNKNOWN204, OP_UNKNOWN205,
|
|
OP_UNKNOWN206, OP_UNKNOWN207,
|
|
OP_UNKNOWN208, OP_UNKNOWN209,
|
|
OP_UNKNOWN210, OP_UNKNOWN211,
|
|
OP_UNKNOWN212, OP_UNKNOWN213,
|
|
OP_UNKNOWN214, OP_UNKNOWN215,
|
|
OP_UNKNOWN216, OP_UNKNOWN217,
|
|
OP_UNKNOWN218, OP_UNKNOWN219,
|
|
OP_UNKNOWN220, OP_UNKNOWN221,
|
|
OP_UNKNOWN222, OP_UNKNOWN223,
|
|
OP_UNKNOWN224, OP_UNKNOWN225,
|
|
OP_UNKNOWN226, OP_UNKNOWN227,
|
|
OP_UNKNOWN228, OP_UNKNOWN229,
|
|
OP_UNKNOWN230, OP_UNKNOWN231,
|
|
OP_UNKNOWN232, OP_UNKNOWN233,
|
|
OP_UNKNOWN234, OP_UNKNOWN235,
|
|
OP_UNKNOWN236, OP_UNKNOWN237,
|
|
OP_UNKNOWN238, OP_UNKNOWN239,
|
|
OP_UNKNOWN240, OP_UNKNOWN241,
|
|
OP_UNKNOWN242, OP_UNKNOWN243,
|
|
OP_UNKNOWN244, OP_UNKNOWN245,
|
|
OP_UNKNOWN246, OP_UNKNOWN247,
|
|
OP_UNKNOWN248:
|
|
if vm.hasFlag(ScriptDiscourageUpgradableNops) {
|
|
return fmt.Errorf("OP_NOP at %d reserved for soft-fork "+
|
|
"upgrades", op.opcode.value)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// opcodeIf treats the top item on the data stack as a boolean and removes it.
|
|
//
|
|
// An appropriate entry is added to the conditional stack depending on whether
|
|
// the boolean is true and whether this if is on an executing branch in order
|
|
// to allow proper execution of further opcodes depending on the conditional
|
|
// logic. When the boolean is true, the first branch will be executed (unless
|
|
// this opcode is nested in a non-executed branch).
|
|
//
|
|
// <expression> if [statements] [else [statements]] endif
|
|
//
|
|
// Note that, unlike for all non-conditional opcodes, this is executed even when
|
|
// it is on a non-executing branch so proper nesting is maintained.
|
|
//
|
|
// Data stack transformation: [... bool] -> [...]
|
|
// Conditional stack transformation: [...] -> [... OpCondValue]
|
|
func opcodeIf(op *parsedOpcode, vm *Engine) error {
|
|
condVal := OpCondFalse
|
|
if vm.isBranchExecuting() {
|
|
ok, err := vm.dstack.PopBool()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if ok {
|
|
condVal = OpCondTrue
|
|
}
|
|
} else {
|
|
condVal = OpCondSkip
|
|
}
|
|
vm.condStack = append(vm.condStack, condVal)
|
|
return nil
|
|
}
|
|
|
|
// opcodeNotIf treats the top item on the data stack as a boolean and removes
|
|
// it.
|
|
//
|
|
// An appropriate entry is added to the conditional stack depending on whether
|
|
// the boolean is true and whether this if is on an executing branch in order
|
|
// to allow proper execution of further opcodes depending on the conditional
|
|
// logic. When the boolean is false, the first branch will be executed (unless
|
|
// this opcode is nested in a non-executed branch).
|
|
//
|
|
// <expression> notif [statements] [else [statements]] endif
|
|
//
|
|
// Note that, unlike for all non-conditional opcodes, this is executed even when
|
|
// it is on a non-executing branch so proper nesting is maintained.
|
|
//
|
|
// Data stack transformation: [... bool] -> [...]
|
|
// Conditional stack transformation: [...] -> [... OpCondValue]
|
|
func opcodeNotIf(op *parsedOpcode, vm *Engine) error {
|
|
condVal := OpCondFalse
|
|
if vm.isBranchExecuting() {
|
|
ok, err := vm.dstack.PopBool()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if !ok {
|
|
condVal = OpCondTrue
|
|
}
|
|
} else {
|
|
condVal = OpCondSkip
|
|
}
|
|
vm.condStack = append(vm.condStack, condVal)
|
|
return nil
|
|
}
|
|
|
|
// opcodeElse inverts conditional execution for other half of if/else/endif.
|
|
//
|
|
// An error is returned if there has not already been a matching OP_IF.
|
|
//
|
|
// Conditional stack transformation: [... OpCondValue] -> [... !OpCondValue]
|
|
func opcodeElse(op *parsedOpcode, vm *Engine) error {
|
|
if len(vm.condStack) == 0 {
|
|
return ErrStackNoIf
|
|
}
|
|
|
|
conditionalIdx := len(vm.condStack) - 1
|
|
switch vm.condStack[conditionalIdx] {
|
|
case OpCondTrue:
|
|
vm.condStack[conditionalIdx] = OpCondFalse
|
|
case OpCondFalse:
|
|
vm.condStack[conditionalIdx] = OpCondTrue
|
|
case OpCondSkip:
|
|
// Value doesn't change in skip since it indicates this opcode
|
|
// is nested in a non-executed branch.
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// opcodeEndif terminates a conditional block, removing the value from the
|
|
// conditional execution stack.
|
|
//
|
|
// An error is returned if there has not already been a matching OP_IF.
|
|
//
|
|
// Conditional stack transformation: [... OpCondValue] -> [...]
|
|
func opcodeEndif(op *parsedOpcode, vm *Engine) error {
|
|
if len(vm.condStack) == 0 {
|
|
return ErrStackNoIf
|
|
}
|
|
|
|
vm.condStack = vm.condStack[:len(vm.condStack)-1]
|
|
return nil
|
|
}
|
|
|
|
// opcodeVerify examines the top item on the data stack as a boolean value and
|
|
// verifies it evaluates to true. An error is returned if it does not.
|
|
func opcodeVerify(op *parsedOpcode, vm *Engine) error {
|
|
verified, err := vm.dstack.PopBool()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if verified != true {
|
|
return ErrStackVerifyFailed
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// opcodeReturn returns an appropriate error since it is always an error to
|
|
// return early from a script.
|
|
func opcodeReturn(op *parsedOpcode, vm *Engine) error {
|
|
return ErrStackEarlyReturn
|
|
}
|
|
|
|
// opcodeCheckLockTimeVerify compares the top item on the data stack to the
|
|
// LockTime field of the transaction containing the script signature
|
|
// validating if the transaction outputs are spendable yet. If flag
|
|
// ScriptVerifyCheckLockTimeVerify is not set, the code continues as if OP_NOP2
|
|
// were executed.
|
|
func opcodeCheckLockTimeVerify(op *parsedOpcode, vm *Engine) error {
|
|
// If the ScriptVerifyCheckLockTimeVerify script flag is not set, treat
|
|
// opcode as OP_NOP2 instead.
|
|
if !vm.hasFlag(ScriptVerifyCheckLockTimeVerify) {
|
|
if vm.hasFlag(ScriptDiscourageUpgradableNops) {
|
|
return errors.New("OP_NOP2 reserved for soft-fork " +
|
|
"upgrades")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// The current transaction locktime is a uint32 resulting in a maximum
|
|
// locktime of 2^32-1 (the year 2106). However, scriptNums are signed
|
|
// and therefore a standard 4-byte scriptNum would only support up to a
|
|
// maximum of 2^31-1 (the year 2038). Thus, a 5-byte scriptNum is used
|
|
// here since it will support up to 2^39-1 which allows dates beyond the
|
|
// current locktime limit.
|
|
//
|
|
// PeekByteArray is used here instead of PeekInt because we do not want
|
|
// to be limited to a 4-byte integer for reasons specified above.
|
|
so, err := vm.dstack.PeekByteArray(0)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
lockTime, err := makeScriptNum(so, vm.dstack.verifyMinimalData, 5)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// In the rare event that the argument may be < 0 due to some arithmetic
|
|
// being done first, you can always use 0 OP_MAX OP_CHECKLOCKTIMEVERIFY.
|
|
if lockTime < 0 {
|
|
return fmt.Errorf("negative locktime: %d", lockTime)
|
|
}
|
|
|
|
// The lock time field of a transaction is either a block height at
|
|
// which the transaction is finalized or a timestamp depending on if the
|
|
// value is before the txscript.LockTimeThreshold. When it is under the
|
|
// threshold it is a block height.
|
|
//
|
|
// The lockTimes in both the script and transaction must be of the same
|
|
// type.
|
|
if !((vm.tx.LockTime < LockTimeThreshold && int64(lockTime) < int64(LockTimeThreshold)) ||
|
|
(vm.tx.LockTime >= LockTimeThreshold && int64(lockTime) >= int64(LockTimeThreshold))) {
|
|
return fmt.Errorf("mismatched locktime types -- tx locktime %d, stack "+
|
|
"locktime %d", vm.tx.LockTime, lockTime)
|
|
}
|
|
|
|
if int64(lockTime) > int64(vm.tx.LockTime) {
|
|
str := "locktime requirement not satisfied -- locktime is " +
|
|
"greater than the transaction locktime: %d > %d"
|
|
return fmt.Errorf(str, lockTime, vm.tx.LockTime)
|
|
}
|
|
|
|
// The lock time feature can also be disabled, thereby bypassing
|
|
// OP_CHECKLOCKTIMEVERIFY, if every transaction input has been finalized by
|
|
// setting its sequence to the maximum value (wire.MaxTxInSequenceNum). This
|
|
// condition would result in the transaction being allowed into the blockchain
|
|
// making the opcode ineffective.
|
|
//
|
|
// This condition is prevented by enforcing that the input being used by
|
|
// the opcode is unlocked (its sequence number is less than the max
|
|
// value). This is sufficient to prove correctness without having to
|
|
// check every input.
|
|
//
|
|
// NOTE: This implies that even if the transaction is not finalized due to
|
|
// another input being unlocked, the opcode execution will still fail when the
|
|
// input being used by the opcode is locked.
|
|
if vm.tx.TxIn[vm.txIdx].Sequence == wire.MaxTxInSequenceNum {
|
|
return errors.New("transaction input is finalized")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// opcodeToAltStack removes the top item from the main data stack and pushes it
|
|
// onto the alternate data stack.
|
|
//
|
|
// Main data stack transformation: [... x1 x2 x3] -> [... x1 x2]
|
|
// Alt data stack transformation: [... y1 y2 y3] -> [... y1 y2 y3 x3]
|
|
func opcodeToAltStack(op *parsedOpcode, vm *Engine) error {
|
|
so, err := vm.dstack.PopByteArray()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
vm.astack.PushByteArray(so)
|
|
|
|
return nil
|
|
}
|
|
|
|
// opcodeFromAltStack removes the top item from the alternate data stack and
|
|
// pushes it onto the main data stack.
|
|
//
|
|
// Main data stack transformation: [... x1 x2 x3] -> [... x1 x2 x3 y3]
|
|
// Alt data stack transformation: [... y1 y2 y3] -> [... y1 y2]
|
|
func opcodeFromAltStack(op *parsedOpcode, vm *Engine) error {
|
|
so, err := vm.astack.PopByteArray()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
vm.dstack.PushByteArray(so)
|
|
|
|
return nil
|
|
}
|
|
|
|
// opcode2Drop removes the top 2 items from the data stack.
|
|
//
|
|
// Stack transformation: [... x1 x2 x3] -> [... x1]
|
|
func opcode2Drop(op *parsedOpcode, vm *Engine) error {
|
|
return vm.dstack.DropN(2)
|
|
}
|
|
|
|
// opcode2Dup duplicates the top 2 items on the data stack.
|
|
//
|
|
// Stack transformation: [... x1 x2 x3] -> [... x1 x2 x3 x2 x3]
|
|
func opcode2Dup(op *parsedOpcode, vm *Engine) error {
|
|
return vm.dstack.DupN(2)
|
|
}
|
|
|
|
// opcode3Dup duplicates the top 3 items on the data stack.
|
|
//
|
|
// Stack transformation: [... x1 x2 x3] -> [... x1 x2 x3 x1 x2 x3]
|
|
func opcode3Dup(op *parsedOpcode, vm *Engine) error {
|
|
return vm.dstack.DupN(3)
|
|
}
|
|
|
|
// opcode2Over duplicates the 2 items before the top 2 items on the data stack.
|
|
//
|
|
// Stack transformation: [... x1 x2 x3 x4] -> [... x1 x2 x3 x4 x1 x2]
|
|
func opcode2Over(op *parsedOpcode, vm *Engine) error {
|
|
return vm.dstack.OverN(2)
|
|
}
|
|
|
|
// opcode2Rot rotates the top 6 items on the data stack to the left twice.
|
|
//
|
|
// Stack transformation: [... x1 x2 x3 x4 x5 x6] -> [... x3 x4 x5 x6 x1 x2]
|
|
func opcode2Rot(op *parsedOpcode, vm *Engine) error {
|
|
return vm.dstack.RotN(2)
|
|
}
|
|
|
|
// opcode2Swap swaps the top 2 items on the data stack with the 2 that come
|
|
// before them.
|
|
//
|
|
// Stack transformation: [... x1 x2 x3 x4] -> [... x3 x4 x1 x2]
|
|
func opcode2Swap(op *parsedOpcode, vm *Engine) error {
|
|
return vm.dstack.SwapN(2)
|
|
}
|
|
|
|
// opcodeIfDup duplicates the top item of the stack if it is not zero.
|
|
//
|
|
// Stack transformation (x1==0): [... x1] -> [... x1]
|
|
// Stack transformation (x1!=0): [... x1] -> [... x1 x1]
|
|
func opcodeIfDup(op *parsedOpcode, vm *Engine) error {
|
|
so, err := vm.dstack.PeekByteArray(0)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Push copy of data iff it isn't zero
|
|
if asBool(so) {
|
|
vm.dstack.PushByteArray(so)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// opcodeDepth pushes the depth of the data stack prior to executing this
|
|
// opcode, encoded as a number, onto the data stack.
|
|
//
|
|
// Stack transformation: [...] -> [... <num of items on the stack>]
|
|
// Example with 2 items: [x1 x2] -> [x1 x2 2]
|
|
// Example with 3 items: [x1 x2 x3] -> [x1 x2 x3 3]
|
|
func opcodeDepth(op *parsedOpcode, vm *Engine) error {
|
|
vm.dstack.PushInt(scriptNum(vm.dstack.Depth()))
|
|
return nil
|
|
}
|
|
|
|
// opcodeDrop removes the top item from the data stack.
|
|
//
|
|
// Stack transformation: [... x1 x2 x3] -> [... x1 x2]
|
|
func opcodeDrop(op *parsedOpcode, vm *Engine) error {
|
|
return vm.dstack.DropN(1)
|
|
}
|
|
|
|
// opcodeDup duplicates the top item on the data stack.
|
|
//
|
|
// Stack transformation: [... x1 x2 x3] -> [... x1 x2 x3 x3]
|
|
func opcodeDup(op *parsedOpcode, vm *Engine) error {
|
|
return vm.dstack.DupN(1)
|
|
}
|
|
|
|
// opcodeNip removes the item before the top item on the data stack.
|
|
//
|
|
// Stack transformation: [... x1 x2 x3] -> [... x1 x3]
|
|
func opcodeNip(op *parsedOpcode, vm *Engine) error {
|
|
return vm.dstack.NipN(1)
|
|
}
|
|
|
|
// opcodeOver duplicates the item before the top item on the data stack.
|
|
//
|
|
// Stack transformation: [... x1 x2 x3] -> [... x1 x2 x3 x2]
|
|
func opcodeOver(op *parsedOpcode, vm *Engine) error {
|
|
return vm.dstack.OverN(1)
|
|
}
|
|
|
|
// opcodePick treats the top item on the data stack as an integer and duplicates
|
|
// the item on the stack that number of items back to the top.
|
|
//
|
|
// Stack transformation: [xn ... x2 x1 x0 n] -> [xn ... x2 x1 x0 xn]
|
|
// Example with n=1: [x2 x1 x0 1] -> [x2 x1 x0 x1]
|
|
// Example with n=2: [x2 x1 x0 2] -> [x2 x1 x0 x2]
|
|
func opcodePick(op *parsedOpcode, vm *Engine) error {
|
|
val, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return vm.dstack.PickN(val.Int32())
|
|
}
|
|
|
|
// opcodeRoll treats the top item on the data stack as an integer and moves
|
|
// the item on the stack that number of items back to the top.
|
|
//
|
|
// Stack transformation: [xn ... x2 x1 x0 n] -> [... x2 x1 x0 xn]
|
|
// Example with n=1: [x2 x1 x0 1] -> [x2 x0 x1]
|
|
// Example with n=2: [x2 x1 x0 2] -> [x1 x0 x2]
|
|
func opcodeRoll(op *parsedOpcode, vm *Engine) error {
|
|
val, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return vm.dstack.RollN(val.Int32())
|
|
}
|
|
|
|
// opcodeRot rotates the top 3 items on the data stack to the left.
|
|
//
|
|
// Stack transformation: [... x1 x2 x3] -> [... x2 x3 x1]
|
|
func opcodeRot(op *parsedOpcode, vm *Engine) error {
|
|
return vm.dstack.RotN(1)
|
|
}
|
|
|
|
// opcodeSwap swaps the top two items on the stack.
|
|
//
|
|
// Stack transformation: [... x1 x2] -> [... x2 x1]
|
|
func opcodeSwap(op *parsedOpcode, vm *Engine) error {
|
|
return vm.dstack.SwapN(1)
|
|
}
|
|
|
|
// opcodeTuck inserts a duplicate of the top item of the data stack before the
|
|
// second-to-top item.
|
|
//
|
|
// Stack transformation: [... x1 x2] -> [... x2 x1 x2]
|
|
func opcodeTuck(op *parsedOpcode, vm *Engine) error {
|
|
return vm.dstack.Tuck()
|
|
}
|
|
|
|
// opcodeCat concatenates the top two stack elements after popping them off, then
|
|
// pushes the result back onto the stack. The opcode fails if the concatenated
|
|
// stack element is too large.
|
|
// Stack transformation: [... x1 x2] -> [... x1 || x2]
|
|
func opcodeCat(op *parsedOpcode, vm *Engine) error {
|
|
a, err := vm.dstack.PopByteArray() // x2
|
|
if err != nil {
|
|
return err
|
|
}
|
|
b, err := vm.dstack.PopByteArray() // x1
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Handle zero length byte slice cases. If one or both of the top stack
|
|
// elements are nil, it's impossible for them to overflow the stack item
|
|
// when either is pushed back on. If both stack items are empty, push an
|
|
// empty byte slice back onto the stack.
|
|
switch {
|
|
case len(a) == 0 && len(b) > 0:
|
|
vm.dstack.PushByteArray(b)
|
|
return nil
|
|
case len(b) == 0 && len(a) > 0:
|
|
vm.dstack.PushByteArray(a)
|
|
return nil
|
|
case len(b) == 0 && len(a) == 0:
|
|
vm.dstack.PushByteArray(nil)
|
|
return nil
|
|
}
|
|
|
|
// We can't overflow the maximum stack item size.
|
|
if len(a)+len(b) > MaxScriptElementSize {
|
|
return ErrStackElementTooBig
|
|
}
|
|
|
|
c := append(b, a...)
|
|
|
|
vm.dstack.PushByteArray(c)
|
|
return nil
|
|
}
|
|
|
|
// opcodeSubstr pops off the top two stack elements and interprets them as
|
|
// integers. If the indices indicated exist within the next stack item that is
|
|
// also popped off, return the relevant substring based on the given start and
|
|
// end indexes.
|
|
// Stack transformation: [... x1 x2 x3] -> [... x1[x3:x2]]
|
|
func opcodeSubstr(op *parsedOpcode, vm *Engine) error {
|
|
v0, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen) // x3
|
|
if err != nil {
|
|
return err
|
|
}
|
|
v1, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen) // x2
|
|
if err != nil {
|
|
return err
|
|
}
|
|
a, err := vm.dstack.PopByteArray() // x1
|
|
if err != nil {
|
|
return err
|
|
}
|
|
aLen := len(a)
|
|
|
|
// Golang uses ints for the indices of slices. Assume that we can get
|
|
// whatever we need from a slice within the boundaries of an int32
|
|
// register.
|
|
v0Recast := int(v0.Int32())
|
|
v1Recast := int(v1.Int32())
|
|
|
|
if aLen == 0 {
|
|
vm.dstack.PushByteArray(nil)
|
|
return nil
|
|
}
|
|
if v0Recast < 0 || v1Recast < 0 {
|
|
return ErrSubstrIdxNegative
|
|
}
|
|
if v0Recast > aLen {
|
|
return ErrSubstrIdxOutOfBounds
|
|
}
|
|
if v1Recast > aLen {
|
|
return ErrSubstrIdxOutOfBounds
|
|
}
|
|
if v0Recast > v1Recast {
|
|
return ErrSubstrIdxOutOfBounds
|
|
}
|
|
|
|
// A substr of the same indices return an empty stack item, similar to
|
|
// Golang.
|
|
if v0Recast == v1Recast {
|
|
vm.dstack.PushByteArray(nil)
|
|
return nil
|
|
}
|
|
|
|
vm.dstack.PushByteArray(a[v0Recast:v1Recast])
|
|
return nil
|
|
}
|
|
|
|
// opcodeLeft pops the first item off the stack as an int and the second item off
|
|
// the stack as a slice. The opcode then prunes the second item from the start
|
|
// index to the given int. Similar to substr, see above comments.
|
|
// Stack transformation: [... x1 x2] -> [... x1[:x2]]
|
|
func opcodeLeft(op *parsedOpcode, vm *Engine) error {
|
|
v0, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen) // x2
|
|
if err != nil {
|
|
return err
|
|
}
|
|
a, err := vm.dstack.PopByteArray() // x1
|
|
if err != nil {
|
|
return err
|
|
}
|
|
aLen := len(a)
|
|
|
|
v0Recast := int(v0.Int32())
|
|
|
|
if aLen == 0 {
|
|
vm.dstack.PushByteArray(nil)
|
|
return nil
|
|
}
|
|
if v0Recast < 0 {
|
|
return ErrSubstrIdxNegative
|
|
}
|
|
if v0Recast > aLen {
|
|
return ErrSubstrIdxOutOfBounds
|
|
}
|
|
|
|
// x1[:0]
|
|
if v0Recast == 0 {
|
|
vm.dstack.PushByteArray(nil)
|
|
return nil
|
|
}
|
|
|
|
vm.dstack.PushByteArray(a[:v0Recast])
|
|
return nil
|
|
}
|
|
|
|
// opcodeRight pops the first item off the stack as an int and the second item off
|
|
// the stack as a slice. The opcode then prunes the second item from the given int
|
|
// index to ending index. Similar to substr, see above comments.
|
|
// Stack transformation: [... x1 x2] -> [... x1[x2:]]
|
|
func opcodeRight(op *parsedOpcode, vm *Engine) error {
|
|
v0, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen) // x2
|
|
if err != nil {
|
|
return err
|
|
}
|
|
a, err := vm.dstack.PopByteArray() // x1
|
|
if err != nil {
|
|
return err
|
|
}
|
|
aLen := len(a)
|
|
|
|
v0Recast := int(v0.Int32())
|
|
|
|
if aLen == 0 {
|
|
vm.dstack.PushByteArray(nil)
|
|
return nil
|
|
}
|
|
if v0Recast < 0 {
|
|
return ErrSubstrIdxNegative
|
|
}
|
|
if v0Recast > aLen {
|
|
return ErrSubstrIdxOutOfBounds
|
|
}
|
|
|
|
// x1[len(a):]
|
|
if v0Recast == aLen {
|
|
vm.dstack.PushByteArray(nil)
|
|
return nil
|
|
}
|
|
|
|
vm.dstack.PushByteArray(a[v0Recast:])
|
|
return nil
|
|
}
|
|
|
|
// opcodeSize pushes the size of the top item of the data stack onto the data
|
|
// stack.
|
|
//
|
|
// Stack transformation: [... x1] -> [... x1 len(x1)]
|
|
func opcodeSize(op *parsedOpcode, vm *Engine) error {
|
|
so, err := vm.dstack.PeekByteArray(0)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
vm.dstack.PushInt(scriptNum(len(so)))
|
|
return nil
|
|
}
|
|
|
|
// opcodeInvert pops the top item off the stack, interprets it as an int32,
|
|
// inverts the bits, and then pushes it back to the stack.
|
|
// Stack transformation: [... x1] -> [... ~x1]
|
|
func opcodeInvert(op *parsedOpcode, vm *Engine) error {
|
|
v0, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
vm.dstack.PushInt(scriptNum(^v0.Int32()))
|
|
return nil
|
|
}
|
|
|
|
// opcodeAnd pops the top two items off the stack, interprets them as int32s,
|
|
// bitwise ANDs the value, and then pushes the result back to the stack.
|
|
// Stack transformation: [... x1 x2] -> [... x1 & x2]
|
|
func opcodeAnd(op *parsedOpcode, vm *Engine) error {
|
|
v0, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
v1, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
vm.dstack.PushInt(scriptNum(v0.Int32() & v1.Int32()))
|
|
return nil
|
|
}
|
|
|
|
// opcodeOr pops the top two items off the stack, interprets them as int32s,
|
|
// bitwise ORs the value, and then pushes the result back to the stack.
|
|
// Stack transformation: [... x1 x2] -> [... x1 | x2]
|
|
func opcodeOr(op *parsedOpcode, vm *Engine) error {
|
|
v0, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
v1, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
vm.dstack.PushInt(scriptNum(v0.Int32() | v1.Int32()))
|
|
return nil
|
|
}
|
|
|
|
// opcodeXor pops the top two items off the stack, interprets them as int32s,
|
|
// bitwise XORs the value, and then pushes the result back to the stack.
|
|
// Stack transformation: [... x1 x2] -> [... x1 ^ x2]
|
|
func opcodeXor(op *parsedOpcode, vm *Engine) error {
|
|
v0, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
v1, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
vm.dstack.PushInt(scriptNum(v0.Int32() ^ v1.Int32()))
|
|
return nil
|
|
}
|
|
|
|
// opcodeEqual removes the top 2 items of the data stack, compares them as raw
|
|
// bytes, and pushes the result, encoded as a boolean, back to the stack.
|
|
//
|
|
// Stack transformation: [... x1 x2] -> [... bool]
|
|
func opcodeEqual(op *parsedOpcode, vm *Engine) error {
|
|
a, err := vm.dstack.PopByteArray()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
b, err := vm.dstack.PopByteArray()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
vm.dstack.PushBool(bytes.Equal(a, b))
|
|
return nil
|
|
}
|
|
|
|
// opcodeEqualVerify is a combination of opcodeEqual and opcodeVerify.
|
|
// Specifically, it removes the top 2 items of the data stack, compares them,
|
|
// and pushes the result, encoded as a boolean, back to the stack. Then, it
|
|
// examines the top item on the data stack as a boolean value and verifies it
|
|
// evaluates to true. An error is returned if it does not.
|
|
//
|
|
// Stack transformation: [... x1 x2] -> [... bool] -> [...]
|
|
func opcodeEqualVerify(op *parsedOpcode, vm *Engine) error {
|
|
err := opcodeEqual(op, vm)
|
|
if err == nil {
|
|
err = opcodeVerify(op, vm)
|
|
}
|
|
return err
|
|
}
|
|
|
|
func rotateRight(value int32, count int32) int32 {
|
|
v := uint32(value)
|
|
c := uint32(count)
|
|
return int32((v >> c) | (v << (32 - c)))
|
|
}
|
|
|
|
// opcodeRotr pushes the top two items off the stack as integers. Both ints are
|
|
// interpreted as int32s. The first item becomes the depth to rotate (up to 31),
|
|
// while the second item is rotated to the right after recasting to a uint32. The
|
|
// rotated item is pushed back to the stack.
|
|
// Stack transformation: [... x1 x2] -> [... rotr(x1, x2)]
|
|
func opcodeRotr(op *parsedOpcode, vm *Engine) error {
|
|
v0, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen) // x2
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
v1, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen) // x1
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
v032 := v0.Int32()
|
|
v132 := v1.Int32()
|
|
|
|
// Don't allow invalid or pointless rotations.
|
|
if v032 < 0 {
|
|
return ErrNegativeRotation
|
|
}
|
|
if v032 > 31 {
|
|
return ErrRotationOverflow
|
|
}
|
|
|
|
vm.dstack.PushInt(scriptNum(rotateRight(v132, v032)))
|
|
return nil
|
|
}
|
|
|
|
func rotateLeft(value int32, count int32) int32 {
|
|
v := uint32(value)
|
|
c := uint32(count)
|
|
return int32((v << c) | (v >> (32 - c)))
|
|
}
|
|
|
|
// opcodeRotl pushes the top two items off the stack as integers. Both ints are
|
|
// interpreted as int32s. The first item becomes the depth to rotate (up to 31),
|
|
// while the second item is rotated to the left after recasting to a uint32. The
|
|
// rotated item is pushed back to the stack.
|
|
// Stack transformation: [... x1 x2] -> [... rotl(x1, x2)]
|
|
func opcodeRotl(op *parsedOpcode, vm *Engine) error {
|
|
v0, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen) // x2
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
v1, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen) // x1
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
v032 := v0.Int32()
|
|
v132 := v1.Int32()
|
|
|
|
// Don't allow invalid or pointless rotations.
|
|
if v032 < 0 {
|
|
return ErrNegativeRotation
|
|
}
|
|
if v032 > 31 {
|
|
return ErrRotationOverflow
|
|
}
|
|
|
|
vm.dstack.PushInt(scriptNum(rotateLeft(v132, v032)))
|
|
return nil
|
|
}
|
|
|
|
// opcode1Add treats the top item on the data stack as an integer and replaces
|
|
// it with its incremented value (plus 1).
|
|
//
|
|
// Stack transformation: [... x1 x2] -> [... x1 x2+1]
|
|
func opcode1Add(op *parsedOpcode, vm *Engine) error {
|
|
m, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
vm.dstack.PushInt(m + 1)
|
|
return nil
|
|
}
|
|
|
|
// opcode1Sub treats the top item on the data stack as an integer and replaces
|
|
// it with its decremented value (minus 1).
|
|
//
|
|
// Stack transformation: [... x1 x2] -> [... x1 x2-1]
|
|
func opcode1Sub(op *parsedOpcode, vm *Engine) error {
|
|
m, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
vm.dstack.PushInt(m - 1)
|
|
|
|
return nil
|
|
}
|
|
|
|
// opcodeNegate treats the top item on the data stack as an integer and replaces
|
|
// it with its negation.
|
|
//
|
|
// Stack transformation: [... x1 x2] -> [... x1 -x2]
|
|
func opcodeNegate(op *parsedOpcode, vm *Engine) error {
|
|
m, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
vm.dstack.PushInt(-m)
|
|
return nil
|
|
}
|
|
|
|
// opcodeAbs treats the top item on the data stack as an integer and replaces it
|
|
// it with its absolute value.
|
|
//
|
|
// Stack transformation: [... x1 x2] -> [... x1 abs(x2)]
|
|
func opcodeAbs(op *parsedOpcode, vm *Engine) error {
|
|
m, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if m < 0 {
|
|
m = -m
|
|
}
|
|
vm.dstack.PushInt(m)
|
|
return nil
|
|
}
|
|
|
|
// opcodeNot treats the top item on the data stack as an integer and replaces
|
|
// it with its "inverted" value (0 becomes 1, non-zero becomes 0).
|
|
//
|
|
// NOTE: While it would probably make more sense to treat the top item as a
|
|
// boolean, and push the opposite, which is really what the intention of this
|
|
// opcode is, it is extremely important that is not done because integers are
|
|
// interpreted differently than booleans and the consensus rules for this opcode
|
|
// dictate the item is interpreted as an integer.
|
|
//
|
|
// Stack transformation (x2==0): [... x1 0] -> [... x1 1]
|
|
// Stack transformation (x2!=0): [... x1 1] -> [... x1 0]
|
|
// Stack transformation (x2!=0): [... x1 17] -> [... x1 0]
|
|
func opcodeNot(op *parsedOpcode, vm *Engine) error {
|
|
m, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if m == 0 {
|
|
vm.dstack.PushInt(scriptNum(1))
|
|
} else {
|
|
vm.dstack.PushInt(scriptNum(0))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// opcode0NotEqual treats the top item on the data stack as an integer and
|
|
// replaces it with either a 0 if it is zero, or a 1 if it is not zero.
|
|
//
|
|
// Stack transformation (x2==0): [... x1 0] -> [... x1 0]
|
|
// Stack transformation (x2!=0): [... x1 1] -> [... x1 1]
|
|
// Stack transformation (x2!=0): [... x1 17] -> [... x1 1]
|
|
func opcode0NotEqual(op *parsedOpcode, vm *Engine) error {
|
|
m, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if m != 0 {
|
|
m = 1
|
|
}
|
|
vm.dstack.PushInt(m)
|
|
return nil
|
|
}
|
|
|
|
// opcodeAdd treats the top two items on the data stack as integers and replaces
|
|
// them with their sum.
|
|
//
|
|
// Stack transformation: [... x1 x2] -> [... x1+x2]
|
|
func opcodeAdd(op *parsedOpcode, vm *Engine) error {
|
|
v0, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
v1, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
vm.dstack.PushInt(v0 + v1)
|
|
return nil
|
|
}
|
|
|
|
// opcodeSub treats the top two items on the data stack as integers and replaces
|
|
// them with the result of subtracting the top entry from the second-to-top
|
|
// entry.
|
|
//
|
|
// Stack transformation: [... x1 x2] -> [... x1-x2]
|
|
func opcodeSub(op *parsedOpcode, vm *Engine) error {
|
|
v0, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
v1, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
vm.dstack.PushInt(v1 - v0)
|
|
return nil
|
|
}
|
|
|
|
// opcodeMul treats the top two items on the data stack as integers and replaces
|
|
// them with the result of multiplying the top entry with the second-to-top
|
|
// entry as 4-byte integers.
|
|
//
|
|
// Stack transformation: [... x1 x2] -> [... x1*x2]
|
|
func opcodeMul(op *parsedOpcode, vm *Engine) error {
|
|
v0, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
v1, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
v2 := v0.Int32() * v1.Int32()
|
|
|
|
vm.dstack.PushInt(scriptNum(v2))
|
|
return nil
|
|
}
|
|
|
|
// opcodeDiv treats the top two items on the data stack as integers and replaces
|
|
// them with the result of dividing the top entry by the second-to-top entry as
|
|
// 4-byte integers.
|
|
//
|
|
// Stack transformation: [... x1 x2] -> [... x1/x2]
|
|
func opcodeDiv(op *parsedOpcode, vm *Engine) error {
|
|
v0, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
v1, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if v0.Int32() == 0 {
|
|
return ErrDivideByZero
|
|
}
|
|
|
|
v2 := v1.Int32() / v0.Int32()
|
|
|
|
vm.dstack.PushInt(scriptNum(v2))
|
|
return nil
|
|
}
|
|
|
|
// opcodeMod treats the top two items on the data stack as integers and replaces
|
|
// them with the result of the modulus the top entry by the second-to-top entry as
|
|
// 4-byte integers.
|
|
//
|
|
// Stack transformation: [... x1 x2] -> [... x1/x2]
|
|
func opcodeMod(op *parsedOpcode, vm *Engine) error {
|
|
v0, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
v1, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if v0.Int32() == 0 {
|
|
return ErrDivideByZero
|
|
}
|
|
|
|
v2 := v1.Int32() % v0.Int32()
|
|
|
|
vm.dstack.PushInt(scriptNum(v2))
|
|
return nil
|
|
}
|
|
|
|
// opcodeLShift pushes the top two items off the stack as integers. Both ints are
|
|
// interpreted as int32s. The first item becomes the depth to shift left, while
|
|
// the second item is shifted that depth to the left. The shifted item is pushed
|
|
// back to the stack as an integer.
|
|
// Stack transformation: [... x1 x2] -> [... x1 << x2]
|
|
func opcodeLShift(op *parsedOpcode, vm *Engine) error {
|
|
v0, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen) // x2
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
v1, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen) // x1
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
v032 := v0.Int32()
|
|
v132 := v1.Int32()
|
|
|
|
// Don't allow invalid or pointless shifts.
|
|
if v032 < 0 {
|
|
return ErrNegativeShift
|
|
}
|
|
if v032 > 32 {
|
|
return ErrShiftOverflow
|
|
}
|
|
|
|
vm.dstack.PushInt(scriptNum(v132 << uint(v032)))
|
|
return nil
|
|
}
|
|
|
|
// opcodeRShift pushes the top two items off the stack as integers. Both ints are
|
|
// interpreted as int32s. The first item becomes the depth to shift right, while
|
|
// the second item is shifted that depth to the right. The shifted item is pushed
|
|
// back to the stack as an integer.
|
|
// Stack transformation: [... x1 x2] -> [... x1 << x2]
|
|
func opcodeRShift(op *parsedOpcode, vm *Engine) error {
|
|
v0, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen) // x2
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
v1, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen) // x1
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
v032 := v0.Int32()
|
|
v132 := v1.Int32()
|
|
|
|
// Don't allow invalid or pointless shifts.
|
|
if v032 < 0 {
|
|
return ErrNegativeShift
|
|
}
|
|
if v032 > 32 {
|
|
return ErrShiftOverflow
|
|
}
|
|
|
|
vm.dstack.PushInt(scriptNum(v132 >> uint(v032)))
|
|
return nil
|
|
}
|
|
|
|
// opcodeBoolAnd treats the top two items on the data stack as integers. When
|
|
// both of them are not zero, they are replaced with a 1, otherwise a 0.
|
|
//
|
|
// Stack transformation (x1==0, x2==0): [... 0 0] -> [... 0]
|
|
// Stack transformation (x1!=0, x2==0): [... 5 0] -> [... 0]
|
|
// Stack transformation (x1==0, x2!=0): [... 0 7] -> [... 0]
|
|
// Stack transformation (x1!=0, x2!=0): [... 4 8] -> [... 1]
|
|
func opcodeBoolAnd(op *parsedOpcode, vm *Engine) error {
|
|
v0, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
v1, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if v0 != 0 && v1 != 0 {
|
|
vm.dstack.PushInt(scriptNum(1))
|
|
} else {
|
|
vm.dstack.PushInt(scriptNum(0))
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// opcodeBoolOr treats the top two items on the data stack as integers. When
|
|
// either of them are not zero, they are replaced with a 1, otherwise a 0.
|
|
//
|
|
// Stack transformation (x1==0, x2==0): [... 0 0] -> [... 0]
|
|
// Stack transformation (x1!=0, x2==0): [... 5 0] -> [... 1]
|
|
// Stack transformation (x1==0, x2!=0): [... 0 7] -> [... 1]
|
|
// Stack transformation (x1!=0, x2!=0): [... 4 8] -> [... 1]
|
|
func opcodeBoolOr(op *parsedOpcode, vm *Engine) error {
|
|
v0, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
v1, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if v0 != 0 || v1 != 0 {
|
|
vm.dstack.PushInt(scriptNum(1))
|
|
} else {
|
|
vm.dstack.PushInt(scriptNum(0))
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// opcodeNumEqual treats the top two items on the data stack as integers. When
|
|
// they are equal, they are replaced with a 1, otherwise a 0.
|
|
//
|
|
// Stack transformation (x1==x2): [... 5 5] -> [... 1]
|
|
// Stack transformation (x1!=x2): [... 5 7] -> [... 0]
|
|
func opcodeNumEqual(op *parsedOpcode, vm *Engine) error {
|
|
v0, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
v1, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if v0 == v1 {
|
|
vm.dstack.PushInt(scriptNum(1))
|
|
} else {
|
|
vm.dstack.PushInt(scriptNum(0))
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// opcodeNumEqualVerify is a combination of opcodeNumEqual and opcodeVerify.
|
|
//
|
|
// Specifically, treats the top two items on the data stack as integers. When
|
|
// they are equal, they are replaced with a 1, otherwise a 0. Then, it examines
|
|
// the top item on the data stack as a boolean value and verifies it evaluates
|
|
// to true. An error is returned if it does not.
|
|
//
|
|
// Stack transformation: [... x1 x2] -> [... bool] -> [...]
|
|
func opcodeNumEqualVerify(op *parsedOpcode, vm *Engine) error {
|
|
err := opcodeNumEqual(op, vm)
|
|
if err == nil {
|
|
err = opcodeVerify(op, vm)
|
|
}
|
|
return err
|
|
}
|
|
|
|
// opcodeNumNotEqual treats the top two items on the data stack as integers.
|
|
// When they are NOT equal, they are replaced with a 1, otherwise a 0.
|
|
//
|
|
// Stack transformation (x1==x2): [... 5 5] -> [... 0]
|
|
// Stack transformation (x1!=x2): [... 5 7] -> [... 1]
|
|
func opcodeNumNotEqual(op *parsedOpcode, vm *Engine) error {
|
|
v0, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
v1, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if v0 != v1 {
|
|
vm.dstack.PushInt(scriptNum(1))
|
|
} else {
|
|
vm.dstack.PushInt(scriptNum(0))
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// opcodeLessThan treats the top two items on the data stack as integers. When
|
|
// the second-to-top item is less than the top item, they are replaced with a 1,
|
|
// otherwise a 0.
|
|
//
|
|
// Stack transformation: [... x1 x2] -> [... bool]
|
|
func opcodeLessThan(op *parsedOpcode, vm *Engine) error {
|
|
v0, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
v1, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if v1 < v0 {
|
|
vm.dstack.PushInt(scriptNum(1))
|
|
} else {
|
|
vm.dstack.PushInt(scriptNum(0))
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// opcodeGreaterThan treats the top two items on the data stack as integers.
|
|
// When the second-to-top item is greater than the top item, they are replaced
|
|
// with a 1, otherwise a 0.
|
|
//
|
|
// Stack transformation: [... x1 x2] -> [... bool]
|
|
func opcodeGreaterThan(op *parsedOpcode, vm *Engine) error {
|
|
v0, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
v1, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if v1 > v0 {
|
|
vm.dstack.PushInt(scriptNum(1))
|
|
} else {
|
|
vm.dstack.PushInt(scriptNum(0))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// opcodeLessThanOrEqual treats the top two items on the data stack as integers.
|
|
// When the second-to-top item is less than or equal to the top item, they are
|
|
// replaced with a 1, otherwise a 0.
|
|
//
|
|
// Stack transformation: [... x1 x2] -> [... bool]
|
|
func opcodeLessThanOrEqual(op *parsedOpcode, vm *Engine) error {
|
|
v0, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
v1, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if v1 <= v0 {
|
|
vm.dstack.PushInt(scriptNum(1))
|
|
} else {
|
|
vm.dstack.PushInt(scriptNum(0))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// opcodeGreaterThanOrEqual treats the top two items on the data stack as
|
|
// integers. When the second-to-top item is greater than or equal to the top
|
|
// item, they are replaced with a 1, otherwise a 0.
|
|
//
|
|
// Stack transformation: [... x1 x2] -> [... bool]
|
|
func opcodeGreaterThanOrEqual(op *parsedOpcode, vm *Engine) error {
|
|
v0, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
v1, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if v1 >= v0 {
|
|
vm.dstack.PushInt(scriptNum(1))
|
|
} else {
|
|
vm.dstack.PushInt(scriptNum(0))
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// opcodeMin treats the top two items on the data stack as integers and replaces
|
|
// them with the minimum of the two.
|
|
//
|
|
// Stack transformation: [... x1 x2] -> [... min(x1, x2)]
|
|
func opcodeMin(op *parsedOpcode, vm *Engine) error {
|
|
v0, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
v1, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if v1 < v0 {
|
|
vm.dstack.PushInt(v1)
|
|
} else {
|
|
vm.dstack.PushInt(v0)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// opcodeMax treats the top two items on the data stack as integers and replaces
|
|
// them with the maximum of the two.
|
|
//
|
|
// Stack transformation: [... x1 x2] -> [... max(x1, x2)]
|
|
func opcodeMax(op *parsedOpcode, vm *Engine) error {
|
|
v0, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
v1, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if v1 > v0 {
|
|
vm.dstack.PushInt(v1)
|
|
} else {
|
|
vm.dstack.PushInt(v0)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// opcodeWithin treats the top 3 items on the data stack as integers. When the
|
|
// value to test is within the specified range (left inclusive), they are
|
|
// replaced with a 1, otherwise a 0.
|
|
//
|
|
// The top item is the max value, the second-top-item is the minimum value, and
|
|
// the third-to-top item is the value to test.
|
|
//
|
|
// Stack transformation: [... x1 min max] -> [... bool]
|
|
func opcodeWithin(op *parsedOpcode, vm *Engine) error {
|
|
maxVal, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
minVal, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
x, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if x >= minVal && x < maxVal {
|
|
vm.dstack.PushInt(scriptNum(1))
|
|
} else {
|
|
vm.dstack.PushInt(scriptNum(0))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// calcHash calculates the hash of hasher over buf.
|
|
func calcHash(buf []byte, hasher hash.Hash) []byte {
|
|
hasher.Write(buf)
|
|
return hasher.Sum(nil)
|
|
}
|
|
|
|
// opcodeRipemd160 treats the top item of the data stack as raw bytes and
|
|
// replaces it with ripemd160(data).
|
|
//
|
|
// Stack transformation: [... x1] -> [... ripemd160(x1)]
|
|
func opcodeRipemd160(op *parsedOpcode, vm *Engine) error {
|
|
buf, err := vm.dstack.PopByteArray()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
vm.dstack.PushByteArray(calcHash(buf, ripemd160.New()))
|
|
return nil
|
|
}
|
|
|
|
// opcodeSha1 treats the top item of the data stack as raw bytes and replaces it
|
|
// with sha1(data).
|
|
//
|
|
// Stack transformation: [... x1] -> [... sha1(x1)]
|
|
func opcodeSha1(op *parsedOpcode, vm *Engine) error {
|
|
buf, err := vm.dstack.PopByteArray()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
hash := sha1.Sum(buf)
|
|
vm.dstack.PushByteArray(hash[:])
|
|
return nil
|
|
}
|
|
|
|
// opcodeSha256 treats the top item of the data stack as raw bytes and replaces
|
|
// it with hash256(data).
|
|
//
|
|
// Stack transformation: [... x1] -> [... hash256(x1)]
|
|
func opcodeSha256(op *parsedOpcode, vm *Engine) error {
|
|
buf, err := vm.dstack.PopByteArray()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
hash := chainhash.HashFuncB(buf)
|
|
vm.dstack.PushByteArray(hash[:])
|
|
return nil
|
|
}
|
|
|
|
// opcodeHash160 treats the top item of the data stack as raw bytes and replaces
|
|
// it with ripemd160(hash256(data)).
|
|
//
|
|
// Stack transformation: [... x1] -> [... ripemd160(hash256(x1))]
|
|
func opcodeHash160(op *parsedOpcode, vm *Engine) error {
|
|
buf, err := vm.dstack.PopByteArray()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
hash := chainhash.HashFuncB(buf)
|
|
vm.dstack.PushByteArray(calcHash(hash[:], ripemd160.New()))
|
|
return nil
|
|
}
|
|
|
|
// opcodeHash256 treats the top item of the data stack as raw bytes and replaces
|
|
// it with hash256(hash256(data)).
|
|
//
|
|
// Stack transformation: [... x1] -> [... hash256(hash256(x1))]
|
|
func opcodeHash256(op *parsedOpcode, vm *Engine) error {
|
|
buf, err := vm.dstack.PopByteArray()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
vm.dstack.PushByteArray(chainhash.HashFuncB(chainhash.HashFuncB(buf)))
|
|
return nil
|
|
}
|
|
|
|
// opcodeCodeSeparator stores the current script offset as the most recently
|
|
// seen OP_CODESEPARATOR which is used during signature checking.
|
|
//
|
|
// This opcode does not change the contents of the data stack.
|
|
// This opcode is disabled in Decred, as it always returns an engine error.
|
|
func opcodeCodeSeparator(op *parsedOpcode, vm *Engine) error {
|
|
vm.lastCodeSep = vm.scriptOff
|
|
return nil
|
|
}
|
|
|
|
// opcodeCheckSig treats the top 2 items on the stack as a public key and a
|
|
// signature and replaces them with a bool which indicates if the signature was
|
|
// successfully verified.
|
|
//
|
|
// The process of verifying a signature requires calculating a signature hash in
|
|
// the same way the transaction signer did. It involves hashing portions of the
|
|
// transaction based on the hash type byte (which is the final byte of the
|
|
// signature) and the portion of the script starting from the most recent
|
|
// OP_CODESEPARATOR (or the beginning of the script if there are none) to the
|
|
// end of the script (with any other OP_CODESEPARATORs removed). Once this
|
|
// "script hash" is calculated, the signature is checked using standard
|
|
// cryptographic methods against the provided public key.
|
|
//
|
|
// Stack transformation: [... signature pubkey] -> [... bool]
|
|
func opcodeCheckSig(op *parsedOpcode, vm *Engine) error {
|
|
pkBytes, err := vm.dstack.PopByteArray()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
fullSigBytes, err := vm.dstack.PopByteArray()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// The signature actually needs needs to be longer than this, but at
|
|
// least 1 byte is needed for the hash type below. The full length is
|
|
// checked depending on the script flags and upon parsing the signature.
|
|
if len(fullSigBytes) < 1 {
|
|
vm.dstack.PushBool(false)
|
|
return nil
|
|
}
|
|
|
|
// Trim off hashtype from the signature string and check if the
|
|
// signature and pubkey conform to the strict encoding requirements
|
|
// depending on the flags.
|
|
//
|
|
// NOTE: When the strict encoding flags are set, any errors in the
|
|
// signature or public encoding here result in an immediate script error
|
|
// (and thus no result bool is pushed to the data stack). This differs
|
|
// from the logic below where any errors in parsing the signature is
|
|
// treated as the signature failure resulting in false being pushed to
|
|
// the data stack. This is required because the more general script
|
|
// validation consensus rules do not have the new strict encoding
|
|
// requirements enabled by the flags.
|
|
hashType := SigHashType(fullSigBytes[len(fullSigBytes)-1])
|
|
sigBytes := fullSigBytes[:len(fullSigBytes)-1]
|
|
if err := vm.checkHashTypeEncoding(hashType); err != nil {
|
|
return err
|
|
}
|
|
if err := vm.checkSignatureEncoding(sigBytes); err != nil {
|
|
return err
|
|
}
|
|
if err := vm.checkPubKeyEncoding(pkBytes); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Get script starting from the most recent OP_CODESEPARATOR.
|
|
subScript := vm.subScript()
|
|
|
|
// Remove the signature since there is no way for a signature to sign
|
|
// itself.
|
|
subScript = removeOpcodeByData(subScript, fullSigBytes)
|
|
|
|
// Generate the signature hash based on the signature hash type.
|
|
var prefixHash *chainhash.Hash
|
|
if hashType&sigHashMask == SigHashAll {
|
|
if optimizeSigVerification {
|
|
ph := vm.tx.CachedTxSha()
|
|
prefixHash = ph
|
|
}
|
|
}
|
|
hash, err := calcSignatureHash(subScript, hashType, &vm.tx, vm.txIdx,
|
|
prefixHash)
|
|
if err != nil {
|
|
vm.dstack.PushBool(false)
|
|
return nil
|
|
}
|
|
|
|
pubKey, err := chainec.Secp256k1.ParsePubKey(pkBytes)
|
|
if err != nil {
|
|
vm.dstack.PushBool(false)
|
|
return nil
|
|
}
|
|
|
|
var signature chainec.Signature
|
|
if vm.hasFlag(ScriptVerifyStrictEncoding) ||
|
|
vm.hasFlag(ScriptVerifyDERSignatures) {
|
|
signature, err = chainec.Secp256k1.ParseDERSignature(sigBytes)
|
|
} else {
|
|
signature, err = chainec.Secp256k1.ParseSignature(sigBytes)
|
|
}
|
|
if err != nil {
|
|
vm.dstack.PushBool(false)
|
|
return nil
|
|
}
|
|
|
|
var valid bool
|
|
if vm.sigCache != nil {
|
|
var sigHash chainhash.Hash
|
|
copy(sigHash[:], hash)
|
|
|
|
valid = vm.sigCache.Exists(sigHash, signature, pubKey)
|
|
if !valid && chainec.Secp256k1.Verify(pubKey, hash,
|
|
signature.GetR(), signature.GetS()) {
|
|
|
|
vm.sigCache.Add(sigHash, signature, pubKey)
|
|
valid = true
|
|
}
|
|
} else {
|
|
valid = chainec.Secp256k1.Verify(pubKey, hash, signature.GetR(),
|
|
signature.GetS())
|
|
}
|
|
|
|
vm.dstack.PushBool(valid)
|
|
return nil
|
|
}
|
|
|
|
// opcodeCheckSigVerify is a combination of opcodeCheckSig and opcodeVerify.
|
|
// The opcodeCheckSig function is invoked followed by opcodeVerify. See the
|
|
// documentation for each of those opcodes for more details.
|
|
//
|
|
// Stack transformation: signature pubkey] -> [... bool] -> [...]
|
|
func opcodeCheckSigVerify(op *parsedOpcode, vm *Engine) error {
|
|
err := opcodeCheckSig(op, vm)
|
|
if err == nil {
|
|
err = opcodeVerify(op, vm)
|
|
}
|
|
return err
|
|
}
|
|
|
|
// parsedSigInfo houses a raw signature along with its parsed form and a flag
|
|
// for whether or not it has already been parsed. It is used to prevent parsing
|
|
// the same signature multiple times when verifying a multisig.
|
|
type parsedSigInfo struct {
|
|
signature []byte
|
|
parsedSignature chainec.Signature
|
|
parsed bool
|
|
}
|
|
|
|
// opcodeCheckMultiSig treats the top item on the stack as an integer number of
|
|
// public keys, followed by that many entries as raw data representing the public
|
|
// keys, followed by the integer number of signatures, followed by that many
|
|
// entries as raw data representing the signatures.
|
|
//
|
|
// All of the aforementioned stack items are replaced with a bool which
|
|
// indicates if the requisite number of signatures were successfully verified.
|
|
//
|
|
// See the opcodeCheckSigVerify documentation for more details about the process
|
|
// for verifying each signature.
|
|
//
|
|
// Stack transformation:
|
|
// [... dummy [sig ...] numsigs [pubkey ...] numpubkeys] -> [... bool]
|
|
func opcodeCheckMultiSig(op *parsedOpcode, vm *Engine) error {
|
|
numKeys, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
numPubKeys := int(numKeys.Int32())
|
|
if numPubKeys < 0 || numPubKeys > MaxPubKeysPerMultiSig {
|
|
return ErrStackTooManyPubKeys
|
|
}
|
|
vm.numOps += numPubKeys
|
|
if vm.numOps > MaxOpsPerScript {
|
|
return ErrStackTooManyOperations
|
|
}
|
|
|
|
pubKeys := make([][]byte, 0, numPubKeys)
|
|
for i := 0; i < numPubKeys; i++ {
|
|
pubKey, err := vm.dstack.PopByteArray()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
pubKeys = append(pubKeys, pubKey)
|
|
}
|
|
|
|
numSigs, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
numSignatures := int(numSigs.Int32())
|
|
if numSignatures < 0 {
|
|
return fmt.Errorf("number of signatures '%d' is less than 0",
|
|
numSignatures)
|
|
}
|
|
if numSignatures > numPubKeys {
|
|
return fmt.Errorf("more signatures than pubkeys: %d > %d",
|
|
numSignatures, numPubKeys)
|
|
}
|
|
|
|
signatures := make([]*parsedSigInfo, 0, numSignatures)
|
|
for i := 0; i < numSignatures; i++ {
|
|
signature, err := vm.dstack.PopByteArray()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
sigInfo := &parsedSigInfo{signature: signature}
|
|
signatures = append(signatures, sigInfo)
|
|
}
|
|
|
|
// Get script starting from the most recent OP_CODESEPARATOR.
|
|
script := vm.subScript()
|
|
|
|
// Remove any of the signatures since there is no way for a signature to
|
|
// sign itself.
|
|
for _, sigInfo := range signatures {
|
|
script = removeOpcodeByData(script, sigInfo.signature)
|
|
}
|
|
|
|
success := true
|
|
numPubKeys++
|
|
pubKeyIdx := -1
|
|
signatureIdx := 0
|
|
for numSignatures > 0 {
|
|
// When there are more signatures than public keys remaining,
|
|
// there is no way to succeed since too many signatures are
|
|
// invalid, so exit early.
|
|
pubKeyIdx++
|
|
numPubKeys--
|
|
if numSignatures > numPubKeys {
|
|
success = false
|
|
break
|
|
}
|
|
|
|
sigInfo := signatures[signatureIdx]
|
|
pubKey := pubKeys[pubKeyIdx]
|
|
|
|
// The order of the signature and public key evaluation is
|
|
// important here since it can be distinguished by an
|
|
// OP_CHECKMULTISIG NOT when the strict encoding flag is set.
|
|
|
|
rawSig := sigInfo.signature
|
|
if len(rawSig) == 0 {
|
|
// Skip to the next pubkey if signature is empty.
|
|
continue
|
|
}
|
|
|
|
// Split the signature into hash type and signature components.
|
|
hashType := SigHashType(rawSig[len(rawSig)-1])
|
|
signature := rawSig[:len(rawSig)-1]
|
|
|
|
// Only parse and check the signature encoding once.
|
|
var parsedSig chainec.Signature
|
|
if !sigInfo.parsed {
|
|
if err := vm.checkHashTypeEncoding(hashType); err != nil {
|
|
return err
|
|
}
|
|
if err := vm.checkSignatureEncoding(signature); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Parse the signature.
|
|
var err error
|
|
if vm.hasFlag(ScriptVerifyStrictEncoding) ||
|
|
vm.hasFlag(ScriptVerifyDERSignatures) {
|
|
|
|
parsedSig, err = chainec.Secp256k1.ParseDERSignature(signature)
|
|
} else {
|
|
parsedSig, err = chainec.Secp256k1.ParseSignature(signature)
|
|
}
|
|
sigInfo.parsed = true
|
|
if err != nil {
|
|
continue
|
|
}
|
|
sigInfo.parsedSignature = parsedSig
|
|
} else {
|
|
// Skip to the next pubkey if the signature is invalid.
|
|
if sigInfo.parsedSignature == nil {
|
|
continue
|
|
}
|
|
|
|
// Use the already parsed signature.
|
|
parsedSig = sigInfo.parsedSignature
|
|
}
|
|
|
|
if err := vm.checkPubKeyEncoding(pubKey); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Parse the pubkey.
|
|
parsedPubKey, err := chainec.Secp256k1.ParsePubKey(pubKey)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
|
|
// Generate the signature hash based on the signature hash type.
|
|
var prefixHash *chainhash.Hash
|
|
if hashType&sigHashMask == SigHashAll {
|
|
if optimizeSigVerification {
|
|
ph := vm.tx.CachedTxSha()
|
|
prefixHash = ph
|
|
}
|
|
}
|
|
hash, err := calcSignatureHash(script, hashType, &vm.tx, vm.txIdx,
|
|
prefixHash)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
var valid bool
|
|
if vm.sigCache != nil {
|
|
var sigHash chainhash.Hash
|
|
copy(sigHash[:], hash)
|
|
|
|
valid = vm.sigCache.Exists(sigHash, parsedSig, parsedPubKey)
|
|
if !valid && chainec.Secp256k1.Verify(parsedPubKey, hash,
|
|
parsedSig.GetR(), parsedSig.GetS()) {
|
|
|
|
vm.sigCache.Add(sigHash, parsedSig, parsedPubKey)
|
|
valid = true
|
|
}
|
|
} else {
|
|
valid = chainec.Secp256k1.Verify(parsedPubKey, hash,
|
|
parsedSig.GetR(), parsedSig.GetS())
|
|
}
|
|
|
|
if valid {
|
|
// PubKey verified, move on to the next signature.
|
|
signatureIdx++
|
|
numSignatures--
|
|
}
|
|
}
|
|
|
|
vm.dstack.PushBool(success)
|
|
return nil
|
|
}
|
|
|
|
// opcodeCheckMultiSigVerify is a combination of opcodeCheckMultiSig and
|
|
// opcodeVerify. The opcodeCheckMultiSig is invoked followed by opcodeVerify.
|
|
// See the documentation for each of those opcodes for more details.
|
|
//
|
|
// Stack transformation:
|
|
// [... dummy [sig ...] numsigs [pubkey ...] numpubkeys] -> [... bool] -> [...]
|
|
func opcodeCheckMultiSigVerify(op *parsedOpcode, vm *Engine) error {
|
|
err := opcodeCheckMultiSig(op, vm)
|
|
if err == nil {
|
|
err = opcodeVerify(op, vm)
|
|
}
|
|
return err
|
|
}
|
|
|
|
// ECDSA signature schemes encoded as a single byte. Secp256k1 traditional
|
|
// is non-accessible through CheckSigAlt, but is used elsewhere for in the
|
|
// sign function to indicate the type of signature to generate.
|
|
type sigTypes uint8
|
|
|
|
var secp = sigTypes(chainec.ECTypeSecp256k1)
|
|
var edwards = sigTypes(chainec.ECTypeEdwards)
|
|
var secSchnorr = sigTypes(chainec.ECTypeSecSchnorr)
|
|
|
|
// opcodeCheckSigAlt accepts a three item stack and pops off the first three
|
|
// items. The first item is a signature type (1-255, can not be zero or the
|
|
// soft fork will fail). Any unused signature types return true, so that future
|
|
// alternative signature methods may be added. The second item popped off the
|
|
// stack is the public key; wrong size pubkeys return false. The third item to
|
|
// be popped off the stack is the signature along with the hash type at the
|
|
// end; wrong sized signatures also return false.
|
|
// Failing to parse a pubkey or signature results in false.
|
|
// After parsing, the signature and pubkey are verified against the message
|
|
// (the hash of this transaction and its input).
|
|
func opcodeCheckSigAlt(op *parsedOpcode, vm *Engine) error {
|
|
sigType, err := vm.dstack.PopInt(altSigSuitesMaxscriptNumLen)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
switch sigTypes(sigType) {
|
|
case sigTypes(0):
|
|
// Zero case; pre-softfork clients will return 0 in this case as well.
|
|
vm.dstack.PushBool(false)
|
|
return nil
|
|
case edwards:
|
|
break
|
|
case secSchnorr:
|
|
break
|
|
default:
|
|
// Caveat: All unknown signature types return true, allowing for future
|
|
// softforks with other new signature types.
|
|
vm.dstack.PushBool(true)
|
|
return nil
|
|
}
|
|
|
|
pkBytes, err := vm.dstack.PopByteArray()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Check the public key lengths. Only 33-byte compressed secp256k1 keys
|
|
// are allowed for secp256k1 Schnorr signatures, which 32 byte keys
|
|
// are used for Curve25519.
|
|
switch sigTypes(sigType) {
|
|
case edwards:
|
|
if len(pkBytes) != 32 {
|
|
vm.dstack.PushBool(false)
|
|
return nil
|
|
}
|
|
case secSchnorr:
|
|
if len(pkBytes) != 33 {
|
|
vm.dstack.PushBool(false)
|
|
return nil
|
|
}
|
|
}
|
|
|
|
fullSigBytes, err := vm.dstack.PopByteArray()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Schnorr signatures are 65 bytes in length (64 bytes for [r,s] and
|
|
// 1 byte appened to the end for hashType).
|
|
switch sigTypes(sigType) {
|
|
case edwards:
|
|
if len(fullSigBytes) != 65 {
|
|
vm.dstack.PushBool(false)
|
|
return nil
|
|
}
|
|
case secSchnorr:
|
|
if len(fullSigBytes) != 65 {
|
|
vm.dstack.PushBool(false)
|
|
return nil
|
|
}
|
|
}
|
|
|
|
// Trim off hashtype from the signature string and check if the
|
|
// signature and pubkey conform to the strict encoding requirements
|
|
// depending on the flags.
|
|
//
|
|
// NOTE: When the strict encoding flags are set, any errors in the
|
|
// signature or public encoding here result in an immediate script error
|
|
// (and thus no result bool is pushed to the data stack). This differs
|
|
// from the logic below where any errors in parsing the signature is
|
|
// treated as the signature failure resulting in false being pushed to
|
|
// the data stack. This is required because the more general script
|
|
// validation consensus rules do not have the new strict encoding
|
|
// requirements enabled by the flags.
|
|
hashType := SigHashType(fullSigBytes[len(fullSigBytes)-1])
|
|
sigBytes := fullSigBytes[:len(fullSigBytes)-1]
|
|
if err := vm.checkHashTypeEncoding(hashType); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Get the subscript.
|
|
subScript := vm.subScript()
|
|
|
|
// Remove the signature since there is no way for a signature to sign
|
|
// itself.
|
|
subScript = removeOpcodeByData(subScript, fullSigBytes)
|
|
|
|
// Generate the signature hash based on the signature hash type.
|
|
var prefixHash *chainhash.Hash
|
|
if hashType&sigHashMask == SigHashAll {
|
|
if optimizeSigVerification {
|
|
ph := vm.tx.CachedTxSha()
|
|
prefixHash = ph
|
|
}
|
|
}
|
|
hash, err := calcSignatureHash(subScript, hashType, &vm.tx, vm.txIdx,
|
|
prefixHash)
|
|
if err != nil {
|
|
vm.dstack.PushBool(false)
|
|
return nil
|
|
}
|
|
|
|
// Get the public key from bytes.
|
|
var pubKey chainec.PublicKey
|
|
switch sigTypes(sigType) {
|
|
case edwards:
|
|
pubKeyEd, err := chainec.Edwards.ParsePubKey(pkBytes)
|
|
if err != nil {
|
|
vm.dstack.PushBool(false)
|
|
return nil
|
|
}
|
|
pubKey = pubKeyEd
|
|
case secSchnorr:
|
|
pubKeySec, err := chainec.SecSchnorr.ParsePubKey(pkBytes)
|
|
if err != nil {
|
|
vm.dstack.PushBool(false)
|
|
return nil
|
|
}
|
|
pubKey = pubKeySec
|
|
}
|
|
|
|
// Get the signature from bytes.
|
|
var signature chainec.Signature
|
|
switch sigTypes(sigType) {
|
|
case edwards:
|
|
sigEd, err := chainec.Edwards.ParseSignature(sigBytes)
|
|
if err != nil {
|
|
vm.dstack.PushBool(false)
|
|
return nil
|
|
}
|
|
signature = sigEd
|
|
case secSchnorr:
|
|
sigSec, err := chainec.SecSchnorr.ParseSignature(sigBytes)
|
|
if err != nil {
|
|
vm.dstack.PushBool(false)
|
|
return nil
|
|
}
|
|
signature = sigSec
|
|
default:
|
|
vm.dstack.PushBool(false)
|
|
return nil
|
|
}
|
|
|
|
// Attempt to validate the signature.
|
|
switch sigTypes(sigType) {
|
|
case edwards:
|
|
ok := chainec.Edwards.Verify(pubKey, hash, signature.GetR(),
|
|
signature.GetS())
|
|
vm.dstack.PushBool(ok)
|
|
return nil
|
|
case secSchnorr:
|
|
ok := chainec.SecSchnorr.Verify(pubKey, hash, signature.GetR(),
|
|
signature.GetS())
|
|
vm.dstack.PushBool(ok)
|
|
return nil
|
|
}
|
|
|
|
// Fallthrough of somekind automatically results in false, but
|
|
// this should never be hit.
|
|
vm.dstack.PushBool(false)
|
|
return nil
|
|
}
|
|
|
|
// opcodeCheckSigAltVerify is a combination of opcodeCheckSigAlt and
|
|
// opcodeVerify. The opcodeCheckSigAlt is invoked followed by opcodeVerify.
|
|
func opcodeCheckSigAltVerify(op *parsedOpcode, vm *Engine) error {
|
|
err := opcodeCheckSigAlt(op, vm)
|
|
if err == nil {
|
|
err = opcodeVerify(op, vm)
|
|
}
|
|
return err
|
|
}
|
|
|
|
// OpcodeByName is a map that can be used to lookup an opcode by its
|
|
// human-readable name (OP_CHECKMULTISIG, OP_CHECKSIG, etc).
|
|
var OpcodeByName = make(map[string]byte)
|
|
|
|
func init() {
|
|
// Initialize the opcode name to value map using the contents of the
|
|
// opcode array. Also add entries for "OP_FALSE", "OP_TRUE", and
|
|
// "OP_NOP2" since they are aliases for "OP_0", "OP_1",
|
|
// and "OP_CHECKLOCKTIMEVERIFY" respectively.
|
|
for _, op := range opcodeArray {
|
|
OpcodeByName[op.name] = op.value
|
|
}
|
|
OpcodeByName["OP_FALSE"] = OP_FALSE
|
|
OpcodeByName["OP_TRUE"] = OP_TRUE
|
|
OpcodeByName["OP_NOP2"] = OP_CHECKLOCKTIMEVERIFY
|
|
}
|