@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/mnemonic/errors.js
CHANGED
package/lib/mnemonic/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
bsv.Mnemonic = require('./mnemonic')
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
// Previously this module required the package root and registered itself onto
|
|
2
|
+
// it (`bsv.Mnemonic = require('./mnemonic')`), which made lib/ depend on
|
|
3
|
+
// index.js. The registration was redundant — index.js assigns bsv.Mnemonic
|
|
4
|
+
// itself — so this is now a plain re-export.
|
|
5
|
+
module.exports = require('./mnemonic')
|
package/lib/mnemonic/mnemonic.js
CHANGED
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
var BN =
|
|
3
|
+
var HDPrivateKey = require('../hdprivatekey')
|
|
4
|
+
var BN = require('../crypto/bn')
|
|
5
5
|
var unorm = require('unorm')
|
|
6
|
-
var _ =
|
|
6
|
+
var _ = require('../util/_')
|
|
7
7
|
|
|
8
8
|
var pbkdf2 = require('./pbkdf2')
|
|
9
9
|
var errors = require('./errors')
|
|
10
|
+
// Named bsvErrors, not errors: `errors` above is this module's OWN error set.
|
|
11
|
+
// The library-wide errors module is a different object and must not shadow it.
|
|
12
|
+
var bsvErrors = require('../errors')
|
|
10
13
|
|
|
11
|
-
var Hash =
|
|
12
|
-
var Random =
|
|
14
|
+
var Hash = require('../crypto/hash')
|
|
15
|
+
var Random = require('../crypto/random')
|
|
13
16
|
|
|
14
|
-
var $ =
|
|
17
|
+
var $ = require('../util/preconditions')
|
|
15
18
|
|
|
16
19
|
/**
|
|
17
20
|
* This is an immutable class that represents a BIP39 Mnemonic code.
|
|
@@ -53,7 +56,7 @@ var Mnemonic = function (data, wordlist) {
|
|
|
53
56
|
} else if (_.isNumber(data)) {
|
|
54
57
|
ent = data
|
|
55
58
|
} else if (data) {
|
|
56
|
-
throw new
|
|
59
|
+
throw new bsvErrors.InvalidArgument('data', 'Must be a Buffer, a string or an integer')
|
|
57
60
|
}
|
|
58
61
|
ent = ent || 128
|
|
59
62
|
|
|
@@ -73,7 +76,7 @@ var Mnemonic = function (data, wordlist) {
|
|
|
73
76
|
throw new errors.InvalidMnemonic(phrase)
|
|
74
77
|
}
|
|
75
78
|
if (ent % 32 !== 0 || ent < 128) {
|
|
76
|
-
throw new
|
|
79
|
+
throw new bsvErrors.InvalidArgument('ENT', 'Values must be ENT > 128 and ENT % 32 == 0')
|
|
77
80
|
}
|
|
78
81
|
|
|
79
82
|
phrase = phrase || Mnemonic._mnemonic(ent, wordlist)
|
|
@@ -241,7 +244,7 @@ Mnemonic.fromSeed = function (seed, wordlist) {
|
|
|
241
244
|
*/
|
|
242
245
|
Mnemonic.prototype.toHDPrivateKey = function (passphrase, network) {
|
|
243
246
|
var seed = this.toSeed(passphrase)
|
|
244
|
-
return
|
|
247
|
+
return HDPrivateKey.fromSeed(seed, network)
|
|
245
248
|
}
|
|
246
249
|
|
|
247
250
|
/**
|
|
@@ -329,6 +332,15 @@ Mnemonic._entropyChecksum = function (entropy) {
|
|
|
329
332
|
return checksum
|
|
330
333
|
}
|
|
331
334
|
|
|
332
|
-
|
|
335
|
+
// Back-reference to the whole library, preserved as public API. Defined as a
|
|
336
|
+
// lazy getter rather than `Mnemonic.bsv = require('../../')`: this module is
|
|
337
|
+
// loaded while index.js is still initializing, so an eager require would
|
|
338
|
+
// capture a half-built namespace. Resolving on first access defers it past
|
|
339
|
+
// load and removes the module-init cycle.
|
|
340
|
+
Object.defineProperty(Mnemonic, 'bsv', {
|
|
341
|
+
configurable: true,
|
|
342
|
+
enumerable: true,
|
|
343
|
+
get: function () { return require('../../') }
|
|
344
|
+
})
|
|
333
345
|
|
|
334
346
|
module.exports = Mnemonic
|
package/lib/ordinals/bsv20.js
CHANGED
|
@@ -17,6 +17,8 @@
|
|
|
17
17
|
* are never coerced to JS numbers. `dec` (decimals, 0–18) scales display only.
|
|
18
18
|
*/
|
|
19
19
|
var inscription = require('./inscription')
|
|
20
|
+
var Script = require('../script')
|
|
21
|
+
var Output = require('../transaction/output')
|
|
20
22
|
|
|
21
23
|
var CONTENT_TYPE = 'application/bsv-20'
|
|
22
24
|
var MAX_DEC = 18
|
|
@@ -261,8 +263,7 @@ function buildDeployMint (params) {
|
|
|
261
263
|
}
|
|
262
264
|
|
|
263
265
|
function outputFor (script, satoshis) {
|
|
264
|
-
|
|
265
|
-
return new bsv.Transaction.Output({ script: script, satoshis: satoshis != null ? satoshis : 1 })
|
|
266
|
+
return new Output({ script: script, satoshis: satoshis != null ? satoshis : 1 })
|
|
266
267
|
}
|
|
267
268
|
|
|
268
269
|
/** 1-sat Output helpers mirroring the builders. */
|
|
@@ -276,8 +277,7 @@ function createAuthOutput (params) { return outputFor(buildAuth(params), params
|
|
|
276
277
|
|
|
277
278
|
/** Extract the JSON body from a locking script, a JSON string, a Buffer, or an object. */
|
|
278
279
|
function bodyOf (input) {
|
|
279
|
-
|
|
280
|
-
if (input && typeof input === 'object' && !Buffer.isBuffer(input) && !(input instanceof bsv.Script)) {
|
|
280
|
+
if (input && typeof input === 'object' && !Buffer.isBuffer(input) && !(input instanceof Script)) {
|
|
281
281
|
return input // already a parsed object
|
|
282
282
|
}
|
|
283
283
|
if (typeof input === 'string' && input.trim()[0] === '{') return input // raw JSON string
|
|
@@ -16,13 +16,13 @@
|
|
|
16
16
|
*
|
|
17
17
|
* This matches the widely-used 1Sat Ordinals format (js-1sat-ord).
|
|
18
18
|
*/
|
|
19
|
-
var
|
|
19
|
+
var Script = require('../script')
|
|
20
|
+
var Opcode = require('../opcode')
|
|
21
|
+
var Address = require('../address')
|
|
22
|
+
var Output = require('../transaction/output')
|
|
20
23
|
|
|
21
24
|
var ORD = Buffer.from('ord', 'utf8')
|
|
22
25
|
|
|
23
|
-
function scriptClass () { return bsv.Script }
|
|
24
|
-
function op () { return bsv.Opcode }
|
|
25
|
-
|
|
26
26
|
/** Describe a rejected value for an error message, without dumping its contents. */
|
|
27
27
|
function typeName (v) {
|
|
28
28
|
if (v === null) return 'null'
|
|
@@ -50,7 +50,6 @@ var CONTENT_ALIASES = ['data', 'body', 'payload', 'text', 'message']
|
|
|
50
50
|
|
|
51
51
|
/** Resolve a base locking script from a Script, an Address, or an address string. */
|
|
52
52
|
function resolveLock (params) {
|
|
53
|
-
var Script = scriptClass()
|
|
54
53
|
var hasLock = params.lock != null
|
|
55
54
|
var hasAddress = params.address != null
|
|
56
55
|
|
|
@@ -81,9 +80,9 @@ function resolveLock (params) {
|
|
|
81
80
|
}
|
|
82
81
|
|
|
83
82
|
if (hasAddress) {
|
|
84
|
-
var addr = (params.address instanceof
|
|
83
|
+
var addr = (params.address instanceof Address)
|
|
85
84
|
? params.address
|
|
86
|
-
:
|
|
85
|
+
: Address.fromString(String(params.address))
|
|
87
86
|
return Script.buildPublicKeyHashOut(addr)
|
|
88
87
|
}
|
|
89
88
|
|
|
@@ -111,7 +110,6 @@ function resolveLock (params) {
|
|
|
111
110
|
*/
|
|
112
111
|
function buildInscription (params) {
|
|
113
112
|
params = params || {}
|
|
114
|
-
var Opcode = op()
|
|
115
113
|
var lock = resolveLock(params)
|
|
116
114
|
|
|
117
115
|
if (params.content == null) {
|
|
@@ -137,7 +135,7 @@ function buildInscription (params) {
|
|
|
137
135
|
}
|
|
138
136
|
|
|
139
137
|
// Clone the base lock so we never mutate the caller's Script.
|
|
140
|
-
var s =
|
|
138
|
+
var s = Script.fromBuffer(lock.toBuffer())
|
|
141
139
|
s.add(Opcode.OP_FALSE)
|
|
142
140
|
s.add(Opcode.OP_IF)
|
|
143
141
|
s.add(ORD)
|
|
@@ -168,8 +166,6 @@ function chunkIsOp (chunk, opcodenum) {
|
|
|
168
166
|
* null if the script carries no inscription envelope.
|
|
169
167
|
*/
|
|
170
168
|
function parseInscription (script) {
|
|
171
|
-
var Script = scriptClass()
|
|
172
|
-
var Opcode = op()
|
|
173
169
|
var s = (script instanceof Script) ? script
|
|
174
170
|
: Buffer.isBuffer(script) ? Script.fromBuffer(script)
|
|
175
171
|
: Script.fromHex(script)
|
|
@@ -235,7 +231,7 @@ function createInscriptionOutput (params) {
|
|
|
235
231
|
if (typeof satoshis !== 'number' || !Number.isInteger(satoshis) || satoshis < 1) {
|
|
236
232
|
throw new Error('satoshis must be a positive integer (1 for a standard 1Sat ordinal)')
|
|
237
233
|
}
|
|
238
|
-
return new
|
|
234
|
+
return new Output({
|
|
239
235
|
script: buildInscription(params),
|
|
240
236
|
satoshis: satoshis
|
|
241
237
|
})
|
package/lib/ordinals/ordlock.js
CHANGED
|
@@ -37,14 +37,19 @@
|
|
|
37
37
|
*
|
|
38
38
|
* Requires post-Genesis limits: call SmartContract.enableGenesis() before verifying.
|
|
39
39
|
*/
|
|
40
|
-
var
|
|
41
|
-
var
|
|
42
|
-
var H = require('../smart_contract/covenant_helpers')
|
|
40
|
+
var P = require('../covenant/pushtx')
|
|
41
|
+
var H = require('../covenant/helpers')
|
|
43
42
|
var inscription = require('./inscription')
|
|
44
43
|
|
|
45
|
-
var Script =
|
|
46
|
-
var Opcode =
|
|
47
|
-
var
|
|
44
|
+
var Script = require('../script')
|
|
45
|
+
var Opcode = require('../opcode')
|
|
46
|
+
var Address = require('../address')
|
|
47
|
+
var PublicKey = require('../publickey')
|
|
48
|
+
var Hash = require('../crypto/hash')
|
|
49
|
+
var Transaction = require('../transaction')
|
|
50
|
+
var Input = require('../transaction/input')
|
|
51
|
+
var Output = require('../transaction/output')
|
|
52
|
+
var BufferReader = require('../encoding/bufferreader')
|
|
48
53
|
|
|
49
54
|
// OrdLock commits to the FULL output set (so payments can be pinned) but leaves the
|
|
50
55
|
// input set open for the buyer's funding — SIGHASH_ALL|ANYONECANPAY|FORKID (0xc1).
|
|
@@ -73,9 +78,9 @@ function coerceScript (v) {
|
|
|
73
78
|
|
|
74
79
|
/** Coerce an Address, PublicKey, PrivateKey, or address string to an Address. */
|
|
75
80
|
function toAddress (v) {
|
|
76
|
-
if (v instanceof
|
|
81
|
+
if (v instanceof Address) return v
|
|
77
82
|
if (v && typeof v.toAddress === 'function') return v.toAddress() // PublicKey / PrivateKey
|
|
78
|
-
return
|
|
83
|
+
return Address.fromString(String(v))
|
|
79
84
|
}
|
|
80
85
|
|
|
81
86
|
/** Resolve a 20-byte HASH160 owner commitment from an Address/PublicKey/key or 20-byte Buffer. */
|
|
@@ -84,7 +89,7 @@ function resolvePubKeyHash (owner) {
|
|
|
84
89
|
if (owner.length !== 20) throw new Error('seller pubkeyhash buffer must be 20 bytes (HASH160)')
|
|
85
90
|
return owner
|
|
86
91
|
}
|
|
87
|
-
if (owner instanceof
|
|
92
|
+
if (owner instanceof PublicKey) return Hash.sha256ripemd160(owner.toBuffer())
|
|
88
93
|
return toAddress(owner).hashBuffer
|
|
89
94
|
}
|
|
90
95
|
|
|
@@ -95,15 +100,15 @@ function resolvePubKeyHash (owner) {
|
|
|
95
100
|
*/
|
|
96
101
|
function payOutputFor (payTo, price) {
|
|
97
102
|
assertSats(price, 'payment price')
|
|
98
|
-
return new
|
|
103
|
+
return new Output({
|
|
99
104
|
script: Script.buildPublicKeyHashOut(toAddress(payTo)), satoshis: price
|
|
100
105
|
})
|
|
101
106
|
}
|
|
102
107
|
|
|
103
108
|
/** Coerce one payment spec to a Transaction.Output. */
|
|
104
109
|
function outputFromSpec (spec) {
|
|
105
|
-
if (spec instanceof
|
|
106
|
-
if (Buffer.isBuffer(spec)) return
|
|
110
|
+
if (spec instanceof Output) return spec
|
|
111
|
+
if (Buffer.isBuffer(spec)) return Output.fromBufferReader(new BufferReader(spec))
|
|
107
112
|
var to = spec.payTo != null ? spec.payTo : spec.address
|
|
108
113
|
var amt = spec.satoshis != null ? spec.satoshis : spec.price
|
|
109
114
|
if (to == null || amt == null) throw new Error('payment spec needs {address|payTo, satoshis|price}')
|
|
@@ -125,7 +130,7 @@ function resolvePayOutputs (params) {
|
|
|
125
130
|
if (params.price != null) {
|
|
126
131
|
var payTo = params.payTo != null ? params.payTo : params.seller
|
|
127
132
|
// A pre-built Output as payTo is used verbatim (its own value); otherwise build P2PKH(price).
|
|
128
|
-
var first = (payTo instanceof
|
|
133
|
+
var first = (payTo instanceof Output) ? payTo : payOutputFor(payTo, params.price)
|
|
129
134
|
var arr = [first]
|
|
130
135
|
if (params.royalties) params.royalties.forEach(function (r) { arr.push(outputFromSpec(r)) })
|
|
131
136
|
return arr
|
|
@@ -199,7 +204,7 @@ function chunkIsOp (chunk, opcodenum) {
|
|
|
199
204
|
function splitPayBlob (blob) {
|
|
200
205
|
var br = new BufferReader(blob)
|
|
201
206
|
var outs = []
|
|
202
|
-
while (!br.eof()) outs.push(
|
|
207
|
+
while (!br.eof()) outs.push(Output.fromBufferReader(br))
|
|
203
208
|
return outs
|
|
204
209
|
}
|
|
205
210
|
|
|
@@ -296,7 +301,7 @@ function parseOrdLock (script, opts) {
|
|
|
296
301
|
if (rebuilt.toHex() !== s.toHex()) return null
|
|
297
302
|
|
|
298
303
|
return {
|
|
299
|
-
seller: { pubKeyHash: sellerPKH, address:
|
|
304
|
+
seller: { pubKeyHash: sellerPKH, address: Address.fromPublicKeyHash(sellerPKH, network).toString() },
|
|
300
305
|
payOutputs: payOutputs,
|
|
301
306
|
payBlob: payBlob,
|
|
302
307
|
totalPrice: totalPrice,
|
|
@@ -317,7 +322,7 @@ function isOrdLock (script, opts) { return parseOrdLock(script, opts) !== null }
|
|
|
317
322
|
function listInscriptionOutput (params) {
|
|
318
323
|
params = params || {}
|
|
319
324
|
var satoshis = params.satoshis != null ? params.satoshis : 1
|
|
320
|
-
return new
|
|
325
|
+
return new Output({ script: buildOrdLock(params), satoshis: satoshis })
|
|
321
326
|
}
|
|
322
327
|
|
|
323
328
|
/**
|
|
@@ -426,7 +431,7 @@ function cancel (params) {
|
|
|
426
431
|
|
|
427
432
|
/** Add an input spending `outpoint` under `script` worth `satoshis`, script-sig empty. */
|
|
428
433
|
function addSpendInput (tx, outpoint, script, satoshis) {
|
|
429
|
-
tx.addInput(new
|
|
434
|
+
tx.addInput(new Input({
|
|
430
435
|
prevTxId: outpoint.txid || outpoint.prevTxId,
|
|
431
436
|
outputIndex: outpoint.outputIndex != null ? outpoint.outputIndex : outpoint.vout,
|
|
432
437
|
script: Script.empty()
|
|
@@ -479,11 +484,11 @@ function buildListingTx (params) {
|
|
|
479
484
|
throw new Error('buildListingTx: insufficient funding — need ' + fee + ' sat fee, funded ' + fundingTotal)
|
|
480
485
|
}
|
|
481
486
|
|
|
482
|
-
var tx = new
|
|
487
|
+
var tx = new Transaction()
|
|
483
488
|
addSpendInput(tx, ordinal, ordinal.script, ordSats) // input 0 = the ordinal (P2PKH)
|
|
484
489
|
funding.forEach(function (f) { addSpendInput(tx, f, f.script, f.satoshis) })
|
|
485
490
|
|
|
486
|
-
tx.addOutput(new
|
|
491
|
+
tx.addOutput(new Output({ script: lock, satoshis: ordSats })) // output 0 = listing
|
|
487
492
|
if (change > 0) {
|
|
488
493
|
tx.addOutput(payOutputFor(params.changeAddress || ordinal.privateKey.toAddress(), change))
|
|
489
494
|
}
|
|
@@ -533,7 +538,7 @@ function buildPurchaseTx (params) {
|
|
|
533
538
|
var payOuts = params.payOutputs
|
|
534
539
|
? params.payOutputs.map(outputFromSpec)
|
|
535
540
|
: parsed.payOutputs.map(function (p) {
|
|
536
|
-
return new
|
|
541
|
+
return new Output({ script: p.script, satoshis: p.satoshis })
|
|
537
542
|
})
|
|
538
543
|
var paidTotal = payOuts.reduce(function (a, o) { return a + o.satoshis }, 0)
|
|
539
544
|
|
|
@@ -545,7 +550,7 @@ function buildPurchaseTx (params) {
|
|
|
545
550
|
' sat (payments ' + paidTotal + ' + fee ' + fee + '), funded ' + fundingTotal)
|
|
546
551
|
}
|
|
547
552
|
|
|
548
|
-
var tx = new
|
|
553
|
+
var tx = new Transaction()
|
|
549
554
|
addSpendInput(tx, listing, lockingScript, ordSats) // input 0 = the listing (covenant)
|
|
550
555
|
params.funding.forEach(function (f) { addSpendInput(tx, f, f.script, f.satoshis) })
|
|
551
556
|
|
|
@@ -728,6 +728,13 @@ function padBufferToSize (buf, len) {
|
|
|
728
728
|
* Based on the inner loop of bitcoind's EvalScript function
|
|
729
729
|
* bitcoind commit: b5d1b1092998bc95313856d535c632ea5a8f9104
|
|
730
730
|
*/
|
|
731
|
+
/** The transaction version as the four little-endian bytes Chronicle compares. */
|
|
732
|
+
function versionLE (version) {
|
|
733
|
+
var buf = Buffer.alloc(4)
|
|
734
|
+
buf.writeInt32LE(version | 0, 0)
|
|
735
|
+
return buf
|
|
736
|
+
}
|
|
737
|
+
|
|
731
738
|
Interpreter.prototype.step = function () {
|
|
732
739
|
var self = this
|
|
733
740
|
|
|
@@ -1044,7 +1051,19 @@ Interpreter.prototype.step = function () {
|
|
|
1044
1051
|
break
|
|
1045
1052
|
|
|
1046
1053
|
case Opcode.OP_VER:
|
|
1047
|
-
// Chronicle: pushes the
|
|
1054
|
+
// Chronicle: pushes the transaction version as FOUR LITTLE-ENDIAN
|
|
1055
|
+
// BYTES, not as a script number. The node is:
|
|
1056
|
+
//
|
|
1057
|
+
// const auto tx_version{checker.Version()};
|
|
1058
|
+
// std::vector<uint8_t> val(sizeof(tx_version));
|
|
1059
|
+
// to_le(tx_version, val.data());
|
|
1060
|
+
// stack.push_back(std::move(val));
|
|
1061
|
+
//
|
|
1062
|
+
// A script number pushes `01` for version 1 where the node pushes
|
|
1063
|
+
// `01000000`, so anything consuming the value diverges.
|
|
1064
|
+
//
|
|
1065
|
+
// Unlike the string opcodes, BAD_OPCODE pre-Chronicle IS correct here —
|
|
1066
|
+
// the node returns it unconditionally.
|
|
1048
1067
|
if ((this.flags & Interpreter.SCRIPT_ENABLE_CHRONICLE) === 0) {
|
|
1049
1068
|
this.errstr = 'SCRIPT_ERR_BAD_OPCODE'
|
|
1050
1069
|
return false
|
|
@@ -1053,18 +1072,26 @@ Interpreter.prototype.step = function () {
|
|
|
1053
1072
|
this.errstr = 'SCRIPT_ERR_UNKNOWN_ERROR'
|
|
1054
1073
|
return false
|
|
1055
1074
|
}
|
|
1056
|
-
this.stack.push(
|
|
1075
|
+
this.stack.push(versionLE(this.tx.version))
|
|
1057
1076
|
break
|
|
1058
1077
|
|
|
1059
1078
|
case Opcode.OP_VERIF:
|
|
1060
1079
|
case Opcode.OP_VERNOTIF:
|
|
1061
|
-
// Chronicle: an IF whose condition is "top of stack equals the
|
|
1062
|
-
// transaction
|
|
1080
|
+
// Chronicle: an IF whose condition is "top of stack equals the
|
|
1081
|
+
// transaction version", closed by OP_ENDIF.
|
|
1063
1082
|
//
|
|
1064
|
-
//
|
|
1065
|
-
//
|
|
1066
|
-
//
|
|
1083
|
+
// if(!utxo_after_chronicle) {
|
|
1084
|
+
// if(utxo_after_genesis && !fExec) break;
|
|
1085
|
+
// else return SCRIPT_ERR_BAD_OPCODE;
|
|
1086
|
+
// }
|
|
1087
|
+
//
|
|
1088
|
+
// So pre-Chronicle they are an error only in an EXECUTED branch. BSV is
|
|
1089
|
+
// post-Genesis, which is the whole condition. Returning BAD_OPCODE
|
|
1090
|
+
// unconditionally rejected scripts the network accepts.
|
|
1067
1091
|
if ((this.flags & Interpreter.SCRIPT_ENABLE_CHRONICLE) === 0) {
|
|
1092
|
+
if (!fExec) {
|
|
1093
|
+
break
|
|
1094
|
+
}
|
|
1068
1095
|
this.errstr = 'SCRIPT_ERR_BAD_OPCODE'
|
|
1069
1096
|
return false
|
|
1070
1097
|
}
|
|
@@ -1078,12 +1105,16 @@ Interpreter.prototype.step = function () {
|
|
|
1078
1105
|
this.errstr = 'SCRIPT_ERR_UNKNOWN_ERROR'
|
|
1079
1106
|
return false
|
|
1080
1107
|
}
|
|
1081
|
-
//
|
|
1082
|
-
//
|
|
1083
|
-
// an
|
|
1084
|
-
//
|
|
1085
|
-
|
|
1086
|
-
|
|
1108
|
+
// BYTE-WISE against the 4-byte little-endian version, not a numeric
|
|
1109
|
+
// compare. An operand of any other length simply yields false — it is
|
|
1110
|
+
// NOT an error — so `OP_2 OP_VERIF` against version 2 is false, where
|
|
1111
|
+
// a numeric comparison made it true. The idiomatic form is
|
|
1112
|
+
// `OP_VER OP_VERIF`.
|
|
1113
|
+
//
|
|
1114
|
+
// MINIMALIF deliberately does not apply: the node guards it with
|
|
1115
|
+
// `(opcode == OP_IF || opcode == OP_NOTIF) && VerifyMinimalIf(flags)`.
|
|
1116
|
+
buf = stacktop(-1)
|
|
1117
|
+
fValue = buf.length === 4 && buf.equals(versionLE(this.tx.version))
|
|
1087
1118
|
if (opcodenum === Opcode.OP_VERNOTIF) {
|
|
1088
1119
|
fValue = !fValue
|
|
1089
1120
|
}
|
|
@@ -1953,21 +1984,39 @@ Interpreter.prototype.step = function () {
|
|
|
1953
1984
|
|
|
1954
1985
|
case Opcode.OP_LEFT:
|
|
1955
1986
|
case Opcode.OP_RIGHT:
|
|
1956
|
-
// (in size -- out)
|
|
1957
|
-
//
|
|
1987
|
+
// (in size -- out) Chronicle, ported from SV Node.
|
|
1988
|
+
// Pre-Chronicle these bytes are UPGRADABLE NOPS on the network — they were
|
|
1989
|
+
// OP_NOP4/OP_NOP5/OP_NOP6 — so the node breaks rather than erroring:
|
|
1990
|
+
//
|
|
1991
|
+
// if(!utxo_after_chronicle) {
|
|
1992
|
+
// if(flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS)
|
|
1993
|
+
// return SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS;
|
|
1994
|
+
// else break;
|
|
1995
|
+
// }
|
|
1996
|
+
//
|
|
1997
|
+
// Running them unconditionally consumed stack where the network does
|
|
1998
|
+
// nothing, which is a wrong answer rather than an error.
|
|
1999
|
+
if ((this.flags & Interpreter.SCRIPT_ENABLE_CHRONICLE) === 0) {
|
|
2000
|
+
if (this.flags & Interpreter.SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) {
|
|
2001
|
+
this.errstr = 'SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS'
|
|
2002
|
+
return false
|
|
2003
|
+
}
|
|
2004
|
+
break
|
|
2005
|
+
}
|
|
2006
|
+
|
|
1958
2007
|
if (this.stack.length < 2) {
|
|
1959
2008
|
this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
|
|
1960
2009
|
return false
|
|
1961
2010
|
}
|
|
1962
2011
|
buf1 = stacktop(-2)
|
|
1963
|
-
n = BN.fromScriptNumBuffer(stacktop(-1), fRequireMinimal).toNumber()
|
|
1964
|
-
|
|
2012
|
+
n = BN.fromScriptNumBuffer(stacktop(-1), fRequireMinimal, Interpreter.MAXIMUM_ELEMENT_SIZE).toNumber()
|
|
2013
|
+
// ERRORS on out of range; it does not clamp. The node is
|
|
2014
|
+
// `if(len < 0 || len > size) return SCRIPT_ERR_INVALID_NUMBER_RANGE`.
|
|
2015
|
+
// Clamping made scripts the node rejects succeed here.
|
|
2016
|
+
if (n < 0 || n > buf1.length) {
|
|
1965
2017
|
this.errstr = 'SCRIPT_ERR_INVALID_NUMBER_RANGE'
|
|
1966
2018
|
return false
|
|
1967
2019
|
}
|
|
1968
|
-
if (n > buf1.length) {
|
|
1969
|
-
n = buf1.length
|
|
1970
|
-
}
|
|
1971
2020
|
this.stack.pop()
|
|
1972
2021
|
if (opcodenum === Opcode.OP_LEFT) {
|
|
1973
2022
|
this.stack[this.stack.length - 1] = Buffer.from(buf1).slice(0, n)
|
|
@@ -1977,25 +2026,41 @@ Interpreter.prototype.step = function () {
|
|
|
1977
2026
|
break
|
|
1978
2027
|
|
|
1979
2028
|
case Opcode.OP_SUBSTR:
|
|
1980
|
-
// (in begin size -- out)
|
|
1981
|
-
//
|
|
2029
|
+
// (in begin size -- out) Chronicle, ported from SV Node.
|
|
2030
|
+
// Pre-Chronicle these bytes are UPGRADABLE NOPS on the network — they were
|
|
2031
|
+
// OP_NOP4/OP_NOP5/OP_NOP6 — so the node breaks rather than erroring:
|
|
2032
|
+
//
|
|
2033
|
+
// if(!utxo_after_chronicle) {
|
|
2034
|
+
// if(flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS)
|
|
2035
|
+
// return SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS;
|
|
2036
|
+
// else break;
|
|
2037
|
+
// }
|
|
2038
|
+
//
|
|
2039
|
+
// Running them unconditionally consumed stack where the network does
|
|
2040
|
+
// nothing, which is a wrong answer rather than an error.
|
|
2041
|
+
if ((this.flags & Interpreter.SCRIPT_ENABLE_CHRONICLE) === 0) {
|
|
2042
|
+
if (this.flags & Interpreter.SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) {
|
|
2043
|
+
this.errstr = 'SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS'
|
|
2044
|
+
return false
|
|
2045
|
+
}
|
|
2046
|
+
break
|
|
2047
|
+
}
|
|
2048
|
+
|
|
1982
2049
|
if (this.stack.length < 3) {
|
|
1983
2050
|
this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
|
|
1984
2051
|
return false
|
|
1985
2052
|
}
|
|
1986
2053
|
buf1 = stacktop(-3)
|
|
1987
|
-
var subSize = BN.fromScriptNumBuffer(stacktop(-1), fRequireMinimal).toNumber()
|
|
1988
|
-
var subBegin = BN.fromScriptNumBuffer(stacktop(-2), fRequireMinimal).toNumber()
|
|
1989
|
-
|
|
2054
|
+
var subSize = BN.fromScriptNumBuffer(stacktop(-1), fRequireMinimal, Interpreter.MAXIMUM_ELEMENT_SIZE).toNumber()
|
|
2055
|
+
var subBegin = BN.fromScriptNumBuffer(stacktop(-2), fRequireMinimal, Interpreter.MAXIMUM_ELEMENT_SIZE).toNumber()
|
|
2056
|
+
// ERRORS on out of range, matching
|
|
2057
|
+
// offset < 0 || offset >= size || len < 0 || len > size - offset
|
|
2058
|
+
// Note `offset >= size` is strict: a begin index AT the end is an
|
|
2059
|
+
// error, not an empty result.
|
|
2060
|
+
if (subBegin < 0 || subBegin >= buf1.length || subSize < 0 || subSize > buf1.length - subBegin) {
|
|
1990
2061
|
this.errstr = 'SCRIPT_ERR_INVALID_NUMBER_RANGE'
|
|
1991
2062
|
return false
|
|
1992
2063
|
}
|
|
1993
|
-
if (subBegin > buf1.length) {
|
|
1994
|
-
subBegin = buf1.length
|
|
1995
|
-
}
|
|
1996
|
-
if (subBegin + subSize > buf1.length) {
|
|
1997
|
-
subSize = buf1.length - subBegin
|
|
1998
|
-
}
|
|
1999
2064
|
this.stack.pop()
|
|
2000
2065
|
this.stack.pop()
|
|
2001
2066
|
this.stack[this.stack.length - 1] = Buffer.from(buf1).slice(subBegin, subBegin + subSize)
|
|
@@ -28,16 +28,18 @@
|
|
|
28
28
|
* always just a 20-byte value the covenant splices into the recreated scriptCode.
|
|
29
29
|
*/
|
|
30
30
|
|
|
31
|
-
var
|
|
31
|
+
var PrivateKey = require('../privatekey')
|
|
32
|
+
var PublicKey = require('../publickey')
|
|
33
|
+
var Script = require('../script')
|
|
32
34
|
var Hash = require('../crypto/hash')
|
|
33
|
-
var H = require('
|
|
35
|
+
var H = require('../covenant/helpers')
|
|
34
36
|
|
|
35
|
-
var Opcode =
|
|
37
|
+
var Opcode = require('../opcode')
|
|
36
38
|
var n = H.scriptNum
|
|
37
39
|
|
|
38
40
|
function pubBuffer (key) {
|
|
39
|
-
if (key instanceof
|
|
40
|
-
if (key instanceof
|
|
41
|
+
if (key instanceof PrivateKey) return key.toPublicKey().toBuffer()
|
|
42
|
+
if (key instanceof PublicKey) return key.toBuffer()
|
|
41
43
|
return key // already a Buffer
|
|
42
44
|
}
|
|
43
45
|
|
|
@@ -71,7 +73,7 @@ function singleKey () {
|
|
|
71
73
|
function redeemScript (m, pubkeys) {
|
|
72
74
|
var nn = pubkeys.length
|
|
73
75
|
if (m < 1 || m > nn || nn < 1 || nn > 16) throw new Error('multisig requires 1 <= m <= n <= 16')
|
|
74
|
-
var s = new
|
|
76
|
+
var s = new Script().add(Opcode['OP_' + m])
|
|
75
77
|
pubkeys.forEach(function (p) { s.add(Buffer.from(p)) }) // each emitted as 0x21||pk (33-byte push)
|
|
76
78
|
s.add(Opcode['OP_' + nn]).add(Opcode.OP_CHECKMULTISIG)
|
|
77
79
|
return s.toBuffer()
|