@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.
- package/CHANGELOG.md +117 -6
- package/README.md +38 -38
- package/bsv-covenant.min.js +1 -1
- package/bsv-ecies.min.js +1 -1
- package/bsv-gdaf.min.js +54 -54
- package/bsv-ltp.min.js +58 -85
- package/bsv-message.min.js +2 -2
- package/bsv-mnemonic.min.js +12 -14
- package/bsv-script-helper.min.js +1 -1
- package/bsv-shamir.min.js +14 -16
- package/bsv-smartcontract.min.js +23 -25
- package/bsv.bundle.js +54 -54
- package/bsv.min.js +54 -54
- package/build/esbuild.js +84 -4
- package/docs/MODULE_REFERENCE_COMPLETE.md +27 -27
- package/docs/advanced/UTXO_MANAGER_GUIDE.md +1 -1
- package/docs/getting-started/INSTALLATION.md +23 -23
- package/docs/getting-started/QUICK_START.md +7 -7
- package/docs/migration/FROM_BSV_1_5_6.md +5 -5
- package/index.js +9 -1
- package/lib/covenant/helpers.js +146 -0
- package/lib/covenant/index.js +21 -0
- package/lib/covenant/pushtx.js +243 -0
- package/lib/covenant-interface.js +408 -397
- package/lib/custom-script-helper.js +44 -38
- package/lib/ecies/bitcore-ecies.js +3 -4
- package/lib/ecies/electrum-ecies.js +4 -6
- package/lib/ecies/errors.js +1 -1
- package/lib/gdaf/attestation-signer.js +7 -7
- package/lib/gdaf/attestation-verifier.js +5 -6
- package/lib/gdaf/did-resolver.js +10 -9
- package/lib/gdaf/smartledger-anchor.js +13 -12
- package/lib/gdaf/zk-prover.js +8 -8
- package/lib/ltp/anchor.js +2 -3
- package/lib/ltp/claim.js +2 -3
- package/lib/ltp/index.js +2 -3
- package/lib/ltp/obligation.js +9 -9
- package/lib/ltp/proof.js +7 -7
- package/lib/ltp/registry.js +4 -5
- package/lib/ltp/right.js +11 -11
- package/lib/message/index.js +5 -4
- package/lib/message/message.js +11 -11
- package/lib/mnemonic/errors.js +1 -1
- package/lib/mnemonic/index.js +5 -4
- package/lib/mnemonic/mnemonic.js +22 -10
- package/lib/ordinals/bsv20.js +4 -4
- package/lib/ordinals/inscription.js +8 -12
- package/lib/ordinals/ordlock.js +26 -21
- package/lib/script/interpreter.js +96 -31
- package/lib/smart_contract/authorizers.js +8 -6
- package/lib/smart_contract/builder.js +32 -26
- package/lib/smart_contract/covenant.js +32 -25
- package/lib/smart_contract/covenant_helpers.js +8 -128
- package/lib/smart_contract/debugger.js +9 -6
- package/lib/smart_contract/dsl.js +5 -6
- package/lib/smart_contract/index.js +11 -8
- package/lib/smart_contract/locks.js +3 -4
- package/lib/smart_contract/opcode_list.js +2 -3
- package/lib/smart_contract/pels.js +4 -5
- package/lib/smart_contract/preimage.js +11 -7
- package/lib/smart_contract/pushtx.js +8 -263
- package/lib/smart_contract/script_interpreter.js +112 -105
- package/lib/smart_contract/script_tester.js +24 -18
- package/lib/smart_contract/script_utils.js +15 -14
- package/lib/smart_contract/sighash.js +23 -15
- package/lib/smart_contract/stack_examiner.js +70 -63
- package/lib/smart_contract/token.js +6 -6
- package/lib/smart_contract/utxo_generator.js +21 -15
- package/lib/smartutxo.js +27 -21
- package/lib/spv/headerchain.js +3 -3
- package/lib/spv/merkleproof.js +3 -3
- package/package.json +4 -2
- package/test/script/chronicle.js +53 -10
- package/test/script/interpreter.js +9 -6
- package/test/script/string_ops.js +26 -10
- 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
|
|
160
|
-
|
|
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:
|
|
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
|
package/lib/spv/headerchain.js
CHANGED
|
@@ -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
|
|
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
|
|
25
|
-
if (typeof h === 'string') return
|
|
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
|
|
package/lib/spv/merkleproof.js
CHANGED
|
@@ -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
|
|
19
|
-
var 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 =
|
|
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.
|
|
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",
|
package/test/script/chronicle.js
CHANGED
|
@@ -114,32 +114,75 @@ describe('Chronicle script surface', function () {
|
|
|
114
114
|
})
|
|
115
115
|
|
|
116
116
|
describe('OP_VERIF / OP_VERNOTIF', function () {
|
|
117
|
-
it('
|
|
118
|
-
//
|
|
119
|
-
//
|
|
120
|
-
|
|
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
|
-
|
|
124
|
-
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
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 —
|
|
12
|
-
//
|
|
13
|
-
//
|
|
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,
|
|
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,
|
|
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
|
-
|
|
56
|
-
|
|
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
|
|
60
|
-
|
|
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,
|
|
86
|
+
interp.verify(new Script(), lock, new Transaction(), 0, CHRONICLE).should.equal(false)
|
|
71
87
|
})
|
|
72
88
|
})
|
package/version.js
CHANGED