@smartledger/bsv 7.12.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.
Files changed (56) hide show
  1. package/CHANGELOG.md +178 -0
  2. package/README.md +38 -38
  3. package/bsv-didweb.min.js +6 -6
  4. package/bsv-gdaf.min.js +66 -66
  5. package/bsv-ltp.min.js +46 -46
  6. package/bsv-mnemonic.min.js +8 -8
  7. package/bsv-smartcontract.min.js +1 -1
  8. package/bsv.bundle.js +66 -66
  9. package/bsv.min.js +66 -66
  10. package/docs/AUDIT_SCOPE.md +29 -21
  11. package/docs/MODULE_REFERENCE_COMPLETE.md +27 -27
  12. package/docs/advanced/UTXO_MANAGER_GUIDE.md +1 -1
  13. package/docs/getting-started/INSTALLATION.md +23 -23
  14. package/docs/getting-started/QUICK_START.md +7 -7
  15. package/docs/migration/FROM_BSV_1_5_6.md +5 -5
  16. package/index.js +10 -2
  17. package/lib/crypto/bn.js +22 -2
  18. package/lib/crypto/hash.browser.js +13 -5
  19. package/lib/crypto/hash.js +58 -2
  20. package/lib/crypto/random.js +72 -15
  21. package/lib/didweb/index.js +88 -9
  22. package/lib/encoding/base58.js +67 -3
  23. package/lib/mnemonic/mnemonic.js +19 -5
  24. package/lib/mnemonic/pbkdf2.js +35 -2
  25. package/lib/script/interpreter.js +420 -58
  26. package/lib/transaction/input/multisig.js +1 -1
  27. package/lib/transaction/input/multisigscripthash.js +1 -1
  28. package/lib/transaction/input/publickey.js +1 -1
  29. package/lib/transaction/input/publickeyhash.js +1 -1
  30. package/lib/transaction/sighash.js +18 -6
  31. package/lib/transaction/signature.js +1 -1
  32. package/lib/util/inherits.js +37 -0
  33. package/package.json +7 -8
  34. package/test/consensus/base58-vectors.js +120 -0
  35. package/test/consensus/sv-script-vectors.js +81 -0
  36. package/test/consensus/sv-sighash-vectors.js +51 -0
  37. package/test/consensus/sv-tx-vectors.js +48 -0
  38. package/test/crypto/backend_selection.js +126 -0
  39. package/test/crypto/random.js +73 -0
  40. package/test/data/bitcoin-sv/README.md +170 -0
  41. package/test/data/bitcoin-sv/base58_encode_decode.json +14 -0
  42. package/test/data/bitcoin-sv/base58_keys_invalid.json +152 -0
  43. package/test/data/bitcoin-sv/base58_keys_valid.json +452 -0
  44. package/test/data/bitcoin-sv/script_tests.json +2591 -0
  45. package/test/data/bitcoin-sv/sighash.json +1003 -0
  46. package/test/data/bitcoin-sv/tx_invalid.json +285 -0
  47. package/test/data/bitcoin-sv/tx_valid.json +367 -0
  48. package/test/didweb/relationships.js +144 -0
  49. package/test/regressions.js +35 -0
  50. package/test/script/chronicle.js +170 -25
  51. package/test/script/defaults.js +93 -0
  52. package/test/script/genesis_limits.js +62 -6
  53. package/test/script/interpreter.js +24 -8
  54. package/test/transaction/sighash.js +21 -1
  55. package/test/transaction/unspentoutput.js +6 -1
  56. package/version.js +1 -1
@@ -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
- stack: (interp.stack || []).map(function (b) { return BN.fromScriptNumBuffer(b).toString() }),
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
- it('is not enabled unless the caller asks: verify() defaults to no flags', function () {
64
- // Deliberately NOT via run(): that helper defaults to CHRONICLE, so it would
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
- var verified = interp.verify(new Script(), script, new bsv.Transaction(), 0)
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('without the flag, errors only in an EXECUTED branch', function () {
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
- // Asserting BAD_OPCODE here made this library reject scripts the network
165
- // accepts.
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: 0 })
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
- var r = shift(5, 1000, Opcode.OP_LSHIFTNUM)
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 chronicle = bsv.Transaction.sighash.sighash(
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, type, 0, f.sub, f.amt, Interpreter.SCRIPT_ENABLE_SIGHASH_FORKID
429
+ f.tx, withoutBit, 0, f.sub, f.amt, Interpreter.SCRIPT_ENABLE_SIGHASH_FORKID
381
430
  )
382
- chronicle.toString('hex').should.not.equal(bip143.toString('hex'))
431
+ bip143.toString('hex').should.not.equal(withForkId.toString('hex'))
383
432
  })
384
433
 
385
- it('is IGNORED without the flag, so existing BIP-143 signatures are unaffected', function () {
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. Honouring it unconditionally would
388
- // reinterpret those as OTDA — a silent validity change on historic data.
389
- var f = fixture()
390
- var withBit = Signature.SIGHASH_ALL | Signature.SIGHASH_FORKID | Signature.SIGHASH_CHRONICLE
391
- var viaForkId = bsv.Transaction.sighash.sighash(
392
- f.tx, withBit, 0, f.sub, f.amt, Interpreter.SCRIPT_ENABLE_SIGHASH_FORKID
393
- )
394
- var forcedOtda = bsv.Transaction.sighash.sighash(f.tx, withBit, 0, f.sub, f.amt, 0)
395
- viaForkId.toString('hex').should.not.equal(forcedOtda.toString('hex'))
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
- Interpreter.MAX_OPS_PER_SCRIPT.should.equal(201)
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 < 220; i++) manyOps.add(Opcode.OP_NOP)
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 >201 opcodes under default limits', function () {
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 >201 opcodes after useGenesisLimits()', function () {
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
- it('rejects a >10 KB script under default limits', function () {
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
- interp.verify(new Script(), scriptOfSize(20 * 1024)).should.equal(false)
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 are "illegal everywhere" in Core, including in an
653
- // unexecuted branch — a rule it applies to no other opcode. BSV dropped
654
- // that at Genesis: the node breaks when the branch is not executed and
655
- // the UTXO predates Chronicle. So these four verify here.
656
- '0|IF VERIF ELSE 1 ENDIF|P2SH,STRICTENC': 'OK',
657
- '0|IF ELSE 1 ELSE VERIF ENDIF|P2SH,STRICTENC': 'OK',
658
- '0|IF VERNOTIF ELSE 1 ENDIF|P2SH,STRICTENC': 'OK',
659
- '0|IF ELSE 1 ELSE VERNOTIF ENDIF|P2SH,STRICTENC': 'OK',
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
- var nhashtype = vector[3]
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')
@@ -2,7 +2,12 @@
2
2
 
3
3
  var chai = require('chai')
4
4
  var expect = chai.expect
5
- var cloneDeep = require('clone-deep')
5
+ /* global structuredClone */
6
+ // structuredClone, not the former clone-deep dependency: the fixture below is plain
7
+ // JSON (strings and numbers), where the two are equivalent. The interpreter's stack
8
+ // clone is NOT — it holds Buffers, which structuredClone would return as Uint8Array.
9
+ // The global comment is for standard@12's eslint, which predates the API.
10
+ var cloneDeep = structuredClone
6
11
 
7
12
  var bsv = require('../..')
8
13
  var UnspentOutput = bsv.Transaction.UnspentOutput
package/version.js CHANGED
@@ -1,3 +1,3 @@
1
1
  'use strict'
2
2
  // GENERATED by scripts/sync-version.js on `npm version` — do not edit.
3
- module.exports = '7.12.0'
3
+ module.exports = '8.0.0'