@smartledger/bsv 7.13.0 → 8.0.1

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 (36) hide show
  1. package/CHANGELOG.md +151 -0
  2. package/README.md +38 -38
  3. package/bsv-gdaf.min.js +55 -55
  4. package/bsv-ltp.min.js +39 -39
  5. package/bsv-smartcontract.min.js +1 -1
  6. package/bsv.bundle.js +55 -55
  7. package/bsv.min.js +55 -55
  8. package/docs/AUDIT_SCOPE.md +21 -12
  9. package/docs/MODULE_REFERENCE_COMPLETE.md +27 -27
  10. package/docs/advanced/UTXO_MANAGER_GUIDE.md +1 -1
  11. package/docs/getting-started/INSTALLATION.md +23 -23
  12. package/docs/getting-started/QUICK_START.md +7 -7
  13. package/docs/migration/FROM_BSV_1_5_6.md +5 -5
  14. package/lib/crypto/bn.js +22 -2
  15. package/lib/script/interpreter.js +396 -58
  16. package/lib/transaction/sighash.js +18 -6
  17. package/package.json +4 -1
  18. package/test/consensus/base58-vectors.js +120 -0
  19. package/test/consensus/sv-script-vectors.js +81 -0
  20. package/test/consensus/sv-sighash-vectors.js +51 -0
  21. package/test/consensus/sv-tx-vectors.js +48 -0
  22. package/test/data/bitcoin-sv/README.md +170 -0
  23. package/test/data/bitcoin-sv/base58_encode_decode.json +14 -0
  24. package/test/data/bitcoin-sv/base58_keys_invalid.json +152 -0
  25. package/test/data/bitcoin-sv/base58_keys_valid.json +452 -0
  26. package/test/data/bitcoin-sv/script_tests.json +2591 -0
  27. package/test/data/bitcoin-sv/sighash.json +1003 -0
  28. package/test/data/bitcoin-sv/tx_invalid.json +285 -0
  29. package/test/data/bitcoin-sv/tx_valid.json +367 -0
  30. package/test/regressions.js +35 -0
  31. package/test/script/chronicle.js +170 -25
  32. package/test/script/defaults.js +160 -0
  33. package/test/script/genesis_limits.js +62 -6
  34. package/test/script/interpreter.js +24 -8
  35. package/test/transaction/sighash.js +21 -1
  36. package/version.js +1 -1
@@ -75,7 +75,8 @@ Interpreter.prototype.verify = function (scriptSig, scriptPubkey, tx, nin, flags
75
75
  nin = 0
76
76
  }
77
77
  if (_.isUndefined(flags)) {
78
- flags = 0
78
+ flags = Interpreter.currentConsensusFlags()
79
+ if (!satoshisBN) flags &= ~Interpreter.SCRIPT_ENABLE_SIGHASH_FORKID
79
80
  }
80
81
 
81
82
  // If FORKID is enabled, we also ensure strict encoding.
@@ -107,7 +108,12 @@ Interpreter.prototype.verify = function (scriptSig, scriptPubkey, tx, nin, flags
107
108
  return false
108
109
  }
109
110
 
110
- if (flags & Interpreter.SCRIPT_VERIFY_P2SH) {
111
+ // Genesis removed P2SH: an output created after it that happens to match the
112
+ // pattern is evaluated literally, with no redeem-script pass.
113
+ var p2sh = (flags & Interpreter.SCRIPT_VERIFY_P2SH) !== 0 &&
114
+ (flags & Interpreter.SCRIPT_UTXO_AFTER_GENESIS) === 0
115
+
116
+ if (p2sh) {
111
117
  stackCopy = this.stack.slice()
112
118
  }
113
119
 
@@ -139,7 +145,7 @@ Interpreter.prototype.verify = function (scriptSig, scriptPubkey, tx, nin, flags
139
145
  }
140
146
 
141
147
  // Additional validation for spend-to-script-hash transactions:
142
- if ((flags & Interpreter.SCRIPT_VERIFY_P2SH) && scriptPubkey.isScriptHashOut()) {
148
+ if (p2sh && scriptPubkey.isScriptHashOut()) {
143
149
  // scriptSig must be literals-only or validation fails
144
150
  if (!scriptSig.isPushOnly()) {
145
151
  this.errstr = 'SCRIPT_ERR_SIG_PUSHONLY'
@@ -191,11 +197,18 @@ Interpreter.prototype.verify = function (scriptSig, scriptPubkey, tx, nin, flags
191
197
  // Disallow CLEANSTACK without P2SH, as otherwise a switch
192
198
  // CLEANSTACK->P2SH+CLEANSTACK would be possible, which is not a
193
199
  // softfork (and P2SH should be one).
194
- if ((flags & Interpreter.SCRIPT_VERIFY_P2SH) === 0) {
200
+ // Genesis removed P2SH, so post-Genesis the pairing no longer applies and
201
+ // CLEANSTACK stands on its own.
202
+ if ((flags & Interpreter.SCRIPT_VERIFY_P2SH) === 0 &&
203
+ (flags & Interpreter.SCRIPT_UTXO_AFTER_GENESIS) === 0) {
195
204
  throw new Error('internal error - CLEANSTACK without P2SH')
196
205
  }
197
206
 
198
- if (stackCopy.length !== 1) {
207
+ // The final stack. After a P2SH evaluation that is stackCopy itself, since
208
+ // the redeem script was evaluated over it, but reading stackCopy directly
209
+ // is wrong once P2SH no longer applies: it is then either the stack as it
210
+ // stood after the scriptSig, or never assigned at all.
211
+ if (this.stack.length !== 1) {
199
212
  this.errstr = 'SCRIPT_ERR_CLEANSTACK'
200
213
  return false
201
214
  }
@@ -212,7 +225,15 @@ Interpreter.prototype.initialize = function (obj) {
212
225
  this.pc = 0
213
226
  this.pbegincodehash = 0
214
227
  this.nOpCount = 0
228
+ this.returned = false
229
+ // Set when an OP_RETURN is reached inside a conditional after Genesis: the
230
+ // rest of the script stops executing while the conditional grammar is still
231
+ // checked to the end.
232
+ this.nonTopLevelReturnAfterGenesis = false
215
233
  this.vfExec = []
234
+ // Whether the conditional at each depth has already seen an OP_ELSE.
235
+ // Genesis allows only one per OP_IF, which needs remembering per level.
236
+ this.vfElse = []
216
237
  this.errstr = ''
217
238
  this.flags = 0
218
239
  }
@@ -227,7 +248,13 @@ Interpreter.prototype.set = function (obj) {
227
248
  this.pc = typeof obj.pc !== 'undefined' ? obj.pc : this.pc
228
249
  this.pbegincodehash = typeof obj.pbegincodehash !== 'undefined' ? obj.pbegincodehash : this.pbegincodehash
229
250
  this.nOpCount = typeof obj.nOpCount !== 'undefined' ? obj.nOpCount : this.nOpCount
251
+ this.returned = typeof obj.returned !== 'undefined' ? obj.returned : this.returned
252
+ this.nonTopLevelReturnAfterGenesis =
253
+ typeof obj.nonTopLevelReturnAfterGenesis !== 'undefined'
254
+ ? obj.nonTopLevelReturnAfterGenesis
255
+ : this.nonTopLevelReturnAfterGenesis
230
256
  this.vfExec = obj.vfExec || this.vfExec
257
+ this.vfElse = obj.vfElse || this.vfElse
231
258
  this.errstr = obj.errstr || this.errstr
232
259
  this.flags = typeof obj.flags !== 'undefined' ? obj.flags : this.flags
233
260
  }
@@ -236,12 +263,19 @@ Interpreter.true = Buffer.from([1])
236
263
  Interpreter.false = Buffer.from([])
237
264
 
238
265
  Interpreter.MAX_SCRIPT_ELEMENT_SIZE = 520
266
+ // CScriptNum's `max_length`: the widest a script NUMBER may be, in bytes. Distinct from
267
+ // MAX_SCRIPT_ELEMENT_SIZE, which caps a pushed data element. Arithmetic opcodes read
268
+ // operands through it, and Chronicle's shift bounds its result against it.
239
269
  Interpreter.MAXIMUM_ELEMENT_SIZE = 4
270
+
240
271
  // Maximum number of non-push opcodes per script. Pre-Genesis consensus is 201;
241
272
  // post-Genesis BSV removed this limit. Exposed as a constant (instead of a magic
242
273
  // number) so applications can opt into post-Genesis rules — e.g. OP_PUSH_TX
243
274
  // covenants, which need a few hundred opcodes — without forking the interpreter.
244
- Interpreter.MAX_OPS_PER_SCRIPT = 201
275
+ // BSV's pre-Genesis figure is 500, not Bitcoin Core's 201: the limit was
276
+ // raised before Genesis removed it altogether. Carrying Core's number rejected
277
+ // scripts the network accepted.
278
+ Interpreter.MAX_OPS_PER_SCRIPT = 500
245
279
  // Maximum total serialized script size. Pre-Genesis consensus is 10,000 bytes;
246
280
  // post-Genesis BSV removed this limit too. It was previously a literal inside
247
281
  // evaluate(), so `useGenesisLimits()` could not lift it and any script over 10 KB —
@@ -249,6 +283,16 @@ Interpreter.MAX_OPS_PER_SCRIPT = 201
249
283
  // no matter what the caller asked for.
250
284
  Interpreter.MAX_SCRIPT_SIZE = 10000
251
285
 
286
+ // Genesis and Chronicle limits, from the node's src/consensus/consensus.h.
287
+ // These are the values the WIP note above asked to be pinned against the node
288
+ // source: Genesis raised the script-number bound to 750,000 bytes and
289
+ // Chronicle to 32,000,000, and removed the element, script size and operation
290
+ // caps outright.
291
+ Interpreter.UNLIMITED = Number.MAX_SAFE_INTEGER
292
+ Interpreter.MAX_SCRIPT_NUM_LENGTH_AFTER_GENESIS = 750000
293
+ Interpreter.MAX_SCRIPT_NUM_LENGTH_AFTER_CHRONICLE = 32000000
294
+ Interpreter.MAX_PUBKEYS_PER_MULTISIG_AFTER_GENESIS = 4294967295
295
+
252
296
  Interpreter.LOCKTIME_THRESHOLD = 500000000
253
297
  Interpreter.LOCKTIME_THRESHOLD_BN = new BN(Interpreter.LOCKTIME_THRESHOLD)
254
298
 
@@ -398,17 +442,41 @@ Interpreter.SCRIPT_ENABLE_REPLAY_PROTECTION = (1 << 17)
398
442
 
399
443
  // Enable new opcodes.
400
444
  //
401
- Interpreter.SCRIPT_ENABLE_MONOLITH_OPCODES = (1 << 18)
445
+ // Moved off 1<<18 and 1<<19, which the reference node assigns to
446
+ // SCRIPT_GENESIS and SCRIPT_UTXO_AFTER_GENESIS. Sharing those bits meant that
447
+ // node-derived flags passed into this library were silently read as something
448
+ // else. These two are BCH-era flags the node does not define at all, so their
449
+ // positions carry no consensus meaning and are free to move.
450
+ Interpreter.SCRIPT_ENABLE_MONOLITH_OPCODES = (1 << 11)
402
451
 
403
452
  // Are the Magnetic upgrade opcodes enabled?
404
453
  //
405
- Interpreter.SCRIPT_ENABLE_MAGNETIC_OPCODES = (1 << 19)
454
+ Interpreter.SCRIPT_ENABLE_MAGNETIC_OPCODES = (1 << 12)
455
+
456
+ // The era flags, at the bit positions src/script/script_flags.h assigns them.
457
+ // Keep them in sync: they are consensus-relevant and are passed across the
458
+ // boundary with node-derived test vectors.
459
+ //
460
+ // The distinction between the pairs matters. SCRIPT_UTXO_AFTER_* describes the
461
+ // output being spent and governs almost every rule, because an output made
462
+ // before an upgrade is spent under the old rules forever. SCRIPT_GENESIS and
463
+ // SCRIPT_CHRONICLE describe the block the spending transaction is in.
464
+ Interpreter.SCRIPT_GENESIS = (1 << 18)
465
+ Interpreter.SCRIPT_UTXO_AFTER_GENESIS = (1 << 19)
406
466
 
407
467
  // Chronicle restores OP_2MUL/OP_2DIV and gives OP_VER/OP_VERIF/OP_VERNOTIF meaning.
408
468
  // Off by default: enabling it changes script evaluation, so it is an explicit opt-in
409
469
  // exactly like the Monolith and Magnetic flags above.
410
470
  Interpreter.SCRIPT_ENABLE_CHRONICLE = (1 << 20)
411
471
 
472
+ // The node's name for the same bit: Chronicle rules apply to the block the
473
+ // spending transaction is in.
474
+ Interpreter.SCRIPT_CHRONICLE = Interpreter.SCRIPT_ENABLE_CHRONICLE
475
+
476
+ // Was the output being spent created after Chronicle activated? This is what
477
+ // the node gates the restored opcodes on.
478
+ Interpreter.SCRIPT_UTXO_AFTER_CHRONICLE = (1 << 21)
479
+
412
480
  /**
413
481
  * Block height at which Chronicle activated on BSV mainnet (2026-04-07).
414
482
  *
@@ -432,9 +500,21 @@ Interpreter.CHRONICLE_ACTIVATION_HEIGHT = 943816
432
500
  * every output created since is subject to it. Pass `false` to validate the spend of a
433
501
  * pre-activation UTXO, which is exactly the distinction the node makes.
434
502
  *
503
+ * CLTV and CSV are deliberately ABSENT. Genesis reverted both opcodes to OP_NOP2/OP_NOP3,
504
+ * and the node ignores their flags entirely once the UTXO is post-Genesis:
505
+ *
506
+ * if (!(flags & SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY) || utxo_after_genesis) {
507
+ * // not enabled; treat as a NOP2
508
+ *
509
+ * Including them made this function reject `<n> OP_CHECKLOCKTIMEVERIFY OP_DROP OP_1`,
510
+ * which mainnet accepts — a validator STRICTER than consensus, which is as wrong as one
511
+ * that is looser and harder to notice, because nothing that tests this library against
512
+ * itself can see it. The flags still exist for callers deliberately emulating
513
+ * pre-Genesis rules; they are simply not mainnet.
514
+ *
435
515
  * NOTE: script-number and element-size limits are NOT flags — they are process-wide
436
- * statics raised by `useGenesisLimits()`. A post-Genesis validator needs both this flag
437
- * set and that call.
516
+ * statics. This function cannot set them, which is why `useMainnetConsensus()` exists;
517
+ * prefer it unless you are managing the limits yourself.
438
518
  *
439
519
  * @param {object} [opts]
440
520
  * @param {boolean} [opts.afterChronicle=true] is the UTXO being spent post-activation
@@ -448,17 +528,97 @@ Interpreter.mainnetFlags = function (opts) {
448
528
  Interpreter.SCRIPT_VERIFY_LOW_S |
449
529
  Interpreter.SCRIPT_VERIFY_NULLFAIL |
450
530
  Interpreter.SCRIPT_VERIFY_MINIMALDATA |
451
- Interpreter.SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY |
452
- Interpreter.SCRIPT_VERIFY_CHECKSEQUENCEVERIFY |
453
531
  Interpreter.SCRIPT_ENABLE_SIGHASH_FORKID |
454
532
  Interpreter.SCRIPT_ENABLE_MAGNETIC_OPCODES |
455
- Interpreter.SCRIPT_ENABLE_MONOLITH_OPCODES
533
+ Interpreter.SCRIPT_ENABLE_MONOLITH_OPCODES |
534
+ // The era flags. Without these the interpreter falls back to the pre-Genesis
535
+ // statics, so a validator built from a helper named after mainnet was applying
536
+ // 2019 limits — most sharply the 4-byte script-number bound, where post-Genesis
537
+ // is 750,000 and post-Chronicle 32,000,000. Genesis is unconditional here: it
538
+ // activated in 2020 and cannot be opted out of by anything still being spent.
539
+ Interpreter.SCRIPT_GENESIS |
540
+ Interpreter.SCRIPT_UTXO_AFTER_GENESIS
456
541
  if (opts.afterChronicle !== false) {
457
- flags |= Interpreter.SCRIPT_ENABLE_CHRONICLE
542
+ flags |= Interpreter.SCRIPT_ENABLE_CHRONICLE | Interpreter.SCRIPT_UTXO_AFTER_CHRONICLE
458
543
  }
459
544
  return flags
460
545
  }
461
546
 
547
+ /**
548
+ * Configure this process for BSV mainnet consensus and return the matching flags.
549
+ *
550
+ * Flags and limits are separate mechanisms here — flags are an argument to `verify()`,
551
+ * limits are process-wide statics — and that split is what made `mainnetFlags()` alone
552
+ * insufficient: it returns mainnet flags while the interpreter still holds the
553
+ * PRE-Genesis 520 / 201 / 10,000 caps, so a 12,801-byte script valid on mainnet was
554
+ * rejected with SCRIPT_ERR_SCRIPT_SIZE.
555
+ *
556
+ * This is the single call that makes both agree. It MUTATES process-wide state, which is
557
+ * why it is named `use*` like `useGenesisLimits()` rather than reading like a getter.
558
+ *
559
+ * @param {object} [opts]
560
+ * @param {boolean} [opts.afterChronicle=true] is the UTXO being spent post-activation
561
+ * @param {number} [opts.max] element-size ceiling to pass through to useGenesisLimits()
562
+ * @returns {number} the flags to hand to verify()
563
+ */
564
+ /**
565
+ * The flags describing BSV mainnet as it is today, and the default for `verify()`.
566
+ *
567
+ * Until 8.0.0 `verify()` defaulted to `0` — no rules at all. A BSV library whose
568
+ * out-of-the-box answer described Bitcoin in 2015 is wrong in the direction that is
569
+ * hardest to notice: it accepts scripts the network rejects, and nothing that tests this
570
+ * library against itself can see it. The era now has to be stated to get anything else.
571
+ *
572
+ * The set is derived from what the node applies, not assembled by judgement:
573
+ *
574
+ * MONOLITH / MAGNETIC BSV restored these opcodes in 2018 and the node does not gate
575
+ * them. This library still does, so omitting them here would be
576
+ * STRICTER than consensus. tools/sv-vector-harness.js sets the
577
+ * same pair as its baseline for every vector, for this reason.
578
+ * GENESIS rules keyed to the era of the spending transaction
579
+ * UTXO_AFTER_GENESIS rules keyed to the era of the output being spent (2020)
580
+ * CHRONICLE the spending transaction's era (2026)
581
+ * UTXO_AFTER_CHRONICLE the spent output's era
582
+ *
583
+ * Spending a pre-activation output is the explicit case, because that is the input the
584
+ * caller knows and the library cannot: `mainnetFlags({ afterChronicle: false })`, or a
585
+ * hand-assembled set for older eras.
586
+ *
587
+ * FORKID is deliberately absent here and added by `verify()` only when the input amount
588
+ * is available, since the digest cannot be computed without it.
589
+ *
590
+ * @returns {number}
591
+ */
592
+ Interpreter.currentConsensusFlags = function () {
593
+ return Interpreter.SCRIPT_ENABLE_MONOLITH_OPCODES |
594
+ Interpreter.SCRIPT_ENABLE_MAGNETIC_OPCODES |
595
+ Interpreter.SCRIPT_GENESIS |
596
+ Interpreter.SCRIPT_UTXO_AFTER_GENESIS |
597
+ Interpreter.SCRIPT_ENABLE_CHRONICLE |
598
+ Interpreter.SCRIPT_UTXO_AFTER_CHRONICLE |
599
+ Interpreter.SCRIPT_ENABLE_SIGHASH_FORKID
600
+ }
601
+
602
+ Interpreter.useMainnetConsensus = function (opts) {
603
+ opts = opts || {}
604
+ Interpreter.useGenesisLimits(opts.max)
605
+
606
+ // The script-number bound is NOT set here. It is era-derived from the flags by
607
+ // Interpreter#maxScriptNumLength(): 4 bytes pre-Genesis, 750,000 after Genesis,
608
+ // 32,000,000 after Chronicle. An earlier version of this function pinned
609
+ // MAXIMUM_ELEMENT_SIZE to a static value to stop useGenesisLimits() raising it to
610
+ // 0x7fffffff, which made Chronicle's shift-overflow check unreachable. That was
611
+ // treating the symptom: the real defect was mainnetFlags() omitting the era flags,
612
+ // so the era-derived bound never applied. Fixed there instead.
613
+ //
614
+ // The node's vectors settle the pre-Genesis value at 4 and are silent on the rest —
615
+ // all 22 SCRIPTNUM_OVERFLOW rows carry P2SH,STRICTENC and no era flag. Raising the
616
+ // static bound to 8 turns 15 of them into false accepts, which is how that was
617
+ // measured.
618
+
619
+ return Interpreter.mainnetFlags(opts)
620
+ }
621
+
462
622
  /* Below flags apply in the context of BIP 68 */
463
623
  /**
464
624
  * If this flag set, CTxIn::nSequence is NOT interpreted as a relative
@@ -526,6 +686,20 @@ Interpreter.prototype.checkSignatureEncoding = function (buf) {
526
686
  return false
527
687
  }
528
688
 
689
+ // A signature may only ask for the original digest where Chronicle
690
+ // applies. This is where the node stops a pre-Chronicle signature whose
691
+ // type byte happens to set 0x20 from being read as one asking for OTDA:
692
+ //
693
+ // if(!chronicleEnabled && usesChronicle) return SCRIPT_ERR_ILLEGAL_CHRONICLE;
694
+ //
695
+ // It rejects such a signature outright rather than reinterpreting it,
696
+ // which is why SignatureHash() itself can route on the bit alone.
697
+ if (!(this.flags & Interpreter.SCRIPT_CHRONICLE) &&
698
+ (sig.nhashtype & Signature.SIGHASH_CHRONICLE)) {
699
+ this.errstr = 'SCRIPT_ERR_ILLEGAL_CHRONICLE'
700
+ return false
701
+ }
702
+
529
703
  if ((this.flags & Interpreter.SCRIPT_ENABLE_SIGHASH_FORKID) &&
530
704
  !(sig.nhashtype & Signature.SIGHASH_FORKID)) {
531
705
  this.errstr = 'SCRIPT_ERR_MUST_USE_FORKID'
@@ -554,6 +728,67 @@ Interpreter.prototype.checkPubkeyEncoding = function (buf) {
554
728
  *
555
729
  */
556
730
 
731
+ /**
732
+ * Which era's rules apply.
733
+ *
734
+ * The node decides almost everything by the era of the output being spent, so
735
+ * these read the SCRIPT_UTXO_AFTER_* flags rather than a process-wide setting.
736
+ * A caller that sets no era flag gets the previous behaviour exactly: the
737
+ * limit methods below fall back to the mutable statics, so useGenesisLimits()
738
+ * and setLimits() keep working as they did.
739
+ */
740
+ Interpreter.prototype.isAfterGenesis = function () {
741
+ return (this.flags & Interpreter.SCRIPT_UTXO_AFTER_GENESIS) !== 0
742
+ }
743
+
744
+ /**
745
+ * SCRIPT_ENABLE_CHRONICLE is accepted alongside SCRIPT_UTXO_AFTER_CHRONICLE.
746
+ * The former is this library's existing opt-in and sits on the node's
747
+ * SCRIPT_CHRONICLE bit; the latter is what the node actually gates the
748
+ * restored opcodes on. Either enables them, so existing callers are unaffected.
749
+ */
750
+ Interpreter.prototype.isAfterChronicle = function () {
751
+ return (this.flags &
752
+ (Interpreter.SCRIPT_UTXO_AFTER_CHRONICLE | Interpreter.SCRIPT_ENABLE_CHRONICLE)) !== 0
753
+ }
754
+
755
+ /** Genesis removed this limit; before it, whatever the statics say. */
756
+ Interpreter.prototype.maxScriptElementSize = function () {
757
+ return this.isAfterGenesis() ? Interpreter.UNLIMITED : Interpreter.MAX_SCRIPT_ELEMENT_SIZE
758
+ }
759
+
760
+ /** Genesis removed this limit too. */
761
+ Interpreter.prototype.maxScriptSize = function () {
762
+ return this.isAfterGenesis() ? Interpreter.UNLIMITED : Interpreter.MAX_SCRIPT_SIZE
763
+ }
764
+
765
+ /** And this one. Note the pre-Genesis figure on BSV is 500, not Core's 201. */
766
+ Interpreter.prototype.maxOpsPerScript = function () {
767
+ return this.isAfterGenesis() ? Interpreter.UNLIMITED : Interpreter.MAX_OPS_PER_SCRIPT
768
+ }
769
+
770
+ /**
771
+ * The widest a script number may be. Four bytes before Genesis, which is why
772
+ * pre-Genesis contracts cannot do arithmetic on satoshi amounts; Genesis
773
+ * raised it to 750KB and Chronicle to 32MB.
774
+ */
775
+ Interpreter.prototype.maxScriptNumLength = function () {
776
+ if (this.isAfterChronicle()) {
777
+ return Interpreter.MAX_SCRIPT_NUM_LENGTH_AFTER_CHRONICLE
778
+ }
779
+ if (this.isAfterGenesis()) {
780
+ return Interpreter.MAX_SCRIPT_NUM_LENGTH_AFTER_GENESIS
781
+ }
782
+ return Interpreter.MAXIMUM_ELEMENT_SIZE
783
+ }
784
+
785
+ /** Genesis raised this rather than removing it: the node caps at UINT32_MAX. */
786
+ Interpreter.prototype.maxPubKeysPerMultisig = function () {
787
+ return this.isAfterGenesis()
788
+ ? Interpreter.MAX_PUBKEYS_PER_MULTISIG_AFTER_GENESIS
789
+ : 20
790
+ }
791
+
557
792
  Interpreter._isMinimallyEncoded = function (buf, nMaxNumSize) {
558
793
  nMaxNumSize = nMaxNumSize || Interpreter.MAXIMUM_ELEMENT_SIZE
559
794
  if (buf.length > nMaxNumSize) {
@@ -636,7 +871,7 @@ Interpreter._minimallyEncode = function (buf) {
636
871
  * bitcoind commit: b5d1b1092998bc95313856d535c632ea5a8f9104
637
872
  */
638
873
  Interpreter.prototype.evaluate = function () {
639
- if (this.script.toBuffer().length > Interpreter.MAX_SCRIPT_SIZE) {
874
+ if (this.script.toBuffer().length > this.maxScriptSize()) {
640
875
  this.errstr = 'SCRIPT_ERR_SCRIPT_SIZE'
641
876
  return false
642
877
  }
@@ -649,6 +884,12 @@ Interpreter.prototype.evaluate = function () {
649
884
  return false
650
885
  }
651
886
  this._callbackStep(thisStep)
887
+ if (this.returned) {
888
+ // A top-level OP_RETURN after Genesis: the script is over and the top
889
+ // stack item decides. Nothing after it is read, so an unbalanced
890
+ // conditional or an invalid opcode beyond this point is not an error.
891
+ return true
892
+ }
652
893
  }
653
894
 
654
895
  // Size limits
@@ -657,7 +898,12 @@ Interpreter.prototype.evaluate = function () {
657
898
  return false
658
899
  }
659
900
  } catch (e) {
660
- this.errstr = 'SCRIPT_ERR_UNKNOWN_ERROR: ' + e
901
+ // An error that knows the node's result code reports it. Script number
902
+ // decoding is the case that matters: 78 of the corpus's rejected vectors
903
+ // expect SCRIPTNUM_MINENCODE or SCRIPTNUM_OVERFLOW, and every one of them
904
+ // used to arrive here and be flattened into UNKNOWN_ERROR. The script
905
+ // failed either way, so the accept/reject vectors could not see it.
906
+ this.errstr = e.scriptErr || ('SCRIPT_ERR_UNKNOWN_ERROR: ' + e)
661
907
  return false
662
908
  }
663
909
 
@@ -718,7 +964,11 @@ Interpreter.prototype.checkLockTime = function (nLockTime) {
718
964
  // prevent this condition. Alternatively we could test all
719
965
  // inputs, but testing just this input minimizes the data
720
966
  // required to prove correct CHECKLOCKTIMEVERIFY execution.
721
- if (this.tx.inputs[this.nin].isFinal()) {
967
+ // Same guard as checkSequence: no input at `nin` means the locktime cannot be
968
+ // satisfied. Reached only when the comparisons above pass, which is why this one
969
+ // never surfaced as a TypeError — the ordering hid it, not a check.
970
+ var input = this.tx.inputs[this.nin]
971
+ if (!input || input.isFinal()) {
722
972
  return false
723
973
  }
724
974
 
@@ -732,9 +982,19 @@ Interpreter.prototype.checkLockTime = function (nLockTime) {
732
982
  * the transaction's sequence
733
983
  */
734
984
  Interpreter.prototype.checkSequence = function (nSequence) {
985
+ // No input at `nin` means the relative locktime cannot be satisfied, so fail the
986
+ // script rather than dereferencing undefined. This used to throw a TypeError that the
987
+ // evaluator's try/catch converted into SCRIPT_ERR_UNKNOWN_ERROR — a misleading error
988
+ // that pointed at the script instead of at the caller's index. The same shape as the
989
+ // `new BN(...)` note below, and as the CHECKLOCKTIMEVERIFY guard.
990
+ var input = this.tx.inputs[this.nin]
991
+ if (!input) {
992
+ return false
993
+ }
994
+
735
995
  // Relative lock times are supported by comparing the passed in operand to
736
996
  // the sequence number of the input.
737
- var txToSequence = this.tx.inputs[this.nin].sequenceNumber
997
+ var txToSequence = input.sequenceNumber
738
998
 
739
999
  // Fail if the transaction's version number is not set high enough to
740
1000
  // trigger BIP 68 rules.
@@ -819,7 +1079,7 @@ Interpreter.prototype.step = function () {
819
1079
  // "disabled" is stronger than "unimplemented": a disabled opcode fails the
820
1080
  // script even in an UNEXECUTED branch, which is why this lives in
821
1081
  // isOpcodeDisabled rather than in the evaluation switch.
822
- if ((self.flags & Interpreter.SCRIPT_ENABLE_CHRONICLE) === 0) {
1082
+ if (!self.isAfterChronicle()) {
823
1083
  return true
824
1084
  }
825
1085
  break
@@ -857,8 +1117,6 @@ Interpreter.prototype.step = function () {
857
1117
 
858
1118
  var fRequireMinimal = (this.flags & Interpreter.SCRIPT_VERIFY_MINIMALDATA) !== 0
859
1119
 
860
- // bool fExec = !count(vfExec.begin(), vfExec.end(), false);
861
- var fExec = (this.vfExec.indexOf(false) === -1)
862
1120
  var buf, buf1, buf2, spliced, n, x1, x2, bn, bn1, bn2, bufSig, bufPubkey, subscript
863
1121
  var sig, pubkey
864
1122
  var fValue, fSuccess
@@ -867,22 +1125,35 @@ Interpreter.prototype.step = function () {
867
1125
  var chunk = this.script.chunks[this.pc]
868
1126
  this.pc++
869
1127
  var opcodenum = chunk.opcodenum
1128
+
1129
+ // bool fExec = !count(vfExec.begin(), vfExec.end(), false);
1130
+ //
1131
+ // Computed after the opcode is read, because it depends on it: once an
1132
+ // OP_RETURN has been seen inside a conditional after Genesis, nothing but a
1133
+ // further OP_RETURN executes, while the conditional grammar is still checked
1134
+ // through to the end of the script.
1135
+ var fExec = (this.vfExec.indexOf(false) === -1) &&
1136
+ (!this.nonTopLevelReturnAfterGenesis || opcodenum === Opcode.OP_RETURN)
870
1137
  if (_.isUndefined(opcodenum)) {
871
1138
  this.errstr = 'SCRIPT_ERR_UNDEFINED_OPCODE'
872
1139
  return false
873
1140
  }
874
- if (chunk.buf && chunk.buf.length > Interpreter.MAX_SCRIPT_ELEMENT_SIZE) {
1141
+ if (chunk.buf && chunk.buf.length > this.maxScriptElementSize()) {
875
1142
  this.errstr = 'SCRIPT_ERR_PUSH_SIZE'
876
1143
  return false
877
1144
  }
878
1145
 
879
1146
  // Note how Opcode.OP_RESERVED does not count towards the opcode limit.
880
- if (opcodenum > Opcode.OP_16 && ++(this.nOpCount) > Interpreter.MAX_OPS_PER_SCRIPT) {
1147
+ if (opcodenum > Opcode.OP_16 && ++(this.nOpCount) > this.maxOpsPerScript()) {
881
1148
  this.errstr = 'SCRIPT_ERR_OP_COUNT'
882
1149
  return false
883
1150
  }
884
1151
 
885
- if (isOpcodeDisabled(opcodenum)) {
1152
+ // Before Genesis the mere presence of a disabled opcode invalidates the
1153
+ // script, even in a branch that never runs. After it, only executing one
1154
+ // fails — the node states it as `IsOpcodeDisabled(...) && (!utxo_after_genesis
1155
+ // || fExec)`.
1156
+ if (isOpcodeDisabled(opcodenum) && (!this.isAfterGenesis() || fExec)) {
886
1157
  this.errstr = 'SCRIPT_ERR_DISABLED_OPCODE'
887
1158
  return false
888
1159
  }
@@ -895,7 +1166,13 @@ Interpreter.prototype.step = function () {
895
1166
  if (!chunk.buf) {
896
1167
  this.stack.push(Interpreter.false)
897
1168
  } else if (chunk.len !== chunk.buf.length) {
898
- throw new Error(`Length of push value not equal to length of data (${chunk.len},${chunk.buf.length})`)
1169
+ // A push that declares more bytes than the script carries — "PUSHDATA1
1170
+ // with not enough bytes" and its PUSHDATA2/4 counterparts. The node
1171
+ // fails these as SCRIPT_ERR_BAD_OPCODE. Throwing reached the evaluator's
1172
+ // catch and became UNKNOWN_ERROR; this is inside step(), which can
1173
+ // simply fail.
1174
+ this.errstr = 'SCRIPT_ERR_BAD_OPCODE'
1175
+ return false
899
1176
  } else {
900
1177
  this.stack.push(chunk.buf)
901
1178
  }
@@ -937,7 +1214,14 @@ Interpreter.prototype.step = function () {
937
1214
  case Opcode.OP_NOP2:
938
1215
  case Opcode.OP_CHECKLOCKTIMEVERIFY:
939
1216
 
940
- if (!(this.flags & Interpreter.SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY)) {
1217
+ // Genesis reverted this to an upgradable NOP for outputs created
1218
+ // after it, so a post-Genesis script containing it enforces no
1219
+ // locktime at all. The node reads
1220
+ // !(flags & SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY) || utxo_after_genesis
1221
+ // and without the second half a transaction the network accepts is
1222
+ // rejected here.
1223
+ if (!(this.flags & Interpreter.SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY) ||
1224
+ this.isAfterGenesis()) {
941
1225
  // not enabled; treat as a NOP2
942
1226
  if (this.flags & Interpreter.SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) {
943
1227
  this.errstr = 'SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS'
@@ -985,7 +1269,14 @@ Interpreter.prototype.step = function () {
985
1269
  case Opcode.OP_NOP3:
986
1270
  case Opcode.OP_CHECKSEQUENCEVERIFY:
987
1271
 
988
- if (!(this.flags & Interpreter.SCRIPT_VERIFY_CHECKSEQUENCEVERIFY)) {
1272
+ // Genesis reverted this to an upgradable NOP for outputs created
1273
+ // after it, so a post-Genesis script containing it enforces no
1274
+ // locktime at all. The node reads
1275
+ // !(flags & SCRIPT_VERIFY_CHECKSEQUENCEVERIFY) || utxo_after_genesis
1276
+ // and without the second half a transaction the network accepts is
1277
+ // rejected here.
1278
+ if (!(this.flags & Interpreter.SCRIPT_VERIFY_CHECKSEQUENCEVERIFY) ||
1279
+ this.isAfterGenesis()) {
989
1280
  // not enabled; treat as a NOP3
990
1281
  if (this.flags & Interpreter.SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) {
991
1282
  this.errstr = 'SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS'
@@ -1056,7 +1347,7 @@ Interpreter.prototype.step = function () {
1056
1347
  //
1057
1348
  // Rejecting them outright would make this library refuse scripts the network
1058
1349
  // accepts, which is the mirror of the bug that made them silently succeed.
1059
- if ((this.flags & Interpreter.SCRIPT_ENABLE_CHRONICLE) === 0) {
1350
+ if (!this.isAfterChronicle()) {
1060
1351
  if (this.flags & Interpreter.SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) {
1061
1352
  this.errstr = 'SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS'
1062
1353
  return false
@@ -1069,7 +1360,7 @@ Interpreter.prototype.step = function () {
1069
1360
  this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
1070
1361
  return false
1071
1362
  }
1072
- var maxNumSize = Interpreter.MAXIMUM_ELEMENT_SIZE
1363
+ var maxNumSize = this.maxScriptNumLength()
1073
1364
  var shiftBn = BN.fromScriptNumBuffer(stacktop(-1), fRequireMinimal, maxNumSize)
1074
1365
  if (shiftBn.isNeg()) {
1075
1366
  this.errstr = 'SCRIPT_ERR_INVALID_NUMBER_RANGE'
@@ -1133,7 +1424,7 @@ Interpreter.prototype.step = function () {
1133
1424
  //
1134
1425
  // Unlike the string opcodes, BAD_OPCODE pre-Chronicle IS correct here —
1135
1426
  // the node returns it unconditionally.
1136
- if ((this.flags & Interpreter.SCRIPT_ENABLE_CHRONICLE) === 0) {
1427
+ if (!this.isAfterChronicle()) {
1137
1428
  this.errstr = 'SCRIPT_ERR_BAD_OPCODE'
1138
1429
  return false
1139
1430
  }
@@ -1157,8 +1448,13 @@ Interpreter.prototype.step = function () {
1157
1448
  // So pre-Chronicle they are an error only in an EXECUTED branch. BSV is
1158
1449
  // post-Genesis, which is the whole condition. Returning BAD_OPCODE
1159
1450
  // unconditionally rejected scripts the network accepts.
1160
- if ((this.flags & Interpreter.SCRIPT_ENABLE_CHRONICLE) === 0) {
1161
- if (!fExec) {
1451
+ if (!this.isAfterChronicle()) {
1452
+ // Genesis is part of the condition, not an assumption: before it
1453
+ // these are illegal everywhere, including in a branch that never
1454
+ // runs, and only from Genesis does an unexecuted one become
1455
+ // harmless. The era is carried in the flags now, so a pre-Genesis
1456
+ // output is validated as one.
1457
+ if (this.isAfterGenesis() && !fExec) {
1162
1458
  break
1163
1459
  }
1164
1460
  this.errstr = 'SCRIPT_ERR_BAD_OPCODE'
@@ -1190,6 +1486,7 @@ Interpreter.prototype.step = function () {
1190
1486
  this.stack.pop()
1191
1487
  }
1192
1488
  this.vfExec.push(fValue)
1489
+ this.vfElse.push(false)
1193
1490
  break
1194
1491
 
1195
1492
  case Opcode.OP_IF:
@@ -1221,14 +1518,21 @@ Interpreter.prototype.step = function () {
1221
1518
  this.stack.pop()
1222
1519
  }
1223
1520
  this.vfExec.push(fValue)
1521
+ this.vfElse.push(false)
1224
1522
  break
1225
1523
 
1226
1524
  case Opcode.OP_ELSE:
1227
- if (this.vfExec.length === 0) {
1525
+ // Genesis allows only one OP_ELSE per OP_IF. A second one is
1526
+ // unbalanced, and accepting it means accepting scripts the network
1527
+ // rejects — the node states it as
1528
+ // if (vfExec.empty() || (vfElse.back() && utxo_after_genesis))
1529
+ if (this.vfExec.length === 0 ||
1530
+ (this.vfElse[this.vfElse.length - 1] && this.isAfterGenesis())) {
1228
1531
  this.errstr = 'SCRIPT_ERR_UNBALANCED_CONDITIONAL'
1229
1532
  return false
1230
1533
  }
1231
1534
  this.vfExec[this.vfExec.length - 1] = !this.vfExec[this.vfExec.length - 1]
1535
+ this.vfElse[this.vfElse.length - 1] = true
1232
1536
  break
1233
1537
 
1234
1538
  case Opcode.OP_ENDIF:
@@ -1237,6 +1541,7 @@ Interpreter.prototype.step = function () {
1237
1541
  return false
1238
1542
  }
1239
1543
  this.vfExec.pop()
1544
+ this.vfElse.pop()
1240
1545
  break
1241
1546
 
1242
1547
  case Opcode.OP_VERIFY:
@@ -1257,6 +1562,21 @@ Interpreter.prototype.step = function () {
1257
1562
  break
1258
1563
 
1259
1564
  case Opcode.OP_RETURN:
1565
+ if (this.isAfterGenesis()) {
1566
+ if (this.vfExec.length === 0) {
1567
+ // Genesis restored OP_RETURN's original meaning: it terminates the
1568
+ // script and the top stack item decides validity. The remainder
1569
+ // cannot affect the outcome, even if it holds unbalanced
1570
+ // conditionals or invalid opcodes, which is what makes
1571
+ // OP_FALSE OP_RETURN <data> outputs safe to carry anything.
1572
+ this.returned = true
1573
+ break
1574
+ }
1575
+ // Inside a conditional, suppress the rest but keep checking grammar.
1576
+ this.nonTopLevelReturnAfterGenesis = true
1577
+ break
1578
+ }
1579
+ // Before Genesis, an OP_RETURN alone invalidates the script.
1260
1580
  this.errstr = 'SCRIPT_ERR_OP_RETURN'
1261
1581
  return false
1262
1582
  // break // unreachable
@@ -1414,7 +1734,7 @@ Interpreter.prototype.step = function () {
1414
1734
  return false
1415
1735
  }
1416
1736
  buf = stacktop(-1)
1417
- bn = BN.fromScriptNumBuffer(buf, fRequireMinimal)
1737
+ bn = BN.fromScriptNumBuffer(buf, fRequireMinimal, this.maxScriptNumLength())
1418
1738
  n = bn.toNumber()
1419
1739
  this.stack.pop()
1420
1740
  if (n < 0 || n >= this.stack.length) {
@@ -1524,6 +1844,10 @@ Interpreter.prototype.step = function () {
1524
1844
  // (x -- out)
1525
1845
  if (this.stack.length < 1) {
1526
1846
  this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
1847
+ // The missing return here let evaluation continue and crash on the
1848
+ // absent operand, reporting an internal TypeError rather than the
1849
+ // stack error it had already decided on.
1850
+ return false
1527
1851
  }
1528
1852
  buf = stacktop(-1)
1529
1853
  for (let i = 0; i < buf.length; i++) {
@@ -1543,7 +1867,7 @@ Interpreter.prototype.step = function () {
1543
1867
  this.stack.pop()
1544
1868
  } else {
1545
1869
  bn1 = new BN(buf1)
1546
- bn2 = BN.fromScriptNumBuffer(stacktop(-1), fRequireMinimal)
1870
+ bn2 = BN.fromScriptNumBuffer(stacktop(-1), fRequireMinimal, this.maxScriptNumLength())
1547
1871
  n = bn2.toNumber()
1548
1872
  if (n < 0) {
1549
1873
  this.errstr = 'SCRIPT_ERR_INVALID_NUMBER_RANGE'
@@ -1608,7 +1932,7 @@ Interpreter.prototype.step = function () {
1608
1932
  return false
1609
1933
  }
1610
1934
  buf = stacktop(-1)
1611
- bn = BN.fromScriptNumBuffer(buf, fRequireMinimal)
1935
+ bn = BN.fromScriptNumBuffer(buf, fRequireMinimal, this.maxScriptNumLength())
1612
1936
  switch (opcodenum) {
1613
1937
  case Opcode.OP_2MUL:
1614
1938
  bn = bn.mul(new BN(2))
@@ -1667,8 +1991,8 @@ Interpreter.prototype.step = function () {
1667
1991
  this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
1668
1992
  return false
1669
1993
  }
1670
- bn1 = BN.fromScriptNumBuffer(stacktop(-2), fRequireMinimal, Interpreter.MAXIMUM_ELEMENT_SIZE)
1671
- bn2 = BN.fromScriptNumBuffer(stacktop(-1), fRequireMinimal, Interpreter.MAXIMUM_ELEMENT_SIZE)
1994
+ bn1 = BN.fromScriptNumBuffer(stacktop(-2), fRequireMinimal, this.maxScriptNumLength())
1995
+ bn2 = BN.fromScriptNumBuffer(stacktop(-1), fRequireMinimal, this.maxScriptNumLength())
1672
1996
  bn = new BN(0)
1673
1997
 
1674
1998
  switch (opcodenum) {
@@ -1685,8 +2009,12 @@ Interpreter.prototype.step = function () {
1685
2009
  break
1686
2010
 
1687
2011
  case Opcode.OP_DIV:
1688
- // denominator must not be 0
1689
- if (bn2 === 0) {
2012
+ // denominator must not be 0. bn2 is a BN, so `bn2 === 0` was never
2013
+ // true and this guard never fired — bn.js asserted instead, and
2014
+ // the evaluator's catch reported SCRIPT_ERR_UNKNOWN_ERROR. The
2015
+ // script still failed, which is why the accept/reject vectors
2016
+ // stayed green while the reason was wrong.
2017
+ if (bn2.cmp(BN.Zero) === 0) {
1690
2018
  this.errstr = 'SCRIPT_ERR_DIV_BY_ZERO'
1691
2019
  return false
1692
2020
  }
@@ -1694,9 +2022,9 @@ Interpreter.prototype.step = function () {
1694
2022
  break
1695
2023
 
1696
2024
  case Opcode.OP_MOD:
1697
- // divisor must not be 0
1698
- if (bn2 === 0) {
1699
- this.errstr = 'SCRIPT_ERR_DIV_BY_ZERO'
2025
+ // divisor must not be 0. The node reports this one separately.
2026
+ if (bn2.cmp(BN.Zero) === 0) {
2027
+ this.errstr = 'SCRIPT_ERR_MOD_BY_ZERO'
1700
2028
  return false
1701
2029
  }
1702
2030
  bn = bn1.mod(bn2)
@@ -1766,9 +2094,9 @@ Interpreter.prototype.step = function () {
1766
2094
  this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
1767
2095
  return false
1768
2096
  }
1769
- bn1 = BN.fromScriptNumBuffer(stacktop(-3), fRequireMinimal, Interpreter.MAXIMUM_ELEMENT_SIZE)
1770
- bn2 = BN.fromScriptNumBuffer(stacktop(-2), fRequireMinimal, Interpreter.MAXIMUM_ELEMENT_SIZE)
1771
- var bn3 = BN.fromScriptNumBuffer(stacktop(-1), fRequireMinimal, Interpreter.MAXIMUM_ELEMENT_SIZE)
2097
+ bn1 = BN.fromScriptNumBuffer(stacktop(-3), fRequireMinimal, this.maxScriptNumLength())
2098
+ bn2 = BN.fromScriptNumBuffer(stacktop(-2), fRequireMinimal, this.maxScriptNumLength())
2099
+ var bn3 = BN.fromScriptNumBuffer(stacktop(-1), fRequireMinimal, this.maxScriptNumLength())
1772
2100
  // bool fValue = (bn2 <= bn1 && bn1 < bn3);
1773
2101
  fValue = (bn2.cmp(bn1) <= 0) && (bn1.cmp(bn3) < 0)
1774
2102
  this.stack.pop()
@@ -1880,9 +2208,10 @@ Interpreter.prototype.step = function () {
1880
2208
  return false
1881
2209
  }
1882
2210
 
1883
- var nKeysCount = BN.fromScriptNumBuffer(stacktop(-i), fRequireMinimal).toNumber()
2211
+ var nKeysCount = BN.fromScriptNumBuffer(stacktop(-i), fRequireMinimal, this.maxScriptNumLength()).toNumber()
1884
2212
  // TODO: Keys and opcount are parameterized in client. No magic numbers!
1885
- if (nKeysCount < 0 || nKeysCount > 20) {
2213
+ // Genesis raised this to UINT32_MAX rather than removing it.
2214
+ if (nKeysCount < 0 || nKeysCount > this.maxPubKeysPerMultisig()) {
1886
2215
  this.errstr = 'SCRIPT_ERR_PUBKEY_COUNT'
1887
2216
  return false
1888
2217
  }
@@ -1906,7 +2235,7 @@ Interpreter.prototype.step = function () {
1906
2235
  return false
1907
2236
  }
1908
2237
 
1909
- var nSigsCount = BN.fromScriptNumBuffer(stacktop(-i), fRequireMinimal).toNumber()
2238
+ var nSigsCount = BN.fromScriptNumBuffer(stacktop(-i), fRequireMinimal, this.maxScriptNumLength()).toNumber()
1910
2239
  if (nSigsCount < 0 || nSigsCount > nKeysCount) {
1911
2240
  this.errstr = 'SCRIPT_ERR_SIG_COUNT'
1912
2241
  return false
@@ -2019,7 +2348,12 @@ Interpreter.prototype.step = function () {
2019
2348
 
2020
2349
  buf1 = stacktop(-2)
2021
2350
  buf2 = stacktop(-1)
2022
- if (buf1.length + buf2.length > Interpreter.MAX_SCRIPT_ELEMENT_SIZE) {
2351
+ // Era-derived, like every other element size check. Genesis lifted the
2352
+ // 520-byte cap, and reading the static here meant OP_CAT kept
2353
+ // enforcing it after Genesis — rejecting a concatenation the network
2354
+ // accepts. No vector in the corpus covers this, so it is held by
2355
+ // test/script/genesis_limits.js instead.
2356
+ if (buf1.length + buf2.length > this.maxScriptElementSize()) {
2023
2357
  this.errstr = 'SCRIPT_ERR_PUSH_SIZE'
2024
2358
  return false
2025
2359
  }
@@ -2035,7 +2369,7 @@ Interpreter.prototype.step = function () {
2035
2369
  buf1 = stacktop(-2)
2036
2370
 
2037
2371
  // Make sure the split point is apropriate.
2038
- var position = BN.fromScriptNumBuffer(stacktop(-1), fRequireMinimal).toNumber()
2372
+ var position = BN.fromScriptNumBuffer(stacktop(-1), fRequireMinimal, this.maxScriptNumLength()).toNumber()
2039
2373
  if (position < 0 || position > buf1.length) {
2040
2374
  this.errstr = 'SCRIPT_ERR_INVALID_SPLIT_RANGE'
2041
2375
  return false
@@ -2065,7 +2399,7 @@ Interpreter.prototype.step = function () {
2065
2399
  //
2066
2400
  // Running them unconditionally consumed stack where the network does
2067
2401
  // nothing, which is a wrong answer rather than an error.
2068
- if ((this.flags & Interpreter.SCRIPT_ENABLE_CHRONICLE) === 0) {
2402
+ if (!this.isAfterChronicle()) {
2069
2403
  if (this.flags & Interpreter.SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) {
2070
2404
  this.errstr = 'SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS'
2071
2405
  return false
@@ -2078,7 +2412,7 @@ Interpreter.prototype.step = function () {
2078
2412
  return false
2079
2413
  }
2080
2414
  buf1 = stacktop(-2)
2081
- n = BN.fromScriptNumBuffer(stacktop(-1), fRequireMinimal, Interpreter.MAXIMUM_ELEMENT_SIZE).toNumber()
2415
+ n = BN.fromScriptNumBuffer(stacktop(-1), fRequireMinimal, this.maxScriptNumLength()).toNumber()
2082
2416
  // ERRORS on out of range; it does not clamp. The node is
2083
2417
  // `if(len < 0 || len > size) return SCRIPT_ERR_INVALID_NUMBER_RANGE`.
2084
2418
  // Clamping made scripts the node rejects succeed here.
@@ -2107,7 +2441,7 @@ Interpreter.prototype.step = function () {
2107
2441
  //
2108
2442
  // Running them unconditionally consumed stack where the network does
2109
2443
  // nothing, which is a wrong answer rather than an error.
2110
- if ((this.flags & Interpreter.SCRIPT_ENABLE_CHRONICLE) === 0) {
2444
+ if (!this.isAfterChronicle()) {
2111
2445
  if (this.flags & Interpreter.SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) {
2112
2446
  this.errstr = 'SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS'
2113
2447
  return false
@@ -2120,8 +2454,8 @@ Interpreter.prototype.step = function () {
2120
2454
  return false
2121
2455
  }
2122
2456
  buf1 = stacktop(-3)
2123
- var subSize = BN.fromScriptNumBuffer(stacktop(-1), fRequireMinimal, Interpreter.MAXIMUM_ELEMENT_SIZE).toNumber()
2124
- var subBegin = BN.fromScriptNumBuffer(stacktop(-2), fRequireMinimal, Interpreter.MAXIMUM_ELEMENT_SIZE).toNumber()
2457
+ var subSize = BN.fromScriptNumBuffer(stacktop(-1), fRequireMinimal, this.maxScriptNumLength()).toNumber()
2458
+ var subBegin = BN.fromScriptNumBuffer(stacktop(-2), fRequireMinimal, this.maxScriptNumLength()).toNumber()
2125
2459
  // ERRORS on out of range, matching
2126
2460
  // offset < 0 || offset >= size || len < 0 || len > size - offset
2127
2461
  // Note `offset >= size` is strict: a begin index AT the end is an
@@ -2145,8 +2479,12 @@ Interpreter.prototype.step = function () {
2145
2479
  return false
2146
2480
  }
2147
2481
 
2148
- var size = BN.fromScriptNumBuffer(stacktop(-1), fRequireMinimal).toNumber()
2149
- if (size > Interpreter.MAX_SCRIPT_ELEMENT_SIZE) {
2482
+ var size = BN.fromScriptNumBuffer(stacktop(-1), fRequireMinimal, this.maxScriptNumLength()).toNumber()
2483
+ // A negative size is a push size failure, not an encoding one. Without
2484
+ // the lower bound it fell through to the rawnum.length > size test,
2485
+ // which any number passes when size is negative, and reported
2486
+ // IMPOSSIBLE_ENCODING instead.
2487
+ if (size < 0 || size > this.maxScriptElementSize()) {
2150
2488
  this.errstr = 'SCRIPT_ERR_PUSH_SIZE'
2151
2489
  return false
2152
2490
  }