@smartledger/bsv 8.3.1 → 9.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (169) hide show
  1. package/CHANGELOG.md +228 -0
  2. package/README.md +152 -1031
  3. package/STABILITY.md +134 -0
  4. package/bsv-gdaf.min.js +58 -53
  5. package/bsv-ltp.min.js +23 -18
  6. package/bsv-script-helper.min.js +1 -1
  7. package/bsv-smartcontract.min.js +21 -21
  8. package/bsv.bundle.js +58 -53
  9. package/bsv.d.ts +0 -4
  10. package/bsv.min.js +58 -53
  11. package/docs/BRC220_BATCH_LEAF_AMENDMENT.md +82 -7
  12. package/docs/MODULE_REFERENCE_COMPLETE.md +27 -27
  13. package/docs/README.md +2 -1
  14. package/docs/THREAT_MODEL.md +10 -2
  15. package/docs/advanced/UTXO_MANAGER_GUIDE.md +1 -1
  16. package/docs/getting-started/INSTALLATION.md +23 -23
  17. package/docs/getting-started/QUICK_START.md +7 -7
  18. package/docs/migration/FROM_BSV_1_5_6.md +5 -5
  19. package/docs/proposals/10.0.0-package-split.md +131 -0
  20. package/index.js +15 -26
  21. package/lib/block/merkleblock.js +19 -5
  22. package/lib/covenant/helpers.js +34 -35
  23. package/lib/covenant/pushtx.js +2 -2
  24. package/lib/custom-script-helper.js +0 -16
  25. package/lib/hdprivatekey.js +15 -0
  26. package/lib/ordinals/ordlock.js +1 -1
  27. package/lib/script/interpreter.js +109 -1
  28. package/lib/smart_contract/builder.js +14 -0
  29. package/lib/smart_contract/debugger.js +2 -2
  30. package/lib/smart_contract/dsl.js +2 -2
  31. package/lib/smart_contract/index.js +0 -3
  32. package/lib/smart_contract/locks.js +1 -41
  33. package/lib/smart_contract/pels.js +1 -1
  34. package/lib/smart_contract/token.js +1 -1
  35. package/lib/util/deprecate.js +159 -0
  36. package/package.json +19 -82
  37. package/tools/gen-brc220-batch-vector.js +205 -0
  38. package/version.js +1 -1
  39. package/.mocharc.json +0 -5
  40. package/test/address.js +0 -629
  41. package/test/block/block.js +0 -239
  42. package/test/block/blockheader.js +0 -270
  43. package/test/block/merkleblock.js +0 -207
  44. package/test/build/bundle_crypto_shim.js +0 -104
  45. package/test/build/bundle_externals.js +0 -125
  46. package/test/build/bundle_smoke.js +0 -55
  47. package/test/build/esbuild_main.js +0 -65
  48. package/test/build/esm_wrapper.js +0 -73
  49. package/test/build/exports_resolution.js +0 -84
  50. package/test/build/version_sync.js +0 -14
  51. package/test/cli/smoke.js +0 -261
  52. package/test/consensus/base58-vectors.js +0 -120
  53. package/test/consensus/sv-script-vectors.js +0 -81
  54. package/test/consensus/sv-sighash-vectors.js +0 -51
  55. package/test/consensus/sv-tx-vectors.js +0 -48
  56. package/test/credentials-test.js +0 -332
  57. package/test/crypto/backend_selection.js +0 -126
  58. package/test/crypto/bn.js +0 -168
  59. package/test/crypto/ecdsa.js +0 -426
  60. package/test/crypto/elliptic-fixed.js +0 -61
  61. package/test/crypto/hash.browser.js +0 -121
  62. package/test/crypto/hash.js +0 -122
  63. package/test/crypto/point.js +0 -193
  64. package/test/crypto/random.js +0 -105
  65. package/test/crypto/security.js +0 -176
  66. package/test/crypto/shamir.js +0 -177
  67. package/test/crypto/shamir_rngcap.js +0 -29
  68. package/test/crypto/signature.js +0 -399
  69. package/test/data/bip69.json +0 -215
  70. package/test/data/bitcoin-sv/README.md +0 -170
  71. package/test/data/bitcoin-sv/base58_encode_decode.json +0 -14
  72. package/test/data/bitcoin-sv/base58_keys_invalid.json +0 -152
  73. package/test/data/bitcoin-sv/base58_keys_valid.json +0 -452
  74. package/test/data/bitcoin-sv/script_tests.json +0 -2591
  75. package/test/data/bitcoin-sv/sighash.json +0 -1003
  76. package/test/data/bitcoin-sv/tx_invalid.json +0 -285
  77. package/test/data/bitcoin-sv/tx_valid.json +0 -367
  78. package/test/data/bitcoind/base58_keys_invalid.json +0 -152
  79. package/test/data/bitcoind/base58_keys_valid.json +0 -452
  80. package/test/data/bitcoind/blocks.json +0 -27
  81. package/test/data/bitcoind/script_tests.json +0 -2244
  82. package/test/data/bitcoind/sig_canonical.json +0 -7
  83. package/test/data/bitcoind/sig_noncanonical.json +0 -22
  84. package/test/data/bitcoind/tx_invalid.json +0 -177
  85. package/test/data/bitcoind/tx_valid.json +0 -224
  86. package/test/data/blk86756-testnet.dat +0 -0
  87. package/test/data/blk86756-testnet.js +0 -12
  88. package/test/data/blk86756-testnet.json +0 -684
  89. package/test/data/ecdsa.json +0 -230
  90. package/test/data/merkleblocks.js +0 -486
  91. package/test/data/messages.json +0 -22
  92. package/test/data/sighash.json +0 -1004
  93. package/test/data/tx_creation.json +0 -85
  94. package/test/didweb/relationships.js +0 -144
  95. package/test/ecies/bitcore-ecies.js +0 -178
  96. package/test/ecies/electrum-ecies.js +0 -206
  97. package/test/encoding/base58.js +0 -131
  98. package/test/encoding/base58check.js +0 -145
  99. package/test/encoding/bufferreader.js +0 -328
  100. package/test/encoding/bufferwriter.js +0 -160
  101. package/test/encoding/varint.js +0 -104
  102. package/test/gdaf/anchor_no_key_leak.js +0 -146
  103. package/test/gdaf/anchor_spv.js +0 -163
  104. package/test/gdaf/canonicalization.js +0 -106
  105. package/test/gdaf/canonicalize.js +0 -140
  106. package/test/gdaf/zk_prover.js +0 -204
  107. package/test/hdkeys.js +0 -365
  108. package/test/hdprivatekey.js +0 -339
  109. package/test/hdpublickey.js +0 -293
  110. package/test/index.js +0 -16
  111. package/test/ltp/ids.js +0 -74
  112. package/test/ltp/right.js +0 -198
  113. package/test/ltp/verify_failclosed.js +0 -134
  114. package/test/message/message.js +0 -190
  115. package/test/mnemonic/data/fixtures.json +0 -300
  116. package/test/mnemonic/mnemonic.js +0 -277
  117. package/test/mnemonic/mocha.opts +0 -1
  118. package/test/mnemonic/pbkdf2.test.js +0 -43
  119. package/test/networks.js +0 -207
  120. package/test/notaryhash/batch_leaf.js +0 -140
  121. package/test/notaryhash/certificate.js +0 -249
  122. package/test/notaryhash/encoding.js +0 -186
  123. package/test/notaryhash/interop.js +0 -112
  124. package/test/notaryhash/merkle.js +0 -181
  125. package/test/notaryhash/script.js +0 -270
  126. package/test/notaryhash/verify.js +0 -342
  127. package/test/opcode.js +0 -186
  128. package/test/ordinals/bsv20.js +0 -337
  129. package/test/ordinals/inscription.js +0 -319
  130. package/test/ordinals/ordlock.js +0 -613
  131. package/test/privatekey.js +0 -540
  132. package/test/publickey.js +0 -411
  133. package/test/regressions.js +0 -215
  134. package/test/script/chronicle.js +0 -543
  135. package/test/script/defaults.js +0 -160
  136. package/test/script/genesis_limits.js +0 -203
  137. package/test/script/interpreter.js +0 -776
  138. package/test/script/script.js +0 -1259
  139. package/test/script/string_ops.js +0 -88
  140. package/test/security/fail_closed_contracts.js +0 -104
  141. package/test/security/threat_model_coverage.js +0 -31
  142. package/test/smart_contract/covenants.js +0 -245
  143. package/test/smart_contract/dsl_debugger.js +0 -101
  144. package/test/smart_contract/extract_field.js +0 -61
  145. package/test/smart_contract/nonenforcing_guard.js +0 -44
  146. package/test/smart_contract/ordinal_transfer.js +0 -81
  147. package/test/smart_contract/preimage.js +0 -98
  148. package/test/smart_contract/sighash_marketplace.js +0 -108
  149. package/test/smart_contract/token_generalized.js +0 -185
  150. package/test/spv/headerchain.js +0 -86
  151. package/test/spv/merkleproof.js +0 -133
  152. package/test/statuslist/failclosed.js +0 -78
  153. package/test/transaction/deserialize.js +0 -33
  154. package/test/transaction/input/input.js +0 -92
  155. package/test/transaction/input/multisig.js +0 -174
  156. package/test/transaction/input/multisigscripthash.js +0 -111
  157. package/test/transaction/input/publickey.js +0 -68
  158. package/test/transaction/input/publickeyhash.js +0 -59
  159. package/test/transaction/output.js +0 -185
  160. package/test/transaction/sighash.js +0 -91
  161. package/test/transaction/signature.js +0 -127
  162. package/test/transaction/transaction.js +0 -1299
  163. package/test/transaction/unspentoutput.js +0 -97
  164. package/test/types/dts_drift.js +0 -124
  165. package/test/types/surface_honesty.js +0 -102
  166. package/test/util/id.js +0 -72
  167. package/test/util/js.js +0 -76
  168. package/test/util/preconditions.js +0 -79
  169. package/test/vcjwt/interop.js +0 -126
package/test/cli/smoke.js DELETED
@@ -1,261 +0,0 @@
1
- 'use strict'
2
-
3
- // End-to-end smoke test for `bin/cli.js`.
4
- //
5
- // Exercises every subcommand advertised in the README quickstart:
6
- // didweb init → vc issue → vc verify
7
- // status create → status set → status check
8
- // anchor hash → anchor build
9
- //
10
- // Each test runs the CLI in an isolated temp directory so the files it
11
- // drops (.well-known/did.json, issuer-key-<kid>.json, etc.) don't pollute
12
- // the repo. We assert on stdout/stderr/exit-code only — the CLI's primary
13
- // output is stdout, status messages go to stderr.
14
-
15
- var expect = require('chai').expect
16
- var spawnSync = require('child_process').spawnSync
17
- var fs = require('fs')
18
- var os = require('os')
19
- var path = require('path')
20
-
21
- var REPO_ROOT = path.resolve(__dirname, '..', '..')
22
- var CLI = path.join(REPO_ROOT, 'bin', 'cli.js')
23
- var PKG_VERSION = require(path.join(REPO_ROOT, 'package.json')).version
24
-
25
- function runCli(args, opts) {
26
- opts = opts || {}
27
- var result = spawnSync(process.execPath, [CLI].concat(args), {
28
- cwd: opts.cwd || REPO_ROOT,
29
- encoding: 'utf8',
30
- timeout: 15000,
31
- env: Object.assign({}, process.env, opts.env || {})
32
- })
33
- return {
34
- stdout: result.stdout || '',
35
- stderr: result.stderr || '',
36
- code: result.status,
37
- signal: result.signal
38
- }
39
- }
40
-
41
- describe('CLI smoke', function () {
42
- this.timeout(20000) // crypto + JWT signing can be slow on cold start
43
-
44
- var tmpDir
45
-
46
- beforeEach(function () {
47
- tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'bsv-cli-smoke-'))
48
- })
49
-
50
- afterEach(function () {
51
- try {
52
- fs.rmSync(tmpDir, { recursive: true, force: true })
53
- } catch (e) { /* best-effort cleanup */ }
54
- })
55
-
56
- describe('meta', function () {
57
- it('--version prints package.json version', function () {
58
- var r = runCli(['--version'])
59
- expect(r.code).to.equal(0)
60
- expect(r.stdout.trim()).to.equal(PKG_VERSION)
61
- })
62
-
63
- it('-v is an alias for --version', function () {
64
- var r = runCli(['-v'])
65
- expect(r.code).to.equal(0)
66
- expect(r.stdout.trim()).to.equal(PKG_VERSION)
67
- })
68
-
69
- it('no args prints the help banner with the current version', function () {
70
- var r = runCli([])
71
- expect(r.code).to.equal(0)
72
- expect(r.stdout).to.include('SmartLedger BSV CLI v' + PKG_VERSION)
73
- expect(r.stdout).to.include('didweb init')
74
- expect(r.stdout).to.include('vc issue')
75
- expect(r.stdout).to.include('status create')
76
- expect(r.stdout).to.include('anchor hash')
77
- })
78
-
79
- it('--help prints the help banner', function () {
80
- var r = runCli(['--help'])
81
- expect(r.code).to.equal(0)
82
- expect(r.stdout).to.include('Usage:')
83
- })
84
-
85
- it('unknown top-level command exits non-zero', function () {
86
- var r = runCli(['nope'])
87
- expect(r.code).to.not.equal(0)
88
- expect(r.stderr).to.match(/Unknown command/i)
89
- })
90
- })
91
-
92
- describe('didweb', function () {
93
- it('init --domain creates .well-known files and an issuer key', function () {
94
- var r = runCli(['didweb', 'init', '--domain', 'example.com', '--alg', 'ES256'], { cwd: tmpDir })
95
- expect(r.code, r.stderr).to.equal(0)
96
-
97
- var didPath = path.join(tmpDir, '.well-known', 'did.json')
98
- var jwksPath = path.join(tmpDir, '.well-known', 'jwks.json')
99
- expect(fs.existsSync(didPath), 'did.json missing').to.equal(true)
100
- expect(fs.existsSync(jwksPath), 'jwks.json missing').to.equal(true)
101
-
102
- var didDoc = JSON.parse(fs.readFileSync(didPath, 'utf8'))
103
- expect(didDoc.id).to.equal('did:web:example.com')
104
-
105
- var jwks = JSON.parse(fs.readFileSync(jwksPath, 'utf8'))
106
- expect(jwks.keys).to.be.an('array').with.length.greaterThan(0)
107
- expect(jwks.keys[0].kty).to.be.a('string')
108
-
109
- // Issuer key file is named issuer-key-<kid>.json
110
- var keyFiles = fs.readdirSync(tmpDir).filter(function (f) {
111
- return f.startsWith('issuer-key-') && f.endsWith('.json')
112
- })
113
- expect(keyFiles, 'issuer key not written').to.have.length(1)
114
-
115
- var keyData = JSON.parse(fs.readFileSync(path.join(tmpDir, keyFiles[0]), 'utf8'))
116
- expect(keyData.did).to.equal('did:web:example.com')
117
- expect(keyData.privateJwk).to.be.an('object')
118
- expect(keyData.publicJwk).to.be.an('object')
119
- expect(keyData.alg).to.equal('ES256')
120
- })
121
-
122
- it('init --alg ES256K produces a secp256k1 key', function () {
123
- var r = runCli(['didweb', 'init', '--domain', 'example.org', '--alg', 'ES256K'], { cwd: tmpDir })
124
- expect(r.code, r.stderr).to.equal(0)
125
-
126
- var keyFiles = fs.readdirSync(tmpDir).filter(function (f) {
127
- return f.startsWith('issuer-key-')
128
- })
129
- var keyData = JSON.parse(fs.readFileSync(path.join(tmpDir, keyFiles[0]), 'utf8'))
130
- expect(keyData.alg).to.equal('ES256K')
131
- })
132
-
133
- it('init without --domain exits non-zero', function () {
134
- var r = runCli(['didweb', 'init'], { cwd: tmpDir })
135
- expect(r.code).to.not.equal(0)
136
- expect(r.stderr).to.match(/--domain is required/)
137
- })
138
- })
139
-
140
- describe('vc → status → anchor end-to-end', function () {
141
- // One big sequenced test that uses didweb init's output to issue,
142
- // verify, anchor, and revoke a credential — mirrors the README's
143
- // quickstart exactly.
144
- it('full credential lifecycle', function () {
145
- // 1. Init a DID:web issuer
146
- var initRes = runCli(['didweb', 'init', '--domain', 'example.com', '--alg', 'ES256'], { cwd: tmpDir })
147
- expect(initRes.code, initRes.stderr).to.equal(0)
148
-
149
- // The CLI writes the key file as issuer-key-<kid>.json but `vc issue`
150
- // looks for `issuer-key.json` by default. Rename so we can use the
151
- // default --key path.
152
- var keyFile = fs.readdirSync(tmpDir).filter(function (f) {
153
- return f.startsWith('issuer-key-')
154
- })[0]
155
- fs.renameSync(path.join(tmpDir, keyFile), path.join(tmpDir, 'issuer-key.json'))
156
-
157
- // 2. Issue a credential
158
- var issueRes = runCli([
159
- 'vc', 'issue',
160
- '--issuer', 'did:web:example.com',
161
- '--subject', 'did:example:alice',
162
- '--types', 'VerifiableCredential,AgeCredential',
163
- '--claims', JSON.stringify({ ageOver: 18, country: 'US' })
164
- ], { cwd: tmpDir })
165
- expect(issueRes.code, issueRes.stderr).to.equal(0)
166
-
167
- // JWT format: three base64url segments separated by `.`
168
- var jwt = issueRes.stdout.trim()
169
- expect(jwt.split('.')).to.have.length(3)
170
-
171
- // 3. Verify the credential
172
- fs.writeFileSync(path.join(tmpDir, 'cred.jwt'), jwt)
173
- var verifyRes = runCli(['vc', 'verify', 'cred.jwt'], { cwd: tmpDir })
174
- expect(verifyRes.code, verifyRes.stderr).to.equal(0)
175
- expect(verifyRes.stderr).to.match(/VALID/)
176
- // Verified payload echoed on stdout
177
- var payload = JSON.parse(verifyRes.stdout)
178
- expect(payload.iss).to.equal('did:web:example.com')
179
-
180
- // 4. Anchor the credential hash
181
- var anchorRes = runCli(['anchor', 'hash', 'cred.jwt'], { cwd: tmpDir })
182
- expect(anchorRes.code, anchorRes.stderr).to.equal(0)
183
- var hash = anchorRes.stdout.trim()
184
- expect(hash).to.match(/^[0-9a-f]{64}$/)
185
-
186
- // 5. Build an anchor payload around that hash
187
- var buildRes = runCli([
188
- 'anchor', 'build',
189
- '--kind', 'VC_ANCHOR_SHA256',
190
- '--hash', hash,
191
- '--issuer', 'did:web:example.com'
192
- ], { cwd: tmpDir })
193
- expect(buildRes.code, buildRes.stderr).to.equal(0)
194
- var payloadJson = JSON.parse(buildRes.stdout)
195
- expect(payloadJson.hash).to.equal(hash)
196
-
197
- // 6. Create a status list
198
- var statusCreateRes = runCli([
199
- 'status', 'create',
200
- '--issuer', 'did:web:example.com'
201
- ], { cwd: tmpDir })
202
- expect(statusCreateRes.code, statusCreateRes.stderr).to.equal(0)
203
- var listJwt = statusCreateRes.stdout.trim()
204
- expect(listJwt.split('.')).to.have.length(3)
205
-
206
- // 7. Revoke index 42
207
- fs.writeFileSync(path.join(tmpDir, 'list.jwt'), listJwt)
208
- var statusSetRes = runCli([
209
- 'status', 'set',
210
- '--list', 'list.jwt',
211
- '--index', '42',
212
- '--status', 'revoked'
213
- ], { cwd: tmpDir })
214
- expect(statusSetRes.code, statusSetRes.stderr).to.equal(0)
215
- var updatedListJwt = statusSetRes.stdout.trim()
216
- expect(updatedListJwt.split('.')).to.have.length(3)
217
-
218
- // 8. Check the new status at index 42
219
- fs.writeFileSync(path.join(tmpDir, 'list-updated.jwt'), updatedListJwt)
220
- var statusCheckRes = runCli([
221
- 'status', 'check',
222
- '--list', 'list-updated.jwt',
223
- '--index', '42'
224
- ], { cwd: tmpDir })
225
- expect(statusCheckRes.code, statusCheckRes.stderr).to.equal(0)
226
- expect(statusCheckRes.stdout.trim()).to.equal('revoked')
227
-
228
- // 9. A different index should still report valid
229
- var statusCheckValidRes = runCli([
230
- 'status', 'check',
231
- '--list', 'list-updated.jwt',
232
- '--index', '0'
233
- ], { cwd: tmpDir })
234
- expect(statusCheckValidRes.code, statusCheckValidRes.stderr).to.equal(0)
235
- expect(statusCheckValidRes.stdout.trim()).to.equal('valid')
236
- })
237
- })
238
-
239
- describe('error handling', function () {
240
- it('vc issue without --issuer exits non-zero', function () {
241
- var r = runCli(['vc', 'issue', '--subject', 'x', '--claims', '{}'], { cwd: tmpDir })
242
- expect(r.code).to.not.equal(0)
243
- expect(r.stderr).to.match(/--issuer/)
244
- })
245
-
246
- it('vc verify on a missing file exits non-zero', function () {
247
- var r = runCli(['vc', 'verify', 'no-such-file.jwt'], { cwd: tmpDir })
248
- expect(r.code).to.not.equal(0)
249
- })
250
-
251
- it('status set without --list exits non-zero', function () {
252
- var r = runCli(['status', 'set', '--index', '1', '--status', 'revoked'], { cwd: tmpDir })
253
- expect(r.code).to.not.equal(0)
254
- })
255
-
256
- it('anchor build without --kind exits non-zero', function () {
257
- var r = runCli(['anchor', 'build', '--hash', 'x', '--issuer', 'y'], { cwd: tmpDir })
258
- expect(r.code).to.not.equal(0)
259
- })
260
- })
261
- })
@@ -1,120 +0,0 @@
1
- 'use strict'
2
-
3
- /**
4
- * Base58 and Base58Check vectors from SV Node v1.2.0.
5
- *
6
- * `base58_encode_decode.json` had no counterpart in the inherited bitcoind
7
- * corpus and nothing else here exercises it. It is small, but it is the only
8
- * place the raw codec is pinned against the node in both directions, and it
9
- * carries the two cases an implementation gets wrong: the empty input, and
10
- * leading zero bytes, which base58 encodes as leading '1's rather than as part
11
- * of a number.
12
- *
13
- * The key vectors are content-identical to the bitcoind copies that
14
- * test/address.js and test/privatekey.js already use — same 50 rows, different
15
- * whitespace. They are run here against the SV copies regardless, so that the
16
- * corpus under test/data/bitcoin-sv is the one this library is measured
17
- * against. That directory is the declared specification, and re-copying it
18
- * from a newer node tag should move these tests with it.
19
- */
20
-
21
- require('chai').should()
22
- const bsv = require('../..')
23
- const Base58 = bsv.encoding.Base58
24
- const Base58Check = bsv.encoding.Base58Check
25
- const Address = bsv.Address
26
- const PrivateKey = bsv.PrivateKey
27
-
28
- const encodeDecode = require('../data/bitcoin-sv/base58_encode_decode.json')
29
- const keysValid = require('../data/bitcoin-sv/base58_keys_valid.json')
30
- const keysInvalid = require('../data/bitcoin-sv/base58_keys_invalid.json')
31
-
32
- describe('base58 vectors (SV Node v1.2.0)', function () {
33
- describe('the raw codec', function () {
34
- it('encodes every vector to the recorded string', function () {
35
- encodeDecode.forEach(function (v, i) {
36
- Base58.encode(Buffer.from(v[0], 'hex'))
37
- .should.equal(v[1], 'encoding row ' + i + ' (' + v[0] + ')')
38
- })
39
- })
40
-
41
- it('decodes every vector back to the recorded bytes', function () {
42
- encodeDecode.forEach(function (v, i) {
43
- Base58.decode(v[1]).toString('hex')
44
- .should.equal(v[0], 'decoding row ' + i + ' (' + JSON.stringify(v[1]) + ')')
45
- })
46
- })
47
-
48
- it('keeps leading zero bytes as leading ones', function () {
49
- // Ten zero bytes encode as ten '1's. An implementation that treats the
50
- // input purely as a number loses them, and every address starting 1
51
- // depends on this.
52
- Base58.encode(Buffer.alloc(10)).should.equal('1111111111')
53
- Base58.decode('1111111111').should.deep.equal(Buffer.alloc(10))
54
- })
55
-
56
- it('round-trips the empty input', function () {
57
- Base58.encode(Buffer.alloc(0)).should.equal('')
58
- Base58.decode('').length.should.equal(0)
59
- })
60
- })
61
-
62
- describe('keys and addresses', function () {
63
- it('accepts every valid key vector', function () {
64
- let addresses = 0
65
- let privkeys = 0
66
- keysValid.forEach(function (v, i) {
67
- const str = v[0]
68
- const meta = v[2]
69
- if (meta.isPrivkey) {
70
- const key = PrivateKey.fromWIF(str)
71
- key.toWIF().should.equal(str, 'WIF round trip at ' + i)
72
- privkeys++
73
- } else {
74
- const network = meta.isTestnet ? 'testnet' : 'livenet'
75
- const address = Address.fromString(str, network)
76
- address.toString().should.equal(str, 'address round trip at ' + i)
77
- address.hashBuffer.toString('hex')
78
- .should.equal(v[1], 'hash at ' + i)
79
- address.type.should.equal(
80
- meta.addrType === 'script' ? Address.PayToScriptHash : Address.PayToPublicKeyHash,
81
- 'type at ' + i)
82
- addresses++
83
- }
84
- })
85
- // Both kinds must actually have been reached.
86
- addresses.should.be.above(0)
87
- privkeys.should.be.above(0)
88
- })
89
-
90
- it('rejects every invalid key vector, as neither address nor key', function () {
91
- // The claim these vectors make is that the string is not a valid address
92
- // and not a valid WIF — not that it fails Base58Check. Several of them
93
- // carry a perfectly good checksum and are simply the wrong length or
94
- // version, so the checksum layer accepts them and the layer above is
95
- // what has to refuse. Asserting the stronger thing would be asserting
96
- // something the corpus does not say.
97
- let checksumOk = 0
98
- keysInvalid.forEach(function (v, i) {
99
- const str = v[0]
100
- Address.isValid(str).should.equal(false, 'Address accepted row ' + i)
101
-
102
- let isKey = true
103
- try {
104
- PrivateKey.fromWIF(str)
105
- } catch (e) {
106
- isKey = false
107
- }
108
- isKey.should.equal(false, 'PrivateKey accepted row ' + i)
109
-
110
- try {
111
- Base58Check.decode(str)
112
- checksumOk++
113
- } catch (e) { /* a bad checksum is one way to be invalid, not the only one */ }
114
- })
115
- // Guards the reasoning above: if none of them had a valid checksum, this
116
- // test would be weaker than it looks and Base58Check could be asserted.
117
- checksumOk.should.be.above(0)
118
- })
119
- })
120
- })
@@ -1,81 +0,0 @@
1
- 'use strict'
2
-
3
- /**
4
- * Consensus ratchet over the SV Node script vectors.
5
- *
6
- * A report tells you where you are; this stops you going backwards. Both read
7
- * the same harness, so the progress figure and the gate cannot disagree.
8
- *
9
- * False accepts are held at zero outright rather than through an allowlist,
10
- * because accepting a script the network rejects is the direction that can
11
- * cost money. False rejects are held at zero too — the corpus passes
12
- * completely, so there is nothing to exempt and no list to maintain.
13
- */
14
-
15
- require('chai').should()
16
- const harness = require('../../tools/sv-vector-harness')
17
-
18
- describe('SV Node script vectors', function () {
19
- this.timeout(120000)
20
-
21
- let results = null
22
-
23
- before(function () {
24
- results = harness.runAll()
25
- })
26
-
27
- it('runs the whole corpus', function () {
28
- results.length.should.equal(1483)
29
- })
30
-
31
- it('uses no flag the harness does not recognise', function () {
32
- // An unrecognised flag means vectors run under the wrong rules, and any
33
- // pass among them means nothing.
34
- const unknown = new Set()
35
- results.forEach(r => r.unknownFlags.forEach(f => unknown.add(f)))
36
- Array.from(unknown).should.deep.equal([])
37
- })
38
-
39
- it('accepts nothing the node rejects', function () {
40
- const accepts = results.filter(r => r.direction === 'accept')
41
- const detail = accepts.map(r =>
42
- '\n ' + r.id + ' ' + r.reason + '\n ' + harness.describe(r.row)).join('')
43
- accepts.length.should.equal(0, 'false accepts must stay at zero:' + detail)
44
- })
45
-
46
- it('rejects nothing the node accepts', function () {
47
- const rejects = results.filter(r => r.direction === 'reject')
48
- const detail = rejects.map(r =>
49
- '\n ' + r.id + ' ' + r.reason + '\n ' + harness.describe(r.row)).join('')
50
- rejects.length.should.equal(0, 'false rejects must stay at zero:' + detail)
51
- })
52
-
53
- it('fails for the reason the node gives', function () {
54
- // Matching the outcome is not the same as matching the reason, and the gap
55
- // hid three real bugs — see ERROR_CODE_ALIASES in the harness. Each left
56
- // the script failing, so the two tests above stayed green throughout.
57
- const wrong = results.filter(r => r.codeMatches === false)
58
- const detail = wrong.map(r =>
59
- '\n ' + r.id + ' expected ' + r.expectedCode + ', reported ' + r.gotCode +
60
- '\n ' + harness.describe(r.row)).join('')
61
- wrong.length.should.equal(0,
62
- wrong.length + ' vector(s) fail for the wrong reason:' + detail)
63
- })
64
-
65
- it('compares a code on every vector the node rejects', function () {
66
- // Guards the test above: if `comparable` ever narrowed, it would pass by
67
- // checking nothing.
68
- const rejected = results.filter(r => r.row.expected !== 'OK' && r.passed)
69
- rejected.length.should.equal(600)
70
- rejected.every(r => r.codeMatches !== null).should.equal(true)
71
- })
72
-
73
- it('uses every alias it grants', function () {
74
- // The ratchet's other direction. An alias no vector produces any more is
75
- // an exemption outliving its reason, and should be deleted rather than
76
- // left to cover something later.
77
- const produced = new Set(results.filter(r => r.gotCode).map(r => r.gotCode))
78
- const unused = Object.keys(harness.ERROR_CODE_ALIASES).filter(a => !produced.has(a))
79
- unused.should.deep.equal([], 'alias(es) no vector produces; remove them')
80
- })
81
- })
@@ -1,51 +0,0 @@
1
- 'use strict'
2
-
3
- /**
4
- * Transaction digest vectors from SV Node v1.2.0 — the regression gate.
5
- *
6
- * The work is in tools/sv-sighash-harness.js, which npm run vectors:sv-sighash
7
- * also uses, so the progress report and this gate cannot disagree about what
8
- * passes. That file documents the corpus layout and the node's routing.
9
- *
10
- * Unlike the script and transaction vectors, this one carries no known-failure
11
- * list. It has never had a failing row and there is no reason it should: a
12
- * digest is a pure function of a transaction and a hash type, with no era to
13
- * negotiate.
14
- */
15
-
16
- require('chai').should()
17
- const harness = require('../../tools/sv-sighash-harness')
18
-
19
- describe('SV Node sighash vectors', function () {
20
- this.timeout(120000)
21
-
22
- const results = harness.runAll()
23
-
24
- it('covers the whole corpus', function () {
25
- results.length.should.equal(1000)
26
- })
27
-
28
- it('matches the node on both digest columns', function () {
29
- const failures = results.filter(r => !r.passed)
30
- .map(r => '#' + r.index + ' ' + r.reason)
31
- failures.slice(0, 8).should.deep.equal([],
32
- failures.length + ' of ' + results.length + ' rows disagree with the node')
33
- })
34
-
35
- it('routes every Chronicle-bit row to the original digest', function () {
36
- // Stated separately so a routing regression reads as one rather than as
37
- // hundreds of unexplained hash mismatches.
38
- const withBit = harness.chronicleRows()
39
- withBit.length.should.equal(511)
40
- withBit.forEach(v => v[4].should.equal(v[5]))
41
- results.filter(r => r.chronicleBit)
42
- .forEach(r => r.algorithm.should.equal('OTDA'))
43
- })
44
-
45
- it('still exercises both algorithms', function () {
46
- // Guards the test above: if the routing collapsed to OTDA everywhere it
47
- // would pass, and this is what would notice.
48
- results.filter(r => r.algorithm === 'BIP143').length.should.be.above(0)
49
- results.filter(r => r.algorithm === 'OTDA').length.should.be.above(0)
50
- })
51
- })
@@ -1,48 +0,0 @@
1
- 'use strict'
2
-
3
- /**
4
- * Consensus ratchet over the SV Node transaction vectors.
5
- *
6
- * These reach a level the script corpus cannot. A script vector evaluates one
7
- * unlocking script against one locking script; these deserialise a whole
8
- * transaction, resolve each input against the output it claims to spend, and
9
- * require every one to verify, with locktimes and sequence numbers in play.
10
- *
11
- * That level earned itself immediately: it found that Genesis reverts
12
- * OP_CHECKLOCKTIMEVERIFY and OP_CHECKSEQUENCEVERIFY to upgradable NOPs, which
13
- * this library did not implement and no script vector can reach — the
14
- * behaviour only appears once a real nLockTime and sequence number exist.
15
- */
16
-
17
- require('chai').should()
18
- const harness = require('../../tools/sv-tx-harness')
19
-
20
- describe('SV Node transaction vectors', function () {
21
- this.timeout(120000)
22
-
23
- let results = null
24
-
25
- before(function () {
26
- results = harness.runAll()
27
- })
28
-
29
- it('runs both files', function () {
30
- results.length.should.equal(161)
31
- results.filter(r => r.expected).length.should.equal(93)
32
- results.filter(r => !r.expected).length.should.equal(68)
33
- })
34
-
35
- it('accepts no transaction the node rejects', function () {
36
- const accepts = results.filter(r => r.direction === 'accept')
37
- const detail = accepts.map(r =>
38
- '\n ' + r.id + ' ' + r.reason + '\n ' + harness.describe(r)).join('')
39
- accepts.length.should.equal(0, 'false accepts must stay at zero:' + detail)
40
- })
41
-
42
- it('rejects no transaction the node accepts', function () {
43
- const rejects = results.filter(r => r.direction === 'reject')
44
- const detail = rejects.map(r =>
45
- '\n ' + r.id + ' ' + r.reason + '\n ' + harness.describe(r)).join('')
46
- rejects.length.should.equal(0, 'false rejects must stay at zero:' + detail)
47
- })
48
- })