@smartledger/bsv 7.8.1 → 7.10.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 (76) hide show
  1. package/CHANGELOG.md +117 -6
  2. package/README.md +38 -38
  3. package/bsv-covenant.min.js +1 -1
  4. package/bsv-ecies.min.js +1 -1
  5. package/bsv-gdaf.min.js +54 -54
  6. package/bsv-ltp.min.js +58 -85
  7. package/bsv-message.min.js +2 -2
  8. package/bsv-mnemonic.min.js +12 -14
  9. package/bsv-script-helper.min.js +1 -1
  10. package/bsv-shamir.min.js +14 -16
  11. package/bsv-smartcontract.min.js +23 -25
  12. package/bsv.bundle.js +54 -54
  13. package/bsv.min.js +54 -54
  14. package/build/esbuild.js +84 -4
  15. package/docs/MODULE_REFERENCE_COMPLETE.md +27 -27
  16. package/docs/advanced/UTXO_MANAGER_GUIDE.md +1 -1
  17. package/docs/getting-started/INSTALLATION.md +23 -23
  18. package/docs/getting-started/QUICK_START.md +7 -7
  19. package/docs/migration/FROM_BSV_1_5_6.md +5 -5
  20. package/index.js +9 -1
  21. package/lib/covenant/helpers.js +146 -0
  22. package/lib/covenant/index.js +21 -0
  23. package/lib/covenant/pushtx.js +243 -0
  24. package/lib/covenant-interface.js +408 -397
  25. package/lib/custom-script-helper.js +44 -38
  26. package/lib/ecies/bitcore-ecies.js +3 -4
  27. package/lib/ecies/electrum-ecies.js +4 -6
  28. package/lib/ecies/errors.js +1 -1
  29. package/lib/gdaf/attestation-signer.js +7 -7
  30. package/lib/gdaf/attestation-verifier.js +5 -6
  31. package/lib/gdaf/did-resolver.js +10 -9
  32. package/lib/gdaf/smartledger-anchor.js +13 -12
  33. package/lib/gdaf/zk-prover.js +8 -8
  34. package/lib/ltp/anchor.js +2 -3
  35. package/lib/ltp/claim.js +2 -3
  36. package/lib/ltp/index.js +2 -3
  37. package/lib/ltp/obligation.js +9 -9
  38. package/lib/ltp/proof.js +7 -7
  39. package/lib/ltp/registry.js +4 -5
  40. package/lib/ltp/right.js +11 -11
  41. package/lib/message/index.js +5 -4
  42. package/lib/message/message.js +11 -11
  43. package/lib/mnemonic/errors.js +1 -1
  44. package/lib/mnemonic/index.js +5 -4
  45. package/lib/mnemonic/mnemonic.js +22 -10
  46. package/lib/ordinals/bsv20.js +4 -4
  47. package/lib/ordinals/inscription.js +8 -12
  48. package/lib/ordinals/ordlock.js +26 -21
  49. package/lib/script/interpreter.js +96 -31
  50. package/lib/smart_contract/authorizers.js +8 -6
  51. package/lib/smart_contract/builder.js +32 -26
  52. package/lib/smart_contract/covenant.js +32 -25
  53. package/lib/smart_contract/covenant_helpers.js +8 -128
  54. package/lib/smart_contract/debugger.js +9 -6
  55. package/lib/smart_contract/dsl.js +5 -6
  56. package/lib/smart_contract/index.js +11 -8
  57. package/lib/smart_contract/locks.js +3 -4
  58. package/lib/smart_contract/opcode_list.js +2 -3
  59. package/lib/smart_contract/pels.js +4 -5
  60. package/lib/smart_contract/preimage.js +11 -7
  61. package/lib/smart_contract/pushtx.js +8 -263
  62. package/lib/smart_contract/script_interpreter.js +112 -105
  63. package/lib/smart_contract/script_tester.js +24 -18
  64. package/lib/smart_contract/script_utils.js +15 -14
  65. package/lib/smart_contract/sighash.js +23 -15
  66. package/lib/smart_contract/stack_examiner.js +70 -63
  67. package/lib/smart_contract/token.js +6 -6
  68. package/lib/smart_contract/utxo_generator.js +21 -15
  69. package/lib/smartutxo.js +27 -21
  70. package/lib/spv/headerchain.js +3 -3
  71. package/lib/spv/merkleproof.js +3 -3
  72. package/package.json +4 -2
  73. package/test/script/chronicle.js +53 -10
  74. package/test/script/interpreter.js +9 -6
  75. package/test/script/string_ops.js +26 -10
  76. package/version.js +1 -1
package/lib/smartutxo.js CHANGED
@@ -35,6 +35,13 @@ const debug = function () {
35
35
  if (enabled) console.log.apply(console, arguments)
36
36
  }
37
37
 
38
+ // Library primitives, required directly rather than through the package root.
39
+ // createMockUTXOs() previously did a lazy `require('../')` to dodge the
40
+ // module-init cycle; with the cycle gone these can be plain top-level imports.
41
+ const Script = require('./script')
42
+ const Address = require('./address')
43
+ const Random = require('./crypto/random')
44
+
38
45
  // Browser-compatible imports
39
46
  let fs, path, crypto, blockchainState
40
47
 
@@ -54,9 +61,9 @@ if (typeof window === 'undefined' && typeof require === 'function') {
54
61
  * Comprehensive UTXO Management System for BSV development
55
62
  */
56
63
  class SmartUTXOManager {
57
- constructor(options = {}) {
64
+ constructor (options = {}) {
58
65
  this.options = options || {}
59
-
66
+
60
67
  // Initialize blockchain state - this creates the file if needed
61
68
  this.loadState()
62
69
  }
@@ -64,7 +71,7 @@ class SmartUTXOManager {
64
71
  /**
65
72
  * Load blockchain state from file (initializes if needed)
66
73
  */
67
- loadState() {
74
+ loadState () {
68
75
  try {
69
76
  const state = blockchainState.loadBlockchainState()
70
77
  return state
@@ -75,9 +82,9 @@ class SmartUTXOManager {
75
82
  }
76
83
 
77
84
  /**
78
- * Save blockchain state to file
85
+ * Save blockchain state to file
79
86
  */
80
- saveState() {
87
+ saveState () {
81
88
  try {
82
89
  const state = blockchainState.loadBlockchainState()
83
90
  blockchainState.saveBlockchainState(state)
@@ -93,15 +100,15 @@ class SmartUTXOManager {
93
100
  * @param {string} address - Bitcoin address
94
101
  * @returns {Array} Array of UTXO objects
95
102
  */
96
- getUTXOsForAddress(address) {
103
+ getUTXOsForAddress (address) {
97
104
  try {
98
105
  const state = blockchainState.loadBlockchainState()
99
-
106
+
100
107
  // Check if wallet exists
101
108
  if (!state.wallets || !state.wallets[address]) {
102
109
  return []
103
110
  }
104
-
111
+
105
112
  // Return the wallet's UTXOs
106
113
  return state.wallets[address].utxos || []
107
114
  } catch (error) {
@@ -114,7 +121,7 @@ class SmartUTXOManager {
114
121
  * Add a new UTXO to the system
115
122
  * @param {Object} utxo - UTXO object {txid, vout, address, satoshis, script}
116
123
  */
117
- addUTXO(utxo) {
124
+ addUTXO (utxo) {
118
125
  try {
119
126
  // Use the correct API: addUTXO(utxo, ownerAddress)
120
127
  blockchainState.addUTXO(utxo, utxo.address)
@@ -128,7 +135,7 @@ class SmartUTXOManager {
128
135
  * @param {Array} inputs - Array of input objects {txid, vout}
129
136
  * @param {string} spentInTx - Optional transaction ID where UTXO was spent
130
137
  */
131
- spendUTXOs(inputs, spentInTx = 'manual-spend') {
138
+ spendUTXOs (inputs, spentInTx = 'manual-spend') {
132
139
  try {
133
140
  for (const input of inputs) {
134
141
  // Use the correct API: spendUTXO(txid, vout, spentInTx)
@@ -153,18 +160,17 @@ class SmartUTXOManager {
153
160
  * @param {number} satoshis - Satoshis per UTXO
154
161
  * @returns {Array} Array of created UTXOs
155
162
  */
156
- createMockUTXOs(address, count = 5, satoshis = 100000) {
163
+ createMockUTXOs (address, count = 5, satoshis = 100000) {
157
164
  // Use bsv's own RNG so this works in both Node and browser builds
158
165
  // (the Node `crypto` import above is undefined in browser context).
159
- const bsv = require('../')
160
- const lockingScriptHex = bsv.Script.buildPublicKeyHashOut(
161
- bsv.Address.fromString(address)
166
+ const lockingScriptHex = Script.buildPublicKeyHashOut(
167
+ Address.fromString(address)
162
168
  ).toHex()
163
169
 
164
170
  const mockUTXOs = []
165
171
  for (let i = 0; i < count; i++) {
166
172
  mockUTXOs.push({
167
- txid: bsv.crypto.Random.getRandomBuffer(32).toString('hex'),
173
+ txid: Random.getRandomBuffer(32).toString('hex'),
168
174
  vout: i,
169
175
  address,
170
176
  satoshis,
@@ -179,15 +185,15 @@ class SmartUTXOManager {
179
185
  * @param {string} address - Bitcoin address
180
186
  * @returns {number} Total satoshis
181
187
  */
182
- getBalance(address) {
188
+ getBalance (address) {
183
189
  try {
184
190
  const state = blockchainState.loadBlockchainState()
185
-
191
+
186
192
  // Check if wallet exists
187
193
  if (!state.wallets || !state.wallets[address]) {
188
194
  return 0
189
195
  }
190
-
196
+
191
197
  // Return the wallet's total value
192
198
  return state.wallets[address].totalValue || 0
193
199
  } catch (error) {
@@ -200,7 +206,7 @@ class SmartUTXOManager {
200
206
  * Get blockchain statistics
201
207
  * @returns {Object} Stats object
202
208
  */
203
- getStats() {
209
+ getStats () {
204
210
  try {
205
211
  const state = blockchainState.getBlockchainStats() // This returns the full state
206
212
  return {
@@ -219,7 +225,7 @@ class SmartUTXOManager {
219
225
  /**
220
226
  * Reset blockchain state
221
227
  */
222
- reset() {
228
+ reset () {
223
229
  try {
224
230
  const statePath = path.join(__dirname, '../utilities/blockchain-state.json')
225
231
  if (fs.existsSync(statePath)) {
@@ -232,4 +238,4 @@ class SmartUTXOManager {
232
238
  }
233
239
  }
234
240
 
235
- module.exports = SmartUTXOManager
241
+ module.exports = SmartUTXOManager
@@ -15,14 +15,14 @@
15
15
  * (or anchor) must match; the headers around it are then real work extending a block
16
16
  * you trust. Full difficulty-retarget validation is intentionally out of scope here.
17
17
  */
18
- var bsv = require('../..')
18
+ var BlockHeader = require('../block/blockheader')
19
19
 
20
20
  function rev (b) { return Buffer.from(b).reverse() }
21
21
 
22
22
  function toHeader (h) {
23
23
  if (h && typeof h.validProofOfWork === 'function') return h
24
- if (Buffer.isBuffer(h)) return bsv.BlockHeader.fromBuffer(h)
25
- if (typeof h === 'string') return bsv.BlockHeader.fromBuffer(Buffer.from(h, 'hex'))
24
+ if (Buffer.isBuffer(h)) return BlockHeader.fromBuffer(h)
25
+ if (typeof h === 'string') return BlockHeader.fromBuffer(Buffer.from(h, 'hex'))
26
26
  throw new Error('each header must be a BlockHeader, an 80-byte Buffer, or hex')
27
27
  }
28
28
 
@@ -15,8 +15,8 @@
15
15
  * lib/block/{block,merkleblock}.js. A node of '*' (or '' / null) means "duplicate the
16
16
  * working hash" — Bitcoin's odd-node rule, per the TSC Merkle Proof standard.
17
17
  */
18
- var bsv = require('../..')
19
- var Hash = bsv.crypto.Hash
18
+ var BlockHeader = require('../block/blockheader')
19
+ var Hash = require('../crypto/hash')
20
20
 
21
21
  var HEX32 = /^[0-9a-fA-F]{64}$/
22
22
 
@@ -81,7 +81,7 @@ function verifyMerkleProof (proof) {
81
81
  function verifyTxInclusion (params) {
82
82
  var header = params.header
83
83
  if (Buffer.isBuffer(header) || typeof header === 'string') {
84
- header = bsv.BlockHeader.fromBuffer(Buffer.isBuffer(header) ? header : Buffer.from(header, 'hex'))
84
+ header = BlockHeader.fromBuffer(Buffer.isBuffer(header) ? header : Buffer.from(header, 'hex'))
85
85
  }
86
86
  if (!header || !header.merkleRoot) throw new Error('a valid block header is required')
87
87
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@smartledger/bsv",
3
- "version": "7.8.1",
3
+ "version": "7.10.0",
4
4
  "description": "🚀 Complete Bitcoin SV development framework with legally-recognizable DID:web + W3C VC-JWT toolkit, Legal Token Protocol (LTP), Global Digital Attestation Framework (GDAF), StatusList2021 revocation, and 16 flexible loading options. Standards-based credentials with ES256/ES256K support, on-chain BSV anchoring, and comprehensive Bitcoin SV API. Perfect for legal tokens, verifiable credentials, DeFi, smart contracts, and secure Bitcoin applications.",
5
5
  "author": "SmartLedger Technology <hello@smartledger.technology> (https://smartledger.technology)",
6
6
  "homepage": "https://github.com/codenlighten/smartledger-bsv#readme",
@@ -31,6 +31,7 @@
31
31
  "./vcjwt": "./vcjwt-entry.js",
32
32
  "./lib/anchor": "./lib/anchor/index.js",
33
33
  "./lib/block": "./lib/block/index.js",
34
+ "./lib/covenant": "./lib/covenant/index.js",
34
35
  "./lib/didweb": "./lib/didweb/index.js",
35
36
  "./lib/ecies": "./lib/ecies/index.js",
36
37
  "./lib/errors": "./lib/errors/index.js",
@@ -58,6 +59,8 @@
58
59
  "scripts": {
59
60
  "lint": "standard",
60
61
  "check:load-order": "node scripts/check-address-load-order.js",
62
+ "conformance": "node conformance/verify.js",
63
+ "conformance:generate": "node conformance/generate.js",
61
64
  "lint:ratchet": "node scripts/lint-ratchet.js",
62
65
  "lint:ratchet:update": "node scripts/lint-ratchet.js --update",
63
66
  "test": "mocha",
@@ -227,7 +230,6 @@
227
230
  "@noble/ciphers": "2.2.0",
228
231
  "@noble/curves": "2.2.0",
229
232
  "@noble/hashes": "2.2.0",
230
- "aes-js": "^3.1.2",
231
233
  "bn.js": "=4.12.5",
232
234
  "bs58": "=4.0.1",
233
235
  "clone-deep": "^4.0.1",
@@ -114,32 +114,75 @@ describe('Chronicle script surface', function () {
114
114
  })
115
115
 
116
116
  describe('OP_VERIF / OP_VERNOTIF', function () {
117
- it('are BAD_OPCODE without the flag EVEN IN AN UNEXECUTED BRANCH', function () {
118
- // A rule Bitcoin applies to no other opcode, which is why the flag check sits
119
- // outside the fExec guard. If it moved inside, this script would pass.
120
- var r = run(function (s) {
117
+ it('without the flag, errors only in an EXECUTED branch', function () {
118
+ // Core treats OP_VERIF as illegal everywhere, including unexecuted
119
+ // branches — a rule it applies to no other opcode. BSV dropped that at
120
+ // Genesis, and the node is explicit:
121
+ //
122
+ // if(!utxo_after_chronicle) {
123
+ // if(utxo_after_genesis && !fExec) break;
124
+ // else return SCRIPT_ERR_BAD_OPCODE;
125
+ // }
126
+ //
127
+ // Asserting BAD_OPCODE here made this library reject scripts the network
128
+ // accepts.
129
+ var unexecuted = run(function (s) {
121
130
  s.add(Opcode.OP_0).add(Opcode.OP_IF).add(Opcode.OP_VERIF).add(Opcode.OP_ENDIF).add(Opcode.OP_1)
122
131
  }, { flags: 0 })
123
- r.verified.should.equal(false)
124
- r.errstr.should.match(/BAD_OPCODE/)
132
+ unexecuted.verified.should.equal(true)
133
+
134
+ var executed = run(function (s) {
135
+ s.add(Opcode.OP_1).add(Opcode.OP_VERIF).add(Opcode.OP_ENDIF)
136
+ }, { flags: 0 })
137
+ executed.verified.should.equal(false)
138
+ executed.errstr.should.match(/BAD_OPCODE/)
125
139
  })
126
140
 
127
- it('OP_VERIF takes the branch when the top of stack equals the tx version', function () {
141
+ // The comparison is BYTE-WISE against the four little-endian version
142
+ // bytes, not numeric:
143
+ //
144
+ // if(vch.size() == 4) { to_le(checker.Version(), val.data());
145
+ // fValue = std::ranges::equal(val, vch); }
146
+ //
147
+ // So a 1-byte script number never matches, however equal it looks
148
+ // numerically, and the idiomatic form is `OP_VER OP_VERIF`.
149
+ var LE = function (v) {
150
+ var b = Buffer.alloc(4)
151
+ b.writeInt32LE(v, 0)
152
+ return b
153
+ }
154
+
155
+ it('OP_VERIF takes the branch on a 4-byte little-endian version match', function () {
128
156
  var taken = run(function (s) {
129
- s.add(new BN(2).toScriptNumBuffer()).add(Opcode.OP_VERIF).add(Opcode.OP_1).add(Opcode.OP_ENDIF)
157
+ s.add(LE(2)).add(Opcode.OP_VERIF).add(Opcode.OP_1).add(Opcode.OP_ENDIF)
130
158
  }, { version: 2 })
131
159
  taken.verified.should.equal(true)
132
160
 
133
161
  var notTaken = run(function (s) {
134
- s.add(new BN(9).toScriptNumBuffer()).add(Opcode.OP_VERIF).add(Opcode.OP_1).add(Opcode.OP_ENDIF).add(Opcode.OP_1)
162
+ s.add(LE(9)).add(Opcode.OP_VERIF).add(Opcode.OP_1).add(Opcode.OP_ENDIF).add(Opcode.OP_1)
135
163
  }, { version: 2 })
136
164
  notTaken.verified.should.equal(true)
137
165
  notTaken.stack.length.should.equal(1) // only the trailing OP_1
138
166
  })
139
167
 
168
+ it('a numerically-equal operand of the wrong LENGTH does not match', function () {
169
+ var r = run(function (s) {
170
+ s.add(new BN(2).toScriptNumBuffer()).add(Opcode.OP_VERIF).add(Opcode.OP_1).add(Opcode.OP_ENDIF).add(Opcode.OP_1)
171
+ }, { version: 2 })
172
+ r.verified.should.equal(true)
173
+ r.stack.length.should.equal(1) // branch NOT taken
174
+ })
175
+
176
+ it('OP_VER feeds OP_VERIF directly', function () {
177
+ var r = run(function (s) {
178
+ s.add(Opcode.OP_VER).add(Opcode.OP_VERIF).add(Opcode.OP_1).add(Opcode.OP_ENDIF)
179
+ }, { version: 2 })
180
+ r.verified.should.equal(true)
181
+ })
182
+
140
183
  it('OP_VERNOTIF is its negation', function () {
141
184
  var r = run(function (s) {
142
- s.add(new BN(9).toScriptNumBuffer()).add(Opcode.OP_VERNOTIF).add(Opcode.OP_1).add(Opcode.OP_ENDIF)
185
+ s.add(LE(9)).add(Opcode.OP_VERNOTIF).add(Opcode.OP_1).add(Opcode.OP_ENDIF)
143
186
  }, { version: 2 })
144
187
  r.verified.should.equal(true)
145
188
  })
@@ -649,6 +649,14 @@ 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
660
  "'a' 'b'|CAT|P2SH,STRICTENC": 'OK',
653
661
  "'a' 'b' 0|IF CAT ELSE 1 ENDIF|P2SH,STRICTENC": 'OK',
654
662
  "'abc' 1|SPLIT|P2SH,STRICTENC": 'OK',
@@ -661,15 +669,10 @@ describe('Interpreter', function () {
661
669
  '2 2 0 IF DIV ELSE 1 ENDIF|NOP|P2SH,STRICTENC': 'OK',
662
670
  '2 2 0 IF MOD ELSE 1 ENDIF|NOP|P2SH,STRICTENC': 'OK',
663
671
  '2 DUP DIV|1 EQUAL|P2SH,STRICTENC': 'OK',
664
- '7 3 MOD|1 EQUAL|P2SH,STRICTENC': 'OK',
672
+ '7 3 MOD|1 EQUAL|P2SH,STRICTENC': 'OK'
665
673
 
666
674
  // Chronicle byte reassignment (see the note above). Values are the BSV error,
667
675
  // recorded for documentation; the harness only distinguishes 'OK' from not-'OK'.
668
- '1|NOP1 CHECKLOCKTIMEVERIFY CHECKSEQUENCEVERIFY NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10 1 EQUAL|P2SH,STRICTENC': 'SCRIPT_ERR_INVALID_STACK_OPERATION',
669
- "'NOP_1_to_10' NOP1 CHECKLOCKTIMEVERIFY CHECKSEQUENCEVERIFY NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10|'NOP_1_to_10' EQUAL|P2SH,STRICTENC": 'SCRIPT_ERR_INVALID_STACK_OPERATION',
670
- 'NOP|NOP4 1|P2SH,STRICTENC': 'SCRIPT_ERR_INVALID_STACK_OPERATION',
671
- 'NOP|NOP5 1|P2SH,STRICTENC': 'SCRIPT_ERR_INVALID_STACK_OPERATION',
672
- 'NOP|NOP6 1|P2SH,STRICTENC': 'SCRIPT_ERR_INVALID_STACK_OPERATION'
673
676
  }
674
677
 
675
678
  describe('bitcoind script evaluation fixtures', function () {
@@ -7,10 +7,15 @@ var Interpreter = bsv.Script.Interpreter
7
7
  var Script = bsv.Script
8
8
  var Opcode = bsv.Opcode
9
9
  var Transaction = bsv.Transaction
10
+ var CHRONICLE = Interpreter.SCRIPT_ENABLE_CHRONICLE
10
11
 
11
- // OP_SUBSTR / OP_LEFT / OP_RIGHT — re-enabled BSV (Chronicle) string opcodes,
12
- // original Satoshi semantics. Declared in the opcode map at 0xb3/0xb4/0xb5 but
13
- // previously unimplemented (BAD_OPCODE). These tests verify behavior end-to-end.
12
+ // OP_SUBSTR / OP_LEFT / OP_RIGHT — Chronicle string opcodes at 0xb3/0xb4/0xb5.
13
+ //
14
+ // Every case here passes SCRIPT_ENABLE_CHRONICLE, because without it these
15
+ // bytes are UPGRADABLE NOPS, exactly as they are on a pre-Chronicle node. An
16
+ // earlier version of these tests ran them with flags=0 and passed, which is
17
+ // what hid the fact that the interpreter was executing them unconditionally —
18
+ // more permissively than the network.
14
19
  describe('String opcodes OP_SUBSTR / OP_LEFT / OP_RIGHT', function () {
15
20
  var DATA = Buffer.from('aabbccdd', 'hex')
16
21
 
@@ -20,14 +25,14 @@ describe('String opcodes OP_SUBSTR / OP_LEFT / OP_RIGHT', function () {
20
25
  buildOps(lock)
21
26
  lock.add(Buffer.from(expectedHex, 'hex')).add(Opcode.OP_EQUAL)
22
27
  var interp = new Interpreter()
23
- return interp.verify(new Script(), lock, new Transaction(), 0, 0)
28
+ return interp.verify(new Script(), lock, new Transaction(), 0, CHRONICLE)
24
29
  }
25
30
  function errors (buildOps) {
26
31
  var lock = new Script().add(DATA)
27
32
  buildOps(lock)
28
33
  var interp = new Interpreter()
29
34
  var ok
30
- try { ok = interp.verify(new Script(), lock, new Transaction(), 0, 0) } catch (e) { ok = false }
35
+ try { ok = interp.verify(new Script(), lock, new Transaction(), 0, CHRONICLE) } catch (e) { ok = false }
31
36
  return ok === false
32
37
  }
33
38
 
@@ -52,12 +57,23 @@ describe('String opcodes OP_SUBSTR / OP_LEFT / OP_RIGHT', function () {
52
57
  yields(function (s) { s.add(Opcode.OP_1).add(Opcode.OP_2).add(Opcode.OP_SUBSTR) }, 'bbcc').should.equal(true)
53
58
  })
54
59
 
55
- it('OP_LEFT clamps n greater than the length', function () {
56
- yields(function (s) { s.add(Opcode.OP_10).add(Opcode.OP_LEFT) }, 'aabbccdd').should.equal(true)
60
+ // The node ERRORS rather than clamping:
61
+ // if(len < 0 || len > size) return SCRIPT_ERR_INVALID_NUMBER_RANGE;
62
+ // Clamping made scripts the node rejects succeed here.
63
+ it('OP_LEFT rejects n greater than the length', function () {
64
+ errors(function (s) { s.add(Opcode.OP_10).add(Opcode.OP_LEFT) }).should.equal(true)
57
65
  })
58
66
 
59
- it('OP_RIGHT clamps n greater than the length', function () {
60
- yields(function (s) { s.add(Opcode.OP_10).add(Opcode.OP_RIGHT) }, 'aabbccdd').should.equal(true)
67
+ it('OP_RIGHT rejects n greater than the length', function () {
68
+ errors(function (s) { s.add(Opcode.OP_10).add(Opcode.OP_RIGHT) }).should.equal(true)
69
+ })
70
+
71
+ it('is a no-op without SCRIPT_ENABLE_CHRONICLE, as a pre-Chronicle node is', function () {
72
+ const interp = new Interpreter()
73
+ const lock = new Script().add(DATA).add(Opcode.OP_2).add(Opcode.OP_LEFT)
74
+ interp.verify(new Script(), lock, new Transaction(), 0, 0).should.equal(true)
75
+ // Untouched: the opcode did nothing, so both operands survive.
76
+ interp.stack.length.should.equal(2)
61
77
  })
62
78
 
63
79
  it('rejects a negative size', function () {
@@ -67,6 +83,6 @@ describe('String opcodes OP_SUBSTR / OP_LEFT / OP_RIGHT', function () {
67
83
  it('rejects OP_LEFT with too few stack items', function () {
68
84
  var interp = new Interpreter()
69
85
  var lock = new Script().add(Opcode.OP_LEFT) // nothing to operate on
70
- interp.verify(new Script(), lock, new Transaction(), 0, 0).should.equal(false)
86
+ interp.verify(new Script(), lock, new Transaction(), 0, CHRONICLE).should.equal(false)
71
87
  })
72
88
  })
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.8.1'
3
+ module.exports = '7.10.0'