@smartledger/bsv 8.3.1 → 9.1.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 (169) hide show
  1. package/CHANGELOG.md +228 -0
  2. package/README.md +152 -1031
  3. package/STABILITY.md +134 -0
  4. package/bsv-gdaf.min.js +58 -53
  5. package/bsv-ltp.min.js +23 -18
  6. package/bsv-script-helper.min.js +1 -1
  7. package/bsv-smartcontract.min.js +21 -21
  8. package/bsv.bundle.js +58 -53
  9. package/bsv.d.ts +0 -4
  10. package/bsv.min.js +58 -53
  11. package/docs/BRC220_BATCH_LEAF_AMENDMENT.md +82 -7
  12. package/docs/MODULE_REFERENCE_COMPLETE.md +27 -27
  13. package/docs/README.md +2 -1
  14. package/docs/THREAT_MODEL.md +10 -2
  15. package/docs/advanced/UTXO_MANAGER_GUIDE.md +1 -1
  16. package/docs/getting-started/INSTALLATION.md +23 -23
  17. package/docs/getting-started/QUICK_START.md +7 -7
  18. package/docs/migration/FROM_BSV_1_5_6.md +5 -5
  19. package/docs/proposals/10.0.0-package-split.md +131 -0
  20. package/index.js +15 -26
  21. package/lib/block/merkleblock.js +19 -5
  22. package/lib/covenant/helpers.js +34 -35
  23. package/lib/covenant/pushtx.js +2 -2
  24. package/lib/custom-script-helper.js +0 -16
  25. package/lib/hdprivatekey.js +15 -0
  26. package/lib/ordinals/ordlock.js +1 -1
  27. package/lib/script/interpreter.js +109 -1
  28. package/lib/smart_contract/builder.js +14 -0
  29. package/lib/smart_contract/debugger.js +2 -2
  30. package/lib/smart_contract/dsl.js +2 -2
  31. package/lib/smart_contract/index.js +0 -3
  32. package/lib/smart_contract/locks.js +1 -41
  33. package/lib/smart_contract/pels.js +1 -1
  34. package/lib/smart_contract/token.js +1 -1
  35. package/lib/util/deprecate.js +159 -0
  36. package/package.json +19 -82
  37. package/tools/gen-brc220-batch-vector.js +205 -0
  38. package/version.js +1 -1
  39. package/.mocharc.json +0 -5
  40. package/test/address.js +0 -629
  41. package/test/block/block.js +0 -239
  42. package/test/block/blockheader.js +0 -270
  43. package/test/block/merkleblock.js +0 -207
  44. package/test/build/bundle_crypto_shim.js +0 -104
  45. package/test/build/bundle_externals.js +0 -125
  46. package/test/build/bundle_smoke.js +0 -55
  47. package/test/build/esbuild_main.js +0 -65
  48. package/test/build/esm_wrapper.js +0 -73
  49. package/test/build/exports_resolution.js +0 -84
  50. package/test/build/version_sync.js +0 -14
  51. package/test/cli/smoke.js +0 -261
  52. package/test/consensus/base58-vectors.js +0 -120
  53. package/test/consensus/sv-script-vectors.js +0 -81
  54. package/test/consensus/sv-sighash-vectors.js +0 -51
  55. package/test/consensus/sv-tx-vectors.js +0 -48
  56. package/test/credentials-test.js +0 -332
  57. package/test/crypto/backend_selection.js +0 -126
  58. package/test/crypto/bn.js +0 -168
  59. package/test/crypto/ecdsa.js +0 -426
  60. package/test/crypto/elliptic-fixed.js +0 -61
  61. package/test/crypto/hash.browser.js +0 -121
  62. package/test/crypto/hash.js +0 -122
  63. package/test/crypto/point.js +0 -193
  64. package/test/crypto/random.js +0 -105
  65. package/test/crypto/security.js +0 -176
  66. package/test/crypto/shamir.js +0 -177
  67. package/test/crypto/shamir_rngcap.js +0 -29
  68. package/test/crypto/signature.js +0 -399
  69. package/test/data/bip69.json +0 -215
  70. package/test/data/bitcoin-sv/README.md +0 -170
  71. package/test/data/bitcoin-sv/base58_encode_decode.json +0 -14
  72. package/test/data/bitcoin-sv/base58_keys_invalid.json +0 -152
  73. package/test/data/bitcoin-sv/base58_keys_valid.json +0 -452
  74. package/test/data/bitcoin-sv/script_tests.json +0 -2591
  75. package/test/data/bitcoin-sv/sighash.json +0 -1003
  76. package/test/data/bitcoin-sv/tx_invalid.json +0 -285
  77. package/test/data/bitcoin-sv/tx_valid.json +0 -367
  78. package/test/data/bitcoind/base58_keys_invalid.json +0 -152
  79. package/test/data/bitcoind/base58_keys_valid.json +0 -452
  80. package/test/data/bitcoind/blocks.json +0 -27
  81. package/test/data/bitcoind/script_tests.json +0 -2244
  82. package/test/data/bitcoind/sig_canonical.json +0 -7
  83. package/test/data/bitcoind/sig_noncanonical.json +0 -22
  84. package/test/data/bitcoind/tx_invalid.json +0 -177
  85. package/test/data/bitcoind/tx_valid.json +0 -224
  86. package/test/data/blk86756-testnet.dat +0 -0
  87. package/test/data/blk86756-testnet.js +0 -12
  88. package/test/data/blk86756-testnet.json +0 -684
  89. package/test/data/ecdsa.json +0 -230
  90. package/test/data/merkleblocks.js +0 -486
  91. package/test/data/messages.json +0 -22
  92. package/test/data/sighash.json +0 -1004
  93. package/test/data/tx_creation.json +0 -85
  94. package/test/didweb/relationships.js +0 -144
  95. package/test/ecies/bitcore-ecies.js +0 -178
  96. package/test/ecies/electrum-ecies.js +0 -206
  97. package/test/encoding/base58.js +0 -131
  98. package/test/encoding/base58check.js +0 -145
  99. package/test/encoding/bufferreader.js +0 -328
  100. package/test/encoding/bufferwriter.js +0 -160
  101. package/test/encoding/varint.js +0 -104
  102. package/test/gdaf/anchor_no_key_leak.js +0 -146
  103. package/test/gdaf/anchor_spv.js +0 -163
  104. package/test/gdaf/canonicalization.js +0 -106
  105. package/test/gdaf/canonicalize.js +0 -140
  106. package/test/gdaf/zk_prover.js +0 -204
  107. package/test/hdkeys.js +0 -365
  108. package/test/hdprivatekey.js +0 -339
  109. package/test/hdpublickey.js +0 -293
  110. package/test/index.js +0 -16
  111. package/test/ltp/ids.js +0 -74
  112. package/test/ltp/right.js +0 -198
  113. package/test/ltp/verify_failclosed.js +0 -134
  114. package/test/message/message.js +0 -190
  115. package/test/mnemonic/data/fixtures.json +0 -300
  116. package/test/mnemonic/mnemonic.js +0 -277
  117. package/test/mnemonic/mocha.opts +0 -1
  118. package/test/mnemonic/pbkdf2.test.js +0 -43
  119. package/test/networks.js +0 -207
  120. package/test/notaryhash/batch_leaf.js +0 -140
  121. package/test/notaryhash/certificate.js +0 -249
  122. package/test/notaryhash/encoding.js +0 -186
  123. package/test/notaryhash/interop.js +0 -112
  124. package/test/notaryhash/merkle.js +0 -181
  125. package/test/notaryhash/script.js +0 -270
  126. package/test/notaryhash/verify.js +0 -342
  127. package/test/opcode.js +0 -186
  128. package/test/ordinals/bsv20.js +0 -337
  129. package/test/ordinals/inscription.js +0 -319
  130. package/test/ordinals/ordlock.js +0 -613
  131. package/test/privatekey.js +0 -540
  132. package/test/publickey.js +0 -411
  133. package/test/regressions.js +0 -215
  134. package/test/script/chronicle.js +0 -543
  135. package/test/script/defaults.js +0 -160
  136. package/test/script/genesis_limits.js +0 -203
  137. package/test/script/interpreter.js +0 -776
  138. package/test/script/script.js +0 -1259
  139. package/test/script/string_ops.js +0 -88
  140. package/test/security/fail_closed_contracts.js +0 -104
  141. package/test/security/threat_model_coverage.js +0 -31
  142. package/test/smart_contract/covenants.js +0 -245
  143. package/test/smart_contract/dsl_debugger.js +0 -101
  144. package/test/smart_contract/extract_field.js +0 -61
  145. package/test/smart_contract/nonenforcing_guard.js +0 -44
  146. package/test/smart_contract/ordinal_transfer.js +0 -81
  147. package/test/smart_contract/preimage.js +0 -98
  148. package/test/smart_contract/sighash_marketplace.js +0 -108
  149. package/test/smart_contract/token_generalized.js +0 -185
  150. package/test/spv/headerchain.js +0 -86
  151. package/test/spv/merkleproof.js +0 -133
  152. package/test/statuslist/failclosed.js +0 -78
  153. package/test/transaction/deserialize.js +0 -33
  154. package/test/transaction/input/input.js +0 -92
  155. package/test/transaction/input/multisig.js +0 -174
  156. package/test/transaction/input/multisigscripthash.js +0 -111
  157. package/test/transaction/input/publickey.js +0 -68
  158. package/test/transaction/input/publickeyhash.js +0 -59
  159. package/test/transaction/output.js +0 -185
  160. package/test/transaction/sighash.js +0 -91
  161. package/test/transaction/signature.js +0 -127
  162. package/test/transaction/transaction.js +0 -1299
  163. package/test/transaction/unspentoutput.js +0 -97
  164. package/test/types/dts_drift.js +0 -124
  165. package/test/types/surface_honesty.js +0 -102
  166. package/test/util/id.js +0 -72
  167. package/test/util/js.js +0 -76
  168. package/test/util/preconditions.js +0 -79
  169. package/test/vcjwt/interop.js +0 -126
@@ -23,42 +23,42 @@ var Signature = require('../crypto/signature')
23
23
  // SIGHASH_ALL | SIGHASH_FORKID — the BSV default these covenants are built for.
24
24
  var SIGHASH = Signature.SIGHASH_ALL | Signature.SIGHASH_FORKID // 0x41
25
25
 
26
- // Post-Genesis consensus + STANDARD RELAY flags — what mainnet miners actually
27
- // enforce. Includes SCRIPT_VERIFY_MINIMALDATA (every push must be minimal) and
28
- // SCRIPT_VERIFY_LOW_S (canonical signatures). Verifying with these flags locally
29
- // mirrors mainnet relay/consensus policy, so a covenant that passes here is
30
- // expected to be accepted on broadcast — catch non-relayable scripts before then.
31
- function flags () {
32
- var I = Interpreter
33
- return I.SCRIPT_VERIFY_P2SH |
34
- I.SCRIPT_VERIFY_STRICTENC |
35
- I.SCRIPT_VERIFY_DERSIG |
36
- I.SCRIPT_VERIFY_LOW_S |
37
- I.SCRIPT_VERIFY_MINIMALDATA |
38
- I.SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY |
39
- I.SCRIPT_VERIFY_CHECKSEQUENCEVERIFY |
40
- I.SCRIPT_ENABLE_SIGHASH_FORKID |
41
- I.SCRIPT_ENABLE_MAGNETIC_OPCODES |
42
- I.SCRIPT_ENABLE_MONOLITH_OPCODES |
43
- // REQUIRED, not optional. pushTxCore emits OP_RIGHT/OP_LEFT — see
44
- // extractHashOutputs and assertSighashType — and those bytes (180/181) are
45
- // upgradable NOPs on the network until Chronicle activates. Without this
46
- // flag the interpreter treats them as no-ops, exactly as a pre-Chronicle
47
- // node does, and the covenant does not verify.
48
- //
49
- // Stated plainly: OP_PUSH_TX covenants built by this library DEPEND on
50
- // Chronicle and cannot be spent on a pre-Chronicle chain. That was
51
- // previously invisible because the interpreter ran the string opcodes
52
- // unconditionally — more permissively than the network.
53
- I.SCRIPT_ENABLE_CHRONICLE
54
- }
55
-
56
26
  /**
57
- * Opt into post-Genesis script limits (needed by OP_PUSH_TX covenants).
58
- * Thin wrapper over Interpreter.useGenesisLimits (added in 4.1.0).
27
+ * Current BSV mainnet consensus + standard relay flags — what miners actually
28
+ * enforce. A covenant that verifies here is expected to be accepted on broadcast.
29
+ *
30
+ * This DELEGATES to Interpreter.mainnetFlags() rather than assembling a list, and
31
+ * that is the whole point. Until 8.4.0 it was hand-assembled, and the hand-written
32
+ * list omitted the three UTXO-ERA flags — SCRIPT_GENESIS, SCRIPT_UTXO_AFTER_GENESIS
33
+ * and SCRIPT_UTXO_AFTER_CHRONICLE. It carried SCRIPT_ENABLE_CHRONICLE, which enables
34
+ * the string opcodes, so the omission was easy to miss: the opcodes ran, and only the
35
+ * *limits* were wrong.
36
+ *
37
+ * The era flags are what the interpreter derives its data limits from. Without them
38
+ * every covenant was verified under PRE-GENESIS rules — a 520-byte element cap that
39
+ * BSV removed in February 2020. An OP_PUSH_TX preimage is ~585 bytes, so this
40
+ * library's flagship feature could not verify against its own harness, and
41
+ * `enableGenesis()` existed to paper over it by raising process-wide statics. That
42
+ * was treating the symptom: raising the statics cannot enable post-Genesis
43
+ * arithmetic (only the era flags can) and it weakens pre-Genesis validation, turning
44
+ * 15 of the reference node's 22 SCRIPTNUM_OVERFLOW vectors into false accepts.
45
+ *
46
+ * Delegating also means the covenant path tracks consensus automatically instead of
47
+ * drifting the next time an era activates. `mainnetFlags()` is the same function the
48
+ * Interpreter uses for a no-flags verify(), so "verify locally" and "what the network
49
+ * does" cannot diverge again without both moving together.
50
+ *
51
+ * Two flags in the old list are deliberately gone: SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY
52
+ * and SCRIPT_VERIFY_CHECKSEQUENCEVERIFY. Genesis reverted OP_CLTV/OP_CSV to
53
+ * upgradable NOPs for outputs created after it (see interpreter.js, the
54
+ * `isAfterGenesis()` short-circuit), so once the era flags are present these two
55
+ * change nothing. Keeping them would have implied a time-lock guarantee mainnet does
56
+ * not provide, which is why the CLTV-based locks were removed in 9.0.0.
57
+ *
58
+ * NULLFAIL is gained, which is strictly stricter.
59
59
  */
60
- function enableGenesis (max) {
61
- return Interpreter.useGenesisLimits(max)
60
+ function flags () {
61
+ return Interpreter.mainnetFlags()
62
62
  }
63
63
 
64
64
  /**
@@ -135,7 +135,6 @@ function scriptNum (n) {
135
135
  module.exports = {
136
136
  SIGHASH: SIGHASH,
137
137
  flags: flags,
138
- enableGenesis: enableGenesis,
139
138
  verify: verify,
140
139
  rawPreimage: rawPreimage,
141
140
  sighashDigest: sighashDigest,
@@ -13,8 +13,8 @@
13
13
  * Optimal parameters: private key a = 1, ephemeral k = 1 => r = Gx,
14
14
  * s = (e + Gx) mod n, pubkey P = 02||Gx, e = HASH256(preimage).
15
15
  *
16
- * Requires post-Genesis limits — call SmartContract.enableGenesis() (a.k.a
17
- * Interpreter.useGenesisLimits()) before verifying these scripts.
16
+ * Verifies under mainnet consensus flags with no opt-in (8.4.0+). Earlier versions
17
+ * required SmartContract.enableGenesis() first; that call is now a deprecated no-op.
18
18
  */
19
19
 
20
20
  var Script = require('../script')
@@ -71,22 +71,6 @@ class CustomScriptHelper {
71
71
  return script;
72
72
  }
73
73
 
74
- /**
75
- * Create a time-locked script (CHECKLOCKTIMEVERIFY)
76
- * @param {number} lockTime - Block height or timestamp
77
- * @param {Script} baseScript - Base script to execute after time lock
78
- * @returns {Script} Time-locked script
79
- */
80
- static createTimelockScript(lockTime, baseScript) {
81
- const lockTimeBuffer = Buffer.from(lockTime.toString(16).padStart(8, '0'), 'hex').reverse();
82
-
83
- return new Script()
84
- .add(lockTimeBuffer)
85
- .add(Opcode.OP_CHECKLOCKTIMEVERIFY)
86
- .add(Opcode.OP_DROP)
87
- .add(baseScript.toBuffer());
88
- }
89
-
90
74
  /**
91
75
  * Create a conditional script (IF/ELSE/ENDIF)
92
76
  * @param {Script} ifScript - Script to execute if condition is true
@@ -133,6 +133,21 @@ HDPrivateKey._getDerivationIndexes = function (path) {
133
133
  /**
134
134
  * WARNING: This method is deprecated. Use deriveChild or deriveNonCompliantChild instead. This is not BIP32 compliant
135
135
  *
136
+ * This one keeps THROWING rather than warning and delegating, and the reason is
137
+ * worth stating because it is the exception STABILITY.md carves out rather than
138
+ * an oversight.
139
+ *
140
+ * `derive` is ambiguous. Its two replacements return DIFFERENT KEYS:
141
+ * `deriveChild` is BIP32-compliant, `deriveNonCompliantChild` reproduces the old
142
+ * behaviour. Picking one here would silently hand roughly half of all callers
143
+ * keys they did not ask for — and a wrong derivation path means addresses whose
144
+ * funds cannot be recovered with the key the caller believes they hold. There is
145
+ * no default that is safe for everyone, so the caller has to choose, and the
146
+ * error names both options.
147
+ *
148
+ * A deprecation warning is the right tool when the replacement is obvious (see
149
+ * `MerkleBlock#filterdTxsHash`, a misspelling that now delegates). It is the
150
+ * wrong tool when guessing costs money.
136
151
  *
137
152
  * Get a derived child based on a string or number.
138
153
  *
@@ -35,7 +35,7 @@
35
35
  * OP_ENDIF
36
36
  * [OP_FALSE OP_IF "ord" … OP_ENDIF] // optional inert inscription envelope
37
37
  *
38
- * Requires post-Genesis limits: call SmartContract.enableGenesis() before verifying.
38
+ * Verifies under mainnet consensus flags with no opt-in (8.4.0+).
39
39
  */
40
40
  var P = require('../covenant/pushtx')
41
41
  var H = require('../covenant/helpers')
@@ -65,7 +65,7 @@ var Interpreter = function Interpreter (obj) {
65
65
  *
66
66
  * Translated from bitcoind's VerifyScript
67
67
  */
68
- Interpreter.prototype.verify = function (scriptSig, scriptPubkey, tx, nin, flags, satoshisBN) {
68
+ Interpreter.prototype._verifyCore = function (scriptSig, scriptPubkey, tx, nin, flags, satoshisBN) {
69
69
  var Transaction = require('../transaction')
70
70
 
71
71
  if (_.isUndefined(tx)) {
@@ -506,6 +506,114 @@ Interpreter.SCRIPT_UTXO_AFTER_CHRONICLE = (1 << 21)
506
506
  */
507
507
  Interpreter.CHRONICLE_ACTIVATION_HEIGHT = 943816
508
508
 
509
+ /**
510
+ * Flags and *limits* are separate mechanisms. The era bits below are what the
511
+ * interpreter derives its element-size, script-size, opcode-count and
512
+ * script-number caps from — so a caller who hand-assembles a flag word out of
513
+ * named constants gets the feature opcodes they asked for while silently keeping
514
+ * the pre-Genesis caps. The script runs, which is what makes it hard to see;
515
+ * nothing looks wrong until a large push is rejected and the error names the
516
+ * push rather than the flags.
517
+ *
518
+ * Warning on every era-less verify() is not an option. Pre-Genesis validation is
519
+ * legitimate and common: the reference script_tests.json vectors are era-less by
520
+ * construction, and roughly three quarters of this library's own verify() calls
521
+ * are era-less for that reason. So the notice fires only on the intersection of
522
+ * two facts — an explicit era-less flag word AND a failure whose threshold is
523
+ * era-derived. Measured across the suite that combination accounts for ~5% of
524
+ * era-less failures, all of them genuine pre-Genesis vectors, and it is exactly
525
+ * the state a covenant author who guessed at flags ends up in.
526
+ */
527
+ /**
528
+ * Failures whose threshold moved with an era: the cap that moved, and the flag
529
+ * that ACTUALLY lifts it.
530
+ *
531
+ * `lifts` is per-error on purpose. An earlier version tested a single ERA_FLAGS
532
+ * word containing all four era bits, which silenced the notice for the most likely
533
+ * form of the mistake: `SCRIPT_GENESIS` is the constant a hand-assembling caller
534
+ * reaches for — it is the one named "GENESIS" — but the size caps read
535
+ * `isAfterGenesis()`, which tests SCRIPT_UTXO_AFTER_GENESIS and nothing else. A
536
+ * flag word carrying SCRIPT_GENESIS alone still gets the 520-byte cap, still fails
537
+ * with PUSH_SIZE, and got no explanation.
538
+ *
539
+ * Each entry therefore names the bit its own cap is derived from:
540
+ * maxScriptElementSize/maxScriptSize/maxOpsPerScript -> isAfterGenesis()
541
+ * maxScriptNumLength -> isAfterChronicle(), then isAfterGenesis()
542
+ */
543
+ Interpreter.ERA_SENSITIVE_ERRORS = {
544
+ SCRIPT_ERR_PUSH_SIZE: {
545
+ cap: 'stack element size (capped at 520 bytes pre-Genesis, unbounded after)',
546
+ lifts: Interpreter.SCRIPT_UTXO_AFTER_GENESIS
547
+ },
548
+ SCRIPT_ERR_SCRIPT_SIZE: {
549
+ cap: 'total script size (capped at 10,000 bytes pre-Genesis, unbounded after)',
550
+ lifts: Interpreter.SCRIPT_UTXO_AFTER_GENESIS
551
+ },
552
+ SCRIPT_ERR_OP_COUNT: {
553
+ cap: 'opcode count (capped at 201 pre-Genesis, unbounded after)',
554
+ lifts: Interpreter.SCRIPT_UTXO_AFTER_GENESIS
555
+ },
556
+ SCRIPT_ERR_SCRIPTNUM_OVERFLOW: {
557
+ cap: 'script number width (4 bytes pre-Genesis, 750,000 after Genesis, 32,000,000 after Chronicle)',
558
+ lifts: Interpreter.SCRIPT_UTXO_AFTER_GENESIS | Interpreter.SCRIPT_UTXO_AFTER_CHRONICLE
559
+ }
560
+ }
561
+
562
+ /**
563
+ * Every era bit, kept for callers that want to ask "is this flag word era-aware at
564
+ * all". NOT used to gate the diagnostic — see ERA_SENSITIVE_ERRORS.lifts.
565
+ */
566
+ Interpreter.ERA_FLAGS =
567
+ Interpreter.SCRIPT_GENESIS |
568
+ Interpreter.SCRIPT_UTXO_AFTER_GENESIS |
569
+ Interpreter.SCRIPT_ENABLE_CHRONICLE |
570
+ Interpreter.SCRIPT_UTXO_AFTER_CHRONICLE
571
+
572
+ /** Set false to silence the notice. `eraHint` is still populated. */
573
+ Interpreter.eraDiagnostics =
574
+ !(typeof process !== 'undefined' && process.env && process.env.BSV_NO_ERA_HINT === '1')
575
+
576
+ var eraWarned = false
577
+
578
+ Interpreter.prototype._eraDiagnose = function (flags) {
579
+ // Only an EXPLICIT flag word can be wrong this way; omitting flags already
580
+ // resolves to current mainnet via currentConsensusFlags().
581
+ if (flags === undefined) return
582
+ var entry = Interpreter.ERA_SENSITIVE_ERRORS[this.errstr]
583
+ if (!entry) return
584
+ // Gate on the bit that lifts THIS cap, not on any era bit being present.
585
+ if ((flags & entry.lifts) !== 0) return
586
+ var cap = entry.cap
587
+
588
+ this.eraHint =
589
+ this.errstr + ' was produced under PRE-GENESIS limits: ' + cap + '.\n' +
590
+ 'The flags passed to verify() (0x' + (flags >>> 0).toString(16) + ') carry no era bit, ' +
591
+ 'so those caps applied regardless of which feature opcodes were enabled.\n' +
592
+ 'To validate against BSV as it is today, omit the flags argument or pass ' +
593
+ 'Interpreter.mainnetFlags(). If you are deliberately testing pre-Genesis ' +
594
+ 'consensus this failure is correct — set Interpreter.eraDiagnostics = false ' +
595
+ '(or BSV_NO_ERA_HINT=1) to silence this.'
596
+
597
+ if (Interpreter.eraDiagnostics && !eraWarned) {
598
+ eraWarned = true
599
+ console.warn('\n[@smartledger/bsv] ' + this.eraHint + '\n(shown once per process)\n')
600
+ }
601
+ }
602
+
603
+ /**
604
+ * Verify, then explain an era-caused failure if that is what happened.
605
+ * Wraps _verifyCore rather than editing its ten-odd early returns.
606
+ */
607
+ Interpreter.prototype.verify = function (scriptSig, scriptPubkey, tx, nin, flags, satoshisBN) {
608
+ this.eraHint = null
609
+ var ok = this._verifyCore(scriptSig, scriptPubkey, tx, nin, flags, satoshisBN)
610
+ if (!ok) this._eraDiagnose(flags)
611
+ return ok
612
+ }
613
+
614
+ /** Test hook: forget that the notice has been shown. */
615
+ Interpreter._resetEraWarning = function () { eraWarned = false }
616
+
509
617
  /**
510
618
  * The script-verification flags matching BSV mainnet consensus.
511
619
  *
@@ -20,6 +20,7 @@ var Hash = require('../crypto/hash')
20
20
  var BN = require('../crypto/bn')
21
21
  var Transaction = require('../transaction')
22
22
  var Script = require('../script')
23
+ var deprecate = require('../util/deprecate')
23
24
 
24
25
  /**
25
26
  * @deprecated NON-ENFORCING. `buildLockingScript` / `createCovenant` emit
@@ -57,6 +58,19 @@ function Builder(privateKey, options) {
57
58
  // The scripts this class builds are non-enforcing (see the class @deprecated note).
58
59
  // Refuse to hand one back as if it were a real covenant unless explicitly acknowledged.
59
60
  Builder.prototype._assertEnforcingAllowed = function () {
61
+ if (this.allowNonEnforcing) {
62
+ // Opting in is legitimate (demos, tests, the docs' worked examples) but it
63
+ // is not permanent. Say so once, and here rather than at construction, so the
64
+ // notice fires only for callers actually taking a script away with them.
65
+ deprecate({
66
+ what: 'SmartContract.Builder ({ allowNonEnforcing: true })',
67
+ since: '9.1.0',
68
+ removeIn: '10.0.0',
69
+ use: 'SmartContract.policy(), or SmartContract.PushTx / Token / valueCovenant',
70
+ why: 'the scripts it emits reduce to plain P2PK and constrain nothing about the spend'
71
+ })
72
+ return
73
+ }
60
74
  if (!this.allowNonEnforcing) {
61
75
  throw new Error(
62
76
  'SmartContract.Builder produces a NON-ENFORCING script (constant hash-lock → ' +
@@ -5,8 +5,8 @@
5
5
  * Step-traces a locking/unlocking pair through Script.Interpreter and records the
6
6
  * stack + alt-stack after every opcode, so you can watch an OP_PUSH_TX covenant
7
7
  * build its signature and enforce its constraints. Uses the interpreter's
8
- * stepListener hook. Call SmartContract.enableGenesis() first for OP_PUSH_TX
9
- * covenants (their preimage element / opcode count exceed pre-Genesis limits).
8
+ * stepListener hook. No opt-in is needed since 8.4.0: covenants verify under mainnet
9
+ * consensus flags, whose era bits lift the pre-Genesis element and opcode caps.
10
10
  */
11
11
 
12
12
  var Interpreter = require('../script/interpreter')
@@ -14,8 +14,8 @@
14
14
  * // c.unlock(spendTx, satoshis) -> grinds + returns the preimage unlock Script
15
15
  *
16
16
  * Each clause compiles to one preimage-field check on top of a single OP_PUSH_TX
17
- * authentication; clauses AND together. Requires post-Genesis limits at verify
18
- * time (SmartContract.enableGenesis()).
17
+ * authentication; clauses AND together. Verifies under mainnet consensus flags with
18
+ * no opt-in (8.4.0+).
19
19
  */
20
20
 
21
21
  var PushTx = require('../covenant/pushtx')
@@ -70,9 +70,6 @@ SmartContract.trace = function (unlockingScript, lockingScript, opts) {
70
70
 
71
71
  // --- Covenant convenience API (v4.2.0) ---
72
72
  // Opt into post-Genesis script limits (required by OP_PUSH_TX covenants).
73
- SmartContract.enableGenesis = function (max) {
74
- return SmartContract.CovenantHelpers.enableGenesis(max)
75
- }
76
73
  // Verify an unlocking/locking pair through the consensus interpreter.
77
74
  SmartContract.verifyScript = function (unlockingScript, lockingScript, opts) {
78
75
  return SmartContract.CovenantHelpers.verify(unlockingScript, lockingScript, opts)
@@ -10,7 +10,6 @@ var H = require('../covenant/helpers')
10
10
  var Script = require('../script')
11
11
  var Opcode = require('../opcode')
12
12
  var signInput = H.signInput
13
- var n = H.scriptNum
14
13
 
15
14
  /** Hash-lock: reveal a preimage whose SHA-256 matches a digest. */
16
15
  function hashLock (secret) {
@@ -36,20 +35,6 @@ function p2pkh (privateKey) {
36
35
  }
37
36
  }
38
37
 
39
- /** CLTV absolute time-lock: <locktime> CLTV DROP <pk> CHECKSIG. */
40
- function timeLockCLTV (privateKey, locktime) {
41
- var pub = privateKey.toPublicKey()
42
- var lock = new Script()
43
- .add(n(locktime)).add(Opcode.OP_CHECKLOCKTIMEVERIFY).add(Opcode.OP_DROP)
44
- .add(pub.toBuffer()).add(Opcode.OP_CHECKSIG)
45
- return {
46
- lock: lock,
47
- meta: { name: 'cltv-timelock', locktime: locktime },
48
- // Caller must set spend.nLockTime >= locktime and input sequence < 0xffffffff.
49
- unlock: function (spend, sats) { return new Script().add(signInput(spend, privateKey, 0, lock, sats)) }
50
- }
51
- }
52
-
53
38
  /** m-of-n multisig. */
54
39
  function multisig (m, privateKeys) {
55
40
  var pubs = privateKeys.map(function (k) { return k.toPublicKey() })
@@ -68,33 +53,8 @@ function multisig (m, privateKeys) {
68
53
  }
69
54
  }
70
55
 
71
- /** HTLC: hash-OR-timeout. */
72
- function htlc (opts) {
73
- var digest = Hash.sha256(opts.secret)
74
- var lock = new Script()
75
- .add(Opcode.OP_IF)
76
- .add(Opcode.OP_SHA256).add(digest).add(Opcode.OP_EQUALVERIFY)
77
- .add(opts.receiver.toPublicKey().toBuffer()).add(Opcode.OP_CHECKSIG)
78
- .add(Opcode.OP_ELSE)
79
- .add(n(opts.timeout)).add(Opcode.OP_CHECKLOCKTIMEVERIFY).add(Opcode.OP_DROP)
80
- .add(opts.sender.toPublicKey().toBuffer()).add(Opcode.OP_CHECKSIG)
81
- .add(Opcode.OP_ENDIF)
82
- return {
83
- lock: lock,
84
- meta: { name: 'htlc', digest: digest.toString('hex'), timeout: opts.timeout },
85
- unlockClaim: function (spend, sats) {
86
- return new Script().add(signInput(spend, opts.receiver, 0, lock, sats)).add(opts.secret).add(Opcode.OP_1)
87
- },
88
- unlockRefund: function (spend, sats) {
89
- return new Script().add(signInput(spend, opts.sender, 0, lock, sats)).add(Opcode.OP_0)
90
- }
91
- }
92
- }
93
-
94
56
  module.exports = {
95
57
  hashLock: hashLock,
96
58
  p2pkh: p2pkh,
97
- timeLockCLTV: timeLockCLTV,
98
- multisig: multisig,
99
- htlc: htlc
59
+ multisig: multisig
100
60
  }
@@ -14,7 +14,7 @@
14
14
  * the slice preimage[104 : len-52] is exactly the `scriptlen||script` half of a
15
15
  * TxOut, so the next output is `<newValue:8-LE> || preimage[104:len-52]`.
16
16
  *
17
- * Requires post-Genesis limits (SmartContract.enableGenesis()).
17
+ * Verifies under mainnet consensus flags with no opt-in (8.4.0+).
18
18
  */
19
19
 
20
20
  var P = require('../covenant/pushtx')
@@ -36,7 +36,7 @@
36
36
  * surrounding output bytes and the token's value; the covenant binds them
37
37
  * into the committed hashOutputs. Value conservation is left to the network.
38
38
  *
39
- * Requires post-Genesis limits (SmartContract.enableGenesis()).
39
+ * Verifies under mainnet consensus flags with no opt-in (8.4.0+).
40
40
  */
41
41
 
42
42
  var BN = require('../crypto/bn')
@@ -0,0 +1,159 @@
1
+ 'use strict'
2
+
3
+ /**
4
+ * Runtime deprecation notices.
5
+ *
6
+ * A semver major is a promise that the consumer's code breaks. Between 4.0.0
7
+ * (2026-05-31) and 9.0.0 (2026-08-21) this library made that promise six times,
8
+ * and the mechanism was almost always the same: an API that had become wrong was
9
+ * changed to `throw`, in the same release that decided it was wrong. Correct
10
+ * diagnosis, no warning period.
11
+ *
12
+ * `MerkleBlock#filterdTxsHash` was one of those and now delegates with a notice.
13
+ * `HDPrivateKey#derive` still throws deliberately: its replacements return
14
+ * different keys, so guessing on the caller's behalf risks funds. That is the
15
+ * narrow exception in STABILITY.md, not a gap in this module.
16
+ *
17
+ * The fix is not to keep bad APIs. It is to separate the moment we say "this is
18
+ * wrong" from the moment we break callers:
19
+ *
20
+ * minor mark it. Callers see a warning naming the replacement, and keep
21
+ * working. `removeIn` states the version that will break them.
22
+ * major remove it, on a schedule announced at least one minor in advance.
23
+ *
24
+ * Deprecating is therefore a NON-breaking act and belongs in a minor. That is
25
+ * what makes a long-lived 9.x possible: correctness fixes ship continuously,
26
+ * breakage batches into one planned major with a migration path already in the
27
+ * consumer's logs.
28
+ *
29
+ * Nothing here ever throws. A deprecation that throws is just a breaking change
30
+ * wearing a warning's name.
31
+ */
32
+
33
+ var seen = Object.create(null)
34
+
35
+ /** Every notice fired this process, for tests and for `--audit`-style tooling. */
36
+ var fired = []
37
+
38
+ /**
39
+ * Warnings are on unless explicitly silenced. Consumers who have logged the
40
+ * migration and do not want the noise set BSV_NO_DEPRECATION_WARNINGS=1; the
41
+ * record in `fired` is kept either way so tooling still sees it.
42
+ */
43
+ // Guarded like every other process.env read in lib/ (see lib/smartutxo.js,
44
+ // lib/browser-utxo-manager.js). This module is inlined into every feature bundle,
45
+ // and `exports` publishes lib/ subpaths directly, so an unguarded read here is a
46
+ // ReferenceError in any browser bundler that does not shim `process`.
47
+ var enabled = !(typeof process !== 'undefined' && process.env &&
48
+ process.env.BSV_NO_DEPRECATION_WARNINGS === '1')
49
+
50
+ /**
51
+ * `what` is the one field with no sensible default: it is the string the notice is
52
+ * keyed and deduplicated on. Everything else degrades gracefully.
53
+ */
54
+ function assertOpts (opts, caller) {
55
+ if (!opts || typeof opts.what !== 'string' || opts.what === '') {
56
+ throw new TypeError(caller + '() requires { what: string }')
57
+ }
58
+ }
59
+
60
+ function format (opts) {
61
+ var msg = '[@smartledger/bsv] ' + opts.what + ' is deprecated'
62
+ if (opts.since) msg += ' since ' + opts.since
63
+ msg += '.'
64
+ if (opts.why) msg += ' ' + opts.why.charAt(0).toUpperCase() + opts.why.slice(1) + '.'
65
+ if (opts.use) msg += ' Use ' + opts.use + ' instead.'
66
+ msg += opts.removeIn
67
+ ? ' It will be removed in ' + opts.removeIn + '.'
68
+ : ' A removal version has not been set; it will not be removed in a 9.x release.'
69
+ return msg
70
+ }
71
+
72
+ /**
73
+ * Emit a deprecation notice at most once per `what` per process.
74
+ *
75
+ * @param {object} opts
76
+ * @param {string} opts.what the API being deprecated, as a caller writes it
77
+ * @param {string} [opts.since] version that deprecated it
78
+ * @param {string} [opts.removeIn] version that will remove it (a major)
79
+ * @param {string} [opts.use] the replacement, as a caller would write it
80
+ * @param {string} [opts.why] one clause; why it is wrong, not what to do
81
+ * @returns {boolean} true if this call emitted (false if already seen)
82
+ */
83
+ function deprecate (opts) {
84
+ if (!opts || !opts.what) throw new TypeError('deprecate() requires { what }')
85
+ if (seen[opts.what]) return false
86
+ seen[opts.what] = true
87
+
88
+ var message = format(opts)
89
+ fired.push({
90
+ what: opts.what,
91
+ since: opts.since || null,
92
+ removeIn: opts.removeIn || null,
93
+ use: opts.use || null,
94
+ message: message
95
+ })
96
+ if (enabled) console.warn(message)
97
+ return true
98
+ }
99
+
100
+ /**
101
+ * Wrap a function so calling it warns once, then behaves exactly as before.
102
+ * Preserves name, arity and `this`, so it is safe on prototype methods.
103
+ *
104
+ * Klass.prototype.old = deprecate.fn(Klass.prototype.old, {
105
+ * what: 'Klass#old', since: '9.1.0', removeIn: '10.0.0', use: 'Klass#new'
106
+ * })
107
+ */
108
+ deprecate.fn = function (fn, opts) {
109
+ if (typeof fn !== 'function') throw new TypeError('deprecate.fn() requires a function')
110
+ // Validate HERE, not inside the wrapper. Deferring it meant `deprecate.fn(f)` wrapped
111
+ // cleanly and then threw on every subsequent call — turning a deprecation into the
112
+ // breaking change this module exists to avoid, at a call site far from the mistake.
113
+ // Wrapping is a one-time author action; failing there is loud, immediate and cheap.
114
+ assertOpts(opts, 'deprecate.fn')
115
+ var wrapper = function () {
116
+ deprecate(opts)
117
+ return fn.apply(this, arguments)
118
+ }
119
+ Object.defineProperty(wrapper, 'name', { value: fn.name, configurable: true })
120
+ Object.defineProperty(wrapper, 'length', { value: fn.length, configurable: true })
121
+ wrapper.__wrapped = fn
122
+ wrapper.__deprecation = opts
123
+ return wrapper
124
+ }
125
+
126
+ /**
127
+ * Deprecate a property access (an alias namespace, a renamed field).
128
+ * Warns on first read; the value is computed once and cached.
129
+ */
130
+ deprecate.property = function (target, name, get, opts) {
131
+ assertOpts(opts, 'deprecate.property')
132
+ var cached
133
+ var loaded = false
134
+ Object.defineProperty(target, name, {
135
+ configurable: true,
136
+ enumerable: true,
137
+ get: function () {
138
+ deprecate(opts)
139
+ if (!loaded) { cached = get(); loaded = true }
140
+ return cached
141
+ }
142
+ })
143
+ return target
144
+ }
145
+
146
+ /** Notices fired this process, in order. */
147
+ deprecate.fired = function () { return fired.slice() }
148
+
149
+ /** Silence output. The `fired` record is still kept. */
150
+ deprecate.setEnabled = function (v) { enabled = !!v }
151
+ deprecate.isEnabled = function () { return enabled }
152
+
153
+ /** Test hook: forget what has been warned about. */
154
+ deprecate.reset = function () {
155
+ seen = Object.create(null)
156
+ fired.length = 0
157
+ }
158
+
159
+ module.exports = deprecate