@smartledger/bsv 7.13.0 → 8.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/CHANGELOG.md +106 -0
- package/README.md +38 -38
- package/bsv-gdaf.min.js +55 -55
- package/bsv-ltp.min.js +39 -39
- package/bsv-smartcontract.min.js +1 -1
- package/bsv.bundle.js +55 -55
- package/bsv.min.js +55 -55
- package/docs/AUDIT_SCOPE.md +21 -12
- package/docs/MODULE_REFERENCE_COMPLETE.md +27 -27
- package/docs/advanced/UTXO_MANAGER_GUIDE.md +1 -1
- package/docs/getting-started/INSTALLATION.md +23 -23
- package/docs/getting-started/QUICK_START.md +7 -7
- package/docs/migration/FROM_BSV_1_5_6.md +5 -5
- package/lib/crypto/bn.js +22 -2
- package/lib/script/interpreter.js +399 -56
- package/lib/transaction/sighash.js +18 -6
- package/package.json +4 -1
- package/test/consensus/base58-vectors.js +120 -0
- package/test/consensus/sv-script-vectors.js +81 -0
- package/test/consensus/sv-sighash-vectors.js +51 -0
- package/test/consensus/sv-tx-vectors.js +48 -0
- package/test/data/bitcoin-sv/README.md +170 -0
- package/test/data/bitcoin-sv/base58_encode_decode.json +14 -0
- package/test/data/bitcoin-sv/base58_keys_invalid.json +152 -0
- package/test/data/bitcoin-sv/base58_keys_valid.json +452 -0
- package/test/data/bitcoin-sv/script_tests.json +2591 -0
- package/test/data/bitcoin-sv/sighash.json +1003 -0
- package/test/data/bitcoin-sv/tx_invalid.json +285 -0
- package/test/data/bitcoin-sv/tx_valid.json +367 -0
- package/test/regressions.js +35 -0
- package/test/script/chronicle.js +170 -25
- package/test/script/defaults.js +93 -0
- package/test/script/genesis_limits.js +62 -6
- package/test/script/interpreter.js +24 -8
- package/test/transaction/sighash.js +21 -1
- package/version.js +1 -1
package/test/script/chronicle.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
/* global describe, it */
|
|
3
|
+
/* global describe, it, beforeEach, afterEach */
|
|
4
4
|
|
|
5
5
|
// The BSV Chronicle script surface: OP_2MUL/OP_2DIV restored, OP_VER/OP_VERIF/
|
|
6
6
|
// OP_VERNOTIF given meaning, and SIGHASH_CHRONICLE selecting the Original
|
|
@@ -35,7 +35,12 @@ function run (build, opts) {
|
|
|
35
35
|
return {
|
|
36
36
|
verified: verified,
|
|
37
37
|
errstr: interp.errstr || '',
|
|
38
|
-
|
|
38
|
+
// Read with the era's width, not BN's four-byte default: post-Genesis
|
|
39
|
+
// results are routinely wider than that, and a default-width read throws
|
|
40
|
+
// on them rather than reporting the value.
|
|
41
|
+
stack: (interp.stack || []).map(function (b) {
|
|
42
|
+
return BN.fromScriptNumBuffer(b, false, Math.max(b.length, 4)).toString()
|
|
43
|
+
}),
|
|
39
44
|
// The raw bytes as well: several Chronicle behaviours are about WIDTH, not
|
|
40
45
|
// value, and a script-number reading collapses that distinction.
|
|
41
46
|
raw: (interp.stack || []).map(function (b) { return Buffer.from(b) })
|
|
@@ -60,12 +65,25 @@ describe('Chronicle script surface', function () {
|
|
|
60
65
|
// — and Interpreter.DEFAULT_FLAGS does not exist, so it evaluated `undefined & n`,
|
|
61
66
|
// which is 0 for every n. A tautology, written by me, in the same change that added
|
|
62
67
|
// the flag. What it MEANT to assert is that verify() enables nothing on its own.
|
|
63
|
-
|
|
64
|
-
|
|
68
|
+
// The intent inverted in 8.0.0. It used to assert that verify() enables nothing on
|
|
69
|
+
// its own, which was true and was the bug: a BSV library whose default described
|
|
70
|
+
// Bitcoin in 2015 accepted scripts the network rejects. The default is now current
|
|
71
|
+
// mainnet, so the assertion is that Chronicle IS on without being asked for.
|
|
72
|
+
it('is enabled by default, because mainnet has it', function () {
|
|
73
|
+
// Deliberately NOT via run(): that helper passes CHRONICLE explicitly, so it would
|
|
65
74
|
// measure the helper rather than the library. Omit the argument entirely.
|
|
66
75
|
var script = new Script().add(Opcode.OP_VER)
|
|
67
76
|
var interp = new Interpreter()
|
|
68
|
-
|
|
77
|
+
interp.verify(new Script(), script, new bsv.Transaction(), 0)
|
|
78
|
+
// OP_VER is meaningful under Chronicle; BAD_OPCODE would mean it was not enabled.
|
|
79
|
+
;(interp.errstr || '').should.not.match(/BAD_OPCODE/)
|
|
80
|
+
;(Interpreter.currentConsensusFlags() & CHRONICLE).should.equal(CHRONICLE)
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
it('can still be turned off for a pre-activation UTXO', function () {
|
|
84
|
+
var script = new Script().add(Opcode.OP_VER)
|
|
85
|
+
var interp = new Interpreter()
|
|
86
|
+
var verified = interp.verify(new Script(), script, new bsv.Transaction(), 0, 0)
|
|
69
87
|
verified.should.equal(false)
|
|
70
88
|
interp.errstr.should.match(/BAD_OPCODE/)
|
|
71
89
|
})
|
|
@@ -151,7 +169,7 @@ describe('Chronicle script surface', function () {
|
|
|
151
169
|
})
|
|
152
170
|
|
|
153
171
|
describe('OP_VERIF / OP_VERNOTIF', function () {
|
|
154
|
-
it('
|
|
172
|
+
it('after Genesis, errors only in an EXECUTED branch', function () {
|
|
155
173
|
// Core treats OP_VERIF as illegal everywhere, including unexecuted
|
|
156
174
|
// branches — a rule it applies to no other opcode. BSV dropped that at
|
|
157
175
|
// Genesis, and the node is explicit:
|
|
@@ -161,13 +179,22 @@ describe('Chronicle script surface', function () {
|
|
|
161
179
|
// else return SCRIPT_ERR_BAD_OPCODE;
|
|
162
180
|
// }
|
|
163
181
|
//
|
|
164
|
-
//
|
|
165
|
-
//
|
|
182
|
+
// Note the condition includes utxo_after_genesis, so the era has to be
|
|
183
|
+
// stated. Run without it, this is a pre-Genesis output, and then Core's
|
|
184
|
+
// rule is also BSV's: illegal everywhere, which the node's own corpus
|
|
185
|
+
// confirms for exactly these scripts.
|
|
166
186
|
var unexecuted = run(function (s) {
|
|
167
187
|
s.add(Opcode.OP_0).add(Opcode.OP_IF).add(Opcode.OP_VERIF).add(Opcode.OP_ENDIF).add(Opcode.OP_1)
|
|
168
|
-
}, { flags:
|
|
188
|
+
}, { flags: Interpreter.SCRIPT_UTXO_AFTER_GENESIS })
|
|
169
189
|
unexecuted.verified.should.equal(true)
|
|
170
190
|
|
|
191
|
+
// Pre-Genesis the same script is invalid, unexecuted branch or not.
|
|
192
|
+
var preGenesis = run(function (s) {
|
|
193
|
+
s.add(Opcode.OP_0).add(Opcode.OP_IF).add(Opcode.OP_VERIF).add(Opcode.OP_ENDIF).add(Opcode.OP_1)
|
|
194
|
+
}, { flags: 0 })
|
|
195
|
+
preGenesis.verified.should.equal(false)
|
|
196
|
+
preGenesis.errstr.should.match(/BAD_OPCODE/)
|
|
197
|
+
|
|
171
198
|
var executed = run(function (s) {
|
|
172
199
|
s.add(Opcode.OP_1).add(Opcode.OP_VERIF).add(Opcode.OP_ENDIF)
|
|
173
200
|
}, { flags: 0 })
|
|
@@ -328,11 +355,25 @@ describe('Chronicle script surface', function () {
|
|
|
328
355
|
it('left shift overflows rather than growing without bound', function () {
|
|
329
356
|
// CScriptNum bounds this BEFORE shifting (current_size + shift_bytes >
|
|
330
357
|
// max_length), so a huge count cannot allocate a huge number first.
|
|
331
|
-
|
|
358
|
+
//
|
|
359
|
+
// The count has to exceed the real bound to test that. Chronicle's
|
|
360
|
+
// max_length is 32,000,000 bytes, so 1000 bits — 125 bytes — is a
|
|
361
|
+
// perfectly valid post-Chronicle number and overflows only against the
|
|
362
|
+
// pre-Genesis four. This used to pass because the bound was four
|
|
363
|
+
// whatever the era.
|
|
364
|
+
var r = shift(5, 8 * Interpreter.MAX_SCRIPT_NUM_LENGTH_AFTER_CHRONICLE,
|
|
365
|
+
Opcode.OP_LSHIFTNUM)
|
|
332
366
|
r.verified.should.equal(false)
|
|
333
367
|
r.errstr.should.match(/OVERFLOW/)
|
|
334
368
|
})
|
|
335
369
|
|
|
370
|
+
it('leaves a shift inside the bound alone', function () {
|
|
371
|
+
// The counterpart: 1000 bits is valid post-Chronicle, and was not before.
|
|
372
|
+
var r = shift(5, 1000, Opcode.OP_LSHIFTNUM)
|
|
373
|
+
r.verified.should.equal(true)
|
|
374
|
+
r.raw[0].length.should.equal(126)
|
|
375
|
+
})
|
|
376
|
+
|
|
336
377
|
it('fails on a short stack', function () {
|
|
337
378
|
var r = run(function (s) { s.add(new BN(1).toScriptNumBuffer()).add(Opcode.OP_LSHIFTNUM) })
|
|
338
379
|
r.verified.should.equal(false)
|
|
@@ -370,29 +411,133 @@ describe('Chronicle script surface', function () {
|
|
|
370
411
|
it('OVERRIDES FORKID — otherwise the bit could never select OTDA in practice', function () {
|
|
371
412
|
// FORKID is set on essentially every BSV signature written since 2018, so a
|
|
372
413
|
// CHRONICLE bit that only applied when FORKID was absent would mean nothing.
|
|
414
|
+
//
|
|
415
|
+
// Stated against the algorithm rather than against the flag: the node
|
|
416
|
+
// routes on the bit alone, so with the bit set, enabling forkid makes no
|
|
417
|
+
// difference and the result is the original digest either way.
|
|
373
418
|
var f = fixture()
|
|
374
419
|
var type = Signature.SIGHASH_ALL | Signature.SIGHASH_FORKID | Signature.SIGHASH_CHRONICLE
|
|
375
|
-
var
|
|
376
|
-
f.tx, type, 0, f.sub, f.amt,
|
|
377
|
-
Interpreter.SCRIPT_ENABLE_SIGHASH_FORKID | CHRONICLE
|
|
420
|
+
var withForkId = bsv.Transaction.sighash.sighash(
|
|
421
|
+
f.tx, type, 0, f.sub, f.amt, Interpreter.SCRIPT_ENABLE_SIGHASH_FORKID
|
|
378
422
|
)
|
|
423
|
+
var forcedOtda = bsv.Transaction.sighash.sighash(f.tx, type, 0, f.sub, f.amt, 0)
|
|
424
|
+
withForkId.toString('hex').should.equal(forcedOtda.toString('hex'))
|
|
425
|
+
|
|
426
|
+
// And it does override: without the bit the same transaction takes BIP-143.
|
|
427
|
+
var withoutBit = Signature.SIGHASH_ALL | Signature.SIGHASH_FORKID
|
|
379
428
|
var bip143 = bsv.Transaction.sighash.sighash(
|
|
380
|
-
f.tx,
|
|
429
|
+
f.tx, withoutBit, 0, f.sub, f.amt, Interpreter.SCRIPT_ENABLE_SIGHASH_FORKID
|
|
381
430
|
)
|
|
382
|
-
|
|
431
|
+
bip143.toString('hex').should.not.equal(withForkId.toString('hex'))
|
|
383
432
|
})
|
|
384
433
|
|
|
385
|
-
it('
|
|
434
|
+
it('cannot be used outside Chronicle, so old BIP-143 signatures are unaffected', function () {
|
|
386
435
|
// Before the upgrade the 0x20 bit means nothing, so signatures already exist
|
|
387
|
-
// whose type byte happens to set it.
|
|
388
|
-
//
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
)
|
|
394
|
-
|
|
395
|
-
|
|
436
|
+
// whose type byte happens to set it. Reinterpreting those as OTDA would be
|
|
437
|
+
// a silent validity change on historic data.
|
|
438
|
+
//
|
|
439
|
+
// The node prevents that in CheckSignatureEncoding rather than in the
|
|
440
|
+
// digest function: a signature carrying the bit outside Chronicle is
|
|
441
|
+
// REJECTED, not reinterpreted, so it never reaches a digest at all. That
|
|
442
|
+
// is what lets SignatureHash() route on the bit alone, and gating the
|
|
443
|
+
// digest instead made 260 of the node's 1000 vectors disagree.
|
|
444
|
+
var priv = new bsv.PrivateKey()
|
|
445
|
+
var hashbuf = bsv.crypto.Hash.sha256(Buffer.from('chronicle bit'))
|
|
446
|
+
var type = Signature.SIGHASH_ALL | Signature.SIGHASH_FORKID | Signature.SIGHASH_CHRONICLE
|
|
447
|
+
var sig = bsv.crypto.ECDSA.sign(hashbuf, priv)
|
|
448
|
+
sig.nhashtype = type
|
|
449
|
+
|
|
450
|
+
var interp = new Interpreter()
|
|
451
|
+
interp.set({ flags: Interpreter.SCRIPT_ENABLE_SIGHASH_FORKID | Interpreter.SCRIPT_VERIFY_STRICTENC })
|
|
452
|
+
interp.checkSignatureEncoding(sig.toTxFormat()).should.equal(false)
|
|
453
|
+
interp.errstr.should.equal('SCRIPT_ERR_ILLEGAL_CHRONICLE')
|
|
454
|
+
|
|
455
|
+
// With Chronicle in force it is allowed.
|
|
456
|
+
var ok = new Interpreter()
|
|
457
|
+
ok.set({
|
|
458
|
+
flags: Interpreter.SCRIPT_ENABLE_SIGHASH_FORKID |
|
|
459
|
+
Interpreter.SCRIPT_VERIFY_STRICTENC | Interpreter.SCRIPT_CHRONICLE
|
|
460
|
+
})
|
|
461
|
+
ok.checkSignatureEncoding(sig.toTxFormat()).should.equal(true)
|
|
462
|
+
})
|
|
463
|
+
})
|
|
464
|
+
|
|
465
|
+
describe('mainnet consensus helpers', function () {
|
|
466
|
+
var BN2 = bsv.crypto.BN
|
|
467
|
+
|
|
468
|
+
// useMainnetConsensus() mutates process-wide statics, so the limits are saved
|
|
469
|
+
// and restored around every case here. Without this the raised caps leak into
|
|
470
|
+
// every later test in the run — 27 of them, when it was first written.
|
|
471
|
+
var savedLimits
|
|
472
|
+
beforeEach(function () { savedLimits = Interpreter.getLimits() })
|
|
473
|
+
afterEach(function () { Interpreter.setLimits(savedLimits) })
|
|
474
|
+
|
|
475
|
+
// Genesis reverted CLTV/CSV to OP_NOP2/OP_NOP3, and the node ignores their flags
|
|
476
|
+
// once the UTXO is post-Genesis:
|
|
477
|
+
// if (!(flags & SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY) || utxo_after_genesis)
|
|
478
|
+
// Including them made mainnetFlags() reject scripts mainnet accepts.
|
|
479
|
+
it('mainnetFlags omits CLTV and CSV', function () {
|
|
480
|
+
var f = Interpreter.mainnetFlags()
|
|
481
|
+
;(f & Interpreter.SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY).should.equal(0)
|
|
482
|
+
;(f & Interpreter.SCRIPT_VERIFY_CHECKSEQUENCEVERIFY).should.equal(0)
|
|
483
|
+
})
|
|
484
|
+
|
|
485
|
+
it('mainnetFlags accepts a CLTV script, as mainnet does', function () {
|
|
486
|
+
var lock = new Script()
|
|
487
|
+
.add(new BN2(500000000).toScriptNumBuffer())
|
|
488
|
+
.add(Opcode.OP_CHECKLOCKTIMEVERIFY)
|
|
489
|
+
.add(Opcode.OP_DROP)
|
|
490
|
+
.add(Opcode.OP_1)
|
|
491
|
+
var tx = new bsv.Transaction()
|
|
492
|
+
tx.version = 2
|
|
493
|
+
var interp = new Interpreter()
|
|
494
|
+
interp.verify(new Script(), lock, tx, 0, Interpreter.mainnetFlags(), new BN2(0))
|
|
495
|
+
.should.equal(true)
|
|
496
|
+
interp.errstr.should.equal('')
|
|
497
|
+
})
|
|
498
|
+
|
|
499
|
+
it('mainnetFlags accepts a CSV script, as mainnet does', function () {
|
|
500
|
+
var lock = new Script()
|
|
501
|
+
.add(new BN2(1000).toScriptNumBuffer())
|
|
502
|
+
.add(Opcode.OP_CHECKSEQUENCEVERIFY)
|
|
503
|
+
.add(Opcode.OP_DROP)
|
|
504
|
+
.add(Opcode.OP_1)
|
|
505
|
+
var tx = new bsv.Transaction()
|
|
506
|
+
tx.version = 2
|
|
507
|
+
var interp = new Interpreter()
|
|
508
|
+
interp.verify(new Script(), lock, tx, 0, Interpreter.mainnetFlags(), new BN2(0))
|
|
509
|
+
.should.equal(true)
|
|
510
|
+
})
|
|
511
|
+
|
|
512
|
+
// The flags still exist for pre-Genesis emulation — that capability is retained,
|
|
513
|
+
// it is simply not what mainnet does.
|
|
514
|
+
it('the CLTV flag still enforces when a caller asks for it', function () {
|
|
515
|
+
var lock = new Script()
|
|
516
|
+
.add(new BN2(500000000).toScriptNumBuffer())
|
|
517
|
+
.add(Opcode.OP_CHECKLOCKTIMEVERIFY)
|
|
518
|
+
.add(Opcode.OP_DROP)
|
|
519
|
+
.add(Opcode.OP_1)
|
|
520
|
+
var tx = new bsv.Transaction()
|
|
521
|
+
tx.version = 2
|
|
522
|
+
var interp = new Interpreter()
|
|
523
|
+
interp.verify(new Script(), lock, tx, 0,
|
|
524
|
+
Interpreter.SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY, new BN2(0)).should.equal(false)
|
|
525
|
+
interp.errstr.should.match(/UNSATISFIED_LOCKTIME/)
|
|
526
|
+
})
|
|
527
|
+
|
|
528
|
+
// Flags and limits are separate mechanisms; mainnetFlags() cannot set the statics.
|
|
529
|
+
// A script over the pre-Genesis 10,000-byte cap is valid on mainnet.
|
|
530
|
+
it('useMainnetConsensus lifts the limits that mainnetFlags cannot', function () {
|
|
531
|
+
var big = new Script()
|
|
532
|
+
for (var i = 0; i < 400; i++) big.add(Buffer.alloc(30, 1)).add(Opcode.OP_DROP)
|
|
533
|
+
big.add(Opcode.OP_1)
|
|
534
|
+
big.toBuffer().length.should.be.above(10000)
|
|
535
|
+
|
|
536
|
+
var flags = Interpreter.useMainnetConsensus()
|
|
537
|
+
var interp = new Interpreter()
|
|
538
|
+
interp.verify(new Script(), big, new bsv.Transaction(), 0, flags, new BN2(0))
|
|
539
|
+
.should.equal(true)
|
|
540
|
+
Interpreter.MAX_SCRIPT_SIZE.should.be.above(10000)
|
|
396
541
|
})
|
|
397
542
|
})
|
|
398
543
|
})
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
/* global describe, it */
|
|
4
|
+
|
|
5
|
+
// `verify()` describes BSV mainnet as it is today when the caller says nothing.
|
|
6
|
+
//
|
|
7
|
+
// Until 8.0.0 it defaulted to `0` — no rules at all. That is the wrong direction to be
|
|
8
|
+
// wrong in: a validator looser than consensus accepts scripts the network rejects, and
|
|
9
|
+
// nothing that tests this library against itself can see it. The node vectors found 21
|
|
10
|
+
// such cases the first time they were run.
|
|
11
|
+
//
|
|
12
|
+
// The set is not assembled by judgement. It mirrors what tools/sv-vector-harness.js
|
|
13
|
+
// applies, including the MONOLITH/MAGNETIC pair — BSV restored those opcodes in 2018 and
|
|
14
|
+
// the node does not gate them, so omitting them here would make the default STRICTER
|
|
15
|
+
// than consensus.
|
|
16
|
+
|
|
17
|
+
require('chai').should()
|
|
18
|
+
var bsv = require('../..')
|
|
19
|
+
var Script = bsv.Script
|
|
20
|
+
var Interpreter = Script.Interpreter
|
|
21
|
+
var Opcode = bsv.Opcode
|
|
22
|
+
var BN = bsv.crypto.BN
|
|
23
|
+
|
|
24
|
+
describe('verify() consensus defaults', function () {
|
|
25
|
+
var FLAGS = Interpreter.currentConsensusFlags()
|
|
26
|
+
|
|
27
|
+
it('includes both era pairs, for the spend and the output being spent', function () {
|
|
28
|
+
;[
|
|
29
|
+
'SCRIPT_GENESIS', 'SCRIPT_UTXO_AFTER_GENESIS',
|
|
30
|
+
'SCRIPT_ENABLE_CHRONICLE', 'SCRIPT_UTXO_AFTER_CHRONICLE'
|
|
31
|
+
].forEach(function (name) {
|
|
32
|
+
(FLAGS & Interpreter[name]).should.equal(Interpreter[name], name + ' missing from the default')
|
|
33
|
+
})
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
// Omitting these would make the library stricter than the node, which is the error
|
|
37
|
+
// #112 fixed in mainnetFlags(). The harness sets the same pair for every vector.
|
|
38
|
+
it('enables the opcode groups the node does not gate', function () {
|
|
39
|
+
(FLAGS & Interpreter.SCRIPT_ENABLE_MONOLITH_OPCODES)
|
|
40
|
+
.should.equal(Interpreter.SCRIPT_ENABLE_MONOLITH_OPCODES)
|
|
41
|
+
;(FLAGS & Interpreter.SCRIPT_ENABLE_MAGNETIC_OPCODES)
|
|
42
|
+
.should.equal(Interpreter.SCRIPT_ENABLE_MAGNETIC_OPCODES)
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
it('does not enable the pre-Genesis timelock flags', function () {
|
|
46
|
+
// Genesis reverted CLTV/CSV to upgradable NOPs; carrying their flags made
|
|
47
|
+
// mainnetFlags() report timelocked outputs unspendable. See #112.
|
|
48
|
+
;(FLAGS & Interpreter.SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY).should.equal(0)
|
|
49
|
+
;(FLAGS & Interpreter.SCRIPT_VERIFY_CHECKSEQUENCEVERIFY).should.equal(0)
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
describe('applied by verify()', function () {
|
|
53
|
+
function evaluate (build, args) {
|
|
54
|
+
var script = new Script()
|
|
55
|
+
build(script)
|
|
56
|
+
var interp = new Interpreter()
|
|
57
|
+
var verified = interp.verify.apply(interp, [new Script(), script].concat(args || []))
|
|
58
|
+
return { verified: verified, errstr: interp.errstr || '' }
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// OP_VER is a Chronicle opcode. Reaching it without BAD_OPCODE proves the default
|
|
62
|
+
// enabled Chronicle rather than merely exposing a constant.
|
|
63
|
+
it('evaluates a Chronicle opcode with no flags argument', function () {
|
|
64
|
+
var r = evaluate(function (s) { s.add(Opcode.OP_VER) }, [new bsv.Transaction(), 0])
|
|
65
|
+
r.errstr.should.not.match(/BAD_OPCODE/)
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
it('still lets the caller select older rules explicitly', function () {
|
|
69
|
+
var r = evaluate(function (s) { s.add(Opcode.OP_VER) }, [new bsv.Transaction(), 0, 0])
|
|
70
|
+
r.verified.should.equal(false)
|
|
71
|
+
r.errstr.should.match(/BAD_OPCODE/)
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
// FORKID changes the sighash algorithm and cannot be applied without the input
|
|
75
|
+
// amount — verify() rejects that combination outright. Rather than forcing every
|
|
76
|
+
// caller to supply satoshis for scripts containing no signature check, the flag is
|
|
77
|
+
// dropped when there is nothing for it to act on. A FORKID-signed input without the
|
|
78
|
+
// amount then fails to verify, which is a false negative, never a false positive.
|
|
79
|
+
it('drops FORKID when no input amount is supplied, instead of throwing', function () {
|
|
80
|
+
;(function () {
|
|
81
|
+
evaluate(function (s) { s.add(Opcode.OP_1) }, [new bsv.Transaction(), 0])
|
|
82
|
+
}).should.not.throw()
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
it('keeps FORKID when the input amount is supplied', function () {
|
|
86
|
+
var interp = new Interpreter()
|
|
87
|
+
var script = new Script().add(Opcode.OP_1)
|
|
88
|
+
interp.verify(new Script(), script, new bsv.Transaction(), 0, undefined, new BN(1000))
|
|
89
|
+
;(interp.flags & Interpreter.SCRIPT_ENABLE_SIGHASH_FORKID)
|
|
90
|
+
.should.equal(Interpreter.SCRIPT_ENABLE_SIGHASH_FORKID)
|
|
91
|
+
})
|
|
92
|
+
})
|
|
93
|
+
})
|
|
@@ -24,7 +24,8 @@ describe('Interpreter post-Genesis limits', function () {
|
|
|
24
24
|
it('keeps pre-Genesis defaults out of the box', function () {
|
|
25
25
|
Interpreter.MAX_SCRIPT_ELEMENT_SIZE.should.equal(520)
|
|
26
26
|
Interpreter.MAXIMUM_ELEMENT_SIZE.should.equal(4)
|
|
27
|
-
|
|
27
|
+
// 500, not Core's 201: BSV raised the limit before Genesis removed it.
|
|
28
|
+
Interpreter.MAX_OPS_PER_SCRIPT.should.equal(500)
|
|
28
29
|
})
|
|
29
30
|
|
|
30
31
|
it('useGenesisLimits() lifts all three caps', function () {
|
|
@@ -59,15 +60,17 @@ describe('Interpreter post-Genesis limits', function () {
|
|
|
59
60
|
})
|
|
60
61
|
|
|
61
62
|
// 220 OP_NOPs then OP_1 — more non-push opcodes than the 201 cap allows.
|
|
63
|
+
// Over BSV's pre-Genesis limit of 500. It used to be 220, which is over
|
|
64
|
+
// Core's 201 but comfortably inside what BSV allowed.
|
|
62
65
|
var manyOps = new Script()
|
|
63
|
-
for (var i = 0; i <
|
|
66
|
+
for (var i = 0; i < 520; i++) manyOps.add(Opcode.OP_NOP)
|
|
64
67
|
manyOps.add(Opcode.OP_1)
|
|
65
68
|
|
|
66
|
-
it('rejects
|
|
69
|
+
it('rejects more opcodes than the pre-Genesis limit allows', function () {
|
|
67
70
|
run(manyOps).should.equal(false)
|
|
68
71
|
})
|
|
69
72
|
|
|
70
|
-
it('allows
|
|
73
|
+
it('allows them after useGenesisLimits()', function () {
|
|
71
74
|
Interpreter.useGenesisLimits()
|
|
72
75
|
run(manyOps).should.equal(true)
|
|
73
76
|
})
|
|
@@ -87,11 +90,23 @@ describe('Interpreter post-Genesis limits', function () {
|
|
|
87
90
|
Interpreter.MAX_SCRIPT_SIZE.should.equal(10000)
|
|
88
91
|
})
|
|
89
92
|
|
|
90
|
-
|
|
93
|
+
// Intent inverted in 8.0.0. verify() now defaults to current mainnet, where Genesis
|
|
94
|
+
// removed the size cap, so a 20 KB script is accepted unless the caller asks for the
|
|
95
|
+
// pre-Genesis era. The cap is still enforced — it just has to be selected, which is
|
|
96
|
+
// what the following test asserts.
|
|
97
|
+
it('accepts a >10 KB script under the default (post-Genesis) rules', function () {
|
|
98
|
+
Interpreter.useGenesisLimits()
|
|
99
|
+
Interpreter.MAX_SCRIPT_SIZE = 10000 // the static cap is irrelevant post-Genesis
|
|
100
|
+
var interp = new Interpreter()
|
|
101
|
+
interp.verify(new Script(), scriptOfSize(20 * 1024)).should.equal(true)
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
it('rejects a >10 KB script when the pre-Genesis era is asked for', function () {
|
|
91
105
|
Interpreter.useGenesisLimits() // lift element/ops caps so SIZE is what is under test
|
|
92
106
|
Interpreter.MAX_SCRIPT_SIZE = 10000 // ...but keep the pre-Genesis size cap
|
|
93
107
|
var interp = new Interpreter()
|
|
94
|
-
|
|
108
|
+
// Flags omitted would mean post-Genesis; 0 selects the older rules explicitly.
|
|
109
|
+
interp.verify(new Script(), scriptOfSize(20 * 1024), new bsv.Transaction(), 0, 0).should.equal(false)
|
|
95
110
|
interp.errstr.should.equal('SCRIPT_ERR_SCRIPT_SIZE')
|
|
96
111
|
})
|
|
97
112
|
|
|
@@ -100,6 +115,47 @@ describe('Interpreter post-Genesis limits', function () {
|
|
|
100
115
|
run(scriptOfSize(20 * 1024)).should.equal(true)
|
|
101
116
|
})
|
|
102
117
|
|
|
118
|
+
// Genesis lifted the 520-byte element cap, and OP_CAT is where an
|
|
119
|
+
// implementation is most likely to keep enforcing it: it is the one opcode
|
|
120
|
+
// that can grow an element past the limit from two legal halves. This read
|
|
121
|
+
// the static constant rather than the era-derived size, so it stayed capped
|
|
122
|
+
// at 520 after Genesis and rejected concatenations the network accepts.
|
|
123
|
+
//
|
|
124
|
+
// No vector in the SV corpus covers it, so the corpus passes completely
|
|
125
|
+
// either way. It is held here instead.
|
|
126
|
+
describe('OP_CAT and the element size cap', function () {
|
|
127
|
+
var MONOLITH = Interpreter.SCRIPT_ENABLE_MONOLITH_OPCODES
|
|
128
|
+
|
|
129
|
+
// Two 300-byte pushes: each is legal pre-Genesis, their concatenation is
|
|
130
|
+
// not. Nothing but the cap distinguishes the two cases below.
|
|
131
|
+
var cat = new Script()
|
|
132
|
+
.add(Buffer.alloc(300, 1))
|
|
133
|
+
.add(Buffer.alloc(300, 1))
|
|
134
|
+
.add(Opcode.OP_CAT)
|
|
135
|
+
|
|
136
|
+
function runWith (flags) {
|
|
137
|
+
var interp = new Interpreter()
|
|
138
|
+
var ok
|
|
139
|
+
try {
|
|
140
|
+
ok = interp.verify(new Script(), cat, new Transaction(), 0, flags)
|
|
141
|
+
} catch (e) {
|
|
142
|
+
ok = false
|
|
143
|
+
}
|
|
144
|
+
return { ok: ok, errstr: interp.errstr }
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
it('rejects a 600-byte concatenation before Genesis', function () {
|
|
148
|
+
var got = runWith(MONOLITH)
|
|
149
|
+
got.ok.should.equal(false)
|
|
150
|
+
got.errstr.should.equal('SCRIPT_ERR_PUSH_SIZE')
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
it('allows it after Genesis', function () {
|
|
154
|
+
var got = runWith(MONOLITH | Interpreter.SCRIPT_UTXO_AFTER_GENESIS)
|
|
155
|
+
got.ok.should.equal(true, 'rejected with ' + got.errstr)
|
|
156
|
+
})
|
|
157
|
+
})
|
|
158
|
+
|
|
103
159
|
it('useGenesisLimits raises all four caps, and getLimits/setLimits round-trip', function () {
|
|
104
160
|
var before = Interpreter.getLimits()
|
|
105
161
|
before.maxScriptSize.should.equal(10000)
|
|
@@ -649,14 +649,22 @@ describe('Interpreter', function () {
|
|
|
649
649
|
// (0xba is no longer a NOP either; it is unassigned, which now AGREES with
|
|
650
650
|
// Core, so its former override has been removed.)
|
|
651
651
|
var BSV_DIVERGENCES = {
|
|
652
|
-
// - OP_VERIF/OP_VERNOTIF
|
|
653
|
-
//
|
|
654
|
-
//
|
|
655
|
-
//
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
652
|
+
// - The four OP_VERIF/OP_VERNOTIF rows that used to be listed here are
|
|
653
|
+
// gone. They were overridden to 'OK' on the reasoning that BSV dropped
|
|
654
|
+
// Core's "illegal everywhere" rule at Genesis, which is half the rule.
|
|
655
|
+
// The node reads
|
|
656
|
+
//
|
|
657
|
+
// if(!utxo_after_chronicle) {
|
|
658
|
+
// if(utxo_after_genesis && !fExec) break;
|
|
659
|
+
// else return SCRIPT_ERR_BAD_OPCODE;
|
|
660
|
+
// }
|
|
661
|
+
//
|
|
662
|
+
// so an unexecuted one is harmless only when the UTXO is post-Genesis.
|
|
663
|
+
// These rows carry P2SH,STRICTENC and no Genesis flag, so they are
|
|
664
|
+
// pre-Genesis and BAD_OPCODE is right — and the node's own corpus says
|
|
665
|
+
// so, in test/data/bitcoin-sv, with the same comment. The override was
|
|
666
|
+
// a reasonable inference while this library could not express an era
|
|
667
|
+
// and everything was implicitly post-Genesis. It can now.
|
|
660
668
|
"'a' 'b'|CAT|P2SH,STRICTENC": 'OK',
|
|
661
669
|
"'a' 'b' 0|IF CAT ELSE 1 ENDIF|P2SH,STRICTENC": 'OK',
|
|
662
670
|
"'abc' 1|SPLIT|P2SH,STRICTENC": 'OK',
|
|
@@ -689,6 +697,14 @@ describe('Interpreter', function () {
|
|
|
689
697
|
extraData = vector.shift()
|
|
690
698
|
}
|
|
691
699
|
|
|
700
|
+
// Bitcoin Core's 201-operation limit. BSV raised it to 500 before
|
|
701
|
+
// Genesis removed it altogether, so these five rows describe a rule
|
|
702
|
+
// the network has not applied since 2020. The node's own corpus in
|
|
703
|
+
// test/data/bitcoin-sv contains no OP_COUNT row at all.
|
|
704
|
+
if (vector[3] === 'OP_COUNT') {
|
|
705
|
+
return
|
|
706
|
+
}
|
|
707
|
+
|
|
692
708
|
var fullScriptString = `${vector[0]} ${vector[1]}`
|
|
693
709
|
var divergeKey = `${vector[0]}|${vector[1]}|${vector[2]}`
|
|
694
710
|
var expectedError = Object.prototype.hasOwnProperty.call(BSV_DIVERGENCES, divergeKey)
|
|
@@ -32,7 +32,10 @@ describe('sighash', function () {
|
|
|
32
32
|
var scriptbuf = buffer.Buffer.from(vector[1], 'hex')
|
|
33
33
|
var subscript = Script(scriptbuf)
|
|
34
34
|
var nin = vector[2]
|
|
35
|
-
|
|
35
|
+
// This vector happens to set the Chronicle bit as well. Only BIP-143 needs
|
|
36
|
+
// the input's amount, so the bit has to be cleared for its omission to be
|
|
37
|
+
// an error at all.
|
|
38
|
+
var nhashtype = vector[3] & ~Signature.SIGHASH_CHRONICLE
|
|
36
39
|
var sighashbuf = buffer.Buffer.from(vector[4], 'hex')
|
|
37
40
|
var tx = new Transaction(txbuf)
|
|
38
41
|
|
|
@@ -46,11 +49,28 @@ describe('sighash', function () {
|
|
|
46
49
|
})
|
|
47
50
|
|
|
48
51
|
var zeroBN = BN.Zero
|
|
52
|
+
// These vectors were recorded before Chronicle, when bit 0x20 of the sighash
|
|
53
|
+
// type carried no meaning and BIP-143 was selected on the forkid bit alone.
|
|
54
|
+
// Chronicle gave 0x20 to SIGHASH_CHRONICLE, which selects the original digest
|
|
55
|
+
// even when forkid is present, so for a row setting both bits the recorded
|
|
56
|
+
// digest is no longer the answer. Those 251 rows are skipped rather than
|
|
57
|
+
// restated: editing a copied corpus costs it the outside-check value it was
|
|
58
|
+
// imported for, and the behaviour they used to pin is covered properly by
|
|
59
|
+
// test/consensus/sv-sighash-vectors.js, whose vectors come from the Chronicle
|
|
60
|
+
// node itself and carry both digests for every row.
|
|
61
|
+
function usesChronicleDigest (nhashtype) {
|
|
62
|
+
var t = nhashtype >>> 0
|
|
63
|
+
return (t & Signature.SIGHASH_FORKID) !== 0 && (t & Signature.SIGHASH_CHRONICLE) !== 0
|
|
64
|
+
}
|
|
65
|
+
|
|
49
66
|
vectorsSighash.forEach(function (vector, i) {
|
|
50
67
|
if (i === 0 || !vector[4]) {
|
|
51
68
|
// First element is just a row describing the next ones
|
|
52
69
|
return
|
|
53
70
|
}
|
|
71
|
+
if (usesChronicleDigest(vector[3])) {
|
|
72
|
+
return
|
|
73
|
+
}
|
|
54
74
|
it('test vector from bitcoind #' + i + ' (' + vector[4].substring(0, 16) + ')', function () {
|
|
55
75
|
var txbuf = buffer.Buffer.from(vector[0], 'hex')
|
|
56
76
|
var scriptbuf = buffer.Buffer.from(vector[1], 'hex')
|
package/version.js
CHANGED