@smartledger/bsv 9.0.0 → 9.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +164 -0
- package/README.md +152 -1041
- package/STABILITY.md +134 -0
- package/bsv-gdaf.min.js +53 -48
- package/bsv-ltp.min.js +23 -18
- package/bsv-smartcontract.min.js +18 -18
- package/bsv.bundle.js +53 -48
- package/bsv.min.js +53 -48
- 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/docs/proposals/10.0.0-package-split.md +131 -0
- package/index.js +5 -0
- package/lib/block/merkleblock.js +53 -9
- package/lib/hdprivatekey.js +15 -0
- package/lib/script/interpreter.js +109 -1
- package/lib/smart_contract/builder.js +14 -0
- package/lib/util/deprecate.js +159 -0
- package/package.json +19 -82
- package/version.js +1 -1
- package/.mocharc.json +0 -5
- package/test/address.js +0 -629
- package/test/block/block.js +0 -239
- package/test/block/blockheader.js +0 -270
- package/test/block/merkleblock.js +0 -207
- package/test/build/bundle_crypto_shim.js +0 -104
- package/test/build/bundle_externals.js +0 -125
- package/test/build/bundle_smoke.js +0 -55
- package/test/build/esbuild_main.js +0 -65
- package/test/build/esm_wrapper.js +0 -97
- package/test/build/exports_resolution.js +0 -84
- package/test/build/version_sync.js +0 -14
- package/test/cli/smoke.js +0 -261
- package/test/consensus/base58-vectors.js +0 -120
- package/test/consensus/sv-script-vectors.js +0 -81
- package/test/consensus/sv-sighash-vectors.js +0 -51
- package/test/consensus/sv-tx-vectors.js +0 -48
- package/test/credentials-test.js +0 -332
- package/test/crypto/backend_selection.js +0 -126
- package/test/crypto/bn.js +0 -168
- package/test/crypto/ecdsa.js +0 -426
- package/test/crypto/elliptic-fixed.js +0 -61
- package/test/crypto/hash.browser.js +0 -121
- package/test/crypto/hash.js +0 -122
- package/test/crypto/point.js +0 -193
- package/test/crypto/random.js +0 -105
- package/test/crypto/security.js +0 -176
- package/test/crypto/shamir.js +0 -177
- package/test/crypto/shamir_rngcap.js +0 -29
- package/test/crypto/signature.js +0 -399
- package/test/data/bip69.json +0 -215
- package/test/data/bitcoin-sv/README.md +0 -170
- package/test/data/bitcoin-sv/base58_encode_decode.json +0 -14
- package/test/data/bitcoin-sv/base58_keys_invalid.json +0 -152
- package/test/data/bitcoin-sv/base58_keys_valid.json +0 -452
- package/test/data/bitcoin-sv/script_tests.json +0 -2591
- package/test/data/bitcoin-sv/sighash.json +0 -1003
- package/test/data/bitcoin-sv/tx_invalid.json +0 -285
- package/test/data/bitcoin-sv/tx_valid.json +0 -367
- package/test/data/bitcoind/base58_keys_invalid.json +0 -152
- package/test/data/bitcoind/base58_keys_valid.json +0 -452
- package/test/data/bitcoind/blocks.json +0 -27
- package/test/data/bitcoind/script_tests.json +0 -2244
- package/test/data/bitcoind/sig_canonical.json +0 -7
- package/test/data/bitcoind/sig_noncanonical.json +0 -22
- package/test/data/bitcoind/tx_invalid.json +0 -177
- package/test/data/bitcoind/tx_valid.json +0 -224
- package/test/data/blk86756-testnet.dat +0 -0
- package/test/data/blk86756-testnet.js +0 -12
- package/test/data/blk86756-testnet.json +0 -684
- package/test/data/brc220-batch-vector.json +0 -129
- package/test/data/ecdsa.json +0 -230
- package/test/data/merkleblocks.js +0 -486
- package/test/data/messages.json +0 -22
- package/test/data/sighash.json +0 -1004
- package/test/data/tx_creation.json +0 -85
- package/test/didweb/relationships.js +0 -144
- package/test/ecies/bitcore-ecies.js +0 -178
- package/test/ecies/electrum-ecies.js +0 -206
- package/test/encoding/base58.js +0 -131
- package/test/encoding/base58check.js +0 -145
- package/test/encoding/bufferreader.js +0 -328
- package/test/encoding/bufferwriter.js +0 -160
- package/test/encoding/varint.js +0 -104
- package/test/gdaf/anchor_no_key_leak.js +0 -146
- package/test/gdaf/anchor_spv.js +0 -163
- package/test/gdaf/canonicalization.js +0 -106
- package/test/gdaf/canonicalize.js +0 -140
- package/test/gdaf/zk_prover.js +0 -204
- package/test/hdkeys.js +0 -365
- package/test/hdprivatekey.js +0 -339
- package/test/hdpublickey.js +0 -293
- package/test/index.js +0 -16
- package/test/ltp/ids.js +0 -74
- package/test/ltp/right.js +0 -198
- package/test/ltp/verify_failclosed.js +0 -134
- package/test/message/message.js +0 -190
- package/test/mnemonic/data/fixtures.json +0 -300
- package/test/mnemonic/mnemonic.js +0 -277
- package/test/mnemonic/mocha.opts +0 -1
- package/test/mnemonic/pbkdf2.test.js +0 -43
- package/test/networks.js +0 -207
- package/test/notaryhash/batch_leaf.js +0 -140
- package/test/notaryhash/batch_vector.js +0 -282
- package/test/notaryhash/certificate.js +0 -249
- package/test/notaryhash/encoding.js +0 -186
- package/test/notaryhash/interop.js +0 -112
- package/test/notaryhash/merkle.js +0 -181
- package/test/notaryhash/script.js +0 -270
- package/test/notaryhash/verify.js +0 -342
- package/test/opcode.js +0 -186
- package/test/ordinals/bsv20.js +0 -337
- package/test/ordinals/inscription.js +0 -329
- package/test/ordinals/ordlock.js +0 -567
- package/test/privatekey.js +0 -540
- package/test/publickey.js +0 -411
- package/test/regressions.js +0 -215
- package/test/script/chronicle.js +0 -543
- package/test/script/defaults.js +0 -160
- package/test/script/genesis_limits.js +0 -203
- package/test/script/interpreter.js +0 -776
- package/test/script/script.js +0 -1259
- package/test/script/string_ops.js +0 -88
- package/test/security/fail_closed_contracts.js +0 -104
- package/test/security/threat_model_coverage.js +0 -31
- package/test/smart_contract/covenants.js +0 -207
- package/test/smart_contract/dsl_debugger.js +0 -92
- package/test/smart_contract/extract_field.js +0 -61
- package/test/smart_contract/nonenforcing_guard.js +0 -44
- package/test/smart_contract/ordinal_transfer.js +0 -71
- package/test/smart_contract/preimage.js +0 -98
- package/test/smart_contract/sighash_marketplace.js +0 -98
- package/test/smart_contract/token_generalized.js +0 -175
- package/test/spv/headerchain.js +0 -86
- package/test/spv/merkleproof.js +0 -133
- package/test/statuslist/failclosed.js +0 -78
- package/test/transaction/deserialize.js +0 -33
- package/test/transaction/input/input.js +0 -92
- package/test/transaction/input/multisig.js +0 -174
- package/test/transaction/input/multisigscripthash.js +0 -111
- package/test/transaction/input/publickey.js +0 -68
- package/test/transaction/input/publickeyhash.js +0 -59
- package/test/transaction/output.js +0 -185
- package/test/transaction/sighash.js +0 -91
- package/test/transaction/signature.js +0 -127
- package/test/transaction/transaction.js +0 -1299
- package/test/transaction/unspentoutput.js +0 -97
- package/test/types/dts_drift.js +0 -124
- package/test/types/surface_honesty.js +0 -102
- package/test/util/id.js +0 -72
- package/test/util/js.js +0 -76
- package/test/util/preconditions.js +0 -79
- package/test/vcjwt/interop.js +0 -126
package/test/script/chronicle.js
DELETED
|
@@ -1,543 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
/* global describe, it, beforeEach, afterEach */
|
|
4
|
-
|
|
5
|
-
// The BSV Chronicle script surface: OP_2MUL/OP_2DIV restored, OP_VER/OP_VERIF/
|
|
6
|
-
// OP_VERNOTIF given meaning, and SIGHASH_CHRONICLE selecting the Original
|
|
7
|
-
// Transaction Digest Algorithm. All of it sits behind SCRIPT_ENABLE_CHRONICLE.
|
|
8
|
-
//
|
|
9
|
-
// The default (flag off) behaviour is pinned just as carefully as the enabled
|
|
10
|
-
// behaviour. Enabling an opcode by accident is a consensus change, and the
|
|
11
|
-
// pre-Chronicle rules are what every existing signature and script was written
|
|
12
|
-
// against.
|
|
13
|
-
|
|
14
|
-
require('chai').should()
|
|
15
|
-
var bsv = require('../..')
|
|
16
|
-
var Interpreter = bsv.Script.Interpreter
|
|
17
|
-
var Opcode = bsv.Opcode
|
|
18
|
-
var Script = bsv.Script
|
|
19
|
-
var BN = bsv.crypto.BN
|
|
20
|
-
var Signature = bsv.crypto.Signature
|
|
21
|
-
|
|
22
|
-
var CHRONICLE = Interpreter.SCRIPT_ENABLE_CHRONICLE
|
|
23
|
-
|
|
24
|
-
/** Evaluate `build`ed script against a tx of `version`, returning the outcome. */
|
|
25
|
-
function run (build, opts) {
|
|
26
|
-
opts = opts || {}
|
|
27
|
-
var tx = new bsv.Transaction()
|
|
28
|
-
if (opts.version != null) tx.version = opts.version
|
|
29
|
-
var script = new Script()
|
|
30
|
-
build(script)
|
|
31
|
-
var interp = new Interpreter()
|
|
32
|
-
var verified = interp.verify(
|
|
33
|
-
new Script(), script, tx, 0, opts.flags == null ? CHRONICLE : opts.flags, new BN(0)
|
|
34
|
-
)
|
|
35
|
-
return {
|
|
36
|
-
verified: verified,
|
|
37
|
-
errstr: interp.errstr || '',
|
|
38
|
-
// Read with the era's width, not BN's four-byte default: post-Genesis
|
|
39
|
-
// results are routinely wider than that, and a default-width read throws
|
|
40
|
-
// on them rather than reporting the value.
|
|
41
|
-
stack: (interp.stack || []).map(function (b) {
|
|
42
|
-
return BN.fromScriptNumBuffer(b, false, Math.max(b.length, 4)).toString()
|
|
43
|
-
}),
|
|
44
|
-
// The raw bytes as well: several Chronicle behaviours are about WIDTH, not
|
|
45
|
-
// value, and a script-number reading collapses that distinction.
|
|
46
|
-
raw: (interp.stack || []).map(function (b) { return Buffer.from(b) })
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
describe('Chronicle script surface', function () {
|
|
51
|
-
describe('SCRIPT_ENABLE_CHRONICLE flag', function () {
|
|
52
|
-
it('is a distinct bit that does not collide with the other opcode flags', function () {
|
|
53
|
-
CHRONICLE.should.be.a('number')
|
|
54
|
-
;[
|
|
55
|
-
Interpreter.SCRIPT_ENABLE_MONOLITH_OPCODES,
|
|
56
|
-
Interpreter.SCRIPT_ENABLE_MAGNETIC_OPCODES,
|
|
57
|
-
Interpreter.SCRIPT_ENABLE_SIGHASH_FORKID,
|
|
58
|
-
Interpreter.SCRIPT_ENABLE_REPLAY_PROTECTION
|
|
59
|
-
].forEach(function (other) {
|
|
60
|
-
(CHRONICLE & other).should.equal(0)
|
|
61
|
-
})
|
|
62
|
-
})
|
|
63
|
-
|
|
64
|
-
// This assertion used to read `(Interpreter.DEFAULT_FLAGS & CHRONICLE).should.equal(0)`
|
|
65
|
-
// — and Interpreter.DEFAULT_FLAGS does not exist, so it evaluated `undefined & n`,
|
|
66
|
-
// which is 0 for every n. A tautology, written by me, in the same change that added
|
|
67
|
-
// the flag. What it MEANT to assert is that verify() enables nothing on its own.
|
|
68
|
-
// The intent inverted in 8.0.0. It used to assert that verify() enables nothing on
|
|
69
|
-
// its own, which was true and was the bug: a BSV library whose default described
|
|
70
|
-
// Bitcoin in 2015 accepted scripts the network rejects. The default is now current
|
|
71
|
-
// mainnet, so the assertion is that Chronicle IS on without being asked for.
|
|
72
|
-
it('is enabled by default, because mainnet has it', function () {
|
|
73
|
-
// Deliberately NOT via run(): that helper passes CHRONICLE explicitly, so it would
|
|
74
|
-
// measure the helper rather than the library. Omit the argument entirely.
|
|
75
|
-
var script = new Script().add(Opcode.OP_VER)
|
|
76
|
-
var interp = new Interpreter()
|
|
77
|
-
interp.verify(new Script(), script, new bsv.Transaction(), 0)
|
|
78
|
-
// OP_VER is meaningful under Chronicle; BAD_OPCODE would mean it was not enabled.
|
|
79
|
-
;(interp.errstr || '').should.not.match(/BAD_OPCODE/)
|
|
80
|
-
;(Interpreter.currentConsensusFlags() & CHRONICLE).should.equal(CHRONICLE)
|
|
81
|
-
})
|
|
82
|
-
|
|
83
|
-
it('can still be turned off for a pre-activation UTXO', function () {
|
|
84
|
-
var script = new Script().add(Opcode.OP_VER)
|
|
85
|
-
var interp = new Interpreter()
|
|
86
|
-
var verified = interp.verify(new Script(), script, new bsv.Transaction(), 0, 0)
|
|
87
|
-
verified.should.equal(false)
|
|
88
|
-
interp.errstr.should.match(/BAD_OPCODE/)
|
|
89
|
-
})
|
|
90
|
-
|
|
91
|
-
it('mainnetFlags() opts in, and can opt out for a pre-activation UTXO', function () {
|
|
92
|
-
// Chronicle gates PER UTXO in the node (`utxo_after_chronicle`), so the library
|
|
93
|
-
// cannot decide this globally — it can only make both answers easy to express.
|
|
94
|
-
(Interpreter.mainnetFlags() & CHRONICLE).should.not.equal(0)
|
|
95
|
-
;(Interpreter.mainnetFlags({ afterChronicle: false }) & CHRONICLE).should.equal(0)
|
|
96
|
-
Interpreter.CHRONICLE_ACTIVATION_HEIGHT.should.equal(943816)
|
|
97
|
-
})
|
|
98
|
-
|
|
99
|
-
it('mainnetFlags() actually evaluates a Chronicle script', function () {
|
|
100
|
-
var r = run(function (s) { s.add(Opcode.OP_VER) },
|
|
101
|
-
{ flags: Interpreter.mainnetFlags(), version: 7 })
|
|
102
|
-
r.stack[r.stack.length - 1].should.equal('7')
|
|
103
|
-
|
|
104
|
-
var pre = run(function (s) { s.add(Opcode.OP_VER) },
|
|
105
|
-
{ flags: Interpreter.mainnetFlags({ afterChronicle: false }), version: 7 })
|
|
106
|
-
pre.verified.should.equal(false)
|
|
107
|
-
pre.errstr.should.match(/BAD_OPCODE/)
|
|
108
|
-
})
|
|
109
|
-
})
|
|
110
|
-
|
|
111
|
-
describe('OP_2MUL / OP_2DIV', function () {
|
|
112
|
-
it('stay DISABLED without the flag, even in an unexecuted branch', function () {
|
|
113
|
-
// "Disabled" is stronger than "unimplemented": a disabled opcode fails the
|
|
114
|
-
// script even where it is never executed. That is why the gate lives in
|
|
115
|
-
// isOpcodeDisabled rather than in the evaluation switch — losing this
|
|
116
|
-
// distinction would silently loosen consensus.
|
|
117
|
-
var r = run(function (s) {
|
|
118
|
-
s.add(Opcode.OP_0).add(Opcode.OP_IF).add(Opcode.OP_2MUL).add(Opcode.OP_ENDIF).add(Opcode.OP_1)
|
|
119
|
-
}, { flags: 0 })
|
|
120
|
-
r.verified.should.equal(false)
|
|
121
|
-
r.errstr.should.match(/DISABLED_OPCODE/)
|
|
122
|
-
})
|
|
123
|
-
|
|
124
|
-
it('are usable in an unexecuted branch once enabled', function () {
|
|
125
|
-
var r = run(function (s) {
|
|
126
|
-
s.add(Opcode.OP_0).add(Opcode.OP_IF).add(Opcode.OP_2MUL).add(Opcode.OP_ENDIF).add(Opcode.OP_1)
|
|
127
|
-
})
|
|
128
|
-
r.verified.should.equal(true)
|
|
129
|
-
})
|
|
130
|
-
|
|
131
|
-
it('OP_2MUL doubles, over positive, negative and zero', function () {
|
|
132
|
-
;[[0, '0'], [1, '2'], [7, '14'], [-3, '-6'], [-1, '-2']].forEach(function (t) {
|
|
133
|
-
var r = run(function (s) { s.add(new BN(t[0]).toScriptNumBuffer()).add(Opcode.OP_2MUL) })
|
|
134
|
-
r.stack[r.stack.length - 1].should.equal(t[1])
|
|
135
|
-
})
|
|
136
|
-
})
|
|
137
|
-
|
|
138
|
-
it('OP_2DIV truncates toward zero, so it agrees with OP_DIV by 2', function () {
|
|
139
|
-
// -5 OP_2DIV is -2, not -3. A shift would give -3; bn.js `shrn` also asserts
|
|
140
|
-
// on negatives. This is the case where a rounding change would hide.
|
|
141
|
-
;[0, 1, 5, -5, 7, -7, -1, 1000, -1000].forEach(function (v) {
|
|
142
|
-
var viaOp = run(function (s) { s.add(new BN(v).toScriptNumBuffer()).add(Opcode.OP_2DIV) })
|
|
143
|
-
var viaDiv = run(function (s) {
|
|
144
|
-
s.add(new BN(v).toScriptNumBuffer()).add(new BN(2).toScriptNumBuffer()).add(Opcode.OP_DIV)
|
|
145
|
-
})
|
|
146
|
-
viaOp.stack[viaOp.stack.length - 1].should.equal(viaDiv.stack[viaDiv.stack.length - 1])
|
|
147
|
-
})
|
|
148
|
-
})
|
|
149
|
-
})
|
|
150
|
-
|
|
151
|
-
describe('OP_VER', function () {
|
|
152
|
-
it('is BAD_OPCODE without the flag', function () {
|
|
153
|
-
var r = run(function (s) { s.add(Opcode.OP_VER) }, { flags: 0 })
|
|
154
|
-
r.verified.should.equal(false)
|
|
155
|
-
r.errstr.should.match(/BAD_OPCODE/)
|
|
156
|
-
})
|
|
157
|
-
|
|
158
|
-
it('pushes the executing transaction version', function () {
|
|
159
|
-
;[1, 2, 10].forEach(function (v) {
|
|
160
|
-
var r = run(function (s) { s.add(Opcode.OP_VER) }, { version: v })
|
|
161
|
-
r.stack[r.stack.length - 1].should.equal(String(v))
|
|
162
|
-
// LENGTH too, not just the numeric reading. `01000000` and `01` both read
|
|
163
|
-
// as 1, so the value check alone passes whether OP_VER pushes four
|
|
164
|
-
// little-endian bytes or a minimally-encoded script number — and pushing
|
|
165
|
-
// the script number was the bug fixed in #95.
|
|
166
|
-
r.raw[r.raw.length - 1].length.should.equal(4)
|
|
167
|
-
})
|
|
168
|
-
})
|
|
169
|
-
})
|
|
170
|
-
|
|
171
|
-
describe('OP_VERIF / OP_VERNOTIF', function () {
|
|
172
|
-
it('after Genesis, errors only in an EXECUTED branch', function () {
|
|
173
|
-
// Core treats OP_VERIF as illegal everywhere, including unexecuted
|
|
174
|
-
// branches — a rule it applies to no other opcode. BSV dropped that at
|
|
175
|
-
// Genesis, and the node is explicit:
|
|
176
|
-
//
|
|
177
|
-
// if(!utxo_after_chronicle) {
|
|
178
|
-
// if(utxo_after_genesis && !fExec) break;
|
|
179
|
-
// else return SCRIPT_ERR_BAD_OPCODE;
|
|
180
|
-
// }
|
|
181
|
-
//
|
|
182
|
-
// Note the condition includes utxo_after_genesis, so the era has to be
|
|
183
|
-
// stated. Run without it, this is a pre-Genesis output, and then Core's
|
|
184
|
-
// rule is also BSV's: illegal everywhere, which the node's own corpus
|
|
185
|
-
// confirms for exactly these scripts.
|
|
186
|
-
var unexecuted = run(function (s) {
|
|
187
|
-
s.add(Opcode.OP_0).add(Opcode.OP_IF).add(Opcode.OP_VERIF).add(Opcode.OP_ENDIF).add(Opcode.OP_1)
|
|
188
|
-
}, { flags: Interpreter.SCRIPT_UTXO_AFTER_GENESIS })
|
|
189
|
-
unexecuted.verified.should.equal(true)
|
|
190
|
-
|
|
191
|
-
// Pre-Genesis the same script is invalid, unexecuted branch or not.
|
|
192
|
-
var preGenesis = run(function (s) {
|
|
193
|
-
s.add(Opcode.OP_0).add(Opcode.OP_IF).add(Opcode.OP_VERIF).add(Opcode.OP_ENDIF).add(Opcode.OP_1)
|
|
194
|
-
}, { flags: 0 })
|
|
195
|
-
preGenesis.verified.should.equal(false)
|
|
196
|
-
preGenesis.errstr.should.match(/BAD_OPCODE/)
|
|
197
|
-
|
|
198
|
-
var executed = run(function (s) {
|
|
199
|
-
s.add(Opcode.OP_1).add(Opcode.OP_VERIF).add(Opcode.OP_ENDIF)
|
|
200
|
-
}, { flags: 0 })
|
|
201
|
-
executed.verified.should.equal(false)
|
|
202
|
-
executed.errstr.should.match(/BAD_OPCODE/)
|
|
203
|
-
})
|
|
204
|
-
|
|
205
|
-
// The comparison is BYTE-WISE against the four little-endian version
|
|
206
|
-
// bytes, not numeric:
|
|
207
|
-
//
|
|
208
|
-
// if(vch.size() == 4) { to_le(checker.Version(), val.data());
|
|
209
|
-
// fValue = std::ranges::equal(val, vch); }
|
|
210
|
-
//
|
|
211
|
-
// So a 1-byte script number never matches, however equal it looks
|
|
212
|
-
// numerically, and the idiomatic form is `OP_VER OP_VERIF`.
|
|
213
|
-
var LE = function (v) {
|
|
214
|
-
var b = Buffer.alloc(4)
|
|
215
|
-
b.writeInt32LE(v, 0)
|
|
216
|
-
return b
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
it('OP_VERIF takes the branch on a 4-byte little-endian version match', function () {
|
|
220
|
-
var taken = run(function (s) {
|
|
221
|
-
s.add(LE(2)).add(Opcode.OP_VERIF).add(Opcode.OP_1).add(Opcode.OP_ENDIF)
|
|
222
|
-
}, { version: 2 })
|
|
223
|
-
taken.verified.should.equal(true)
|
|
224
|
-
|
|
225
|
-
var notTaken = run(function (s) {
|
|
226
|
-
s.add(LE(9)).add(Opcode.OP_VERIF).add(Opcode.OP_1).add(Opcode.OP_ENDIF).add(Opcode.OP_1)
|
|
227
|
-
}, { version: 2 })
|
|
228
|
-
notTaken.verified.should.equal(true)
|
|
229
|
-
notTaken.stack.length.should.equal(1) // only the trailing OP_1
|
|
230
|
-
})
|
|
231
|
-
|
|
232
|
-
it('a numerically-equal operand of the wrong LENGTH does not match', function () {
|
|
233
|
-
var r = run(function (s) {
|
|
234
|
-
s.add(new BN(2).toScriptNumBuffer()).add(Opcode.OP_VERIF).add(Opcode.OP_1).add(Opcode.OP_ENDIF).add(Opcode.OP_1)
|
|
235
|
-
}, { version: 2 })
|
|
236
|
-
r.verified.should.equal(true)
|
|
237
|
-
r.stack.length.should.equal(1) // branch NOT taken
|
|
238
|
-
})
|
|
239
|
-
|
|
240
|
-
it('OP_VER feeds OP_VERIF directly', function () {
|
|
241
|
-
var r = run(function (s) {
|
|
242
|
-
s.add(Opcode.OP_VER).add(Opcode.OP_VERIF).add(Opcode.OP_1).add(Opcode.OP_ENDIF)
|
|
243
|
-
}, { version: 2 })
|
|
244
|
-
r.verified.should.equal(true)
|
|
245
|
-
})
|
|
246
|
-
|
|
247
|
-
it('OP_VERNOTIF is its negation', function () {
|
|
248
|
-
var r = run(function (s) {
|
|
249
|
-
s.add(LE(9)).add(Opcode.OP_VERNOTIF).add(Opcode.OP_1).add(Opcode.OP_ENDIF)
|
|
250
|
-
}, { version: 2 })
|
|
251
|
-
r.verified.should.equal(true)
|
|
252
|
-
})
|
|
253
|
-
|
|
254
|
-
it('CONSUMES its operand, mirroring OP_IF', function () {
|
|
255
|
-
// The spec describes the comparison but not the stack effect. An IF that left
|
|
256
|
-
// its condition behind would unbalance every script using it, so this pops.
|
|
257
|
-
// Pinned so a correction shows up as a failure rather than silently.
|
|
258
|
-
var r = run(function (s) {
|
|
259
|
-
s.add(Opcode.OP_7).add(Opcode.OP_2).add(Opcode.OP_VERIF).add(Opcode.OP_ENDIF)
|
|
260
|
-
}, { version: 2 })
|
|
261
|
-
r.verified.should.equal(true)
|
|
262
|
-
r.stack.should.deep.equal(['7']) // the 2 was consumed, the 7 remains
|
|
263
|
-
})
|
|
264
|
-
|
|
265
|
-
it('fails on an empty stack rather than reading past it', function () {
|
|
266
|
-
var r = run(function (s) {
|
|
267
|
-
s.add(Opcode.OP_VERIF).add(Opcode.OP_ENDIF).add(Opcode.OP_1)
|
|
268
|
-
}, { version: 2 })
|
|
269
|
-
r.verified.should.equal(false)
|
|
270
|
-
r.errstr.should.match(/UNBALANCED_CONDITIONAL/)
|
|
271
|
-
})
|
|
272
|
-
})
|
|
273
|
-
|
|
274
|
-
// Ported from SV Node src/script/interpreter.cpp (OP_LSHIFTNUM / OP_RSHIFTNUM) and
|
|
275
|
-
// the CScriptNum / bsv::bint arithmetic behind it. Each case below corresponds to a
|
|
276
|
-
// specific line of that implementation, so a divergence shows up as a named failure.
|
|
277
|
-
describe('OP_LSHIFTNUM / OP_RSHIFTNUM', function () {
|
|
278
|
-
// Push x then n then the opcode: the node's comment is literally `(x n -- out)`,
|
|
279
|
-
// so the COUNT is on top.
|
|
280
|
-
function shift (x, n, op, flags) {
|
|
281
|
-
return run(function (s) {
|
|
282
|
-
s.add(new BN(x).toScriptNumBuffer()).add(new BN(n).toScriptNumBuffer()).add(op)
|
|
283
|
-
}, { flags: flags == null ? CHRONICLE : flags })
|
|
284
|
-
}
|
|
285
|
-
function value (x, n, op) {
|
|
286
|
-
var r = shift(x, n, op)
|
|
287
|
-
return r.stack[r.stack.length - 1]
|
|
288
|
-
}
|
|
289
|
-
// A zero result makes the script fail EVAL_FALSE, so compare against OP_0 instead.
|
|
290
|
-
function isZero (x, n, op) {
|
|
291
|
-
return run(function (s) {
|
|
292
|
-
s.add(new BN(x).toScriptNumBuffer()).add(new BN(n).toScriptNumBuffer()).add(op)
|
|
293
|
-
.add(Opcode.OP_0).add(Opcode.OP_EQUAL)
|
|
294
|
-
}).verified
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
it('are upgradable NOPs before Chronicle, as the node has them', function () {
|
|
298
|
-
// if(!utxo_after_chronicle) { ... else break; } — a no-op, NOT an error.
|
|
299
|
-
// Rejecting here would refuse scripts the network accepts.
|
|
300
|
-
var r = shift(8, 1, Opcode.OP_LSHIFTNUM, 0)
|
|
301
|
-
r.verified.should.equal(true)
|
|
302
|
-
r.stack.should.deep.equal(['8', '1']) // untouched: no shift, nothing popped
|
|
303
|
-
})
|
|
304
|
-
|
|
305
|
-
it('honour DISCOURAGE_UPGRADABLE_NOPS before Chronicle', function () {
|
|
306
|
-
var r = shift(8, 1, Opcode.OP_LSHIFTNUM, Interpreter.SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS)
|
|
307
|
-
r.verified.should.equal(false)
|
|
308
|
-
r.errstr.should.match(/DISCOURAGE_UPGRADABLE_NOPS/)
|
|
309
|
-
})
|
|
310
|
-
|
|
311
|
-
it('left shift multiplies by 2^n, carrying the sign', function () {
|
|
312
|
-
value(1, 4, Opcode.OP_LSHIFTNUM).should.equal('16')
|
|
313
|
-
value(3, 3, Opcode.OP_LSHIFTNUM).should.equal('24')
|
|
314
|
-
value(1, 0, Opcode.OP_LSHIFTNUM).should.equal('1')
|
|
315
|
-
value(-1, 4, Opcode.OP_LSHIFTNUM).should.equal('-16')
|
|
316
|
-
value(-3, 3, Opcode.OP_LSHIFTNUM).should.equal('-24')
|
|
317
|
-
})
|
|
318
|
-
|
|
319
|
-
it('right shift TRUNCATES TOWARD ZERO, which is the whole of "preserving sign"', function () {
|
|
320
|
-
// The node spells this out: "Mathematical division by 2^bit_shift, rounding
|
|
321
|
-
// toward zero ... For negative values: n / 2^k = -((-n) >> k)". A two's
|
|
322
|
-
// complement arithmetic shift would FLOOR instead, giving -3 and -4 here.
|
|
323
|
-
value(-5, 1, Opcode.OP_RSHIFTNUM).should.equal('-2')
|
|
324
|
-
value(-7, 1, Opcode.OP_RSHIFTNUM).should.equal('-3')
|
|
325
|
-
value(5, 1, Opcode.OP_RSHIFTNUM).should.equal('2')
|
|
326
|
-
value(-1000, 3, Opcode.OP_RSHIFTNUM).should.equal('-125')
|
|
327
|
-
})
|
|
328
|
-
|
|
329
|
-
it('agrees with OP_DIV by 2^n, the same convention as OP_2DIV', function () {
|
|
330
|
-
[5, -5, 7, -7, 1000, -1000].forEach(function (x) {
|
|
331
|
-
var viaShift = value(x, 1, Opcode.OP_RSHIFTNUM)
|
|
332
|
-
var viaDiv = run(function (s) {
|
|
333
|
-
s.add(new BN(x).toScriptNumBuffer()).add(new BN(2).toScriptNumBuffer()).add(Opcode.OP_DIV)
|
|
334
|
-
})
|
|
335
|
-
viaShift.should.equal(viaDiv.stack[viaDiv.stack.length - 1])
|
|
336
|
-
})
|
|
337
|
-
})
|
|
338
|
-
|
|
339
|
-
it('rejects a negative shift count', function () {
|
|
340
|
-
// if(n < 0) return SCRIPT_ERR_INVALID_NUMBER_RANGE
|
|
341
|
-
;[Opcode.OP_LSHIFTNUM, Opcode.OP_RSHIFTNUM].forEach(function (op) {
|
|
342
|
-
var r = shift(8, -1, op)
|
|
343
|
-
r.verified.should.equal(false)
|
|
344
|
-
r.errstr.should.match(/INVALID_NUMBER_RANGE/)
|
|
345
|
-
})
|
|
346
|
-
})
|
|
347
|
-
|
|
348
|
-
it('right shift past the bit length is zero, not an error', function () {
|
|
349
|
-
isZero(5, 1000, Opcode.OP_RSHIFTNUM).should.equal(true)
|
|
350
|
-
isZero(-5, 1000, Opcode.OP_RSHIFTNUM).should.equal(true) // and no negative zero
|
|
351
|
-
isZero(1, 1, Opcode.OP_RSHIFTNUM).should.equal(true)
|
|
352
|
-
isZero(-1, 1, Opcode.OP_RSHIFTNUM).should.equal(true)
|
|
353
|
-
})
|
|
354
|
-
|
|
355
|
-
it('left shift overflows rather than growing without bound', function () {
|
|
356
|
-
// CScriptNum bounds this BEFORE shifting (current_size + shift_bytes >
|
|
357
|
-
// max_length), so a huge count cannot allocate a huge number first.
|
|
358
|
-
//
|
|
359
|
-
// The count has to exceed the real bound to test that. Chronicle's
|
|
360
|
-
// max_length is 32,000,000 bytes, so 1000 bits — 125 bytes — is a
|
|
361
|
-
// perfectly valid post-Chronicle number and overflows only against the
|
|
362
|
-
// pre-Genesis four. This used to pass because the bound was four
|
|
363
|
-
// whatever the era.
|
|
364
|
-
var r = shift(5, 8 * Interpreter.MAX_SCRIPT_NUM_LENGTH_AFTER_CHRONICLE,
|
|
365
|
-
Opcode.OP_LSHIFTNUM)
|
|
366
|
-
r.verified.should.equal(false)
|
|
367
|
-
r.errstr.should.match(/OVERFLOW/)
|
|
368
|
-
})
|
|
369
|
-
|
|
370
|
-
it('leaves a shift inside the bound alone', function () {
|
|
371
|
-
// The counterpart: 1000 bits is valid post-Chronicle, and was not before.
|
|
372
|
-
var r = shift(5, 1000, Opcode.OP_LSHIFTNUM)
|
|
373
|
-
r.verified.should.equal(true)
|
|
374
|
-
r.raw[0].length.should.equal(126)
|
|
375
|
-
})
|
|
376
|
-
|
|
377
|
-
it('fails on a short stack', function () {
|
|
378
|
-
var r = run(function (s) { s.add(new BN(1).toScriptNumBuffer()).add(Opcode.OP_LSHIFTNUM) })
|
|
379
|
-
r.verified.should.equal(false)
|
|
380
|
-
r.errstr.should.match(/INVALID_STACK_OPERATION/)
|
|
381
|
-
})
|
|
382
|
-
})
|
|
383
|
-
|
|
384
|
-
describe('SIGHASH_CHRONICLE selects the original digest algorithm', function () {
|
|
385
|
-
function fixture () {
|
|
386
|
-
var key = bsv.PrivateKey.fromBuffer(Buffer.alloc(32, 5))
|
|
387
|
-
var sub = Script.buildPublicKeyHashOut(key.toAddress())
|
|
388
|
-
var tx = new bsv.Transaction()
|
|
389
|
-
tx.uncheckedAddInput(new bsv.Transaction.Input({
|
|
390
|
-
prevTxId: 'aa'.repeat(32), outputIndex: 0, script: Script.empty()
|
|
391
|
-
}))
|
|
392
|
-
tx.addOutput(new bsv.Transaction.Output({ script: sub, satoshis: 1000 }))
|
|
393
|
-
return { tx: tx, sub: sub, amt: new BN(2000) }
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
it('has the constant at 0x20', function () {
|
|
397
|
-
Signature.SIGHASH_CHRONICLE.should.equal(0x20)
|
|
398
|
-
})
|
|
399
|
-
|
|
400
|
-
it('routes to OTDA when the bit is set AND the flag is enabled', function () {
|
|
401
|
-
var f = fixture()
|
|
402
|
-
var type = Signature.SIGHASH_ALL | Signature.SIGHASH_FORKID | Signature.SIGHASH_CHRONICLE
|
|
403
|
-
var enabled = bsv.Transaction.sighash.sighash(
|
|
404
|
-
f.tx, type, 0, f.sub, f.amt,
|
|
405
|
-
Interpreter.SCRIPT_ENABLE_SIGHASH_FORKID | CHRONICLE
|
|
406
|
-
)
|
|
407
|
-
var forcedOtda = bsv.Transaction.sighash.sighash(f.tx, type, 0, f.sub, f.amt, 0)
|
|
408
|
-
enabled.toString('hex').should.equal(forcedOtda.toString('hex'))
|
|
409
|
-
})
|
|
410
|
-
|
|
411
|
-
it('OVERRIDES FORKID — otherwise the bit could never select OTDA in practice', function () {
|
|
412
|
-
// FORKID is set on essentially every BSV signature written since 2018, so a
|
|
413
|
-
// CHRONICLE bit that only applied when FORKID was absent would mean nothing.
|
|
414
|
-
//
|
|
415
|
-
// Stated against the algorithm rather than against the flag: the node
|
|
416
|
-
// routes on the bit alone, so with the bit set, enabling forkid makes no
|
|
417
|
-
// difference and the result is the original digest either way.
|
|
418
|
-
var f = fixture()
|
|
419
|
-
var type = Signature.SIGHASH_ALL | Signature.SIGHASH_FORKID | Signature.SIGHASH_CHRONICLE
|
|
420
|
-
var withForkId = bsv.Transaction.sighash.sighash(
|
|
421
|
-
f.tx, type, 0, f.sub, f.amt, Interpreter.SCRIPT_ENABLE_SIGHASH_FORKID
|
|
422
|
-
)
|
|
423
|
-
var forcedOtda = bsv.Transaction.sighash.sighash(f.tx, type, 0, f.sub, f.amt, 0)
|
|
424
|
-
withForkId.toString('hex').should.equal(forcedOtda.toString('hex'))
|
|
425
|
-
|
|
426
|
-
// And it does override: without the bit the same transaction takes BIP-143.
|
|
427
|
-
var withoutBit = Signature.SIGHASH_ALL | Signature.SIGHASH_FORKID
|
|
428
|
-
var bip143 = bsv.Transaction.sighash.sighash(
|
|
429
|
-
f.tx, withoutBit, 0, f.sub, f.amt, Interpreter.SCRIPT_ENABLE_SIGHASH_FORKID
|
|
430
|
-
)
|
|
431
|
-
bip143.toString('hex').should.not.equal(withForkId.toString('hex'))
|
|
432
|
-
})
|
|
433
|
-
|
|
434
|
-
it('cannot be used outside Chronicle, so old BIP-143 signatures are unaffected', function () {
|
|
435
|
-
// Before the upgrade the 0x20 bit means nothing, so signatures already exist
|
|
436
|
-
// whose type byte happens to set it. Reinterpreting those as OTDA would be
|
|
437
|
-
// a silent validity change on historic data.
|
|
438
|
-
//
|
|
439
|
-
// The node prevents that in CheckSignatureEncoding rather than in the
|
|
440
|
-
// digest function: a signature carrying the bit outside Chronicle is
|
|
441
|
-
// REJECTED, not reinterpreted, so it never reaches a digest at all. That
|
|
442
|
-
// is what lets SignatureHash() route on the bit alone, and gating the
|
|
443
|
-
// digest instead made 260 of the node's 1000 vectors disagree.
|
|
444
|
-
var priv = new bsv.PrivateKey()
|
|
445
|
-
var hashbuf = bsv.crypto.Hash.sha256(Buffer.from('chronicle bit'))
|
|
446
|
-
var type = Signature.SIGHASH_ALL | Signature.SIGHASH_FORKID | Signature.SIGHASH_CHRONICLE
|
|
447
|
-
var sig = bsv.crypto.ECDSA.sign(hashbuf, priv)
|
|
448
|
-
sig.nhashtype = type
|
|
449
|
-
|
|
450
|
-
var interp = new Interpreter()
|
|
451
|
-
interp.set({ flags: Interpreter.SCRIPT_ENABLE_SIGHASH_FORKID | Interpreter.SCRIPT_VERIFY_STRICTENC })
|
|
452
|
-
interp.checkSignatureEncoding(sig.toTxFormat()).should.equal(false)
|
|
453
|
-
interp.errstr.should.equal('SCRIPT_ERR_ILLEGAL_CHRONICLE')
|
|
454
|
-
|
|
455
|
-
// With Chronicle in force it is allowed.
|
|
456
|
-
var ok = new Interpreter()
|
|
457
|
-
ok.set({
|
|
458
|
-
flags: Interpreter.SCRIPT_ENABLE_SIGHASH_FORKID |
|
|
459
|
-
Interpreter.SCRIPT_VERIFY_STRICTENC | Interpreter.SCRIPT_CHRONICLE
|
|
460
|
-
})
|
|
461
|
-
ok.checkSignatureEncoding(sig.toTxFormat()).should.equal(true)
|
|
462
|
-
})
|
|
463
|
-
})
|
|
464
|
-
|
|
465
|
-
describe('mainnet consensus helpers', function () {
|
|
466
|
-
var BN2 = bsv.crypto.BN
|
|
467
|
-
|
|
468
|
-
// useMainnetConsensus() mutates process-wide statics, so the limits are saved
|
|
469
|
-
// and restored around every case here. Without this the raised caps leak into
|
|
470
|
-
// every later test in the run — 27 of them, when it was first written.
|
|
471
|
-
var savedLimits
|
|
472
|
-
beforeEach(function () { savedLimits = Interpreter.getLimits() })
|
|
473
|
-
afterEach(function () { Interpreter.setLimits(savedLimits) })
|
|
474
|
-
|
|
475
|
-
// Genesis reverted CLTV/CSV to OP_NOP2/OP_NOP3, and the node ignores their flags
|
|
476
|
-
// once the UTXO is post-Genesis:
|
|
477
|
-
// if (!(flags & SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY) || utxo_after_genesis)
|
|
478
|
-
// Including them made mainnetFlags() reject scripts mainnet accepts.
|
|
479
|
-
it('mainnetFlags omits CLTV and CSV', function () {
|
|
480
|
-
var f = Interpreter.mainnetFlags()
|
|
481
|
-
;(f & Interpreter.SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY).should.equal(0)
|
|
482
|
-
;(f & Interpreter.SCRIPT_VERIFY_CHECKSEQUENCEVERIFY).should.equal(0)
|
|
483
|
-
})
|
|
484
|
-
|
|
485
|
-
it('mainnetFlags accepts a CLTV script, as mainnet does', function () {
|
|
486
|
-
var lock = new Script()
|
|
487
|
-
.add(new BN2(500000000).toScriptNumBuffer())
|
|
488
|
-
.add(Opcode.OP_CHECKLOCKTIMEVERIFY)
|
|
489
|
-
.add(Opcode.OP_DROP)
|
|
490
|
-
.add(Opcode.OP_1)
|
|
491
|
-
var tx = new bsv.Transaction()
|
|
492
|
-
tx.version = 2
|
|
493
|
-
var interp = new Interpreter()
|
|
494
|
-
interp.verify(new Script(), lock, tx, 0, Interpreter.mainnetFlags(), new BN2(0))
|
|
495
|
-
.should.equal(true)
|
|
496
|
-
interp.errstr.should.equal('')
|
|
497
|
-
})
|
|
498
|
-
|
|
499
|
-
it('mainnetFlags accepts a CSV script, as mainnet does', function () {
|
|
500
|
-
var lock = new Script()
|
|
501
|
-
.add(new BN2(1000).toScriptNumBuffer())
|
|
502
|
-
.add(Opcode.OP_CHECKSEQUENCEVERIFY)
|
|
503
|
-
.add(Opcode.OP_DROP)
|
|
504
|
-
.add(Opcode.OP_1)
|
|
505
|
-
var tx = new bsv.Transaction()
|
|
506
|
-
tx.version = 2
|
|
507
|
-
var interp = new Interpreter()
|
|
508
|
-
interp.verify(new Script(), lock, tx, 0, Interpreter.mainnetFlags(), new BN2(0))
|
|
509
|
-
.should.equal(true)
|
|
510
|
-
})
|
|
511
|
-
|
|
512
|
-
// The flags still exist for pre-Genesis emulation — that capability is retained,
|
|
513
|
-
// it is simply not what mainnet does.
|
|
514
|
-
it('the CLTV flag still enforces when a caller asks for it', function () {
|
|
515
|
-
var lock = new Script()
|
|
516
|
-
.add(new BN2(500000000).toScriptNumBuffer())
|
|
517
|
-
.add(Opcode.OP_CHECKLOCKTIMEVERIFY)
|
|
518
|
-
.add(Opcode.OP_DROP)
|
|
519
|
-
.add(Opcode.OP_1)
|
|
520
|
-
var tx = new bsv.Transaction()
|
|
521
|
-
tx.version = 2
|
|
522
|
-
var interp = new Interpreter()
|
|
523
|
-
interp.verify(new Script(), lock, tx, 0,
|
|
524
|
-
Interpreter.SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY, new BN2(0)).should.equal(false)
|
|
525
|
-
interp.errstr.should.match(/UNSATISFIED_LOCKTIME/)
|
|
526
|
-
})
|
|
527
|
-
|
|
528
|
-
// Flags and limits are separate mechanisms; mainnetFlags() cannot set the statics.
|
|
529
|
-
// A script over the pre-Genesis 10,000-byte cap is valid on mainnet.
|
|
530
|
-
it('useMainnetConsensus lifts the limits that mainnetFlags cannot', function () {
|
|
531
|
-
var big = new Script()
|
|
532
|
-
for (var i = 0; i < 400; i++) big.add(Buffer.alloc(30, 1)).add(Opcode.OP_DROP)
|
|
533
|
-
big.add(Opcode.OP_1)
|
|
534
|
-
big.toBuffer().length.should.be.above(10000)
|
|
535
|
-
|
|
536
|
-
var flags = Interpreter.useMainnetConsensus()
|
|
537
|
-
var interp = new Interpreter()
|
|
538
|
-
interp.verify(new Script(), big, new bsv.Transaction(), 0, flags, new BN2(0))
|
|
539
|
-
.should.equal(true)
|
|
540
|
-
Interpreter.MAX_SCRIPT_SIZE.should.be.above(10000)
|
|
541
|
-
})
|
|
542
|
-
})
|
|
543
|
-
})
|