smartledger-bsv 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +36 -0
- package/README.md +305 -0
- package/SECURITY.md +75 -0
- package/bsv-ecies.min.js +12 -0
- package/bsv-message.min.js +10 -0
- package/bsv-mnemonic.min.js +12 -0
- package/bsv.d.ts +440 -0
- package/bsv.min.js +37 -0
- package/ecies/index.js +1 -0
- package/index.js +101 -0
- package/lib/address.js +526 -0
- package/lib/block/block.js +277 -0
- package/lib/block/blockheader.js +294 -0
- package/lib/block/index.js +4 -0
- package/lib/block/merkleblock.js +316 -0
- package/lib/crypto/bn.js +278 -0
- package/lib/crypto/ecdsa.js +330 -0
- package/lib/crypto/elliptic-fixed.js +74 -0
- package/lib/crypto/hash.browser.js +171 -0
- package/lib/crypto/hash.js +2 -0
- package/lib/crypto/hash.node.js +171 -0
- package/lib/crypto/point.js +217 -0
- package/lib/crypto/random.js +37 -0
- package/lib/crypto/signature.js +410 -0
- package/lib/crypto/smartledger_verify.js +109 -0
- package/lib/ecies/bitcore-ecies.js +163 -0
- package/lib/ecies/electrum-ecies.js +175 -0
- package/lib/ecies/errors.js +16 -0
- package/lib/ecies/index.js +1 -0
- package/lib/encoding/base58.js +108 -0
- package/lib/encoding/base58check.js +112 -0
- package/lib/encoding/bufferreader.js +200 -0
- package/lib/encoding/bufferwriter.js +150 -0
- package/lib/encoding/varint.js +71 -0
- package/lib/errors/index.js +57 -0
- package/lib/errors/spec.js +184 -0
- package/lib/hdprivatekey.js +655 -0
- package/lib/hdpublickey.js +509 -0
- package/lib/message/index.js +4 -0
- package/lib/message/message.js +181 -0
- package/lib/mnemonic/errors.js +18 -0
- package/lib/mnemonic/index.js +4 -0
- package/lib/mnemonic/mnemonic.js +304 -0
- package/lib/mnemonic/pbkdf2.js +68 -0
- package/lib/mnemonic/words/chinese.js +5 -0
- package/lib/mnemonic/words/english.js +5 -0
- package/lib/mnemonic/words/french.js +5 -0
- package/lib/mnemonic/words/index.js +8 -0
- package/lib/mnemonic/words/italian.js +5 -0
- package/lib/mnemonic/words/japanese.js +5 -0
- package/lib/mnemonic/words/spanish.js +5 -0
- package/lib/networks.js +392 -0
- package/lib/opcode.js +248 -0
- package/lib/privatekey.js +373 -0
- package/lib/publickey.js +387 -0
- package/lib/script/index.js +3 -0
- package/lib/script/interpreter.js +1807 -0
- package/lib/script/script.js +1153 -0
- package/lib/transaction/index.js +7 -0
- package/lib/transaction/input/index.js +6 -0
- package/lib/transaction/input/input.js +202 -0
- package/lib/transaction/input/multisig.js +220 -0
- package/lib/transaction/input/multisigscripthash.js +189 -0
- package/lib/transaction/input/publickey.js +96 -0
- package/lib/transaction/input/publickeyhash.js +103 -0
- package/lib/transaction/output.js +192 -0
- package/lib/transaction/sighash.js +288 -0
- package/lib/transaction/signature.js +88 -0
- package/lib/transaction/transaction.js +1208 -0
- package/lib/transaction/unspentoutput.js +97 -0
- package/lib/util/_.js +44 -0
- package/lib/util/js.js +91 -0
- package/lib/util/preconditions.js +34 -0
- package/message/index.js +1 -0
- package/mnemonic/index.js +1 -0
- package/package.json +86 -0
|
@@ -0,0 +1,1807 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
var _ = require('../util/_')
|
|
4
|
+
|
|
5
|
+
var Script = require('./script')
|
|
6
|
+
var Opcode = require('../opcode')
|
|
7
|
+
var BN = require('../crypto/bn')
|
|
8
|
+
var Hash = require('../crypto/hash')
|
|
9
|
+
var Signature = require('../crypto/signature')
|
|
10
|
+
var PublicKey = require('../publickey')
|
|
11
|
+
var cloneDeep = require('clone-deep')
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Bitcoin transactions contain scripts. Each input has a script called the
|
|
15
|
+
* scriptSig, and each output has a script called the scriptPubkey. To validate
|
|
16
|
+
* an input, the input's script is concatenated with the referenced output script,
|
|
17
|
+
* and the result is executed. If at the end of execution the stack contains a
|
|
18
|
+
* "true" value, then the transaction is valid.
|
|
19
|
+
*
|
|
20
|
+
* The primary way to use this class is via the verify function.
|
|
21
|
+
* e.g., Interpreter().verify( ... );
|
|
22
|
+
*/
|
|
23
|
+
var Interpreter = function Interpreter (obj) {
|
|
24
|
+
if (!(this instanceof Interpreter)) {
|
|
25
|
+
return new Interpreter(obj)
|
|
26
|
+
}
|
|
27
|
+
if (obj) {
|
|
28
|
+
this.initialize()
|
|
29
|
+
this.set(obj)
|
|
30
|
+
} else {
|
|
31
|
+
this.initialize()
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Verifies a Script by executing it and returns true if it is valid.
|
|
37
|
+
* This function needs to be provided with the scriptSig and the scriptPubkey
|
|
38
|
+
* separately.
|
|
39
|
+
* @param {Script} scriptSig - the script's first part (corresponding to the tx input)
|
|
40
|
+
* @param {Script} scriptPubkey - the script's last part (corresponding to the tx output)
|
|
41
|
+
* @param {Transaction=} tx - the Transaction containing the scriptSig in one input (used
|
|
42
|
+
* to check signature validity for some opcodes like OP_CHECKSIG)
|
|
43
|
+
* @param {number} nin - index of the transaction input containing the scriptSig verified.
|
|
44
|
+
* @param {number} flags - evaluation flags. See Interpreter.SCRIPT_* constants
|
|
45
|
+
* @param {number} satoshisBN - amount in satoshis of the input to be verified (when FORKID signhash is used)
|
|
46
|
+
*
|
|
47
|
+
* Translated from bitcoind's VerifyScript
|
|
48
|
+
*/
|
|
49
|
+
Interpreter.prototype.verify = function (scriptSig, scriptPubkey, tx, nin, flags, satoshisBN) {
|
|
50
|
+
var Transaction = require('../transaction')
|
|
51
|
+
|
|
52
|
+
if (_.isUndefined(tx)) {
|
|
53
|
+
tx = new Transaction()
|
|
54
|
+
}
|
|
55
|
+
if (_.isUndefined(nin)) {
|
|
56
|
+
nin = 0
|
|
57
|
+
}
|
|
58
|
+
if (_.isUndefined(flags)) {
|
|
59
|
+
flags = 0
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// If FORKID is enabled, we also ensure strict encoding.
|
|
63
|
+
if (flags & Interpreter.SCRIPT_ENABLE_SIGHASH_FORKID) {
|
|
64
|
+
flags |= Interpreter.SCRIPT_VERIFY_STRICTENC
|
|
65
|
+
|
|
66
|
+
// If FORKID is enabled, we need the input amount.
|
|
67
|
+
if (!satoshisBN) {
|
|
68
|
+
throw new Error('internal error - need satoshisBN to verify FORKID transactions')
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
this.set({
|
|
73
|
+
script: scriptSig,
|
|
74
|
+
tx: tx,
|
|
75
|
+
nin: nin,
|
|
76
|
+
flags: flags,
|
|
77
|
+
satoshisBN: satoshisBN
|
|
78
|
+
})
|
|
79
|
+
var stackCopy
|
|
80
|
+
|
|
81
|
+
if ((flags & Interpreter.SCRIPT_VERIFY_SIGPUSHONLY) !== 0 && !scriptSig.isPushOnly()) {
|
|
82
|
+
this.errstr = 'SCRIPT_ERR_SIG_PUSHONLY'
|
|
83
|
+
return false
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// evaluate scriptSig
|
|
87
|
+
if (!this.evaluate()) {
|
|
88
|
+
return false
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (flags & Interpreter.SCRIPT_VERIFY_P2SH) {
|
|
92
|
+
stackCopy = this.stack.slice()
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
var stack = this.stack
|
|
96
|
+
this.initialize()
|
|
97
|
+
this.set({
|
|
98
|
+
script: scriptPubkey,
|
|
99
|
+
stack: stack,
|
|
100
|
+
tx: tx,
|
|
101
|
+
nin: nin,
|
|
102
|
+
flags: flags,
|
|
103
|
+
satoshisBN: satoshisBN
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
// evaluate scriptPubkey
|
|
107
|
+
if (!this.evaluate()) {
|
|
108
|
+
return false
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (this.stack.length === 0) {
|
|
112
|
+
this.errstr = 'SCRIPT_ERR_EVAL_FALSE_NO_RESULT'
|
|
113
|
+
return false
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
var buf = this.stack[this.stack.length - 1]
|
|
117
|
+
if (!Interpreter.castToBool(buf)) {
|
|
118
|
+
this.errstr = 'SCRIPT_ERR_EVAL_FALSE_IN_STACK'
|
|
119
|
+
return false
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Additional validation for spend-to-script-hash transactions:
|
|
123
|
+
if ((flags & Interpreter.SCRIPT_VERIFY_P2SH) && scriptPubkey.isScriptHashOut()) {
|
|
124
|
+
// scriptSig must be literals-only or validation fails
|
|
125
|
+
if (!scriptSig.isPushOnly()) {
|
|
126
|
+
this.errstr = 'SCRIPT_ERR_SIG_PUSHONLY'
|
|
127
|
+
return false
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// stackCopy cannot be empty here, because if it was the
|
|
131
|
+
// P2SH HASH <> EQUAL scriptPubKey would be evaluated with
|
|
132
|
+
// an empty stack and the EvalScript above would return false.
|
|
133
|
+
if (stackCopy.length === 0) {
|
|
134
|
+
throw new Error('internal error - stack copy empty')
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
var redeemScriptSerialized = stackCopy[stackCopy.length - 1]
|
|
138
|
+
var redeemScript = Script.fromBuffer(redeemScriptSerialized)
|
|
139
|
+
stackCopy.pop()
|
|
140
|
+
|
|
141
|
+
this.initialize()
|
|
142
|
+
this.set({
|
|
143
|
+
script: redeemScript,
|
|
144
|
+
stack: stackCopy,
|
|
145
|
+
tx: tx,
|
|
146
|
+
nin: nin,
|
|
147
|
+
flags: flags,
|
|
148
|
+
satoshisBN: satoshisBN
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
// evaluate redeemScript
|
|
152
|
+
if (!this.evaluate()) {
|
|
153
|
+
return false
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (stackCopy.length === 0) {
|
|
157
|
+
this.errstr = 'SCRIPT_ERR_EVAL_FALSE_NO_P2SH_STACK'
|
|
158
|
+
return false
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (!Interpreter.castToBool(stackCopy[stackCopy.length - 1])) {
|
|
162
|
+
this.errstr = 'SCRIPT_ERR_EVAL_FALSE_IN_P2SH_STACK'
|
|
163
|
+
return false
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// The CLEANSTACK check is only performed after potential P2SH evaluation,
|
|
168
|
+
// as the non-P2SH evaluation of a P2SH script will obviously not result in
|
|
169
|
+
// a clean stack (the P2SH inputs remain). The same holds for witness
|
|
170
|
+
// evaluation.
|
|
171
|
+
if ((flags & Interpreter.SCRIPT_VERIFY_CLEANSTACK) !== 0) {
|
|
172
|
+
// Disallow CLEANSTACK without P2SH, as otherwise a switch
|
|
173
|
+
// CLEANSTACK->P2SH+CLEANSTACK would be possible, which is not a
|
|
174
|
+
// softfork (and P2SH should be one).
|
|
175
|
+
if ((flags & Interpreter.SCRIPT_VERIFY_P2SH) === 0) {
|
|
176
|
+
throw new Error('internal error - CLEANSTACK without P2SH')
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (stackCopy.length !== 1) {
|
|
180
|
+
this.errstr = 'SCRIPT_ERR_CLEANSTACK'
|
|
181
|
+
return false
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return true
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
module.exports = Interpreter
|
|
189
|
+
|
|
190
|
+
Interpreter.prototype.initialize = function (obj) {
|
|
191
|
+
this.stack = []
|
|
192
|
+
this.altstack = []
|
|
193
|
+
this.pc = 0
|
|
194
|
+
this.pbegincodehash = 0
|
|
195
|
+
this.nOpCount = 0
|
|
196
|
+
this.vfExec = []
|
|
197
|
+
this.errstr = ''
|
|
198
|
+
this.flags = 0
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
Interpreter.prototype.set = function (obj) {
|
|
202
|
+
this.script = obj.script || this.script
|
|
203
|
+
this.tx = obj.tx || this.tx
|
|
204
|
+
this.nin = typeof obj.nin !== 'undefined' ? obj.nin : this.nin
|
|
205
|
+
this.satoshisBN = obj.satoshisBN || this.satoshisBN
|
|
206
|
+
this.stack = obj.stack || this.stack
|
|
207
|
+
this.altstack = obj.altstack || this.altstack
|
|
208
|
+
this.pc = typeof obj.pc !== 'undefined' ? obj.pc : this.pc
|
|
209
|
+
this.pbegincodehash = typeof obj.pbegincodehash !== 'undefined' ? obj.pbegincodehash : this.pbegincodehash
|
|
210
|
+
this.nOpCount = typeof obj.nOpCount !== 'undefined' ? obj.nOpCount : this.nOpCount
|
|
211
|
+
this.vfExec = obj.vfExec || this.vfExec
|
|
212
|
+
this.errstr = obj.errstr || this.errstr
|
|
213
|
+
this.flags = typeof obj.flags !== 'undefined' ? obj.flags : this.flags
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
Interpreter.true = Buffer.from([1])
|
|
217
|
+
Interpreter.false = Buffer.from([])
|
|
218
|
+
|
|
219
|
+
Interpreter.MAX_SCRIPT_ELEMENT_SIZE = 520
|
|
220
|
+
Interpreter.MAXIMUM_ELEMENT_SIZE = 4
|
|
221
|
+
|
|
222
|
+
Interpreter.LOCKTIME_THRESHOLD = 500000000
|
|
223
|
+
Interpreter.LOCKTIME_THRESHOLD_BN = new BN(Interpreter.LOCKTIME_THRESHOLD)
|
|
224
|
+
|
|
225
|
+
// flags taken from bitcoind
|
|
226
|
+
// bitcoind commit: b5d1b1092998bc95313856d535c632ea5a8f9104
|
|
227
|
+
Interpreter.SCRIPT_VERIFY_NONE = 0
|
|
228
|
+
|
|
229
|
+
// Evaluate P2SH subscripts (softfork safe, BIP16).
|
|
230
|
+
Interpreter.SCRIPT_VERIFY_P2SH = (1 << 0)
|
|
231
|
+
|
|
232
|
+
// Passing a non-strict-DER signature or one with undefined hashtype to a checksig operation causes script failure.
|
|
233
|
+
// Passing a pubkey that is not (0x04 + 64 bytes) or (0x02 or 0x03 + 32 bytes) to checksig causes that pubkey to be
|
|
234
|
+
// skipped (not softfork safe: this flag can widen the validity of OP_CHECKSIG OP_NOT).
|
|
235
|
+
Interpreter.SCRIPT_VERIFY_STRICTENC = (1 << 1)
|
|
236
|
+
|
|
237
|
+
// Passing a non-strict-DER signature to a checksig operation causes script failure (softfork safe, BIP62 rule 1)
|
|
238
|
+
Interpreter.SCRIPT_VERIFY_DERSIG = (1 << 2)
|
|
239
|
+
|
|
240
|
+
// Passing a non-strict-DER signature or one with S > order/2 to a checksig operation causes script failure
|
|
241
|
+
// (softfork safe, BIP62 rule 5).
|
|
242
|
+
Interpreter.SCRIPT_VERIFY_LOW_S = (1 << 3)
|
|
243
|
+
|
|
244
|
+
// verify dummy stack item consumed by CHECKMULTISIG is of zero-length (softfork safe, BIP62 rule 7).
|
|
245
|
+
Interpreter.SCRIPT_VERIFY_NULLDUMMY = (1 << 4)
|
|
246
|
+
|
|
247
|
+
// Using a non-push operator in the scriptSig causes script failure (softfork safe, BIP62 rule 2).
|
|
248
|
+
Interpreter.SCRIPT_VERIFY_SIGPUSHONLY = (1 << 5)
|
|
249
|
+
|
|
250
|
+
// Require minimal encodings for all push operations (OP_0... OP_16, OP_1NEGATE where possible, direct
|
|
251
|
+
// pushes up to 75 bytes, OP_PUSHDATA up to 255 bytes, OP_PUSHDATA2 for anything larger). Evaluating
|
|
252
|
+
// any other push causes the script to fail (BIP62 rule 3).
|
|
253
|
+
// In addition, whenever a stack element is interpreted as a number, it must be of minimal length (BIP62 rule 4).
|
|
254
|
+
// (softfork safe)
|
|
255
|
+
Interpreter.SCRIPT_VERIFY_MINIMALDATA = (1 << 6)
|
|
256
|
+
|
|
257
|
+
// Discourage use of NOPs reserved for upgrades (NOP1-10)
|
|
258
|
+
//
|
|
259
|
+
// Provided so that nodes can avoid accepting or mining transactions
|
|
260
|
+
// containing executed NOP's whose meaning may change after a soft-fork,
|
|
261
|
+
// thus rendering the script invalid; with this flag set executing
|
|
262
|
+
// discouraged NOPs fails the script. This verification flag will never be
|
|
263
|
+
// a mandatory flag applied to scripts in a block. NOPs that are not
|
|
264
|
+
// executed, e.g. within an unexecuted IF ENDIF block, are *not* rejected.
|
|
265
|
+
Interpreter.SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS = (1 << 7)
|
|
266
|
+
|
|
267
|
+
// Require that only a single stack element remains after evaluation. This
|
|
268
|
+
// changes the success criterion from "At least one stack element must
|
|
269
|
+
// remain, and when interpreted as a boolean, it must be true" to "Exactly
|
|
270
|
+
// one stack element must remain, and when interpreted as a boolean, it must
|
|
271
|
+
// be true".
|
|
272
|
+
// (softfork safe, BIP62 rule 6)
|
|
273
|
+
// Note: CLEANSTACK should never be used without P2SH or WITNESS.
|
|
274
|
+
Interpreter.SCRIPT_VERIFY_CLEANSTACK = (1 << 8)
|
|
275
|
+
|
|
276
|
+
// CLTV See BIP65 for details.
|
|
277
|
+
Interpreter.SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY = (1 << 9)
|
|
278
|
+
|
|
279
|
+
// support CHECKSEQUENCEVERIFY opcode
|
|
280
|
+
//
|
|
281
|
+
// See BIP112 for details
|
|
282
|
+
Interpreter.SCRIPT_VERIFY_CHECKSEQUENCEVERIFY = (1 << 10)
|
|
283
|
+
|
|
284
|
+
// Segwit script only: Require the argument of OP_IF/NOTIF to be exactly
|
|
285
|
+
// 0x01 or empty vector
|
|
286
|
+
//
|
|
287
|
+
Interpreter.SCRIPT_VERIFY_MINIMALIF = (1 << 13)
|
|
288
|
+
|
|
289
|
+
// Signature(s) must be empty vector if an CHECK(MULTI)SIG operation failed
|
|
290
|
+
//
|
|
291
|
+
Interpreter.SCRIPT_VERIFY_NULLFAIL = (1 << 14)
|
|
292
|
+
|
|
293
|
+
// Public keys in scripts must be compressed
|
|
294
|
+
Interpreter.SCRIPT_VERIFY_COMPRESSED_PUBKEYTYPE = (1 << 15)
|
|
295
|
+
|
|
296
|
+
// Do we accept signature using SIGHASH_FORKID
|
|
297
|
+
//
|
|
298
|
+
Interpreter.SCRIPT_ENABLE_SIGHASH_FORKID = (1 << 16)
|
|
299
|
+
|
|
300
|
+
// Do we accept activate replay protection using a different fork id.
|
|
301
|
+
//
|
|
302
|
+
Interpreter.SCRIPT_ENABLE_REPLAY_PROTECTION = (1 << 17)
|
|
303
|
+
|
|
304
|
+
// Enable new opcodes.
|
|
305
|
+
//
|
|
306
|
+
Interpreter.SCRIPT_ENABLE_MONOLITH_OPCODES = (1 << 18)
|
|
307
|
+
|
|
308
|
+
// Are the Magnetic upgrade opcodes enabled?
|
|
309
|
+
//
|
|
310
|
+
Interpreter.SCRIPT_ENABLE_MAGNETIC_OPCODES = (1 << 19)
|
|
311
|
+
|
|
312
|
+
/* Below flags apply in the context of BIP 68 */
|
|
313
|
+
/**
|
|
314
|
+
* If this flag set, CTxIn::nSequence is NOT interpreted as a relative
|
|
315
|
+
* lock-time.
|
|
316
|
+
*/
|
|
317
|
+
Interpreter.SEQUENCE_LOCKTIME_DISABLE_FLAG = (1 << 31)
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* If CTxIn::nSequence encodes a relative lock-time and this flag is set,
|
|
321
|
+
* the relative lock-time has units of 512 seconds, otherwise it specifies
|
|
322
|
+
* blocks with a granularity of 1.
|
|
323
|
+
*/
|
|
324
|
+
Interpreter.SEQUENCE_LOCKTIME_TYPE_FLAG = (1 << 22)
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* If CTxIn::nSequence encodes a relative lock-time, this mask is applied to
|
|
328
|
+
* extract that lock-time from the sequence field.
|
|
329
|
+
*/
|
|
330
|
+
Interpreter.SEQUENCE_LOCKTIME_MASK = 0x0000ffff
|
|
331
|
+
|
|
332
|
+
Interpreter.castToBool = function (buf) {
|
|
333
|
+
for (var i = 0; i < buf.length; i++) {
|
|
334
|
+
if (buf[i] !== 0) {
|
|
335
|
+
// can be negative zero
|
|
336
|
+
if (i === buf.length - 1 && buf[i] === 0x80) {
|
|
337
|
+
return false
|
|
338
|
+
}
|
|
339
|
+
return true
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
return false
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Translated from bitcoind's CheckSignatureEncoding
|
|
347
|
+
*/
|
|
348
|
+
Interpreter.prototype.checkSignatureEncoding = function (buf) {
|
|
349
|
+
var sig
|
|
350
|
+
|
|
351
|
+
// Empty signature. Not strictly DER encoded, but allowed to provide a
|
|
352
|
+
// compact way to provide an invalid signature for use with CHECK(MULTI)SIG
|
|
353
|
+
if (buf.length === 0) {
|
|
354
|
+
return true
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
if ((this.flags & (Interpreter.SCRIPT_VERIFY_DERSIG | Interpreter.SCRIPT_VERIFY_LOW_S | Interpreter.SCRIPT_VERIFY_STRICTENC)) !== 0 && !Signature.isTxDER(buf)) {
|
|
358
|
+
this.errstr = 'SCRIPT_ERR_SIG_DER_INVALID_FORMAT'
|
|
359
|
+
return false
|
|
360
|
+
} else if ((this.flags & Interpreter.SCRIPT_VERIFY_LOW_S) !== 0) {
|
|
361
|
+
sig = Signature.fromTxFormat(buf)
|
|
362
|
+
if (!sig.hasLowS()) {
|
|
363
|
+
this.errstr = 'SCRIPT_ERR_SIG_DER_HIGH_S'
|
|
364
|
+
return false
|
|
365
|
+
}
|
|
366
|
+
} else if ((this.flags & Interpreter.SCRIPT_VERIFY_STRICTENC) !== 0) {
|
|
367
|
+
sig = Signature.fromTxFormat(buf)
|
|
368
|
+
if (!sig.hasDefinedHashtype()) {
|
|
369
|
+
this.errstr = 'SCRIPT_ERR_SIG_HASHTYPE'
|
|
370
|
+
return false
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
if (!(this.flags & Interpreter.SCRIPT_ENABLE_SIGHASH_FORKID) &&
|
|
374
|
+
(sig.nhashtype & Signature.SIGHASH_FORKID)) {
|
|
375
|
+
this.errstr = 'SCRIPT_ERR_ILLEGAL_FORKID'
|
|
376
|
+
return false
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
if ((this.flags & Interpreter.SCRIPT_ENABLE_SIGHASH_FORKID) &&
|
|
380
|
+
!(sig.nhashtype & Signature.SIGHASH_FORKID)) {
|
|
381
|
+
this.errstr = 'SCRIPT_ERR_MUST_USE_FORKID'
|
|
382
|
+
return false
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
return true
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* Translated from bitcoind's CheckPubKeyEncoding
|
|
391
|
+
*/
|
|
392
|
+
Interpreter.prototype.checkPubkeyEncoding = function (buf) {
|
|
393
|
+
if ((this.flags & Interpreter.SCRIPT_VERIFY_STRICTENC) !== 0 && !PublicKey.isValid(buf)) {
|
|
394
|
+
this.errstr = 'SCRIPT_ERR_PUBKEYTYPE'
|
|
395
|
+
return false
|
|
396
|
+
}
|
|
397
|
+
return true
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
*
|
|
402
|
+
* Check the buffer is minimally encoded (see https://github.com/bitcoincashorg/spec/blob/master/may-2018-reenabled-opcodes.md#op_bin2num)
|
|
403
|
+
*
|
|
404
|
+
*
|
|
405
|
+
*/
|
|
406
|
+
|
|
407
|
+
Interpreter._isMinimallyEncoded = function (buf, nMaxNumSize) {
|
|
408
|
+
nMaxNumSize = nMaxNumSize || Interpreter.MAXIMUM_ELEMENT_SIZE
|
|
409
|
+
if (buf.length > nMaxNumSize) {
|
|
410
|
+
return false
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
if (buf.length > 0) {
|
|
414
|
+
// Check that the number is encoded with the minimum possible number
|
|
415
|
+
// of bytes.
|
|
416
|
+
//
|
|
417
|
+
// If the most-significant-byte - excluding the sign bit - is zero
|
|
418
|
+
// then we're not minimal. Note how this test also rejects the
|
|
419
|
+
// negative-zero encoding, 0x80.
|
|
420
|
+
if ((buf[buf.length - 1] & 0x7f) === 0) {
|
|
421
|
+
// One exception: if there's more than one byte and the most
|
|
422
|
+
// significant bit of the second-most-significant-byte is set it
|
|
423
|
+
// would conflict with the sign bit. An example of this case is
|
|
424
|
+
// +-255, which encode to 0xff00 and 0xff80 respectively.
|
|
425
|
+
// (big-endian).
|
|
426
|
+
if (buf.length <= 1 || (buf[buf.length - 2] & 0x80) === 0) {
|
|
427
|
+
return false
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
return true
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
/**
|
|
435
|
+
*
|
|
436
|
+
* minimally encode the buffer content
|
|
437
|
+
*
|
|
438
|
+
* @param {number} nMaxNumSize (max allowed size)
|
|
439
|
+
*/
|
|
440
|
+
Interpreter._minimallyEncode = function (buf) {
|
|
441
|
+
if (buf.length === 0) {
|
|
442
|
+
return buf
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
// If the last byte is not 0x00 or 0x80, we are minimally encoded.
|
|
446
|
+
var last = buf[buf.length - 1]
|
|
447
|
+
if (last & 0x7f) {
|
|
448
|
+
return buf
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
// If the script is one byte long, then we have a zero, which encodes as an
|
|
452
|
+
// empty array.
|
|
453
|
+
if (buf.length === 1) {
|
|
454
|
+
return Buffer.from('')
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
// If the next byte has it sign bit set, then we are minimaly encoded.
|
|
458
|
+
if (buf[buf.length - 2] & 0x80) {
|
|
459
|
+
return buf
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
// We are not minimally encoded, we need to figure out how much to trim.
|
|
463
|
+
for (var i = buf.length - 1; i > 0; i--) {
|
|
464
|
+
// We found a non zero byte, time to encode.
|
|
465
|
+
if (buf[i - 1] !== 0) {
|
|
466
|
+
if (buf[i - 1] & 0x80) {
|
|
467
|
+
// We found a byte with it sign bit set so we need one more
|
|
468
|
+
// byte.
|
|
469
|
+
buf[i++] = last
|
|
470
|
+
} else {
|
|
471
|
+
// the sign bit is clear, we can use it.
|
|
472
|
+
buf[i - 1] |= last
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
return buf.slice(0, i)
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
// If we found the whole thing is zeros, then we have a zero.
|
|
480
|
+
return Buffer.from('')
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
/**
|
|
484
|
+
* Based on bitcoind's EvalScript function, with the inner loop moved to
|
|
485
|
+
* Interpreter.prototype.step()
|
|
486
|
+
* bitcoind commit: b5d1b1092998bc95313856d535c632ea5a8f9104
|
|
487
|
+
*/
|
|
488
|
+
Interpreter.prototype.evaluate = function () {
|
|
489
|
+
// TODO: script size should be configurable. no magic numbers
|
|
490
|
+
if (this.script.toBuffer().length > 10000) {
|
|
491
|
+
this.errstr = 'SCRIPT_ERR_SCRIPT_SIZE'
|
|
492
|
+
return false
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
try {
|
|
496
|
+
while (this.pc < this.script.chunks.length) {
|
|
497
|
+
let thisStep = { pc: this.pc, opcode: Opcode.fromNumber(this.script.chunks[this.pc].opcodenum) }
|
|
498
|
+
var fSuccess = this.step()
|
|
499
|
+
if (!fSuccess) {
|
|
500
|
+
return false
|
|
501
|
+
}
|
|
502
|
+
this._callbackStep(thisStep)
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
// Size limits
|
|
506
|
+
if (this.stack.length + this.altstack.length > 1000) {
|
|
507
|
+
this.errstr = 'SCRIPT_ERR_STACK_SIZE'
|
|
508
|
+
return false
|
|
509
|
+
}
|
|
510
|
+
} catch (e) {
|
|
511
|
+
this.errstr = 'SCRIPT_ERR_UNKNOWN_ERROR: ' + e
|
|
512
|
+
return false
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
if (this.vfExec.length > 0) {
|
|
516
|
+
this.errstr = 'SCRIPT_ERR_UNBALANCED_CONDITIONAL'
|
|
517
|
+
return false
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
return true
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
Interpreter.prototype._callbackStep = function (thisStep) {
|
|
524
|
+
if (typeof this.stepListener === 'function') {
|
|
525
|
+
try {
|
|
526
|
+
this.stepListener(thisStep, cloneDeep(this.stack, true), cloneDeep(this.altstack, true))
|
|
527
|
+
} catch (err) {
|
|
528
|
+
console.log(`Error in Step callback:${err}`)
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
/**
|
|
534
|
+
* Checks a locktime parameter with the transaction's locktime.
|
|
535
|
+
* There are two times of nLockTime: lock-by-blockheight and lock-by-blocktime,
|
|
536
|
+
* distinguished by whether nLockTime < LOCKTIME_THRESHOLD = 500000000
|
|
537
|
+
*
|
|
538
|
+
* See the corresponding code on bitcoin core:
|
|
539
|
+
* https://github.com/bitcoin/bitcoin/blob/ffd75adce01a78b3461b3ff05bcc2b530a9ce994/src/script/interpreter.cpp#L1129
|
|
540
|
+
*
|
|
541
|
+
* @param {BN} nLockTime the locktime read from the script
|
|
542
|
+
* @return {boolean} true if the transaction's locktime is less than or equal to
|
|
543
|
+
* the transaction's locktime
|
|
544
|
+
*/
|
|
545
|
+
Interpreter.prototype.checkLockTime = function (nLockTime) {
|
|
546
|
+
// We want to compare apples to apples, so fail the script
|
|
547
|
+
// unless the type of nLockTime being tested is the same as
|
|
548
|
+
// the nLockTime in the transaction.
|
|
549
|
+
if (!(
|
|
550
|
+
(this.tx.nLockTime < Interpreter.LOCKTIME_THRESHOLD && nLockTime.lt(Interpreter.LOCKTIME_THRESHOLD_BN)) ||
|
|
551
|
+
(this.tx.nLockTime >= Interpreter.LOCKTIME_THRESHOLD && nLockTime.gte(Interpreter.LOCKTIME_THRESHOLD_BN))
|
|
552
|
+
)) {
|
|
553
|
+
return false
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
// Now that we know we're comparing apples-to-apples, the
|
|
557
|
+
// comparison is a simple numeric one.
|
|
558
|
+
if (nLockTime.gt(new BN(this.tx.nLockTime))) {
|
|
559
|
+
return false
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
// Finally the nLockTime feature can be disabled and thus
|
|
563
|
+
// CHECKLOCKTIMEVERIFY bypassed if every txin has been
|
|
564
|
+
// finalized by setting nSequence to maxint. The
|
|
565
|
+
// transaction would be allowed into the blockchain, making
|
|
566
|
+
// the opcode ineffective.
|
|
567
|
+
//
|
|
568
|
+
// Testing if this vin is not final is sufficient to
|
|
569
|
+
// prevent this condition. Alternatively we could test all
|
|
570
|
+
// inputs, but testing just this input minimizes the data
|
|
571
|
+
// required to prove correct CHECKLOCKTIMEVERIFY execution.
|
|
572
|
+
if (this.tx.inputs[this.nin].isFinal()) {
|
|
573
|
+
return false
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
return true
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
/**
|
|
580
|
+
* Checks a sequence parameter with the transaction's sequence.
|
|
581
|
+
* @param {BN} nSequence the sequence read from the script
|
|
582
|
+
* @return {boolean} true if the transaction's sequence is less than or equal to
|
|
583
|
+
* the transaction's sequence
|
|
584
|
+
*/
|
|
585
|
+
Interpreter.prototype.checkSequence = function (nSequence) {
|
|
586
|
+
// Relative lock times are supported by comparing the passed in operand to
|
|
587
|
+
// the sequence number of the input.
|
|
588
|
+
var txToSequence = this.tx.inputs[this.nin].sequenceNumber
|
|
589
|
+
|
|
590
|
+
// Fail if the transaction's version number is not set high enough to
|
|
591
|
+
// trigger BIP 68 rules.
|
|
592
|
+
if (this.tx.version < 2) {
|
|
593
|
+
return false
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
// Sequence numbers with their most significant bit set are not consensus
|
|
597
|
+
// constrained. Testing that the transaction's sequence number do not have
|
|
598
|
+
// this bit set prevents using this property to get around a
|
|
599
|
+
// CHECKSEQUENCEVERIFY check.
|
|
600
|
+
if (txToSequence & Interpreter.SEQUENCE_LOCKTIME_DISABLE_FLAG) {
|
|
601
|
+
return false
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
// Mask off any bits that do not have consensus-enforced meaning before
|
|
605
|
+
// doing the integer comparisons
|
|
606
|
+
var nLockTimeMask =
|
|
607
|
+
Interpreter.SEQUENCE_LOCKTIME_TYPE_FLAG | Interpreter.SEQUENCE_LOCKTIME_MASK
|
|
608
|
+
var txToSequenceMasked = new BN(txToSequence & nLockTimeMask)
|
|
609
|
+
var nSequenceMasked = nSequence.and(nLockTimeMask)
|
|
610
|
+
|
|
611
|
+
// There are two kinds of nSequence: lock-by-blockheight and
|
|
612
|
+
// lock-by-blocktime, distinguished by whether nSequenceMasked <
|
|
613
|
+
// CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG.
|
|
614
|
+
//
|
|
615
|
+
// We want to compare apples to apples, so fail the script unless the type
|
|
616
|
+
// of nSequenceMasked being tested is the same as the nSequenceMasked in the
|
|
617
|
+
// transaction.
|
|
618
|
+
var SEQUENCE_LOCKTIME_TYPE_FLAG_BN = new BN(Interpreter.SEQUENCE_LOCKTIME_TYPE_FLAG)
|
|
619
|
+
|
|
620
|
+
if (!((txToSequenceMasked.lt(SEQUENCE_LOCKTIME_TYPE_FLAG_BN) &&
|
|
621
|
+
nSequenceMasked.lt(SEQUENCE_LOCKTIME_TYPE_FLAG_BN)) ||
|
|
622
|
+
(txToSequenceMasked.gte(SEQUENCE_LOCKTIME_TYPE_FLAG_BN) &&
|
|
623
|
+
nSequenceMasked.gte(SEQUENCE_LOCKTIME_TYPE_FLAG_BN)))) {
|
|
624
|
+
return false
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
// Now that we know we're comparing apples-to-apples, the comparison is a
|
|
628
|
+
// simple numeric one.
|
|
629
|
+
if (nSequenceMasked.gt(txToSequenceMasked)) {
|
|
630
|
+
return false
|
|
631
|
+
}
|
|
632
|
+
return true
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
function padBufferToSize (buf, len) {
|
|
636
|
+
let b = buf
|
|
637
|
+
while (b.length < len) {
|
|
638
|
+
b = Buffer.concat([Buffer.from([0x00]), b])
|
|
639
|
+
}
|
|
640
|
+
return b
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
/**
|
|
644
|
+
* Based on the inner loop of bitcoind's EvalScript function
|
|
645
|
+
* bitcoind commit: b5d1b1092998bc95313856d535c632ea5a8f9104
|
|
646
|
+
*/
|
|
647
|
+
Interpreter.prototype.step = function () {
|
|
648
|
+
var self = this
|
|
649
|
+
|
|
650
|
+
function stacktop (i) {
|
|
651
|
+
return self.stack[self.stack.length + i]
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
function isOpcodeDisabled (opcode) {
|
|
655
|
+
switch (opcode) {
|
|
656
|
+
case Opcode.OP_2MUL:
|
|
657
|
+
case Opcode.OP_2DIV:
|
|
658
|
+
|
|
659
|
+
// Disabled opcodes.
|
|
660
|
+
return true
|
|
661
|
+
|
|
662
|
+
case Opcode.OP_INVERT:
|
|
663
|
+
case Opcode.OP_MUL:
|
|
664
|
+
case Opcode.OP_LSHIFT:
|
|
665
|
+
case Opcode.OP_RSHIFT:
|
|
666
|
+
// Opcodes that have been reenabled.
|
|
667
|
+
if ((self.flags & Interpreter.SCRIPT_ENABLE_MAGNETIC_OPCODES) === 0) {
|
|
668
|
+
return true
|
|
669
|
+
}
|
|
670
|
+
break
|
|
671
|
+
case Opcode.OP_DIV:
|
|
672
|
+
case Opcode.OP_MOD:
|
|
673
|
+
case Opcode.OP_SPLIT:
|
|
674
|
+
case Opcode.OP_CAT:
|
|
675
|
+
case Opcode.OP_AND:
|
|
676
|
+
case Opcode.OP_OR:
|
|
677
|
+
case Opcode.OP_XOR:
|
|
678
|
+
case Opcode.OP_BIN2NUM:
|
|
679
|
+
case Opcode.OP_NUM2BIN:
|
|
680
|
+
// Opcodes that have been reenabled.
|
|
681
|
+
if ((self.flags & Interpreter.SCRIPT_ENABLE_MONOLITH_OPCODES) === 0) {
|
|
682
|
+
return true
|
|
683
|
+
}
|
|
684
|
+
break
|
|
685
|
+
default:
|
|
686
|
+
break
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
return false
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
var fRequireMinimal = (this.flags & Interpreter.SCRIPT_VERIFY_MINIMALDATA) !== 0
|
|
693
|
+
|
|
694
|
+
// bool fExec = !count(vfExec.begin(), vfExec.end(), false);
|
|
695
|
+
var fExec = (this.vfExec.indexOf(false) === -1)
|
|
696
|
+
var buf, buf1, buf2, spliced, n, x1, x2, bn, bn1, bn2, bufSig, bufPubkey, subscript
|
|
697
|
+
var sig, pubkey
|
|
698
|
+
var fValue, fSuccess
|
|
699
|
+
|
|
700
|
+
// Read instruction
|
|
701
|
+
var chunk = this.script.chunks[this.pc]
|
|
702
|
+
this.pc++
|
|
703
|
+
var opcodenum = chunk.opcodenum
|
|
704
|
+
if (_.isUndefined(opcodenum)) {
|
|
705
|
+
this.errstr = 'SCRIPT_ERR_UNDEFINED_OPCODE'
|
|
706
|
+
return false
|
|
707
|
+
}
|
|
708
|
+
if (chunk.buf && chunk.buf.length > Interpreter.MAX_SCRIPT_ELEMENT_SIZE) {
|
|
709
|
+
this.errstr = 'SCRIPT_ERR_PUSH_SIZE'
|
|
710
|
+
return false
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
// Note how Opcode.OP_RESERVED does not count towards the opcode limit.
|
|
714
|
+
if (opcodenum > Opcode.OP_16 && ++(this.nOpCount) > 201) {
|
|
715
|
+
this.errstr = 'SCRIPT_ERR_OP_COUNT'
|
|
716
|
+
return false
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
if (isOpcodeDisabled(opcodenum)) {
|
|
720
|
+
this.errstr = 'SCRIPT_ERR_DISABLED_OPCODE'
|
|
721
|
+
return false
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
if (fExec && opcodenum >= 0 && opcodenum <= Opcode.OP_PUSHDATA4) {
|
|
725
|
+
if (fRequireMinimal && !this.script.checkMinimalPush(this.pc - 1)) {
|
|
726
|
+
this.errstr = 'SCRIPT_ERR_MINIMALDATA'
|
|
727
|
+
return false
|
|
728
|
+
}
|
|
729
|
+
if (!chunk.buf) {
|
|
730
|
+
this.stack.push(Interpreter.false)
|
|
731
|
+
} else if (chunk.len !== chunk.buf.length) {
|
|
732
|
+
throw new Error(`Length of push value not equal to length of data (${chunk.len},${chunk.buf.length})`)
|
|
733
|
+
} else {
|
|
734
|
+
this.stack.push(chunk.buf)
|
|
735
|
+
}
|
|
736
|
+
} else if (fExec || (Opcode.OP_IF <= opcodenum && opcodenum <= Opcode.OP_ENDIF)) {
|
|
737
|
+
switch (opcodenum) {
|
|
738
|
+
// Push value
|
|
739
|
+
case Opcode.OP_1NEGATE:
|
|
740
|
+
case Opcode.OP_1:
|
|
741
|
+
case Opcode.OP_2:
|
|
742
|
+
case Opcode.OP_3:
|
|
743
|
+
case Opcode.OP_4:
|
|
744
|
+
case Opcode.OP_5:
|
|
745
|
+
case Opcode.OP_6:
|
|
746
|
+
case Opcode.OP_7:
|
|
747
|
+
case Opcode.OP_8:
|
|
748
|
+
case Opcode.OP_9:
|
|
749
|
+
case Opcode.OP_10:
|
|
750
|
+
case Opcode.OP_11:
|
|
751
|
+
case Opcode.OP_12:
|
|
752
|
+
case Opcode.OP_13:
|
|
753
|
+
case Opcode.OP_14:
|
|
754
|
+
case Opcode.OP_15:
|
|
755
|
+
case Opcode.OP_16:
|
|
756
|
+
// ( -- value)
|
|
757
|
+
// ScriptNum bn((int)opcode - (int)(Opcode.OP_1 - 1));
|
|
758
|
+
n = opcodenum - (Opcode.OP_1 - 1)
|
|
759
|
+
buf = new BN(n).toScriptNumBuffer()
|
|
760
|
+
this.stack.push(buf)
|
|
761
|
+
// The result of these opcodes should always be the minimal way to push the data
|
|
762
|
+
// they push, so no need for a CheckMinimalPush here.
|
|
763
|
+
break
|
|
764
|
+
|
|
765
|
+
//
|
|
766
|
+
// Control
|
|
767
|
+
//
|
|
768
|
+
case Opcode.OP_NOP:
|
|
769
|
+
break
|
|
770
|
+
|
|
771
|
+
case Opcode.OP_NOP2:
|
|
772
|
+
case Opcode.OP_CHECKLOCKTIMEVERIFY:
|
|
773
|
+
|
|
774
|
+
if (!(this.flags & Interpreter.SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY)) {
|
|
775
|
+
// not enabled; treat as a NOP2
|
|
776
|
+
if (this.flags & Interpreter.SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) {
|
|
777
|
+
this.errstr = 'SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS'
|
|
778
|
+
return false
|
|
779
|
+
}
|
|
780
|
+
break
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
if (this.stack.length < 1) {
|
|
784
|
+
this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
|
|
785
|
+
return false
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
// Note that elsewhere numeric opcodes are limited to
|
|
789
|
+
// operands in the range -2**31+1 to 2**31-1, however it is
|
|
790
|
+
// legal for opcodes to produce results exceeding that
|
|
791
|
+
// range. This limitation is implemented by CScriptNum's
|
|
792
|
+
// default 4-byte limit.
|
|
793
|
+
//
|
|
794
|
+
// If we kept to that limit we'd have a year 2038 problem,
|
|
795
|
+
// even though the nLockTime field in transactions
|
|
796
|
+
// themselves is uint32 which only becomes meaningless
|
|
797
|
+
// after the year 2106.
|
|
798
|
+
//
|
|
799
|
+
// Thus as a special case we tell CScriptNum to accept up
|
|
800
|
+
// to 5-byte bignums, which are good until 2**39-1, well
|
|
801
|
+
// beyond the 2**32-1 limit of the nLockTime field itself.
|
|
802
|
+
var nLockTime = BN.fromScriptNumBuffer(this.stack[this.stack.length - 1], fRequireMinimal, 5)
|
|
803
|
+
|
|
804
|
+
// In the rare event that the argument may be < 0 due to
|
|
805
|
+
// some arithmetic being done first, you can always use
|
|
806
|
+
// 0 MAX CHECKLOCKTIMEVERIFY.
|
|
807
|
+
if (nLockTime.lt(new BN(0))) {
|
|
808
|
+
this.errstr = 'SCRIPT_ERR_NEGATIVE_LOCKTIME'
|
|
809
|
+
return false
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
// Actually compare the specified lock time with the transaction.
|
|
813
|
+
if (!this.checkLockTime(nLockTime)) {
|
|
814
|
+
this.errstr = 'SCRIPT_ERR_UNSATISFIED_LOCKTIME'
|
|
815
|
+
return false
|
|
816
|
+
}
|
|
817
|
+
break
|
|
818
|
+
|
|
819
|
+
case Opcode.OP_NOP3:
|
|
820
|
+
case Opcode.OP_CHECKSEQUENCEVERIFY:
|
|
821
|
+
|
|
822
|
+
if (!(this.flags & Interpreter.SCRIPT_VERIFY_CHECKSEQUENCEVERIFY)) {
|
|
823
|
+
// not enabled; treat as a NOP3
|
|
824
|
+
if (this.flags & Interpreter.SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) {
|
|
825
|
+
this.errstr = 'SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS'
|
|
826
|
+
return false
|
|
827
|
+
}
|
|
828
|
+
break
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
if (this.stack.length < 1) {
|
|
832
|
+
this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
|
|
833
|
+
return false
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
// nSequence, like nLockTime, is a 32-bit unsigned
|
|
837
|
+
// integer field. See the comment in CHECKLOCKTIMEVERIFY
|
|
838
|
+
// regarding 5-byte numeric operands.
|
|
839
|
+
|
|
840
|
+
var nSequence = BN.fromScriptNumBuffer(stacktop(-1), fRequireMinimal, 5)
|
|
841
|
+
|
|
842
|
+
// In the rare event that the argument may be < 0 due to
|
|
843
|
+
// some arithmetic being done first, you can always use
|
|
844
|
+
// 0 MAX CHECKSEQUENCEVERIFY.
|
|
845
|
+
if (nSequence.lt(new BN(0))) {
|
|
846
|
+
this.errstr = 'SCRIPT_ERR_NEGATIVE_LOCKTIME'
|
|
847
|
+
return false
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
// To provide for future soft-fork extensibility, if the
|
|
851
|
+
// operand has the disabled lock-time flag set,
|
|
852
|
+
// CHECKSEQUENCEVERIFY behaves as a NOP.
|
|
853
|
+
if ((nSequence &
|
|
854
|
+
Interpreter.SEQUENCE_LOCKTIME_DISABLE_FLAG) !== 0) {
|
|
855
|
+
break
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
// Actually compare the specified lock time with the transaction.
|
|
859
|
+
if (!this.checkSequence(nSequence)) {
|
|
860
|
+
this.errstr = 'SCRIPT_ERR_UNSATISFIED_LOCKTIME'
|
|
861
|
+
return false
|
|
862
|
+
}
|
|
863
|
+
break
|
|
864
|
+
|
|
865
|
+
case Opcode.OP_NOP1:
|
|
866
|
+
case Opcode.OP_NOP4:
|
|
867
|
+
case Opcode.OP_NOP5:
|
|
868
|
+
case Opcode.OP_NOP6:
|
|
869
|
+
case Opcode.OP_NOP7:
|
|
870
|
+
case Opcode.OP_NOP8:
|
|
871
|
+
case Opcode.OP_NOP9:
|
|
872
|
+
case Opcode.OP_NOP10:
|
|
873
|
+
if (this.flags & Interpreter.SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) {
|
|
874
|
+
this.errstr = 'SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS'
|
|
875
|
+
return false
|
|
876
|
+
}
|
|
877
|
+
break
|
|
878
|
+
|
|
879
|
+
case Opcode.OP_IF:
|
|
880
|
+
case Opcode.OP_NOTIF:
|
|
881
|
+
// <expression> if [statements] [else [statements]] endif
|
|
882
|
+
// bool fValue = false;
|
|
883
|
+
fValue = false
|
|
884
|
+
if (fExec) {
|
|
885
|
+
if (this.stack.length < 1) {
|
|
886
|
+
this.errstr = 'SCRIPT_ERR_UNBALANCED_CONDITIONAL'
|
|
887
|
+
return false
|
|
888
|
+
}
|
|
889
|
+
buf = stacktop(-1)
|
|
890
|
+
|
|
891
|
+
if (this.flags & Interpreter.SCRIPT_VERIFY_MINIMALIF) {
|
|
892
|
+
if (buf.length > 1) {
|
|
893
|
+
this.errstr = 'SCRIPT_ERR_MINIMALIF'
|
|
894
|
+
return false
|
|
895
|
+
}
|
|
896
|
+
if (buf.length === 1 && buf[0] !== 1) {
|
|
897
|
+
this.errstr = 'SCRIPT_ERR_MINIMALIF'
|
|
898
|
+
return false
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
fValue = Interpreter.castToBool(buf)
|
|
902
|
+
if (opcodenum === Opcode.OP_NOTIF) {
|
|
903
|
+
fValue = !fValue
|
|
904
|
+
}
|
|
905
|
+
this.stack.pop()
|
|
906
|
+
}
|
|
907
|
+
this.vfExec.push(fValue)
|
|
908
|
+
break
|
|
909
|
+
|
|
910
|
+
case Opcode.OP_ELSE:
|
|
911
|
+
if (this.vfExec.length === 0) {
|
|
912
|
+
this.errstr = 'SCRIPT_ERR_UNBALANCED_CONDITIONAL'
|
|
913
|
+
return false
|
|
914
|
+
}
|
|
915
|
+
this.vfExec[this.vfExec.length - 1] = !this.vfExec[this.vfExec.length - 1]
|
|
916
|
+
break
|
|
917
|
+
|
|
918
|
+
case Opcode.OP_ENDIF:
|
|
919
|
+
if (this.vfExec.length === 0) {
|
|
920
|
+
this.errstr = 'SCRIPT_ERR_UNBALANCED_CONDITIONAL'
|
|
921
|
+
return false
|
|
922
|
+
}
|
|
923
|
+
this.vfExec.pop()
|
|
924
|
+
break
|
|
925
|
+
|
|
926
|
+
case Opcode.OP_VERIFY:
|
|
927
|
+
// (true -- ) or
|
|
928
|
+
// (false -- false) and return
|
|
929
|
+
if (this.stack.length < 1) {
|
|
930
|
+
this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
|
|
931
|
+
return false
|
|
932
|
+
}
|
|
933
|
+
buf = stacktop(-1)
|
|
934
|
+
fValue = Interpreter.castToBool(buf)
|
|
935
|
+
if (fValue) {
|
|
936
|
+
this.stack.pop()
|
|
937
|
+
} else {
|
|
938
|
+
this.errstr = 'SCRIPT_ERR_VERIFY'
|
|
939
|
+
return false
|
|
940
|
+
}
|
|
941
|
+
break
|
|
942
|
+
|
|
943
|
+
case Opcode.OP_RETURN:
|
|
944
|
+
this.errstr = 'SCRIPT_ERR_OP_RETURN'
|
|
945
|
+
return false
|
|
946
|
+
// break // unreachable
|
|
947
|
+
|
|
948
|
+
//
|
|
949
|
+
// Stack ops
|
|
950
|
+
//
|
|
951
|
+
case Opcode.OP_TOALTSTACK:
|
|
952
|
+
if (this.stack.length < 1) {
|
|
953
|
+
this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
|
|
954
|
+
return false
|
|
955
|
+
}
|
|
956
|
+
this.altstack.push(this.stack.pop())
|
|
957
|
+
break
|
|
958
|
+
|
|
959
|
+
case Opcode.OP_FROMALTSTACK:
|
|
960
|
+
if (this.altstack.length < 1) {
|
|
961
|
+
this.errstr = 'SCRIPT_ERR_INVALID_ALTSTACK_OPERATION'
|
|
962
|
+
return false
|
|
963
|
+
}
|
|
964
|
+
this.stack.push(this.altstack.pop())
|
|
965
|
+
break
|
|
966
|
+
|
|
967
|
+
case Opcode.OP_2DROP:
|
|
968
|
+
// (x1 x2 -- )
|
|
969
|
+
if (this.stack.length < 2) {
|
|
970
|
+
this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
|
|
971
|
+
return false
|
|
972
|
+
}
|
|
973
|
+
this.stack.pop()
|
|
974
|
+
this.stack.pop()
|
|
975
|
+
break
|
|
976
|
+
|
|
977
|
+
case Opcode.OP_2DUP:
|
|
978
|
+
// (x1 x2 -- x1 x2 x1 x2)
|
|
979
|
+
if (this.stack.length < 2) {
|
|
980
|
+
this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
|
|
981
|
+
return false
|
|
982
|
+
}
|
|
983
|
+
buf1 = stacktop(-2)
|
|
984
|
+
buf2 = stacktop(-1)
|
|
985
|
+
this.stack.push(Buffer.from(buf1))
|
|
986
|
+
this.stack.push(Buffer.from(buf2))
|
|
987
|
+
break
|
|
988
|
+
|
|
989
|
+
case Opcode.OP_3DUP:
|
|
990
|
+
// (x1 x2 x3 -- x1 x2 x3 x1 x2 x3)
|
|
991
|
+
if (this.stack.length < 3) {
|
|
992
|
+
this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
|
|
993
|
+
return false
|
|
994
|
+
}
|
|
995
|
+
buf1 = stacktop(-3)
|
|
996
|
+
buf2 = stacktop(-2)
|
|
997
|
+
var buf3 = stacktop(-1)
|
|
998
|
+
this.stack.push(Buffer.from(buf1))
|
|
999
|
+
this.stack.push(Buffer.from(buf2))
|
|
1000
|
+
this.stack.push(Buffer.from(buf3))
|
|
1001
|
+
break
|
|
1002
|
+
|
|
1003
|
+
case Opcode.OP_2OVER:
|
|
1004
|
+
// (x1 x2 x3 x4 -- x1 x2 x3 x4 x1 x2)
|
|
1005
|
+
if (this.stack.length < 4) {
|
|
1006
|
+
this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
|
|
1007
|
+
return false
|
|
1008
|
+
}
|
|
1009
|
+
buf1 = stacktop(-4)
|
|
1010
|
+
buf2 = stacktop(-3)
|
|
1011
|
+
this.stack.push(Buffer.from(buf1))
|
|
1012
|
+
this.stack.push(Buffer.from(buf2))
|
|
1013
|
+
break
|
|
1014
|
+
|
|
1015
|
+
case Opcode.OP_2ROT:
|
|
1016
|
+
// (x1 x2 x3 x4 x5 x6 -- x3 x4 x5 x6 x1 x2)
|
|
1017
|
+
if (this.stack.length < 6) {
|
|
1018
|
+
this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
|
|
1019
|
+
return false
|
|
1020
|
+
}
|
|
1021
|
+
spliced = this.stack.splice(this.stack.length - 6, 2)
|
|
1022
|
+
this.stack.push(spliced[0])
|
|
1023
|
+
this.stack.push(spliced[1])
|
|
1024
|
+
break
|
|
1025
|
+
|
|
1026
|
+
case Opcode.OP_2SWAP:
|
|
1027
|
+
// (x1 x2 x3 x4 -- x3 x4 x1 x2)
|
|
1028
|
+
if (this.stack.length < 4) {
|
|
1029
|
+
this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
|
|
1030
|
+
return false
|
|
1031
|
+
}
|
|
1032
|
+
spliced = this.stack.splice(this.stack.length - 4, 2)
|
|
1033
|
+
this.stack.push(spliced[0])
|
|
1034
|
+
this.stack.push(spliced[1])
|
|
1035
|
+
break
|
|
1036
|
+
|
|
1037
|
+
case Opcode.OP_IFDUP:
|
|
1038
|
+
// (x - 0 | x x)
|
|
1039
|
+
if (this.stack.length < 1) {
|
|
1040
|
+
this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
|
|
1041
|
+
return false
|
|
1042
|
+
}
|
|
1043
|
+
buf = stacktop(-1)
|
|
1044
|
+
fValue = Interpreter.castToBool(buf)
|
|
1045
|
+
if (fValue) {
|
|
1046
|
+
this.stack.push(Buffer.from(buf))
|
|
1047
|
+
}
|
|
1048
|
+
break
|
|
1049
|
+
|
|
1050
|
+
case Opcode.OP_DEPTH:
|
|
1051
|
+
// -- stacksize
|
|
1052
|
+
buf = new BN(this.stack.length).toScriptNumBuffer()
|
|
1053
|
+
this.stack.push(buf)
|
|
1054
|
+
break
|
|
1055
|
+
|
|
1056
|
+
case Opcode.OP_DROP:
|
|
1057
|
+
// (x -- )
|
|
1058
|
+
if (this.stack.length < 1) {
|
|
1059
|
+
this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
|
|
1060
|
+
return false
|
|
1061
|
+
}
|
|
1062
|
+
this.stack.pop()
|
|
1063
|
+
break
|
|
1064
|
+
|
|
1065
|
+
case Opcode.OP_DUP:
|
|
1066
|
+
// (x -- x x)
|
|
1067
|
+
if (this.stack.length < 1) {
|
|
1068
|
+
this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
|
|
1069
|
+
return false
|
|
1070
|
+
}
|
|
1071
|
+
this.stack.push(Buffer.from(stacktop(-1)))
|
|
1072
|
+
break
|
|
1073
|
+
|
|
1074
|
+
case Opcode.OP_NIP:
|
|
1075
|
+
// (x1 x2 -- x2)
|
|
1076
|
+
if (this.stack.length < 2) {
|
|
1077
|
+
this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
|
|
1078
|
+
return false
|
|
1079
|
+
}
|
|
1080
|
+
this.stack.splice(this.stack.length - 2, 1)
|
|
1081
|
+
break
|
|
1082
|
+
|
|
1083
|
+
case Opcode.OP_OVER:
|
|
1084
|
+
// (x1 x2 -- x1 x2 x1)
|
|
1085
|
+
if (this.stack.length < 2) {
|
|
1086
|
+
this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
|
|
1087
|
+
return false
|
|
1088
|
+
}
|
|
1089
|
+
this.stack.push(Buffer.from(stacktop(-2)))
|
|
1090
|
+
break
|
|
1091
|
+
|
|
1092
|
+
case Opcode.OP_PICK:
|
|
1093
|
+
case Opcode.OP_ROLL:
|
|
1094
|
+
// (xn ... x2 x1 x0 n - xn ... x2 x1 x0 xn)
|
|
1095
|
+
// (xn ... x2 x1 x0 n - ... x2 x1 x0 xn)
|
|
1096
|
+
if (this.stack.length < 2) {
|
|
1097
|
+
this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
|
|
1098
|
+
return false
|
|
1099
|
+
}
|
|
1100
|
+
buf = stacktop(-1)
|
|
1101
|
+
bn = BN.fromScriptNumBuffer(buf, fRequireMinimal)
|
|
1102
|
+
n = bn.toNumber()
|
|
1103
|
+
this.stack.pop()
|
|
1104
|
+
if (n < 0 || n >= this.stack.length) {
|
|
1105
|
+
this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
|
|
1106
|
+
return false
|
|
1107
|
+
}
|
|
1108
|
+
buf = stacktop(-n - 1)
|
|
1109
|
+
if (opcodenum === Opcode.OP_ROLL) {
|
|
1110
|
+
this.stack.splice(this.stack.length - n - 1, 1)
|
|
1111
|
+
}
|
|
1112
|
+
this.stack.push(Buffer.from(buf))
|
|
1113
|
+
break
|
|
1114
|
+
|
|
1115
|
+
case Opcode.OP_ROT:
|
|
1116
|
+
// (x1 x2 x3 -- x2 x3 x1)
|
|
1117
|
+
// x2 x1 x3 after first swap
|
|
1118
|
+
// x2 x3 x1 after second swap
|
|
1119
|
+
if (this.stack.length < 3) {
|
|
1120
|
+
this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
|
|
1121
|
+
return false
|
|
1122
|
+
}
|
|
1123
|
+
x1 = stacktop(-3)
|
|
1124
|
+
x2 = stacktop(-2)
|
|
1125
|
+
var x3 = stacktop(-1)
|
|
1126
|
+
this.stack[this.stack.length - 3] = x2
|
|
1127
|
+
this.stack[this.stack.length - 2] = x3
|
|
1128
|
+
this.stack[this.stack.length - 1] = x1
|
|
1129
|
+
break
|
|
1130
|
+
|
|
1131
|
+
case Opcode.OP_SWAP:
|
|
1132
|
+
// (x1 x2 -- x2 x1)
|
|
1133
|
+
if (this.stack.length < 2) {
|
|
1134
|
+
this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
|
|
1135
|
+
return false
|
|
1136
|
+
}
|
|
1137
|
+
x1 = stacktop(-2)
|
|
1138
|
+
x2 = stacktop(-1)
|
|
1139
|
+
this.stack[this.stack.length - 2] = x2
|
|
1140
|
+
this.stack[this.stack.length - 1] = x1
|
|
1141
|
+
break
|
|
1142
|
+
|
|
1143
|
+
case Opcode.OP_TUCK:
|
|
1144
|
+
// (x1 x2 -- x2 x1 x2)
|
|
1145
|
+
if (this.stack.length < 2) {
|
|
1146
|
+
this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
|
|
1147
|
+
return false
|
|
1148
|
+
}
|
|
1149
|
+
this.stack.splice(this.stack.length - 2, 0, Buffer.from(stacktop(-1)))
|
|
1150
|
+
break
|
|
1151
|
+
|
|
1152
|
+
case Opcode.OP_SIZE:
|
|
1153
|
+
// (in -- in size)
|
|
1154
|
+
if (this.stack.length < 1) {
|
|
1155
|
+
this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
|
|
1156
|
+
return false
|
|
1157
|
+
}
|
|
1158
|
+
bn = new BN(stacktop(-1).length)
|
|
1159
|
+
this.stack.push(bn.toScriptNumBuffer())
|
|
1160
|
+
break
|
|
1161
|
+
|
|
1162
|
+
//
|
|
1163
|
+
// Bitwise logic
|
|
1164
|
+
//
|
|
1165
|
+
case Opcode.OP_AND:
|
|
1166
|
+
case Opcode.OP_OR:
|
|
1167
|
+
case Opcode.OP_XOR:
|
|
1168
|
+
// (x1 x2 - out)
|
|
1169
|
+
if (this.stack.length < 2) {
|
|
1170
|
+
this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
|
|
1171
|
+
return false
|
|
1172
|
+
}
|
|
1173
|
+
buf1 = stacktop(-2)
|
|
1174
|
+
buf2 = stacktop(-1)
|
|
1175
|
+
|
|
1176
|
+
// Inputs must be the same size
|
|
1177
|
+
if (buf1.length !== buf2.length) {
|
|
1178
|
+
this.errstr = 'SCRIPT_ERR_INVALID_OPERAND_SIZE'
|
|
1179
|
+
return false
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1182
|
+
// To avoid allocating, we modify vch1 in place.
|
|
1183
|
+
switch (opcodenum) {
|
|
1184
|
+
case Opcode.OP_AND:
|
|
1185
|
+
for (let i = 0; i < buf1.length; i++) {
|
|
1186
|
+
buf1[i] &= buf2[i]
|
|
1187
|
+
}
|
|
1188
|
+
break
|
|
1189
|
+
case Opcode.OP_OR:
|
|
1190
|
+
for (let i = 0; i < buf1.length; i++) {
|
|
1191
|
+
buf1[i] |= buf2[i]
|
|
1192
|
+
}
|
|
1193
|
+
break
|
|
1194
|
+
case Opcode.OP_XOR:
|
|
1195
|
+
for (let i = 0; i < buf1.length; i++) {
|
|
1196
|
+
buf1[i] ^= buf2[i]
|
|
1197
|
+
}
|
|
1198
|
+
break
|
|
1199
|
+
default:
|
|
1200
|
+
break
|
|
1201
|
+
}
|
|
1202
|
+
|
|
1203
|
+
// And pop vch2.
|
|
1204
|
+
this.stack.pop()
|
|
1205
|
+
break
|
|
1206
|
+
|
|
1207
|
+
case Opcode.OP_INVERT:
|
|
1208
|
+
// (x -- out)
|
|
1209
|
+
if (this.stack.length < 1) {
|
|
1210
|
+
this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
|
|
1211
|
+
}
|
|
1212
|
+
buf = stacktop(-1)
|
|
1213
|
+
for (let i = 0; i < buf.length; i++) {
|
|
1214
|
+
buf[i] = ~buf[i]
|
|
1215
|
+
}
|
|
1216
|
+
break
|
|
1217
|
+
|
|
1218
|
+
case Opcode.OP_LSHIFT:
|
|
1219
|
+
case Opcode.OP_RSHIFT:
|
|
1220
|
+
// (x n -- out)
|
|
1221
|
+
if (this.stack.length < 2) {
|
|
1222
|
+
this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
|
|
1223
|
+
return false
|
|
1224
|
+
}
|
|
1225
|
+
buf1 = stacktop(-2)
|
|
1226
|
+
if (buf1.length === 0) {
|
|
1227
|
+
this.stack.pop()
|
|
1228
|
+
} else {
|
|
1229
|
+
bn1 = new BN(buf1)
|
|
1230
|
+
bn2 = BN.fromScriptNumBuffer(stacktop(-1), fRequireMinimal)
|
|
1231
|
+
n = bn2.toNumber()
|
|
1232
|
+
if (n < 0) {
|
|
1233
|
+
this.errstr = 'SCRIPT_ERR_INVALID_NUMBER_RANGE'
|
|
1234
|
+
return false
|
|
1235
|
+
}
|
|
1236
|
+
this.stack.pop()
|
|
1237
|
+
this.stack.pop()
|
|
1238
|
+
let shifted
|
|
1239
|
+
if (opcodenum === Opcode.OP_LSHIFT) {
|
|
1240
|
+
shifted = bn1.ushln(n)
|
|
1241
|
+
}
|
|
1242
|
+
if (opcodenum === Opcode.OP_RSHIFT) {
|
|
1243
|
+
shifted = bn1.ushrn(n)
|
|
1244
|
+
}
|
|
1245
|
+
// bitcoin client implementation of l/rshift is unconventional, therefore this implementation is a bit unconventional
|
|
1246
|
+
// bn library has shift functions however it expands the carried bits into a new byte
|
|
1247
|
+
// in contrast to the bitcoin client implementation which drops off the carried bits
|
|
1248
|
+
// in other words, if operand was 1 byte then we put 1 byte back on the stack instead of expanding to more shifted bytes
|
|
1249
|
+
let bufShifted = padBufferToSize(Buffer.from(shifted.toArray().slice(buf1.length * -1)), buf1.length)
|
|
1250
|
+
this.stack.push(bufShifted)
|
|
1251
|
+
}
|
|
1252
|
+
break
|
|
1253
|
+
|
|
1254
|
+
case Opcode.OP_EQUAL:
|
|
1255
|
+
case Opcode.OP_EQUALVERIFY:
|
|
1256
|
+
// case Opcode.OP_NOTEQUAL: // use Opcode.OP_NUMNOTEQUAL
|
|
1257
|
+
// (x1 x2 - bool)
|
|
1258
|
+
if (this.stack.length < 2) {
|
|
1259
|
+
this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
|
|
1260
|
+
return false
|
|
1261
|
+
}
|
|
1262
|
+
buf1 = stacktop(-2)
|
|
1263
|
+
buf2 = stacktop(-1)
|
|
1264
|
+
var fEqual = buf1.toString('hex') === buf2.toString('hex')
|
|
1265
|
+
this.stack.pop()
|
|
1266
|
+
this.stack.pop()
|
|
1267
|
+
this.stack.push(fEqual ? Interpreter.true : Interpreter.false)
|
|
1268
|
+
if (opcodenum === Opcode.OP_EQUALVERIFY) {
|
|
1269
|
+
if (fEqual) {
|
|
1270
|
+
this.stack.pop()
|
|
1271
|
+
} else {
|
|
1272
|
+
this.errstr = 'SCRIPT_ERR_EQUALVERIFY'
|
|
1273
|
+
return false
|
|
1274
|
+
}
|
|
1275
|
+
}
|
|
1276
|
+
break
|
|
1277
|
+
|
|
1278
|
+
//
|
|
1279
|
+
// Numeric
|
|
1280
|
+
//
|
|
1281
|
+
case Opcode.OP_1ADD:
|
|
1282
|
+
case Opcode.OP_1SUB:
|
|
1283
|
+
case Opcode.OP_NEGATE:
|
|
1284
|
+
case Opcode.OP_ABS:
|
|
1285
|
+
case Opcode.OP_NOT:
|
|
1286
|
+
case Opcode.OP_0NOTEQUAL:
|
|
1287
|
+
// (in -- out)
|
|
1288
|
+
if (this.stack.length < 1) {
|
|
1289
|
+
this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
|
|
1290
|
+
return false
|
|
1291
|
+
}
|
|
1292
|
+
buf = stacktop(-1)
|
|
1293
|
+
bn = BN.fromScriptNumBuffer(buf, fRequireMinimal)
|
|
1294
|
+
switch (opcodenum) {
|
|
1295
|
+
case Opcode.OP_1ADD:
|
|
1296
|
+
bn = bn.add(BN.One)
|
|
1297
|
+
break
|
|
1298
|
+
case Opcode.OP_1SUB:
|
|
1299
|
+
bn = bn.sub(BN.One)
|
|
1300
|
+
break
|
|
1301
|
+
case Opcode.OP_NEGATE:
|
|
1302
|
+
bn = bn.neg()
|
|
1303
|
+
break
|
|
1304
|
+
case Opcode.OP_ABS:
|
|
1305
|
+
if (bn.cmp(BN.Zero) < 0) {
|
|
1306
|
+
bn = bn.neg()
|
|
1307
|
+
}
|
|
1308
|
+
break
|
|
1309
|
+
case Opcode.OP_NOT:
|
|
1310
|
+
bn = new BN((bn.cmp(BN.Zero) === 0) + 0)
|
|
1311
|
+
break
|
|
1312
|
+
case Opcode.OP_0NOTEQUAL:
|
|
1313
|
+
bn = new BN((bn.cmp(BN.Zero) !== 0) + 0)
|
|
1314
|
+
break
|
|
1315
|
+
// default: assert(!'invalid opcode'); break; // TODO: does this ever occur?
|
|
1316
|
+
}
|
|
1317
|
+
this.stack.pop()
|
|
1318
|
+
this.stack.push(bn.toScriptNumBuffer())
|
|
1319
|
+
break
|
|
1320
|
+
|
|
1321
|
+
case Opcode.OP_ADD:
|
|
1322
|
+
case Opcode.OP_SUB:
|
|
1323
|
+
case Opcode.OP_MUL:
|
|
1324
|
+
case Opcode.OP_MOD:
|
|
1325
|
+
case Opcode.OP_DIV:
|
|
1326
|
+
case Opcode.OP_BOOLAND:
|
|
1327
|
+
case Opcode.OP_BOOLOR:
|
|
1328
|
+
case Opcode.OP_NUMEQUAL:
|
|
1329
|
+
case Opcode.OP_NUMEQUALVERIFY:
|
|
1330
|
+
case Opcode.OP_NUMNOTEQUAL:
|
|
1331
|
+
case Opcode.OP_LESSTHAN:
|
|
1332
|
+
case Opcode.OP_GREATERTHAN:
|
|
1333
|
+
case Opcode.OP_LESSTHANOREQUAL:
|
|
1334
|
+
case Opcode.OP_GREATERTHANOREQUAL:
|
|
1335
|
+
case Opcode.OP_MIN:
|
|
1336
|
+
case Opcode.OP_MAX:
|
|
1337
|
+
// (x1 x2 -- out)
|
|
1338
|
+
if (this.stack.length < 2) {
|
|
1339
|
+
this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
|
|
1340
|
+
return false
|
|
1341
|
+
}
|
|
1342
|
+
bn1 = BN.fromScriptNumBuffer(stacktop(-2), fRequireMinimal)
|
|
1343
|
+
bn2 = BN.fromScriptNumBuffer(stacktop(-1), fRequireMinimal)
|
|
1344
|
+
bn = new BN(0)
|
|
1345
|
+
|
|
1346
|
+
switch (opcodenum) {
|
|
1347
|
+
case Opcode.OP_ADD:
|
|
1348
|
+
bn = bn1.add(bn2)
|
|
1349
|
+
break
|
|
1350
|
+
|
|
1351
|
+
case Opcode.OP_SUB:
|
|
1352
|
+
bn = bn1.sub(bn2)
|
|
1353
|
+
break
|
|
1354
|
+
|
|
1355
|
+
case Opcode.OP_MUL:
|
|
1356
|
+
bn = bn1.mul(bn2)
|
|
1357
|
+
break
|
|
1358
|
+
|
|
1359
|
+
case Opcode.OP_DIV:
|
|
1360
|
+
// denominator must not be 0
|
|
1361
|
+
if (bn2 === 0) {
|
|
1362
|
+
this.errstr = 'SCRIPT_ERR_DIV_BY_ZERO'
|
|
1363
|
+
return false
|
|
1364
|
+
}
|
|
1365
|
+
bn = bn1.div(bn2)
|
|
1366
|
+
break
|
|
1367
|
+
|
|
1368
|
+
case Opcode.OP_MOD:
|
|
1369
|
+
// divisor must not be 0
|
|
1370
|
+
if (bn2 === 0) {
|
|
1371
|
+
this.errstr = 'SCRIPT_ERR_DIV_BY_ZERO'
|
|
1372
|
+
return false
|
|
1373
|
+
}
|
|
1374
|
+
bn = bn1.mod(bn2)
|
|
1375
|
+
break
|
|
1376
|
+
|
|
1377
|
+
case Opcode.OP_BOOLAND:
|
|
1378
|
+
bn = new BN(((bn1.cmp(BN.Zero) !== 0) && (bn2.cmp(BN.Zero) !== 0)) + 0)
|
|
1379
|
+
break
|
|
1380
|
+
// case Opcode.OP_BOOLOR: bn = (bn1 !== bnZero || bn2 !== bnZero); break;
|
|
1381
|
+
case Opcode.OP_BOOLOR:
|
|
1382
|
+
bn = new BN(((bn1.cmp(BN.Zero) !== 0) || (bn2.cmp(BN.Zero) !== 0)) + 0)
|
|
1383
|
+
break
|
|
1384
|
+
// case Opcode.OP_NUMEQUAL: bn = (bn1 === bn2); break;
|
|
1385
|
+
case Opcode.OP_NUMEQUAL:
|
|
1386
|
+
bn = new BN((bn1.cmp(bn2) === 0) + 0)
|
|
1387
|
+
break
|
|
1388
|
+
// case Opcode.OP_NUMEQUALVERIFY: bn = (bn1 === bn2); break;
|
|
1389
|
+
case Opcode.OP_NUMEQUALVERIFY:
|
|
1390
|
+
bn = new BN((bn1.cmp(bn2) === 0) + 0)
|
|
1391
|
+
break
|
|
1392
|
+
// case Opcode.OP_NUMNOTEQUAL: bn = (bn1 !== bn2); break;
|
|
1393
|
+
case Opcode.OP_NUMNOTEQUAL:
|
|
1394
|
+
bn = new BN((bn1.cmp(bn2) !== 0) + 0)
|
|
1395
|
+
break
|
|
1396
|
+
// case Opcode.OP_LESSTHAN: bn = (bn1 < bn2); break;
|
|
1397
|
+
case Opcode.OP_LESSTHAN:
|
|
1398
|
+
bn = new BN((bn1.cmp(bn2) < 0) + 0)
|
|
1399
|
+
break
|
|
1400
|
+
// case Opcode.OP_GREATERTHAN: bn = (bn1 > bn2); break;
|
|
1401
|
+
case Opcode.OP_GREATERTHAN:
|
|
1402
|
+
bn = new BN((bn1.cmp(bn2) > 0) + 0)
|
|
1403
|
+
break
|
|
1404
|
+
// case Opcode.OP_LESSTHANOREQUAL: bn = (bn1 <= bn2); break;
|
|
1405
|
+
case Opcode.OP_LESSTHANOREQUAL:
|
|
1406
|
+
bn = new BN((bn1.cmp(bn2) <= 0) + 0)
|
|
1407
|
+
break
|
|
1408
|
+
// case Opcode.OP_GREATERTHANOREQUAL: bn = (bn1 >= bn2); break;
|
|
1409
|
+
case Opcode.OP_GREATERTHANOREQUAL:
|
|
1410
|
+
bn = new BN((bn1.cmp(bn2) >= 0) + 0)
|
|
1411
|
+
break
|
|
1412
|
+
case Opcode.OP_MIN:
|
|
1413
|
+
bn = (bn1.cmp(bn2) < 0 ? bn1 : bn2)
|
|
1414
|
+
break
|
|
1415
|
+
case Opcode.OP_MAX:
|
|
1416
|
+
bn = (bn1.cmp(bn2) > 0 ? bn1 : bn2)
|
|
1417
|
+
break
|
|
1418
|
+
// default: assert(!'invalid opcode'); break; //TODO: does this ever occur?
|
|
1419
|
+
}
|
|
1420
|
+
this.stack.pop()
|
|
1421
|
+
this.stack.pop()
|
|
1422
|
+
this.stack.push(bn.toScriptNumBuffer())
|
|
1423
|
+
|
|
1424
|
+
if (opcodenum === Opcode.OP_NUMEQUALVERIFY) {
|
|
1425
|
+
// if (CastToBool(stacktop(-1)))
|
|
1426
|
+
if (Interpreter.castToBool(stacktop(-1))) {
|
|
1427
|
+
this.stack.pop()
|
|
1428
|
+
} else {
|
|
1429
|
+
this.errstr = 'SCRIPT_ERR_NUMEQUALVERIFY'
|
|
1430
|
+
return false
|
|
1431
|
+
}
|
|
1432
|
+
}
|
|
1433
|
+
break
|
|
1434
|
+
|
|
1435
|
+
case Opcode.OP_WITHIN:
|
|
1436
|
+
// (x min max -- out)
|
|
1437
|
+
if (this.stack.length < 3) {
|
|
1438
|
+
this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
|
|
1439
|
+
return false
|
|
1440
|
+
}
|
|
1441
|
+
bn1 = BN.fromScriptNumBuffer(stacktop(-3), fRequireMinimal)
|
|
1442
|
+
bn2 = BN.fromScriptNumBuffer(stacktop(-2), fRequireMinimal)
|
|
1443
|
+
var bn3 = BN.fromScriptNumBuffer(stacktop(-1), fRequireMinimal)
|
|
1444
|
+
// bool fValue = (bn2 <= bn1 && bn1 < bn3);
|
|
1445
|
+
fValue = (bn2.cmp(bn1) <= 0) && (bn1.cmp(bn3) < 0)
|
|
1446
|
+
this.stack.pop()
|
|
1447
|
+
this.stack.pop()
|
|
1448
|
+
this.stack.pop()
|
|
1449
|
+
this.stack.push(fValue ? Interpreter.true : Interpreter.false)
|
|
1450
|
+
break
|
|
1451
|
+
|
|
1452
|
+
//
|
|
1453
|
+
// Crypto
|
|
1454
|
+
//
|
|
1455
|
+
case Opcode.OP_RIPEMD160:
|
|
1456
|
+
case Opcode.OP_SHA1:
|
|
1457
|
+
case Opcode.OP_SHA256:
|
|
1458
|
+
case Opcode.OP_HASH160:
|
|
1459
|
+
case Opcode.OP_HASH256:
|
|
1460
|
+
// (in -- hash)
|
|
1461
|
+
if (this.stack.length < 1) {
|
|
1462
|
+
this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
|
|
1463
|
+
return false
|
|
1464
|
+
}
|
|
1465
|
+
buf = stacktop(-1)
|
|
1466
|
+
// valtype vchHash((opcode === Opcode.OP_RIPEMD160 ||
|
|
1467
|
+
// opcode === Opcode.OP_SHA1 || opcode === Opcode.OP_HASH160) ? 20 : 32);
|
|
1468
|
+
var bufHash
|
|
1469
|
+
if (opcodenum === Opcode.OP_RIPEMD160) {
|
|
1470
|
+
bufHash = Hash.ripemd160(buf)
|
|
1471
|
+
} else if (opcodenum === Opcode.OP_SHA1) {
|
|
1472
|
+
bufHash = Hash.sha1(buf)
|
|
1473
|
+
} else if (opcodenum === Opcode.OP_SHA256) {
|
|
1474
|
+
bufHash = Hash.sha256(buf)
|
|
1475
|
+
} else if (opcodenum === Opcode.OP_HASH160) {
|
|
1476
|
+
bufHash = Hash.sha256ripemd160(buf)
|
|
1477
|
+
} else if (opcodenum === Opcode.OP_HASH256) {
|
|
1478
|
+
bufHash = Hash.sha256sha256(buf)
|
|
1479
|
+
}
|
|
1480
|
+
this.stack.pop()
|
|
1481
|
+
this.stack.push(bufHash)
|
|
1482
|
+
break
|
|
1483
|
+
|
|
1484
|
+
case Opcode.OP_CODESEPARATOR:
|
|
1485
|
+
// Hash starts after the code separator
|
|
1486
|
+
this.pbegincodehash = this.pc
|
|
1487
|
+
break
|
|
1488
|
+
|
|
1489
|
+
case Opcode.OP_CHECKSIG:
|
|
1490
|
+
case Opcode.OP_CHECKSIGVERIFY:
|
|
1491
|
+
// (sig pubkey -- bool)
|
|
1492
|
+
if (this.stack.length < 2) {
|
|
1493
|
+
this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
|
|
1494
|
+
return false
|
|
1495
|
+
}
|
|
1496
|
+
|
|
1497
|
+
bufSig = stacktop(-2)
|
|
1498
|
+
bufPubkey = stacktop(-1)
|
|
1499
|
+
|
|
1500
|
+
if (!this.checkSignatureEncoding(bufSig) || !this.checkPubkeyEncoding(bufPubkey)) {
|
|
1501
|
+
return false
|
|
1502
|
+
}
|
|
1503
|
+
|
|
1504
|
+
// Subset of script starting at the most recent codeseparator
|
|
1505
|
+
// CScript scriptCode(pbegincodehash, pend);
|
|
1506
|
+
subscript = new Script().set({
|
|
1507
|
+
chunks: this.script.chunks.slice(this.pbegincodehash)
|
|
1508
|
+
})
|
|
1509
|
+
|
|
1510
|
+
// Drop the signature, since there's no way for a signature to sign itself
|
|
1511
|
+
var tmpScript = new Script().add(bufSig)
|
|
1512
|
+
subscript.findAndDelete(tmpScript)
|
|
1513
|
+
|
|
1514
|
+
try {
|
|
1515
|
+
sig = Signature.fromTxFormat(bufSig)
|
|
1516
|
+
pubkey = PublicKey.fromBuffer(bufPubkey, false)
|
|
1517
|
+
|
|
1518
|
+
fSuccess = this.tx.verifySignature(sig, pubkey, this.nin, subscript, this.satoshisBN, this.flags)
|
|
1519
|
+
} catch (e) {
|
|
1520
|
+
// invalid sig or pubkey
|
|
1521
|
+
fSuccess = false
|
|
1522
|
+
}
|
|
1523
|
+
|
|
1524
|
+
if (!fSuccess && (this.flags & Interpreter.SCRIPT_VERIFY_NULLFAIL) &&
|
|
1525
|
+
bufSig.length) {
|
|
1526
|
+
this.errstr = 'SCRIPT_ERR_NULLFAIL'
|
|
1527
|
+
return false
|
|
1528
|
+
}
|
|
1529
|
+
|
|
1530
|
+
this.stack.pop()
|
|
1531
|
+
this.stack.pop()
|
|
1532
|
+
|
|
1533
|
+
// stack.push_back(fSuccess ? vchTrue : vchFalse);
|
|
1534
|
+
this.stack.push(fSuccess ? Interpreter.true : Interpreter.false)
|
|
1535
|
+
if (opcodenum === Opcode.OP_CHECKSIGVERIFY) {
|
|
1536
|
+
if (fSuccess) {
|
|
1537
|
+
this.stack.pop()
|
|
1538
|
+
} else {
|
|
1539
|
+
this.errstr = 'SCRIPT_ERR_CHECKSIGVERIFY'
|
|
1540
|
+
return false
|
|
1541
|
+
}
|
|
1542
|
+
}
|
|
1543
|
+
break
|
|
1544
|
+
|
|
1545
|
+
case Opcode.OP_CHECKMULTISIG:
|
|
1546
|
+
case Opcode.OP_CHECKMULTISIGVERIFY:
|
|
1547
|
+
// ([sig ...] num_of_signatures [pubkey ...] num_of_pubkeys -- bool)
|
|
1548
|
+
|
|
1549
|
+
var i = 1
|
|
1550
|
+
if (this.stack.length < i) {
|
|
1551
|
+
this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
|
|
1552
|
+
return false
|
|
1553
|
+
}
|
|
1554
|
+
|
|
1555
|
+
var nKeysCount = BN.fromScriptNumBuffer(stacktop(-i), fRequireMinimal).toNumber()
|
|
1556
|
+
// TODO: Keys and opcount are parameterized in client. No magic numbers!
|
|
1557
|
+
if (nKeysCount < 0 || nKeysCount > 20) {
|
|
1558
|
+
this.errstr = 'SCRIPT_ERR_PUBKEY_COUNT'
|
|
1559
|
+
return false
|
|
1560
|
+
}
|
|
1561
|
+
this.nOpCount += nKeysCount
|
|
1562
|
+
if (this.nOpCount > 201) {
|
|
1563
|
+
this.errstr = 'SCRIPT_ERR_OP_COUNT'
|
|
1564
|
+
return false
|
|
1565
|
+
}
|
|
1566
|
+
// int ikey = ++i;
|
|
1567
|
+
var ikey = ++i
|
|
1568
|
+
i += nKeysCount
|
|
1569
|
+
|
|
1570
|
+
// ikey2 is the position of last non-signature item in
|
|
1571
|
+
// the stack. Top stack item = 1. With
|
|
1572
|
+
// SCRIPT_VERIFY_NULLFAIL, this is used for cleanup if
|
|
1573
|
+
// operation fails.
|
|
1574
|
+
var ikey2 = nKeysCount + 2
|
|
1575
|
+
|
|
1576
|
+
if (this.stack.length < i) {
|
|
1577
|
+
this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
|
|
1578
|
+
return false
|
|
1579
|
+
}
|
|
1580
|
+
|
|
1581
|
+
var nSigsCount = BN.fromScriptNumBuffer(stacktop(-i), fRequireMinimal).toNumber()
|
|
1582
|
+
if (nSigsCount < 0 || nSigsCount > nKeysCount) {
|
|
1583
|
+
this.errstr = 'SCRIPT_ERR_SIG_COUNT'
|
|
1584
|
+
return false
|
|
1585
|
+
}
|
|
1586
|
+
// int isig = ++i;
|
|
1587
|
+
var isig = ++i
|
|
1588
|
+
i += nSigsCount
|
|
1589
|
+
if (this.stack.length < i) {
|
|
1590
|
+
this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
|
|
1591
|
+
return false
|
|
1592
|
+
}
|
|
1593
|
+
|
|
1594
|
+
// Subset of script starting at the most recent codeseparator
|
|
1595
|
+
subscript = new Script().set({
|
|
1596
|
+
chunks: this.script.chunks.slice(this.pbegincodehash)
|
|
1597
|
+
})
|
|
1598
|
+
|
|
1599
|
+
// Drop the signatures, since there's no way for a signature to sign itself
|
|
1600
|
+
for (var k = 0; k < nSigsCount; k++) {
|
|
1601
|
+
bufSig = stacktop(-isig - k)
|
|
1602
|
+
subscript.findAndDelete(new Script().add(bufSig))
|
|
1603
|
+
}
|
|
1604
|
+
|
|
1605
|
+
fSuccess = true
|
|
1606
|
+
while (fSuccess && nSigsCount > 0) {
|
|
1607
|
+
// valtype& vchSig = stacktop(-isig);
|
|
1608
|
+
bufSig = stacktop(-isig)
|
|
1609
|
+
// valtype& vchPubKey = stacktop(-ikey);
|
|
1610
|
+
bufPubkey = stacktop(-ikey)
|
|
1611
|
+
|
|
1612
|
+
if (!this.checkSignatureEncoding(bufSig) || !this.checkPubkeyEncoding(bufPubkey)) {
|
|
1613
|
+
return false
|
|
1614
|
+
}
|
|
1615
|
+
|
|
1616
|
+
var fOk
|
|
1617
|
+
try {
|
|
1618
|
+
sig = Signature.fromTxFormat(bufSig)
|
|
1619
|
+
pubkey = PublicKey.fromBuffer(bufPubkey, false)
|
|
1620
|
+
fOk = this.tx.verifySignature(sig, pubkey, this.nin, subscript, this.satoshisBN, this.flags)
|
|
1621
|
+
} catch (e) {
|
|
1622
|
+
// invalid sig or pubkey
|
|
1623
|
+
fOk = false
|
|
1624
|
+
}
|
|
1625
|
+
|
|
1626
|
+
if (fOk) {
|
|
1627
|
+
isig++
|
|
1628
|
+
nSigsCount--
|
|
1629
|
+
}
|
|
1630
|
+
ikey++
|
|
1631
|
+
nKeysCount--
|
|
1632
|
+
|
|
1633
|
+
// If there are more signatures left than keys left,
|
|
1634
|
+
// then too many signatures have failed
|
|
1635
|
+
if (nSigsCount > nKeysCount) {
|
|
1636
|
+
fSuccess = false
|
|
1637
|
+
}
|
|
1638
|
+
}
|
|
1639
|
+
|
|
1640
|
+
// Clean up stack of actual arguments
|
|
1641
|
+
while (i-- > 1) {
|
|
1642
|
+
if (!fSuccess && (this.flags & Interpreter.SCRIPT_VERIFY_NULLFAIL) &&
|
|
1643
|
+
!ikey2 && stacktop(-1).length) {
|
|
1644
|
+
this.errstr = 'SCRIPT_ERR_NULLFAIL'
|
|
1645
|
+
return false
|
|
1646
|
+
}
|
|
1647
|
+
|
|
1648
|
+
if (ikey2 > 0) {
|
|
1649
|
+
ikey2--
|
|
1650
|
+
}
|
|
1651
|
+
|
|
1652
|
+
this.stack.pop()
|
|
1653
|
+
}
|
|
1654
|
+
|
|
1655
|
+
// A bug causes CHECKMULTISIG to consume one extra argument
|
|
1656
|
+
// whose contents were not checked in any way.
|
|
1657
|
+
//
|
|
1658
|
+
// Unfortunately this is a potential source of mutability,
|
|
1659
|
+
// so optionally verify it is exactly equal to zero prior
|
|
1660
|
+
// to removing it from the stack.
|
|
1661
|
+
if (this.stack.length < 1) {
|
|
1662
|
+
this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
|
|
1663
|
+
return false
|
|
1664
|
+
}
|
|
1665
|
+
if ((this.flags & Interpreter.SCRIPT_VERIFY_NULLDUMMY) && stacktop(-1).length) {
|
|
1666
|
+
this.errstr = 'SCRIPT_ERR_SIG_NULLDUMMY'
|
|
1667
|
+
return false
|
|
1668
|
+
}
|
|
1669
|
+
this.stack.pop()
|
|
1670
|
+
|
|
1671
|
+
this.stack.push(fSuccess ? Interpreter.true : Interpreter.false)
|
|
1672
|
+
|
|
1673
|
+
if (opcodenum === Opcode.OP_CHECKMULTISIGVERIFY) {
|
|
1674
|
+
if (fSuccess) {
|
|
1675
|
+
this.stack.pop()
|
|
1676
|
+
} else {
|
|
1677
|
+
this.errstr = 'SCRIPT_ERR_CHECKMULTISIGVERIFY'
|
|
1678
|
+
return false
|
|
1679
|
+
}
|
|
1680
|
+
}
|
|
1681
|
+
break
|
|
1682
|
+
|
|
1683
|
+
//
|
|
1684
|
+
// Byte string operations
|
|
1685
|
+
//
|
|
1686
|
+
case Opcode.OP_CAT:
|
|
1687
|
+
if (this.stack.length < 2) {
|
|
1688
|
+
this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
|
|
1689
|
+
return false
|
|
1690
|
+
}
|
|
1691
|
+
|
|
1692
|
+
buf1 = stacktop(-2)
|
|
1693
|
+
buf2 = stacktop(-1)
|
|
1694
|
+
if (buf1.length + buf2.length > Interpreter.MAX_SCRIPT_ELEMENT_SIZE) {
|
|
1695
|
+
this.errstr = 'SCRIPT_ERR_PUSH_SIZE'
|
|
1696
|
+
return false
|
|
1697
|
+
}
|
|
1698
|
+
this.stack[this.stack.length - 2] = Buffer.concat([buf1, buf2])
|
|
1699
|
+
this.stack.pop()
|
|
1700
|
+
break
|
|
1701
|
+
|
|
1702
|
+
case Opcode.OP_SPLIT:
|
|
1703
|
+
if (this.stack.length < 2) {
|
|
1704
|
+
this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
|
|
1705
|
+
return false
|
|
1706
|
+
}
|
|
1707
|
+
buf1 = stacktop(-2)
|
|
1708
|
+
|
|
1709
|
+
// Make sure the split point is apropriate.
|
|
1710
|
+
var position = BN.fromScriptNumBuffer(stacktop(-1), fRequireMinimal).toNumber()
|
|
1711
|
+
if (position < 0 || position > buf1.length) {
|
|
1712
|
+
this.errstr = 'SCRIPT_ERR_INVALID_SPLIT_RANGE'
|
|
1713
|
+
return false
|
|
1714
|
+
}
|
|
1715
|
+
|
|
1716
|
+
// Prepare the results in their own buffer as `data`
|
|
1717
|
+
// will be invalidated.
|
|
1718
|
+
// Copy buffer data, to slice it before
|
|
1719
|
+
var n1 = Buffer.from(buf1)
|
|
1720
|
+
|
|
1721
|
+
// Replace existing stack values by the new values.
|
|
1722
|
+
this.stack[this.stack.length - 2] = n1.slice(0, position)
|
|
1723
|
+
this.stack[this.stack.length - 1] = n1.slice(position)
|
|
1724
|
+
break
|
|
1725
|
+
|
|
1726
|
+
//
|
|
1727
|
+
// Conversion operations
|
|
1728
|
+
//
|
|
1729
|
+
case Opcode.OP_NUM2BIN:
|
|
1730
|
+
// (in -- out)
|
|
1731
|
+
if (this.stack.length < 2) {
|
|
1732
|
+
this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
|
|
1733
|
+
return false
|
|
1734
|
+
}
|
|
1735
|
+
|
|
1736
|
+
var size = BN.fromScriptNumBuffer(stacktop(-1), fRequireMinimal).toNumber()
|
|
1737
|
+
if (size > Interpreter.MAX_SCRIPT_ELEMENT_SIZE) {
|
|
1738
|
+
this.errstr = 'SCRIPT_ERR_PUSH_SIZE'
|
|
1739
|
+
return false
|
|
1740
|
+
}
|
|
1741
|
+
|
|
1742
|
+
this.stack.pop()
|
|
1743
|
+
var rawnum = stacktop(-1)
|
|
1744
|
+
|
|
1745
|
+
// Try to see if we can fit that number in the number of
|
|
1746
|
+
// byte requested.
|
|
1747
|
+
rawnum = Interpreter._minimallyEncode(rawnum)
|
|
1748
|
+
|
|
1749
|
+
if (rawnum.length > size) {
|
|
1750
|
+
// We definitively cannot.
|
|
1751
|
+
this.errstr = 'SCRIPT_ERR_IMPOSSIBLE_ENCODING'
|
|
1752
|
+
return false
|
|
1753
|
+
}
|
|
1754
|
+
|
|
1755
|
+
// We already have an element of the right size, we
|
|
1756
|
+
// don't need to do anything.
|
|
1757
|
+
if (rawnum.length === size) {
|
|
1758
|
+
this.stack[this.stack.length - 1] = rawnum
|
|
1759
|
+
break
|
|
1760
|
+
}
|
|
1761
|
+
|
|
1762
|
+
var signbit = 0x00
|
|
1763
|
+
if (rawnum.length > 0) {
|
|
1764
|
+
signbit = rawnum[rawnum.length - 1] & 0x80
|
|
1765
|
+
rawnum[rawnum.length - 1] &= 0x7f
|
|
1766
|
+
}
|
|
1767
|
+
|
|
1768
|
+
var num = Buffer.alloc(size)
|
|
1769
|
+
rawnum.copy(num, 0)
|
|
1770
|
+
|
|
1771
|
+
var l = rawnum.length - 1
|
|
1772
|
+
while (l++ < size - 2) {
|
|
1773
|
+
num[l] = 0x00
|
|
1774
|
+
}
|
|
1775
|
+
|
|
1776
|
+
num[l] = signbit
|
|
1777
|
+
|
|
1778
|
+
this.stack[this.stack.length - 1] = num
|
|
1779
|
+
break
|
|
1780
|
+
|
|
1781
|
+
case Opcode.OP_BIN2NUM:
|
|
1782
|
+
// (in -- out)
|
|
1783
|
+
if (this.stack.length < 1) {
|
|
1784
|
+
this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
|
|
1785
|
+
return false
|
|
1786
|
+
}
|
|
1787
|
+
|
|
1788
|
+
buf1 = stacktop(-1)
|
|
1789
|
+
buf2 = Interpreter._minimallyEncode(buf1)
|
|
1790
|
+
|
|
1791
|
+
this.stack[this.stack.length - 1] = buf2
|
|
1792
|
+
|
|
1793
|
+
// The resulting number must be a valid number.
|
|
1794
|
+
if (!Interpreter._isMinimallyEncoded(buf2)) {
|
|
1795
|
+
this.errstr = 'SCRIPT_ERR_INVALID_NUMBER_RANGE'
|
|
1796
|
+
return false
|
|
1797
|
+
}
|
|
1798
|
+
break
|
|
1799
|
+
|
|
1800
|
+
default:
|
|
1801
|
+
this.errstr = 'SCRIPT_ERR_BAD_OPCODE'
|
|
1802
|
+
return false
|
|
1803
|
+
}
|
|
1804
|
+
}
|
|
1805
|
+
|
|
1806
|
+
return true
|
|
1807
|
+
}
|