@opcat-labs/opcat 1.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.
Files changed (138) hide show
  1. package/.mocharc.yaml +3 -0
  2. package/index.d.ts +1541 -0
  3. package/index.js +74 -0
  4. package/lib/address.js +478 -0
  5. package/lib/block/block.js +277 -0
  6. package/lib/block/blockheader.js +295 -0
  7. package/lib/block/index.js +4 -0
  8. package/lib/block/merkleblock.js +323 -0
  9. package/lib/bn.js +3423 -0
  10. package/lib/crypto/bn.js +278 -0
  11. package/lib/crypto/ecdsa.js +339 -0
  12. package/lib/crypto/hash.browser.js +171 -0
  13. package/lib/crypto/hash.js +2 -0
  14. package/lib/crypto/hash.node.js +171 -0
  15. package/lib/crypto/point.js +221 -0
  16. package/lib/crypto/random.browser.js +28 -0
  17. package/lib/crypto/random.js +2 -0
  18. package/lib/crypto/random.node.js +11 -0
  19. package/lib/crypto/signature.js +325 -0
  20. package/lib/encoding/base58.js +111 -0
  21. package/lib/encoding/base58check.js +121 -0
  22. package/lib/encoding/bufferreader.js +212 -0
  23. package/lib/encoding/bufferwriter.js +140 -0
  24. package/lib/encoding/decode-asm.js +24 -0
  25. package/lib/encoding/decode-hex.js +32 -0
  26. package/lib/encoding/decode-script-chunks.js +43 -0
  27. package/lib/encoding/encode-hex.js +284 -0
  28. package/lib/encoding/is-hex.js +7 -0
  29. package/lib/encoding/varint.js +75 -0
  30. package/lib/errors/index.js +54 -0
  31. package/lib/errors/spec.js +314 -0
  32. package/lib/hash-cache.js +50 -0
  33. package/lib/hdprivatekey.js +678 -0
  34. package/lib/hdpublickey.js +525 -0
  35. package/lib/message/message.js +191 -0
  36. package/lib/mnemonic/mnemonic.js +303 -0
  37. package/lib/mnemonic/pbkdf2.browser.js +68 -0
  38. package/lib/mnemonic/pbkdf2.js +2 -0
  39. package/lib/mnemonic/pbkdf2.node.js +68 -0
  40. package/lib/mnemonic/words/chinese.js +2054 -0
  41. package/lib/mnemonic/words/english.js +2054 -0
  42. package/lib/mnemonic/words/french.js +2054 -0
  43. package/lib/mnemonic/words/index.js +8 -0
  44. package/lib/mnemonic/words/italian.js +2054 -0
  45. package/lib/mnemonic/words/japanese.js +2054 -0
  46. package/lib/mnemonic/words/spanish.js +2054 -0
  47. package/lib/networks.js +379 -0
  48. package/lib/opcode.js +255 -0
  49. package/lib/privatekey.js +374 -0
  50. package/lib/publickey.js +386 -0
  51. package/lib/script/index.js +5 -0
  52. package/lib/script/interpreter.js +1834 -0
  53. package/lib/script/script.js +1074 -0
  54. package/lib/script/stack.js +109 -0
  55. package/lib/script/write-i32-le.js +17 -0
  56. package/lib/script/write-push-data.js +35 -0
  57. package/lib/script/write-u16-le.js +12 -0
  58. package/lib/script/write-u32-le.js +16 -0
  59. package/lib/script/write-u64-le.js +24 -0
  60. package/lib/script/write-u8-le.js +8 -0
  61. package/lib/script/write-varint.js +46 -0
  62. package/lib/transaction/index.js +7 -0
  63. package/lib/transaction/input/index.js +5 -0
  64. package/lib/transaction/input/input.js +354 -0
  65. package/lib/transaction/input/multisig.js +242 -0
  66. package/lib/transaction/input/publickey.js +100 -0
  67. package/lib/transaction/input/publickeyhash.js +118 -0
  68. package/lib/transaction/output.js +231 -0
  69. package/lib/transaction/sighash.js +167 -0
  70. package/lib/transaction/signature.js +97 -0
  71. package/lib/transaction/transaction.js +1639 -0
  72. package/lib/transaction/unspentoutput.js +113 -0
  73. package/lib/util/_.js +47 -0
  74. package/lib/util/js.js +90 -0
  75. package/lib/util/preconditions.js +33 -0
  76. package/package.json +26 -0
  77. package/test/address.js +509 -0
  78. package/test/block/block.js +251 -0
  79. package/test/block/blockheader.js +275 -0
  80. package/test/block/merklebloack.js +211 -0
  81. package/test/crypto/bn.js +177 -0
  82. package/test/crypto/ecdsa.js +391 -0
  83. package/test/crypto/hash.browser.js +135 -0
  84. package/test/crypto/hash.js +136 -0
  85. package/test/crypto/point.js +224 -0
  86. package/test/crypto/random.js +32 -0
  87. package/test/crypto/signature.js +409 -0
  88. package/test/data/bip69.json +215 -0
  89. package/test/data/bitcoind/base58_keys_invalid.json +52 -0
  90. package/test/data/bitcoind/base58_keys_valid.json +335 -0
  91. package/test/data/bitcoind/blocks.json +22 -0
  92. package/test/data/bitcoind/script_tests.json +3822 -0
  93. package/test/data/bitcoind/sig_canonical.json +7 -0
  94. package/test/data/bitcoind/sig_noncanonical.json +36 -0
  95. package/test/data/bitcoind/tx_invalid.json +445 -0
  96. package/test/data/bitcoind/tx_valid.json +44 -0
  97. package/test/data/blk86756-testnet.dat +0 -0
  98. package/test/data/blk86756-testnet.js +14 -0
  99. package/test/data/blk86756-testnet.json +684 -0
  100. package/test/data/block.hex +1 -0
  101. package/test/data/ecdsa.json +230 -0
  102. package/test/data/merkleblocks.js +488 -0
  103. package/test/data/messages.json +22 -0
  104. package/test/data/sighash.json +12 -0
  105. package/test/data/tx_creation.json +95 -0
  106. package/test/encoding/base58.js +131 -0
  107. package/test/encoding/base58check.js +136 -0
  108. package/test/encoding/bufferreader.js +337 -0
  109. package/test/encoding/bufferwriter.js +172 -0
  110. package/test/encoding/varint.js +104 -0
  111. package/test/hashCache.js +67 -0
  112. package/test/hdkeys.js +445 -0
  113. package/test/hdprivatekey.js +332 -0
  114. package/test/hdpublickey.js +304 -0
  115. package/test/index.js +16 -0
  116. package/test/message/message.js +204 -0
  117. package/test/mnemonic/data/fixtures.json +300 -0
  118. package/test/mnemonic/mnemonic.js +259 -0
  119. package/test/mnemonic/mocha.opts +1 -0
  120. package/test/mnemonic/pbkdf2.test.js +59 -0
  121. package/test/networks.js +159 -0
  122. package/test/opcode.js +161 -0
  123. package/test/privatekey.js +439 -0
  124. package/test/publickey.js +554 -0
  125. package/test/script/interpreter.js +734 -0
  126. package/test/script/script.js +1437 -0
  127. package/test/transaction/deserialize.js +34 -0
  128. package/test/transaction/input/input.js +90 -0
  129. package/test/transaction/input/multisig.js +90 -0
  130. package/test/transaction/input/publickey.js +68 -0
  131. package/test/transaction/input/publickeyhash.js +51 -0
  132. package/test/transaction/output.js +185 -0
  133. package/test/transaction/sighash.js +65 -0
  134. package/test/transaction/signature.js +114 -0
  135. package/test/transaction/transaction.js +1109 -0
  136. package/test/transaction/unspentoutput.js +110 -0
  137. package/test/util/js.js +76 -0
  138. package/test/util/preconditions.js +79 -0
@@ -0,0 +1,734 @@
1
+ 'use strict';
2
+
3
+ var should = require('chai').should();
4
+ var opcat = require('../../');
5
+ var Interpreter = opcat.Script.Interpreter;
6
+ var Transaction = opcat.Transaction;
7
+ var PrivateKey = opcat.PrivateKey;
8
+ var Script = opcat.Script;
9
+ var BN = opcat.crypto.BN;
10
+ var BufferWriter = opcat.encoding.BufferWriter;
11
+ var Opcode = opcat.Opcode;
12
+ var _ = require('../../lib/util/_');
13
+
14
+ var scriptTests = require('../data/bitcoind/script_tests');
15
+ var txValid = require('../data/bitcoind/tx_valid');
16
+ var txInvalid = require('../data/bitcoind/tx_invalid');
17
+
18
+ // the script string format used in bitcoind data tests
19
+ Script.fromBitcoindString = function (str) {
20
+ var bw = new BufferWriter();
21
+ var tokens = str.split(' ');
22
+ for (var i = 0; i < tokens.length; i++) {
23
+ var token = tokens[i];
24
+ if (token === '') {
25
+ continue;
26
+ }
27
+
28
+ var opstr;
29
+ var opcodenum;
30
+ var tbuf;
31
+ if (token[0] === '0' && token[1] === 'x') {
32
+ var hex = token.slice(2);
33
+ bw.write(Buffer.from(hex, 'hex'));
34
+ } else if (token[0] === "'") {
35
+ var tstr = token.slice(1, token.length - 1);
36
+ var cbuf = Buffer.from(tstr);
37
+ tbuf = Script().add(cbuf).toBuffer();
38
+ bw.write(tbuf);
39
+ } else if (typeof Opcode['OP_' + token] !== 'undefined') {
40
+ opstr = 'OP_' + token;
41
+ opcodenum = Opcode[opstr];
42
+ bw.writeUInt8(opcodenum);
43
+ } else if (typeof Opcode[token] === 'number') {
44
+ opstr = token;
45
+ opcodenum = Opcode[opstr];
46
+ bw.writeUInt8(opcodenum);
47
+ } else if (!isNaN(parseInt(token))) {
48
+ var script = Script().add(new BN(token).toScriptNumBuffer());
49
+ tbuf = script.toBuffer();
50
+ bw.write(tbuf);
51
+ } else {
52
+ throw new Error('Could not determine type of script value');
53
+ }
54
+ }
55
+ var buf = bw.concat();
56
+ return this.fromBuffer(buf);
57
+ };
58
+
59
+ describe('Interpreter', function () {
60
+ it('should make a new interp', function () {
61
+ var interp = new Interpreter();
62
+ (interp instanceof Interpreter).should.equal(true);
63
+ interp.stack.length.should.equal(0);
64
+ interp.altstack.length.should.equal(0);
65
+ interp.pc.should.equal(0);
66
+ interp.pbegincodehash.should.equal(0);
67
+ interp.nOpCount.should.equal(0);
68
+ interp.vfExec.length.should.equal(0);
69
+ interp.errstr.should.equal('');
70
+ interp.flags.should.equal(0);
71
+ });
72
+ it('interpreter can set new values for stacks', function () {
73
+ const interp = new Interpreter();
74
+ interp.stack.push(Buffer.from(['stack']));
75
+ interp.stack.length.should.equal(1);
76
+ interp.altstack.push(Buffer.from(['altstack']));
77
+ interp.altstack.length.should.equal(1);
78
+ interp.set({ stack: [], altstack: [] });
79
+ interp.stack.length.should.equal(0);
80
+ interp.altstack.length.should.equal(0);
81
+ });
82
+
83
+ describe('@castToBool', function () {
84
+ it('should cast these bufs to bool correctly', function () {
85
+ Interpreter.castToBool(
86
+ new BN(0).toSM({
87
+ endian: 'little',
88
+ }),
89
+ ).should.equal(false);
90
+ Interpreter.castToBool(Buffer.from('0080', 'hex')).should.equal(false); // negative 0
91
+ Interpreter.castToBool(
92
+ new BN(1).toSM({
93
+ endian: 'little',
94
+ }),
95
+ ).should.equal(true);
96
+ Interpreter.castToBool(
97
+ new BN(-1).toSM({
98
+ endian: 'little',
99
+ }),
100
+ ).should.equal(true);
101
+
102
+ var buf = Buffer.from('00', 'hex');
103
+ var bool =
104
+ BN.fromSM(buf, {
105
+ endian: 'little',
106
+ }).cmp(BN.Zero) !== 0;
107
+ Interpreter.castToBool(buf).should.equal(bool);
108
+ });
109
+ });
110
+
111
+ describe('#verify', function () {
112
+ it('should verify these trivial scripts', function () {
113
+ var verified;
114
+ var si = Interpreter();
115
+ verified = si.verify(Script('OP_1'), Script('OP_1'));
116
+ verified.should.equal(true);
117
+ verified = Interpreter().verify(Script('OP_1'), Script('OP_0'));
118
+ verified.should.equal(false);
119
+ verified = Interpreter().verify(Script('OP_0'), Script('OP_1'));
120
+ verified.should.equal(true);
121
+ verified = Interpreter().verify(Script('OP_CODESEPARATOR'), Script('OP_1'));
122
+ verified.should.equal(true);
123
+ verified = Interpreter().verify(Script(''), Script('OP_DEPTH OP_0 OP_EQUAL'));
124
+ verified.should.equal(true);
125
+ verified = Interpreter().verify(
126
+ Script('OP_1 OP_2'),
127
+ Script('OP_2 OP_EQUALVERIFY OP_1 OP_EQUAL'),
128
+ );
129
+ verified.should.equal(true);
130
+ verified = Interpreter().verify(Script('9 0x000000000000000010'), Script(''));
131
+ verified.should.equal(true);
132
+ verified = Interpreter().verify(Script('OP_1'), Script('OP_15 OP_ADD OP_16 OP_EQUAL'));
133
+ verified.should.equal(true);
134
+ verified = Interpreter().verify(Script('OP_0'), Script('OP_IF OP_VER OP_ELSE OP_1 OP_ENDIF'));
135
+ verified.should.equal(true);
136
+ });
137
+
138
+ it('should verify these simple transaction', function () {
139
+ // first we create a transaction
140
+ var privateKey = new PrivateKey('cSBnVM4xvxarwGQuAfQFwqDg9k5tErHUHzgWsEfD4zdwUasvqRVY');
141
+ var publicKey = privateKey.publicKey;
142
+ var fromAddress = publicKey.toAddress();
143
+ var toAddress = 'mrU9pEmAx26HcbKVrABvgL7AwA5fjNFoDc';
144
+ var scriptPubkey = Script.buildPublicKeyHashOut(fromAddress);
145
+ var utxo = {
146
+ address: fromAddress,
147
+ txId: 'a477af6b2667c29670467e4e0728b685ee07b240235771862318e29ddbe58458',
148
+ outputIndex: 0,
149
+ script: scriptPubkey,
150
+ satoshis: 100000,
151
+ };
152
+ var tx = new Transaction().from(utxo).to(toAddress, 100000).sign(privateKey, 1);
153
+
154
+ // we then extract the signature from the first input
155
+ var inputIndex = 0;
156
+ var signature = tx.getSignatures(privateKey, 1)[inputIndex].signature;
157
+
158
+ var scriptSig = Script.buildPublicKeyHashIn(publicKey, signature);
159
+ var flags = Interpreter.SCRIPT_VERIFY_STRICTENC;
160
+ var verified = Interpreter().verify(scriptSig, scriptPubkey, tx, inputIndex, flags);
161
+ verified.should.equal(true);
162
+ });
163
+ });
164
+
165
+ describe('#script debugger', function () {
166
+ it('debugger should fire while executing script', function () {
167
+ var si = Interpreter();
168
+ let debugCount = 0;
169
+ si.stepListener = function (step) {
170
+ debugCount += 1;
171
+ };
172
+ si.verify(Script('OP_1 OP_2 OP_ADD'), Script('OP_3 OP_EQUAL'));
173
+ si.errstr.should.equal('');
174
+ // two scripts. first one has 3 instructions. second one has 2 instructions
175
+ debugCount.should.equal(3 + 2);
176
+ });
177
+ it('debugger error in callback should not kill executing script', function () {
178
+ var si = Interpreter();
179
+ si.stepListener = function (step) {
180
+ throw new Error('This error is expected.');
181
+ };
182
+ si.verify(Script('OP_1 OP_2 OP_ADD'), Script(''));
183
+ const result = [...si.stack.pop()];
184
+ result.should.to.deep.equal([3]);
185
+ si.errstr.should.equal('');
186
+ si.stack.length.should.equal(0);
187
+ });
188
+ it('script debugger should fire and not cause an error', function () {
189
+ var si = Interpreter();
190
+ si.stepListener = debugScript;
191
+ si.verify(Script('OP_1 OP_2 OP_ADD'), Script('OP_3 OP_EQUAL'));
192
+ si.errstr.should.equal('');
193
+ });
194
+ it('script debugger should make copies of stack: no more make copies bcoz memory used', function () {
195
+ /*
196
+ var si = Interpreter()
197
+ let stk, stkval, altstk, altstkval
198
+ si.stepListener = function (step, stack, altstack) {
199
+ // stack is an array of buffers, interpreter must give us copies of stack so we can't mess it up
200
+ console.log(step)
201
+ console.log(stack)
202
+ console.log(altstack)
203
+ // these values will get overwritten each step but we only care about that final values
204
+ stk = (stack === si.stack)
205
+ stkval = (stack[0] === si.stack.stacktop(-si.stack.length))
206
+ altstk = (altstack === si.altstack)
207
+ altstkval = (altstack[0] === si.altstack.stacktop(-si.altstack.length))
208
+ }
209
+ // alt stack is not copied to second script execution so just do everything in second script
210
+ si.verify(Script(''), Script('OP_2 OP_TOALTSTACK OP_1'))
211
+ console.log(si.stack)
212
+ console.log(si.altstack)
213
+ si.errstr.should.equal('')
214
+ si.stack.length.should.equal(1)
215
+ si.altstack.length.should.equal(1)
216
+ stk.should.equal(false)
217
+ stkval.should.equal(false)
218
+ altstk.should.equal(false)
219
+ altstkval.should.equal(false)
220
+ */
221
+ });
222
+ });
223
+
224
+ var getFlags = function getFlags(flagstr) {
225
+ var flags = 0;
226
+ if (flagstr.indexOf('NONE') !== -1) {
227
+ flags = flags | Interpreter.SCRIPT_VERIFY_NONE;
228
+ }
229
+ if (flagstr.indexOf('STRICTENC') !== -1) {
230
+ flags = flags | Interpreter.SCRIPT_VERIFY_STRICTENC;
231
+ }
232
+ if (flagstr.indexOf('DERSIG') !== -1) {
233
+ flags = flags | Interpreter.SCRIPT_VERIFY_DERSIG;
234
+ }
235
+ if (flagstr.indexOf('LOW_S') !== -1) {
236
+ flags = flags | Interpreter.SCRIPT_VERIFY_LOW_S;
237
+ }
238
+ if (flagstr.indexOf('NULLDUMMY') !== -1) {
239
+ flags = flags | Interpreter.SCRIPT_VERIFY_NULLDUMMY;
240
+ }
241
+ if (flagstr.indexOf('SIGPUSHONLY') !== -1) {
242
+ flags = flags | Interpreter.SCRIPT_VERIFY_SIGPUSHONLY;
243
+ }
244
+ if (flagstr.indexOf('MINIMALDATA') !== -1) {
245
+ flags = flags | Interpreter.SCRIPT_VERIFY_MINIMALDATA;
246
+ }
247
+ if (flagstr.indexOf('DISCOURAGE_UPGRADABLE_NOPS') !== -1) {
248
+ flags = flags | Interpreter.SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS;
249
+ }
250
+ if (flagstr.indexOf('CHECKLOCKTIMEVERIFY') !== -1) {
251
+ flags = flags | Interpreter.SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY;
252
+ }
253
+ if (flagstr.indexOf('CHECKSEQUENCEVERIFY') !== -1) {
254
+ flags = flags | Interpreter.SCRIPT_VERIFY_CHECKSEQUENCEVERIFY;
255
+ }
256
+ if (flagstr.indexOf('NULLFAIL') !== -1) {
257
+ flags = flags | Interpreter.SCRIPT_VERIFY_NULLFAIL;
258
+ }
259
+
260
+ if (flagstr.indexOf('MONOLITH') !== -1) {
261
+ flags = flags | Interpreter.SCRIPT_ENABLE_MONOLITH_OPCODES;
262
+ }
263
+
264
+ if (flagstr.indexOf('MAGNETIC') !== -1) {
265
+ flags = flags | Interpreter.SCRIPT_ENABLE_MAGNETIC_OPCODES;
266
+ }
267
+
268
+ return flags;
269
+ };
270
+
271
+ var testFixture = function (vector, expected, extraData) {
272
+ var scriptSig = Script.fromBitcoindString(vector[0]);
273
+ var scriptPubkey = Script.fromBitcoindString(vector[1]);
274
+ var flags = getFlags(vector[2]);
275
+ var inputAmount = 0;
276
+ if (extraData) {
277
+ inputAmount = extraData[0] * 1e8;
278
+ }
279
+
280
+ var hashbuf = Buffer.alloc(32);
281
+ hashbuf.fill(0);
282
+ var credtx = new Transaction();
283
+ credtx.uncheckedAddInput(
284
+ new Transaction.Input({
285
+ prevTxId: '0000000000000000000000000000000000000000000000000000000000000000',
286
+ outputIndex: 0xffffffff,
287
+ sequenceNumber: 0xffffffff,
288
+ script: Script('OP_0 OP_0'),
289
+ }),
290
+ );
291
+ credtx.addOutput(
292
+ new Transaction.Output({
293
+ script: scriptPubkey,
294
+ satoshis: inputAmount,
295
+ }),
296
+ );
297
+ var idbuf = credtx.id;
298
+
299
+ var spendtx = new Transaction();
300
+ spendtx.uncheckedAddInput(
301
+ new Transaction.Input({
302
+ prevTxId: idbuf.toString('hex'),
303
+ outputIndex: 0,
304
+ sequenceNumber: 0xffffffff,
305
+ script: scriptSig,
306
+ output: credtx.outputs[0],
307
+ }),
308
+ );
309
+ spendtx.addOutput(
310
+ new Transaction.Output({
311
+ script: new Script(),
312
+ satoshis: inputAmount,
313
+ }),
314
+ );
315
+
316
+
317
+ //spendtx.sign(opcat.PrivateKey.fromWIF(""))
318
+ Interpreter.MAX_OPCODE_COUNT = 201;
319
+ Interpreter.MAX_SCRIPT_SIZE = 10000;
320
+ var interp = new Interpreter();
321
+ var verified = interp.verify(scriptSig, scriptPubkey, spendtx, 0, flags, new BN(inputAmount));
322
+ verified.should.equal(expected, interp.errstr);
323
+ };
324
+
325
+ const CheckMul = function (a, b, expected) {
326
+ // Negative values for multiplication
327
+ CheckBinaryOpMagnetic(a, b, Opcode.OP_MUL, expected);
328
+ CheckBinaryOpMagnetic(a, NegativeValtype(b), Opcode.OP_MUL, NegativeValtype(expected));
329
+ CheckBinaryOpMagnetic(NegativeValtype(a), b, Opcode.OP_MUL, NegativeValtype(expected));
330
+ CheckBinaryOpMagnetic(NegativeValtype(a), NegativeValtype(b), Opcode.OP_MUL, expected);
331
+
332
+ // Commutativity
333
+ CheckBinaryOpMagnetic(b, a, Opcode.OP_MUL, expected);
334
+ CheckBinaryOpMagnetic(b, NegativeValtype(a), Opcode.OP_MUL, NegativeValtype(expected));
335
+ CheckBinaryOpMagnetic(NegativeValtype(b), a, Opcode.OP_MUL, NegativeValtype(expected));
336
+ CheckBinaryOpMagnetic(NegativeValtype(b), NegativeValtype(a), Opcode.OP_MUL, expected);
337
+
338
+ // Multiplication identities
339
+ CheckBinaryOpMagnetic(a, [0x01], Opcode.OP_MUL, a);
340
+ CheckBinaryOpMagnetic(a, [0x81], Opcode.OP_MUL, NegativeValtype(a));
341
+ CheckBinaryOpMagnetic(a, [], Opcode.OP_MUL, []);
342
+
343
+ CheckBinaryOpMagnetic([0x01], b, Opcode.OP_MUL, b);
344
+ CheckBinaryOpMagnetic([0x81], b, Opcode.OP_MUL, NegativeValtype(b));
345
+ CheckBinaryOpMagnetic([], b, Opcode.OP_MUL, []);
346
+ };
347
+
348
+ const CheckBinaryOpMagnetic = function (a, b, op, expected) {
349
+ const interp = evaluateScript(a, b, op);
350
+ const result = [...interp.stack.pop()];
351
+ result.should.to.deep.equal(expected);
352
+ };
353
+
354
+ const NegativeValtype = function (v) {
355
+ let copy = v.slice();
356
+ if (copy.length) {
357
+ copy[copy.length - 1] ^= 0x80;
358
+ }
359
+ // TODO: expose minimally encode as public method?
360
+ return Interpreter._minimallyEncode(copy);
361
+ };
362
+
363
+ const evaluateScript = function (arraySig, arrayPubKey, op, funcDebug) {
364
+ const interp = new Interpreter();
365
+ interp.stepListener = funcDebug;
366
+ interp.script = new Script().add(Buffer.from(arraySig)).add(Buffer.from(arrayPubKey));
367
+ interp.script.add(op);
368
+ interp.flags =
369
+ Interpreter.SCRIPT_ENABLE_MAGNETIC_OPCODES |
370
+ Interpreter.SCRIPT_ENABLE_MONOLITH_OPCODES;
371
+ interp.evaluate();
372
+ return interp;
373
+ };
374
+
375
+ const debugScript = function (step, stack, altstack) {
376
+ const script = new Script().add(step.opcode);
377
+ // stack is array of buffers
378
+ let stackTop = '>';
379
+ for (let item in stack.reverse()) {
380
+ console.log(`Step ${step.pc}: ${script}:${stackTop}${stack[item].toString('hex')}`);
381
+ stackTop = ' ';
382
+ }
383
+ };
384
+
385
+ const toBitpattern = function (binaryString) {
386
+ return parseInt(binaryString, 2).toString(16).padStart(8, '0');
387
+ };
388
+
389
+ describe('#Empty and null script', function () {
390
+ it('Empty buffer should have value 0x00 in script', function () {
391
+ const s = new Script().add(Buffer.from([]));
392
+ // script does not render anything so it appears invisible
393
+ s.toString().should.equal('OP_0');
394
+ // yet there is a script chunk there
395
+ s.chunks.length.should.equal(1);
396
+ s.chunks[0].opcodenum.should.equal(0);
397
+ });
398
+ it('Zero value (0x00) buffer should have value 0x01 0x00 in script', function () {
399
+ const s = new Script().add(Buffer.from([0x00]));
400
+ s.toString().should.equal('1 0x00');
401
+ s.chunks.length.should.equal(1);
402
+ s.chunks[0].opcodenum.should.equal(1);
403
+ });
404
+ });
405
+
406
+ describe('#NegativeValType', function () {
407
+ it('should pass all tests', function () {
408
+ // Test zero values
409
+ new Script()
410
+ .add(Buffer.from(NegativeValtype([])))
411
+ .should.to.deep.equal(new Script().add(Buffer.from([])));
412
+ new Script()
413
+ .add(Buffer.from(NegativeValtype([0x00])))
414
+ .should.to.deep.equal(new Script().add(Buffer.from([])));
415
+ new Script()
416
+ .add(Buffer.from(NegativeValtype([0x80])))
417
+ .should.to.deep.equal(new Script().add(Buffer.from([])));
418
+ new Script()
419
+ .add(Buffer.from(NegativeValtype([0x00, 0x00])))
420
+ .should.to.deep.equal(new Script().add(Buffer.from([])));
421
+ new Script()
422
+ .add(Buffer.from(NegativeValtype([0x00, 0x80])))
423
+ .should.to.deep.equal(new Script().add(Buffer.from([])));
424
+
425
+ // Non-zero values
426
+ NegativeValtype([0x01]).should.to.deep.equal([0x81]);
427
+ NegativeValtype([0x81]).should.to.deep.equal([0x01]);
428
+ NegativeValtype([0x02, 0x01]).should.to.deep.equal([0x02, 0x81]);
429
+ NegativeValtype([0x02, 0x81]).should.to.deep.equal([0x02, 0x01]);
430
+ NegativeValtype([0xff, 0x02, 0x01]).should.to.deep.equal([0xff, 0x02, 0x81]);
431
+ NegativeValtype([0xff, 0x02, 0x81]).should.to.deep.equal([0xff, 0x02, 0x01]);
432
+ NegativeValtype([0xff, 0xff, 0x02, 0x01]).should.to.deep.equal([0xff, 0xff, 0x02, 0x81]);
433
+ NegativeValtype([0xff, 0xff, 0x02, 0x81]).should.to.deep.equal([0xff, 0xff, 0x02, 0x01]);
434
+
435
+ // Should not be overly-minimized
436
+ NegativeValtype([0xff, 0x80]).should.to.deep.equal([0xff, 0x00]);
437
+ NegativeValtype([0xff, 0x00]).should.to.deep.equal([0xff, 0x80]);
438
+ });
439
+ });
440
+
441
+ describe('#OP_LSHIFT tests from bitcoind', function () {
442
+ it('should not shift when no n value', function () {
443
+ const interp = evaluateScript([0x9f, 0x11, 0xf5, 0x55], [], Opcode.OP_LSHIFT);
444
+ console.log(interp.script);
445
+ const result = interp.stack.pop();
446
+ result.toString('hex').should.equal(toBitpattern('10011111000100011111010101010101'));
447
+ });
448
+ it('should shift left 1', function () {
449
+ const interp = evaluateScript([0x9f, 0x11, 0xf5, 0x55], [0x01], Opcode.OP_LSHIFT);
450
+ const result = interp.stack.pop();
451
+ result.toString('hex').should.equal(toBitpattern('00111110001000111110101010101010'));
452
+ });
453
+ it('should shift left 2', function () {
454
+ const interp = evaluateScript([0x9f, 0x11, 0xf5, 0x55], [0x02], Opcode.OP_LSHIFT);
455
+ const result = interp.stack.pop();
456
+ result.toString('hex').should.equal(toBitpattern('01111100010001111101010101010100'));
457
+ });
458
+ it('should shift left 3', function () {
459
+ const interp = evaluateScript([0x9f, 0x11, 0xf5, 0x55], [0x03], Opcode.OP_LSHIFT);
460
+ const result = interp.stack.pop();
461
+ result.toString('hex').should.equal(toBitpattern('11111000100011111010101010101000'));
462
+ });
463
+ it('should shift left 4', function () {
464
+ const interp = evaluateScript([0x9f, 0x11, 0xf5, 0x55], [0x04], Opcode.OP_LSHIFT);
465
+ const result = interp.stack.pop();
466
+ result.toString('hex').should.equal(toBitpattern('11110001000111110101010101010000'));
467
+ });
468
+ it('should shift left 5', function () {
469
+ const interp = evaluateScript([0x9f, 0x11, 0xf5, 0x55], [0x05], Opcode.OP_LSHIFT);
470
+ const result = interp.stack.pop();
471
+ result.toString('hex').should.equal(toBitpattern('11100010001111101010101010100000'));
472
+ });
473
+ it('should shift left 6', function () {
474
+ const interp = evaluateScript([0x9f, 0x11, 0xf5, 0x55], [0x06], Opcode.OP_LSHIFT);
475
+ const result = interp.stack.pop();
476
+ result.toString('hex').should.equal(toBitpattern('11000100011111010101010101000000'));
477
+ });
478
+ it('should shift left 7', function () {
479
+ const interp = evaluateScript([0x9f, 0x11, 0xf5, 0x55], [0x07], Opcode.OP_LSHIFT);
480
+ const result = interp.stack.pop();
481
+ result.toString('hex').should.equal(toBitpattern('10001000111110101010101010000000'));
482
+ });
483
+ it('should shift left 08', function () {
484
+ const interp = evaluateScript([0x9f, 0x11, 0xf5, 0x55], [0x08], Opcode.OP_LSHIFT);
485
+ const result = interp.stack.pop();
486
+ result.toString('hex').should.equal(toBitpattern('00010001111101010101010100000000'));
487
+ });
488
+ it('should shift left 9', function () {
489
+ const interp = evaluateScript([0x9f, 0x11, 0xf5, 0x55], [0x09], Opcode.OP_LSHIFT);
490
+ const result = interp.stack.pop();
491
+ result.toString('hex').should.equal(toBitpattern('00100011111010101010101000000000'));
492
+ });
493
+ it('should shift left 0A', function () {
494
+ const interp = evaluateScript([0x9f, 0x11, 0xf5, 0x55], [0x0a], Opcode.OP_LSHIFT);
495
+ const result = interp.stack.pop();
496
+ result.toString('hex').should.equal(toBitpattern('01000111110101010101010000000000'));
497
+ });
498
+ it('should shift left 0B', function () {
499
+ const interp = evaluateScript([0x9f, 0x11, 0xf5, 0x55], [0x0b], Opcode.OP_LSHIFT);
500
+ const result = interp.stack.pop();
501
+ result.toString('hex').should.equal(toBitpattern('10001111101010101010100000000000'));
502
+ });
503
+ it('should shift left 0C', function () {
504
+ const interp = evaluateScript([0x9f, 0x11, 0xf5, 0x55], [0x0c], Opcode.OP_LSHIFT);
505
+ const result = interp.stack.pop();
506
+ result.toString('hex').should.equal(toBitpattern('00011111010101010101000000000000'));
507
+ });
508
+ it('should shift left 0D', function () {
509
+ const interp = evaluateScript([0x9f, 0x11, 0xf5, 0x55], [0x0d], Opcode.OP_LSHIFT);
510
+ const result = interp.stack.pop();
511
+ result.toString('hex').should.equal(toBitpattern('00111110101010101010000000000000'));
512
+ });
513
+ it('should shift left 0E', function () {
514
+ const interp = evaluateScript([0x9f, 0x11, 0xf5, 0x55], [0x0e], Opcode.OP_LSHIFT);
515
+ const result = interp.stack.pop();
516
+ result.toString('hex').should.equal(toBitpattern('01111101010101010100000000000000'));
517
+ });
518
+ it('should shift left 0F', function () {
519
+ const interp = evaluateScript([0x9f, 0x11, 0xf5, 0x55], [0x0f], Opcode.OP_LSHIFT);
520
+ const result = interp.stack.pop();
521
+ result.toString('hex').should.equal(toBitpattern('11111010101010101000000000000000'));
522
+ });
523
+ });
524
+
525
+ describe('#OP_RSHIFT tests from bitcoind', function () {
526
+ it('should not shift when no n value', function () {
527
+ const interp = evaluateScript([0x9f, 0x11, 0xf5, 0x55], [], Opcode.OP_RSHIFT);
528
+ const result = interp.stack.pop();
529
+ result.toString('hex').should.equal(toBitpattern('10011111000100011111010101010101'));
530
+ });
531
+ it('should shift right 1', function () {
532
+ const interp = evaluateScript([0x9f, 0x11, 0xf5, 0x55], [0x01], Opcode.OP_RSHIFT);
533
+ const result = interp.stack.pop();
534
+ result.toString('hex').should.equal(toBitpattern('01001111100010001111101010101010'));
535
+ });
536
+ it('should shift right 2', function () {
537
+ const interp = evaluateScript([0x9f, 0x11, 0xf5, 0x55], [0x02], Opcode.OP_RSHIFT);
538
+ const result = interp.stack.pop();
539
+ result.toString('hex').should.equal(toBitpattern('00100111110001000111110101010101'));
540
+ });
541
+ it('should shift right 3', function () {
542
+ const interp = evaluateScript([0x9f, 0x11, 0xf5, 0x55], [0x03], Opcode.OP_RSHIFT);
543
+ const result = interp.stack.pop();
544
+ result.toString('hex').should.equal(toBitpattern('00010011111000100011111010101010'));
545
+ });
546
+ it('should shift right 4', function () {
547
+ const interp = evaluateScript([0x9f, 0x11, 0xf5, 0x55], [0x04], Opcode.OP_RSHIFT);
548
+ const result = interp.stack.pop();
549
+ result.toString('hex').should.equal(toBitpattern('00001001111100010001111101010101'));
550
+ });
551
+ it('should shift right 5', function () {
552
+ const interp = evaluateScript([0x9f, 0x11, 0xf5, 0x55], [0x05], Opcode.OP_RSHIFT);
553
+ const result = interp.stack.pop();
554
+ result.toString('hex').should.equal(toBitpattern('00000100111110001000111110101010'));
555
+ });
556
+ it('should shift right 6', function () {
557
+ const interp = evaluateScript([0x9f, 0x11, 0xf5, 0x55], [0x06], Opcode.OP_RSHIFT);
558
+ const result = interp.stack.pop();
559
+ result.toString('hex').should.equal(toBitpattern('00000010011111000100011111010101'));
560
+ });
561
+ it('should shift right 7', function () {
562
+ const interp = evaluateScript([0x9f, 0x11, 0xf5, 0x55], [0x07], Opcode.OP_RSHIFT);
563
+ const result = interp.stack.pop();
564
+ result.toString('hex').should.equal(toBitpattern('00000001001111100010001111101010'));
565
+ });
566
+ it('should shift right 08', function () {
567
+ const interp = evaluateScript([0x9f, 0x11, 0xf5, 0x55], [0x08], Opcode.OP_RSHIFT);
568
+ const result = interp.stack.pop();
569
+ result.toString('hex').should.equal(toBitpattern('00000000100111110001000111110101'));
570
+ });
571
+ it('should shift right 9', function () {
572
+ const interp = evaluateScript([0x9f, 0x11, 0xf5, 0x55], [0x09], Opcode.OP_RSHIFT);
573
+ const result = interp.stack.pop();
574
+ result.toString('hex').should.equal(toBitpattern('00000000010011111000100011111010'));
575
+ });
576
+ it('should shift right 0A', function () {
577
+ const interp = evaluateScript([0x9f, 0x11, 0xf5, 0x55], [0x0a], Opcode.OP_RSHIFT);
578
+ const result = interp.stack.pop();
579
+ result.toString('hex').should.equal(toBitpattern('00000000001001111100010001111101'));
580
+ });
581
+ it('should shift right 0B', function () {
582
+ const interp = evaluateScript([0x9f, 0x11, 0xf5, 0x55], [0x0b], Opcode.OP_RSHIFT);
583
+ const result = interp.stack.pop();
584
+ result.toString('hex').should.equal(toBitpattern('00000000000100111110001000111110'));
585
+ });
586
+ it('should shift right 0C', function () {
587
+ const interp = evaluateScript([0x9f, 0x11, 0xf5, 0x55], [0x0c], Opcode.OP_RSHIFT);
588
+ const result = interp.stack.pop();
589
+ result.toString('hex').should.equal(toBitpattern('00000000000010011111000100011111'));
590
+ });
591
+ it('should shift right 0D', function () {
592
+ const interp = evaluateScript([0x9f, 0x11, 0xf5, 0x55], [0x0d], Opcode.OP_RSHIFT);
593
+ const result = interp.stack.pop();
594
+ result.toString('hex').should.equal(toBitpattern('00000000000001001111100010001111'));
595
+ });
596
+ it('should shift right 0E', function () {
597
+ const interp = evaluateScript([0x9f, 0x11, 0xf5, 0x55], [0x0e], Opcode.OP_RSHIFT);
598
+ const result = interp.stack.pop();
599
+ result.toString('hex').should.equal(toBitpattern('00000000000000100111110001000111'));
600
+ });
601
+ it('should shift right 0F', function () {
602
+ const interp = evaluateScript([0x9f, 0x11, 0xf5, 0x55], [0x0f], Opcode.OP_RSHIFT);
603
+ const result = interp.stack.pop();
604
+ result.toString('hex').should.equal(toBitpattern('00000000000000010011111000100011'));
605
+ });
606
+ });
607
+ describe('#OP_MUL tests from bitcoind', function () {
608
+ it('OP_MUL tests', function () {
609
+ CheckMul([0x05], [0x06], [0x1e]);
610
+ CheckMul([0x05], [0x26], [0xbe, 0x00]);
611
+ CheckMul([0x45], [0x26], [0x3e, 0x0a]);
612
+ CheckMul([0x02], [0x56, 0x24], [0xac, 0x48]);
613
+ CheckMul([0x05], [0x26, 0x03, 0x32], [0xbe, 0x0f, 0xfa, 0x00]);
614
+ CheckMul([0x06], [0x26, 0x03, 0x32, 0x04], [0xe4, 0x12, 0x2c, 0x19]);
615
+ CheckMul([0xa0, 0xa0], [0xf5, 0xe4], [0x20, 0xb9, 0xdd, 0x0c]); // -20A0*-64F5=0CDDB920
616
+ CheckMul([0x05, 0x26], [0x26, 0x03, 0x32], [0xbe, 0xb3, 0x71, 0x6d, 0x07]);
617
+ CheckMul([0x06, 0x26], [0x26, 0x03, 0x32, 0x04], [0xe4, 0xb6, 0xa3, 0x85, 0x9f, 0x00]);
618
+ CheckMul([0x05, 0x26, 0x09], [0x26, 0x03, 0x32], [0xbe, 0xb3, 0xc7, 0x89, 0xc9, 0x01]);
619
+ CheckMul([0x06, 0x26, 0x09], [0x26, 0x03, 0x32, 0x04], [0xe4, 0xb6, 0xf9, 0xa1, 0x61, 0x26]);
620
+ CheckMul(
621
+ [0x06, 0x26, 0x09, 0x34],
622
+ [0x26, 0x03, 0x32, 0x04],
623
+ [0xe4, 0xb6, 0xf9, 0x59, 0x05, 0x4f, 0xda, 0x00],
624
+ );
625
+ });
626
+ });
627
+
628
+ describe('bitcoind script evaluation fixtures', function () {
629
+ var testAllFixtures = function (set) {
630
+ var c = 0;
631
+ var l = set.length;
632
+ set.forEach(function (vector) {
633
+ if (vector.length === 1) {
634
+ return;
635
+ }
636
+
637
+ var extraData;
638
+ if (_.isArray(vector[0])) {
639
+ extraData = vector.shift();
640
+ }
641
+
642
+ c++;
643
+
644
+ var fullScriptString = `${vector[0]} ${vector[1]}`;
645
+ var expected = vector[3] === 'OK';
646
+ var descstr = vector[4];
647
+ var comment = descstr ? ` (${descstr})` : '';
648
+ var txt = `should ${vector[3]} script_tests vector #${c}/${l}: ${fullScriptString}${comment}`;
649
+
650
+ it(txt, function () {
651
+ testFixture(vector, expected, extraData);
652
+ });
653
+ });
654
+ };
655
+ testAllFixtures(scriptTests);
656
+ });
657
+ describe('bitcoind transaction evaluation fixtures', function () {
658
+ var testTxs = function (set, expected) {
659
+ var c = 0;
660
+ set.forEach(function (vector) {
661
+ if (vector.length === 1) {
662
+ return;
663
+ }
664
+ c++;
665
+ var cc = c; // copy to local
666
+ it('should pass tx_' + (expected ? '' : 'in') + 'valid vector ' + cc, function () {
667
+ var inputs = vector[0];
668
+ var txhex = vector[1];
669
+
670
+ var flags = getFlags(vector[2]);
671
+
672
+ if (vector[2].indexOf('P2SH') !== -1) {
673
+ return; // skip P2SH tests
674
+ }
675
+
676
+ var map = {};
677
+ var satoshisMap = {};
678
+ var dataMap = {};
679
+ inputs.forEach(function (input) {
680
+ var txid = input[0];
681
+ var txoutnum = input[1];
682
+ var scriptPubKeyStr = input[2];
683
+ var satoshis = input[3];
684
+ var dataStr = input[4];
685
+ if (txoutnum === -1) {
686
+ txoutnum = 0xffffffff; // bitcoind casts -1 to an unsigned int
687
+ }
688
+ map[txid + ':' + txoutnum] = Script.fromBitcoindString(scriptPubKeyStr);
689
+ satoshisMap[txid + ':' + txoutnum] = satoshis
690
+ dataMap[txid + ':' + txoutnum] = dataStr ? Buffer.from(dataStr, 'hex') : Buffer.from([])
691
+ });
692
+
693
+ var tx = new Transaction(txhex);
694
+ var allInputsVerified = true;
695
+ tx.inputs.forEach(function (txin, j) {
696
+ if (txin.isNull()) {
697
+ return;
698
+ }
699
+
700
+ var scriptSig = txin.script;
701
+ var txidhex = txin.prevTxId.toString('hex');
702
+ var txoutnum = txin.outputIndex;
703
+ var scriptPubkey = map[txidhex + ':' + txoutnum];
704
+ var data = dataMap[txidhex + ':' + txoutnum];
705
+ var satoshis = satoshisMap[txidhex + ':' + txoutnum]
706
+ should.exist(scriptPubkey);
707
+ should.exist(data);
708
+ should.exist(satoshis);
709
+ (scriptSig !== undefined).should.equal(true);
710
+
711
+
712
+ txin.output = new Transaction.Output({
713
+ satoshis,
714
+ script: scriptPubkey,
715
+ data,
716
+ })
717
+
718
+ var interp = new Interpreter();
719
+ var verified = interp.verify(scriptSig, scriptPubkey, tx, j, flags);
720
+ if (!verified) {
721
+ allInputsVerified = false;
722
+ }
723
+ });
724
+ var txVerified = tx.verify(true);
725
+ txVerified = txVerified === true;
726
+ allInputsVerified = allInputsVerified && txVerified;
727
+ allInputsVerified.should.equal(expected);
728
+ });
729
+ });
730
+ };
731
+ testTxs(txValid, true);
732
+ //testTxs(txInvalid, false);
733
+ });
734
+ });