@smartledger/bsv 8.3.0 → 9.0.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 +133 -0
- package/README.md +374 -222
- package/bsv-gdaf.min.js +49 -49
- package/bsv-script-helper.min.js +1 -1
- package/bsv-smartcontract.min.js +21 -21
- package/bsv.bundle.js +49 -49
- package/bsv.d.ts +0 -4
- package/bsv.min.js +49 -49
- package/docs/BRC220_BATCH_LEAF_AMENDMENT.md +194 -0
- package/docs/BRC220_PLAN.md +9 -0
- package/docs/MODULE_REFERENCE_COMPLETE.md +27 -27
- package/docs/README.md +2 -1
- package/docs/THREAT_MODEL.md +10 -2
- 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 +10 -26
- package/lib/covenant/helpers.js +34 -35
- package/lib/covenant/pushtx.js +2 -2
- package/lib/custom-script-helper.js +0 -16
- package/lib/notaryhash/index.js +20 -0
- package/lib/notaryhash/merkle.js +8 -0
- package/lib/notaryhash/suites.js +17 -1
- package/lib/ordinals/ordlock.js +1 -1
- package/lib/smart_contract/debugger.js +2 -2
- package/lib/smart_contract/dsl.js +2 -2
- package/lib/smart_contract/index.js +0 -3
- package/lib/smart_contract/locks.js +1 -41
- package/lib/smart_contract/pels.js +1 -1
- package/lib/smart_contract/token.js +1 -1
- package/package.json +3 -2
- package/test/build/esm_wrapper.js +32 -8
- package/test/data/brc220-batch-vector.json +129 -0
- package/test/notaryhash/batch_leaf.js +140 -0
- package/test/notaryhash/batch_vector.js +282 -0
- package/test/notaryhash/interop.js +112 -0
- package/test/notaryhash/verify.js +5 -2
- package/test/ordinals/inscription.js +24 -14
- package/test/ordinals/ordlock.js +0 -46
- package/test/smart_contract/covenants.js +0 -38
- package/test/smart_contract/dsl_debugger.js +0 -9
- package/test/smart_contract/ordinal_transfer.js +0 -10
- package/test/smart_contract/sighash_marketplace.js +0 -10
- package/test/smart_contract/token_generalized.js +0 -10
- package/tools/gen-brc220-batch-vector.js +205 -0
- package/version.js +1 -1
package/lib/covenant/helpers.js
CHANGED
|
@@ -23,42 +23,42 @@ var Signature = require('../crypto/signature')
|
|
|
23
23
|
// SIGHASH_ALL | SIGHASH_FORKID — the BSV default these covenants are built for.
|
|
24
24
|
var SIGHASH = Signature.SIGHASH_ALL | Signature.SIGHASH_FORKID // 0x41
|
|
25
25
|
|
|
26
|
-
// Post-Genesis consensus + STANDARD RELAY flags — what mainnet miners actually
|
|
27
|
-
// enforce. Includes SCRIPT_VERIFY_MINIMALDATA (every push must be minimal) and
|
|
28
|
-
// SCRIPT_VERIFY_LOW_S (canonical signatures). Verifying with these flags locally
|
|
29
|
-
// mirrors mainnet relay/consensus policy, so a covenant that passes here is
|
|
30
|
-
// expected to be accepted on broadcast — catch non-relayable scripts before then.
|
|
31
|
-
function flags () {
|
|
32
|
-
var I = Interpreter
|
|
33
|
-
return I.SCRIPT_VERIFY_P2SH |
|
|
34
|
-
I.SCRIPT_VERIFY_STRICTENC |
|
|
35
|
-
I.SCRIPT_VERIFY_DERSIG |
|
|
36
|
-
I.SCRIPT_VERIFY_LOW_S |
|
|
37
|
-
I.SCRIPT_VERIFY_MINIMALDATA |
|
|
38
|
-
I.SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY |
|
|
39
|
-
I.SCRIPT_VERIFY_CHECKSEQUENCEVERIFY |
|
|
40
|
-
I.SCRIPT_ENABLE_SIGHASH_FORKID |
|
|
41
|
-
I.SCRIPT_ENABLE_MAGNETIC_OPCODES |
|
|
42
|
-
I.SCRIPT_ENABLE_MONOLITH_OPCODES |
|
|
43
|
-
// REQUIRED, not optional. pushTxCore emits OP_RIGHT/OP_LEFT — see
|
|
44
|
-
// extractHashOutputs and assertSighashType — and those bytes (180/181) are
|
|
45
|
-
// upgradable NOPs on the network until Chronicle activates. Without this
|
|
46
|
-
// flag the interpreter treats them as no-ops, exactly as a pre-Chronicle
|
|
47
|
-
// node does, and the covenant does not verify.
|
|
48
|
-
//
|
|
49
|
-
// Stated plainly: OP_PUSH_TX covenants built by this library DEPEND on
|
|
50
|
-
// Chronicle and cannot be spent on a pre-Chronicle chain. That was
|
|
51
|
-
// previously invisible because the interpreter ran the string opcodes
|
|
52
|
-
// unconditionally — more permissively than the network.
|
|
53
|
-
I.SCRIPT_ENABLE_CHRONICLE
|
|
54
|
-
}
|
|
55
|
-
|
|
56
26
|
/**
|
|
57
|
-
*
|
|
58
|
-
*
|
|
27
|
+
* Current BSV mainnet consensus + standard relay flags — what miners actually
|
|
28
|
+
* enforce. A covenant that verifies here is expected to be accepted on broadcast.
|
|
29
|
+
*
|
|
30
|
+
* This DELEGATES to Interpreter.mainnetFlags() rather than assembling a list, and
|
|
31
|
+
* that is the whole point. Until 8.4.0 it was hand-assembled, and the hand-written
|
|
32
|
+
* list omitted the three UTXO-ERA flags — SCRIPT_GENESIS, SCRIPT_UTXO_AFTER_GENESIS
|
|
33
|
+
* and SCRIPT_UTXO_AFTER_CHRONICLE. It carried SCRIPT_ENABLE_CHRONICLE, which enables
|
|
34
|
+
* the string opcodes, so the omission was easy to miss: the opcodes ran, and only the
|
|
35
|
+
* *limits* were wrong.
|
|
36
|
+
*
|
|
37
|
+
* The era flags are what the interpreter derives its data limits from. Without them
|
|
38
|
+
* every covenant was verified under PRE-GENESIS rules — a 520-byte element cap that
|
|
39
|
+
* BSV removed in February 2020. An OP_PUSH_TX preimage is ~585 bytes, so this
|
|
40
|
+
* library's flagship feature could not verify against its own harness, and
|
|
41
|
+
* `enableGenesis()` existed to paper over it by raising process-wide statics. That
|
|
42
|
+
* was treating the symptom: raising the statics cannot enable post-Genesis
|
|
43
|
+
* arithmetic (only the era flags can) and it weakens pre-Genesis validation, turning
|
|
44
|
+
* 15 of the reference node's 22 SCRIPTNUM_OVERFLOW vectors into false accepts.
|
|
45
|
+
*
|
|
46
|
+
* Delegating also means the covenant path tracks consensus automatically instead of
|
|
47
|
+
* drifting the next time an era activates. `mainnetFlags()` is the same function the
|
|
48
|
+
* Interpreter uses for a no-flags verify(), so "verify locally" and "what the network
|
|
49
|
+
* does" cannot diverge again without both moving together.
|
|
50
|
+
*
|
|
51
|
+
* Two flags in the old list are deliberately gone: SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY
|
|
52
|
+
* and SCRIPT_VERIFY_CHECKSEQUENCEVERIFY. Genesis reverted OP_CLTV/OP_CSV to
|
|
53
|
+
* upgradable NOPs for outputs created after it (see interpreter.js, the
|
|
54
|
+
* `isAfterGenesis()` short-circuit), so once the era flags are present these two
|
|
55
|
+
* change nothing. Keeping them would have implied a time-lock guarantee mainnet does
|
|
56
|
+
* not provide, which is why the CLTV-based locks were removed in 9.0.0.
|
|
57
|
+
*
|
|
58
|
+
* NULLFAIL is gained, which is strictly stricter.
|
|
59
59
|
*/
|
|
60
|
-
function
|
|
61
|
-
return Interpreter.
|
|
60
|
+
function flags () {
|
|
61
|
+
return Interpreter.mainnetFlags()
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
/**
|
|
@@ -135,7 +135,6 @@ function scriptNum (n) {
|
|
|
135
135
|
module.exports = {
|
|
136
136
|
SIGHASH: SIGHASH,
|
|
137
137
|
flags: flags,
|
|
138
|
-
enableGenesis: enableGenesis,
|
|
139
138
|
verify: verify,
|
|
140
139
|
rawPreimage: rawPreimage,
|
|
141
140
|
sighashDigest: sighashDigest,
|
package/lib/covenant/pushtx.js
CHANGED
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
* Optimal parameters: private key a = 1, ephemeral k = 1 => r = Gx,
|
|
14
14
|
* s = (e + Gx) mod n, pubkey P = 02||Gx, e = HASH256(preimage).
|
|
15
15
|
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
16
|
+
* Verifies under mainnet consensus flags with no opt-in (8.4.0+). Earlier versions
|
|
17
|
+
* required SmartContract.enableGenesis() first; that call is now a deprecated no-op.
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
20
|
var Script = require('../script')
|
|
@@ -71,22 +71,6 @@ class CustomScriptHelper {
|
|
|
71
71
|
return script;
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
/**
|
|
75
|
-
* Create a time-locked script (CHECKLOCKTIMEVERIFY)
|
|
76
|
-
* @param {number} lockTime - Block height or timestamp
|
|
77
|
-
* @param {Script} baseScript - Base script to execute after time lock
|
|
78
|
-
* @returns {Script} Time-locked script
|
|
79
|
-
*/
|
|
80
|
-
static createTimelockScript(lockTime, baseScript) {
|
|
81
|
-
const lockTimeBuffer = Buffer.from(lockTime.toString(16).padStart(8, '0'), 'hex').reverse();
|
|
82
|
-
|
|
83
|
-
return new Script()
|
|
84
|
-
.add(lockTimeBuffer)
|
|
85
|
-
.add(Opcode.OP_CHECKLOCKTIMEVERIFY)
|
|
86
|
-
.add(Opcode.OP_DROP)
|
|
87
|
-
.add(baseScript.toBuffer());
|
|
88
|
-
}
|
|
89
|
-
|
|
90
74
|
/**
|
|
91
75
|
* Create a conditional script (IF/ELSE/ENDIF)
|
|
92
76
|
* @param {Script} ifScript - Script to execute if condition is true
|
package/lib/notaryhash/index.js
CHANGED
|
@@ -241,6 +241,26 @@ NotaryHash.verifyBatchInclusion = function (certificate) {
|
|
|
241
241
|
var m = certificate.merkle
|
|
242
242
|
if (!m) return { valid: false, errors: ['batch certificate has no merkle proof'] }
|
|
243
243
|
|
|
244
|
+
// THE LEAF IS proofHash, NOT canonicalBytes.
|
|
245
|
+
//
|
|
246
|
+
// BRC-220 §On-chain record says the batch tree is RFC 6962 and writes
|
|
247
|
+
// `leaf = SHA256(0x00 ‖ d)` — but that is RFC 6962's own generic notation for the
|
|
248
|
+
// construction, and the spec never binds `d` to a value. `canonicalBytes` appears
|
|
249
|
+
// once in the whole document, in the proofHash definition, and nowhere in the batch
|
|
250
|
+
// text.
|
|
251
|
+
//
|
|
252
|
+
// So this is a choice the implementation had to make, and it is:
|
|
253
|
+
//
|
|
254
|
+
// leaf = SHA-256(0x00 ‖ proofHash) = SHA-256(0x00 ‖ SHA-256(canonicalBytes))
|
|
255
|
+
//
|
|
256
|
+
// The other reading — d = canonicalBytes — is equally sound cryptographically and
|
|
257
|
+
// produces a DIFFERENT root. A certificate built that way fails inclusion here with
|
|
258
|
+
// no error naming the cause: the fold simply does not reach the root. Anyone building
|
|
259
|
+
// batches with the exported NotaryHash.Merkle must use proofHash as the leaf datum.
|
|
260
|
+
//
|
|
261
|
+
// Reasoning and the proposed spec text: docs/BRC220_BATCH_LEAF_AMENDMENT.md.
|
|
262
|
+
// Enforced by test/notaryhash/batch_leaf.js, which checks that a canonicalBytes-leaf
|
|
263
|
+
// tree is rejected rather than trusting the comment.
|
|
244
264
|
var leafData = Buffer.from(certificate.proofHash, 'hex')
|
|
245
265
|
var path = (m.path || []).map(function (node) {
|
|
246
266
|
return Buffer.isBuffer(node) ? node : Buffer.from(node, 'hex')
|
package/lib/notaryhash/merkle.js
CHANGED
|
@@ -26,6 +26,14 @@ var $ = require('../util/preconditions')
|
|
|
26
26
|
* root. Every non-power-of-two tree depends on getting this right.
|
|
27
27
|
*/
|
|
28
28
|
|
|
29
|
+
/**
|
|
30
|
+
* For BRC-220 batch mode the leaf datum `d` is a certificate's **proofHash**, so a leaf
|
|
31
|
+
* is `SHA-256(0x00 ‖ proofHash)`. The spec writes `leaf = SHA256(0x00 ‖ d)` using
|
|
32
|
+
* RFC 6962's generic notation and never binds `d`; passing `canonicalBytes` instead is
|
|
33
|
+
* equally sound and yields a different root, which NotaryHash.verifyBatchInclusion will
|
|
34
|
+
* reject. See docs/BRC220_BATCH_LEAF_AMENDMENT.md.
|
|
35
|
+
*/
|
|
36
|
+
|
|
29
37
|
var Merkle = {}
|
|
30
38
|
|
|
31
39
|
/** Prefix bytes, per RFC 6962 §2.1. */
|
package/lib/notaryhash/suites.js
CHANGED
|
@@ -146,7 +146,23 @@ Suites.register('ECDSA-secp256k1', {
|
|
|
146
146
|
|
|
147
147
|
var ecdsa = new ECDSA()
|
|
148
148
|
ecdsa.hashbuf = payloadHash
|
|
149
|
-
|
|
149
|
+
// NO endian override. `payloadHash` is the scalar, big-endian, exactly as the
|
|
150
|
+
// 32 bytes are given — which is what every other ECDSA implementation does and
|
|
151
|
+
// what BRC-220 means by "signs the payloadHash".
|
|
152
|
+
//
|
|
153
|
+
// 8.3.0 set `endian = 'little'` here, which made ECDSA reverse the digest before
|
|
154
|
+
// reducing it to the scalar. That is Bitcoin's message-signing convention, not
|
|
155
|
+
// this protocol's, and it is why lib/crypto/ecdsa.js offers the option at all.
|
|
156
|
+
//
|
|
157
|
+
// The effect was on the VERIFY side: a signature produced the way BRC-220
|
|
158
|
+
// specifies was rejected, and the only signatures accepted were ones made with
|
|
159
|
+
// bsv's own little-endian convention. Every test in this repo signed that way
|
|
160
|
+
// too, so the module and its tests were self-consistent and wrong together —
|
|
161
|
+
// the exact failure shape test/notaryhash/encoding.js warns about in its header.
|
|
162
|
+
//
|
|
163
|
+
// test/notaryhash/interop.js now pins this against @noble/curves, which shares
|
|
164
|
+
// no verification code with lib/crypto/ecdsa.js. A second implementation is the
|
|
165
|
+
// only thing that can catch a defect where the code and its tests agree.
|
|
150
166
|
ecdsa.pubkey = pubkey
|
|
151
167
|
ecdsa.sig = sig
|
|
152
168
|
return ecdsa.verify() === true
|
package/lib/ordinals/ordlock.js
CHANGED
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
* OP_ENDIF
|
|
36
36
|
* [OP_FALSE OP_IF "ord" … OP_ENDIF] // optional inert inscription envelope
|
|
37
37
|
*
|
|
38
|
-
*
|
|
38
|
+
* Verifies under mainnet consensus flags with no opt-in (8.4.0+).
|
|
39
39
|
*/
|
|
40
40
|
var P = require('../covenant/pushtx')
|
|
41
41
|
var H = require('../covenant/helpers')
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
* Step-traces a locking/unlocking pair through Script.Interpreter and records the
|
|
6
6
|
* stack + alt-stack after every opcode, so you can watch an OP_PUSH_TX covenant
|
|
7
7
|
* build its signature and enforce its constraints. Uses the interpreter's
|
|
8
|
-
* stepListener hook.
|
|
9
|
-
*
|
|
8
|
+
* stepListener hook. No opt-in is needed since 8.4.0: covenants verify under mainnet
|
|
9
|
+
* consensus flags, whose era bits lift the pre-Genesis element and opcode caps.
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
var Interpreter = require('../script/interpreter')
|
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
* // c.unlock(spendTx, satoshis) -> grinds + returns the preimage unlock Script
|
|
15
15
|
*
|
|
16
16
|
* Each clause compiles to one preimage-field check on top of a single OP_PUSH_TX
|
|
17
|
-
* authentication; clauses AND together.
|
|
18
|
-
*
|
|
17
|
+
* authentication; clauses AND together. Verifies under mainnet consensus flags with
|
|
18
|
+
* no opt-in (8.4.0+).
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
21
|
var PushTx = require('../covenant/pushtx')
|
|
@@ -70,9 +70,6 @@ SmartContract.trace = function (unlockingScript, lockingScript, opts) {
|
|
|
70
70
|
|
|
71
71
|
// --- Covenant convenience API (v4.2.0) ---
|
|
72
72
|
// Opt into post-Genesis script limits (required by OP_PUSH_TX covenants).
|
|
73
|
-
SmartContract.enableGenesis = function (max) {
|
|
74
|
-
return SmartContract.CovenantHelpers.enableGenesis(max)
|
|
75
|
-
}
|
|
76
73
|
// Verify an unlocking/locking pair through the consensus interpreter.
|
|
77
74
|
SmartContract.verifyScript = function (unlockingScript, lockingScript, opts) {
|
|
78
75
|
return SmartContract.CovenantHelpers.verify(unlockingScript, lockingScript, opts)
|
|
@@ -10,7 +10,6 @@ var H = require('../covenant/helpers')
|
|
|
10
10
|
var Script = require('../script')
|
|
11
11
|
var Opcode = require('../opcode')
|
|
12
12
|
var signInput = H.signInput
|
|
13
|
-
var n = H.scriptNum
|
|
14
13
|
|
|
15
14
|
/** Hash-lock: reveal a preimage whose SHA-256 matches a digest. */
|
|
16
15
|
function hashLock (secret) {
|
|
@@ -36,20 +35,6 @@ function p2pkh (privateKey) {
|
|
|
36
35
|
}
|
|
37
36
|
}
|
|
38
37
|
|
|
39
|
-
/** CLTV absolute time-lock: <locktime> CLTV DROP <pk> CHECKSIG. */
|
|
40
|
-
function timeLockCLTV (privateKey, locktime) {
|
|
41
|
-
var pub = privateKey.toPublicKey()
|
|
42
|
-
var lock = new Script()
|
|
43
|
-
.add(n(locktime)).add(Opcode.OP_CHECKLOCKTIMEVERIFY).add(Opcode.OP_DROP)
|
|
44
|
-
.add(pub.toBuffer()).add(Opcode.OP_CHECKSIG)
|
|
45
|
-
return {
|
|
46
|
-
lock: lock,
|
|
47
|
-
meta: { name: 'cltv-timelock', locktime: locktime },
|
|
48
|
-
// Caller must set spend.nLockTime >= locktime and input sequence < 0xffffffff.
|
|
49
|
-
unlock: function (spend, sats) { return new Script().add(signInput(spend, privateKey, 0, lock, sats)) }
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
38
|
/** m-of-n multisig. */
|
|
54
39
|
function multisig (m, privateKeys) {
|
|
55
40
|
var pubs = privateKeys.map(function (k) { return k.toPublicKey() })
|
|
@@ -68,33 +53,8 @@ function multisig (m, privateKeys) {
|
|
|
68
53
|
}
|
|
69
54
|
}
|
|
70
55
|
|
|
71
|
-
/** HTLC: hash-OR-timeout. */
|
|
72
|
-
function htlc (opts) {
|
|
73
|
-
var digest = Hash.sha256(opts.secret)
|
|
74
|
-
var lock = new Script()
|
|
75
|
-
.add(Opcode.OP_IF)
|
|
76
|
-
.add(Opcode.OP_SHA256).add(digest).add(Opcode.OP_EQUALVERIFY)
|
|
77
|
-
.add(opts.receiver.toPublicKey().toBuffer()).add(Opcode.OP_CHECKSIG)
|
|
78
|
-
.add(Opcode.OP_ELSE)
|
|
79
|
-
.add(n(opts.timeout)).add(Opcode.OP_CHECKLOCKTIMEVERIFY).add(Opcode.OP_DROP)
|
|
80
|
-
.add(opts.sender.toPublicKey().toBuffer()).add(Opcode.OP_CHECKSIG)
|
|
81
|
-
.add(Opcode.OP_ENDIF)
|
|
82
|
-
return {
|
|
83
|
-
lock: lock,
|
|
84
|
-
meta: { name: 'htlc', digest: digest.toString('hex'), timeout: opts.timeout },
|
|
85
|
-
unlockClaim: function (spend, sats) {
|
|
86
|
-
return new Script().add(signInput(spend, opts.receiver, 0, lock, sats)).add(opts.secret).add(Opcode.OP_1)
|
|
87
|
-
},
|
|
88
|
-
unlockRefund: function (spend, sats) {
|
|
89
|
-
return new Script().add(signInput(spend, opts.sender, 0, lock, sats)).add(Opcode.OP_0)
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
56
|
module.exports = {
|
|
95
57
|
hashLock: hashLock,
|
|
96
58
|
p2pkh: p2pkh,
|
|
97
|
-
|
|
98
|
-
multisig: multisig,
|
|
99
|
-
htlc: htlc
|
|
59
|
+
multisig: multisig
|
|
100
60
|
}
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* the slice preimage[104 : len-52] is exactly the `scriptlen||script` half of a
|
|
15
15
|
* TxOut, so the next output is `<newValue:8-LE> || preimage[104:len-52]`.
|
|
16
16
|
*
|
|
17
|
-
*
|
|
17
|
+
* Verifies under mainnet consensus flags with no opt-in (8.4.0+).
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
20
|
var P = require('../covenant/pushtx')
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
* surrounding output bytes and the token's value; the covenant binds them
|
|
37
37
|
* into the committed hashOutputs. Value conservation is left to the network.
|
|
38
38
|
*
|
|
39
|
-
*
|
|
39
|
+
* Verifies under mainnet consensus flags with no opt-in (8.4.0+).
|
|
40
40
|
*/
|
|
41
41
|
|
|
42
42
|
var BN = require('../crypto/bn')
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@smartledger/bsv",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "9.0.0",
|
|
4
4
|
"description": "🚀 Complete Bitcoin SV development framework with legally-recognizable DID:web + W3C VC-JWT toolkit, Legal Token Protocol (LTP), Global Digital Attestation Framework (GDAF), StatusList2021 revocation, and 16 flexible loading options. Standards-based credentials with ES256/ES256K support, on-chain BSV anchoring, and comprehensive Bitcoin SV API. Perfect for legal tokens, verifiable credentials, DeFi, smart contracts, and secure Bitcoin applications.",
|
|
5
5
|
"author": "SmartLedger Technology <hello@smartledger.technology> (https://smartledger.technology)",
|
|
6
6
|
"homepage": "https://github.com/codenlighten/smartledger-bsv#readme",
|
|
@@ -65,6 +65,7 @@
|
|
|
65
65
|
"vectors:sv-tx": "node tools/sv-tx-report.js",
|
|
66
66
|
"vectors:sv-sighash": "node tools/sv-sighash-report.js",
|
|
67
67
|
"conformance:generate": "node conformance/generate.js",
|
|
68
|
+
"check:readme": "node scripts/check-readme-accuracy.js",
|
|
68
69
|
"lint:ratchet": "node scripts/lint-ratchet.js",
|
|
69
70
|
"lint:ratchet:update": "node scripts/lint-ratchet.js --update",
|
|
70
71
|
"test": "mocha",
|
|
@@ -97,7 +98,7 @@
|
|
|
97
98
|
"test:browser": "echo 'Open tests/standalone-modules-test.html in browser for comprehensive testing'",
|
|
98
99
|
"test:bundle": "echo 'Open tests/bundle-completeness-test.html in browser to verify bundle completeness'",
|
|
99
100
|
"preimage:extract": "node examples/preimage/extract_preimage_bidirectional.js",
|
|
100
|
-
"prepublishOnly": "npm run build-all",
|
|
101
|
+
"prepublishOnly": "npm run build-all && npm run check:readme",
|
|
101
102
|
"sync-cdn": "node scripts/sync-cdn-urls.js",
|
|
102
103
|
"version": "node scripts/sync-cdn-urls.js && node scripts/sync-version.js && node scripts/gen-esm-wrapper.js && git add README.md docs version.js index.mjs",
|
|
103
104
|
"test:browser:ci": "node tests/browser-smoke-runner.js"
|
|
@@ -43,9 +43,30 @@ describe('ESM wrapper (index.mjs)', function () {
|
|
|
43
43
|
var bsv = require('../..')
|
|
44
44
|
var names = gen.exportableNames(bsv)
|
|
45
45
|
names.length.should.be.above(100)
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
// The library currently has NO accessor properties — bsv.SmartUTXO, the last one,
|
|
49
|
+
// was removed in 9.0.0. The exclusion rule still matters: re-exporting a getter as a
|
|
50
|
+
// named ESM binding evaluates it at import time, which for a deprecated accessor
|
|
51
|
+
// means a warning (or worse, a side effect) fires on a bare `import`. Testing that
|
|
52
|
+
// against a synthetic accessor keeps the guarantee under test instead of letting it
|
|
53
|
+
// rot untested until someone adds a getter back.
|
|
54
|
+
itFromCheckout('excludes accessor properties from the named bindings', function () {
|
|
55
|
+
var bsv = require('../..')
|
|
56
|
+
var probe = '__esmAccessorProbe__'
|
|
57
|
+
var touched = false
|
|
58
|
+
Object.defineProperty(bsv, probe, {
|
|
59
|
+
configurable: true,
|
|
60
|
+
enumerable: true,
|
|
61
|
+
get: function () { touched = true; return 1 }
|
|
62
|
+
})
|
|
63
|
+
try {
|
|
64
|
+
var names = gen.exportableNames(bsv)
|
|
65
|
+
names.should.not.include(probe)
|
|
66
|
+
touched.should.equal(false, 'exportableNames must not invoke the getter')
|
|
67
|
+
} finally {
|
|
68
|
+
delete bsv[probe]
|
|
69
|
+
}
|
|
49
70
|
})
|
|
50
71
|
|
|
51
72
|
it('resolves real ESM default + named imports natively', function () {
|
|
@@ -55,9 +76,9 @@ describe('ESM wrapper (index.mjs)', function () {
|
|
|
55
76
|
'PrivateKey === bsv.PrivateKey && typeof crypto.ECDSA === "function") ? 0 : 3)')
|
|
56
77
|
})
|
|
57
78
|
|
|
58
|
-
it('
|
|
59
|
-
// Re-exporting
|
|
60
|
-
// must be empty for a bare `import './index.mjs'`.
|
|
79
|
+
it('emits nothing on stderr at import', function () {
|
|
80
|
+
// Re-exporting a deprecated getter would trip its console.warn at import time;
|
|
81
|
+
// stderr must be empty for a bare `import './index.mjs'`.
|
|
61
82
|
var res = spawnSync(process.execPath,
|
|
62
83
|
['--input-type=module', '-e', 'import ' + JSON.stringify('./index.mjs') + ';'],
|
|
63
84
|
{ cwd: ROOT, encoding: 'utf8' })
|
|
@@ -65,9 +86,12 @@ describe('ESM wrapper (index.mjs)', function () {
|
|
|
65
86
|
res.stderr.should.equal('')
|
|
66
87
|
})
|
|
67
88
|
|
|
68
|
-
it('
|
|
89
|
+
it('no longer exposes bsv.SmartUTXO, which was removed in 9.0.0', function () {
|
|
90
|
+
// Deliberately asserted rather than dropped: the namespace export is gone, and the
|
|
91
|
+
// module is reached by direct import — require('@smartledger/bsv/lib/smartutxo') —
|
|
92
|
+
// which is what its deprecation warning instructed from 4.0.1 onward.
|
|
69
93
|
runEsm(
|
|
70
94
|
'import bsv from ' + JSON.stringify('./index.mjs') + ';' +
|
|
71
|
-
'process.exit(("SmartUTXO" in bsv) ?
|
|
95
|
+
'process.exit(("SmartUTXO" in bsv) ? 3 : 0)')
|
|
72
96
|
})
|
|
73
97
|
})
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_comment": "BRC-220 batch-mode golden vector. Generated by tools/gen-brc220-batch-vector.js; do not hand-edit. Every value is derived from the labelled preimages recorded on each proof, so the file is reproducible from scratch in any language. THE POINT OF THIS FILE: BRC-220 writes the batch leaf as SHA256(0x00 || d) and never says what d is. This vector fixes d = proofHash. The `rejectedReading` block records what the same five proofs produce under d = canonicalBytes — equally sound cryptographically, a different root, and therefore not interoperable. An implementation matching `rejectedReading.root` has made the other choice, which is exactly the confusion this vector exists to make visible. This is a conformance target produced by @smartledger/bsv, not external validation. The tree beneath it is externally anchored: the RFC 6962 construction is verified against the published Certificate Transparency roots in test/notaryhash/merkle.js. n = 5 deliberately: RFC 6962 splits at the largest power of two BELOW n, so this splits 4/1 (a midpoint split would give 2/3 and a different root), and the odd count exercises the rule that the last leaf is never duplicated.",
|
|
3
|
+
"spec": "BRC-220",
|
|
4
|
+
"tree": "RFC 6962",
|
|
5
|
+
"leafDatum": "proofHash",
|
|
6
|
+
"leafRule": "leaf = SHA-256(0x00 || proofHash); node = SHA-256(0x01 || left || right)",
|
|
7
|
+
"leafCount": 5,
|
|
8
|
+
"root": "abb53eb3b2e3530d51685c6813bb85c85892d2f214c2dc504029d071434ac074",
|
|
9
|
+
"onChainRecordTail": {
|
|
10
|
+
"_comment": "The batch record is \"NOTARYHASH\" | u8(1) | u8(2) | merkleRoot(32) | u32be(leafCount).",
|
|
11
|
+
"merkleRoot": "abb53eb3b2e3530d51685c6813bb85c85892d2f214c2dc504029d071434ac074",
|
|
12
|
+
"leafCountU32be": "00000005"
|
|
13
|
+
},
|
|
14
|
+
"rejectedReading": {
|
|
15
|
+
"_comment": "What d = canonicalBytes yields over the SAME five proofs. Recorded so the divergence is checkable, not to endorse it.",
|
|
16
|
+
"leafDatum": "canonicalBytes",
|
|
17
|
+
"root": "4a59ade74941e4d6ca4b7c9f610e0a01a0c3f24cfa94efe816e53ef85f99e324"
|
|
18
|
+
},
|
|
19
|
+
"proofs": [
|
|
20
|
+
{
|
|
21
|
+
"leafIndex": 0,
|
|
22
|
+
"keyPreimage": "BRC-220/batch-vector/key/0",
|
|
23
|
+
"payloadPreimage": "BRC-220/batch-vector/payload/0",
|
|
24
|
+
"algorithm": "ECDSA-secp256k1",
|
|
25
|
+
"hashAlgorithm": "SHA-256",
|
|
26
|
+
"encoding": "raw",
|
|
27
|
+
"payloadHash": "c61d9c7e35b46dc1ceea30094e1a2809d45d16014fa70ccfc75fc4d6f672643b",
|
|
28
|
+
"publicKey": "02ce29a831e3d359386c7f70ef7fd85a75d79168d546dd8a60a520df0e24c65ef3",
|
|
29
|
+
"signature": "1026f99510a52863e43e3e5a57395c9838a3e44a768932d35b460a287630c24e3bc3b81e1bb2cb7c834f5be97936a6a49ff9eb7adaae7670e32d6bc3a5c067cf",
|
|
30
|
+
"createdAt": "2026-01-01T00:00:00.000Z",
|
|
31
|
+
"createdAtUnix": 1767225600,
|
|
32
|
+
"canonicalBytes": "0000000e4e6f74617279486173682f312e30010000000f45434453412d736563703235366b31000000075348412d32353600000020c61d9c7e35b46dc1ceea30094e1a2809d45d16014fa70ccfc75fc4d6f672643b0000002102ce29a831e3d359386c7f70ef7fd85a75d79168d546dd8a60a520df0e24c65ef3000000401026f99510a52863e43e3e5a57395c9838a3e44a768932d35b460a287630c24e3bc3b81e1bb2cb7c834f5be97936a6a49ff9eb7adaae7670e32d6bc3a5c067cf000000006955b900",
|
|
33
|
+
"proofHash": "83f3f73ebc5146b96cce1ee0b6ed4fd251a933a5332fbe5e5ab80da7920fe2c9",
|
|
34
|
+
"leafHash": "27547ba238fba426b766979a4a46cd97578945cf450c113e45b487291cb56ba4",
|
|
35
|
+
"leafHashUnderRejectedReading": "ab0ee539d3e08e07a6aac157af2d3df5da5f637c5c360fa158a00d14c6644f05",
|
|
36
|
+
"path": [
|
|
37
|
+
"7cd7c9b4bc74dcc5d586f7b04f1f7bdf025a15f7e173dba021c8ed7fd84acdbf",
|
|
38
|
+
"15c4df48172c7607990059e0f646616f7e68a33f8f5e1a7b54a9fa5ee770bbb4",
|
|
39
|
+
"8591a9b65f86529312b0eae212a95c15fd407f36cb8f4872a01bc0a64f13df83"
|
|
40
|
+
]
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"leafIndex": 1,
|
|
44
|
+
"keyPreimage": "BRC-220/batch-vector/key/1",
|
|
45
|
+
"payloadPreimage": "BRC-220/batch-vector/payload/1",
|
|
46
|
+
"algorithm": "ECDSA-secp256k1",
|
|
47
|
+
"hashAlgorithm": "SHA-256",
|
|
48
|
+
"encoding": "raw",
|
|
49
|
+
"payloadHash": "7509fe7fc39be0a6a6fc7350287f96a03911c8a3af188d8fb4b42f92957562a1",
|
|
50
|
+
"publicKey": "02b3dfb7e2a167aa401547d93e1b684b6c9896b67d3aadb7d938cdb00040e64ce3",
|
|
51
|
+
"signature": "1014debea11afb698d3fe0778bfd6390efdb28f8fe160eb4f382213f35641afd4a308a159d342a7507873fff587eaad5ae73eed047b1dbb27ee2b6b0924f6d60",
|
|
52
|
+
"createdAt": "2026-01-02T00:00:00.000Z",
|
|
53
|
+
"createdAtUnix": 1767312000,
|
|
54
|
+
"canonicalBytes": "0000000e4e6f74617279486173682f312e30010000000f45434453412d736563703235366b31000000075348412d323536000000207509fe7fc39be0a6a6fc7350287f96a03911c8a3af188d8fb4b42f92957562a10000002102b3dfb7e2a167aa401547d93e1b684b6c9896b67d3aadb7d938cdb00040e64ce3000000401014debea11afb698d3fe0778bfd6390efdb28f8fe160eb4f382213f35641afd4a308a159d342a7507873fff587eaad5ae73eed047b1dbb27ee2b6b0924f6d600000000069570a80",
|
|
55
|
+
"proofHash": "29fca10808a3653efbe38abd5f0b926aa09f13bff7847475139a422869729e77",
|
|
56
|
+
"leafHash": "7cd7c9b4bc74dcc5d586f7b04f1f7bdf025a15f7e173dba021c8ed7fd84acdbf",
|
|
57
|
+
"leafHashUnderRejectedReading": "320aeefe6077a6163d6d72bda3b54443bb973220ef94a448e7e8c9be787f1242",
|
|
58
|
+
"path": [
|
|
59
|
+
"27547ba238fba426b766979a4a46cd97578945cf450c113e45b487291cb56ba4",
|
|
60
|
+
"15c4df48172c7607990059e0f646616f7e68a33f8f5e1a7b54a9fa5ee770bbb4",
|
|
61
|
+
"8591a9b65f86529312b0eae212a95c15fd407f36cb8f4872a01bc0a64f13df83"
|
|
62
|
+
]
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"leafIndex": 2,
|
|
66
|
+
"keyPreimage": "BRC-220/batch-vector/key/2",
|
|
67
|
+
"payloadPreimage": "BRC-220/batch-vector/payload/2",
|
|
68
|
+
"algorithm": "ECDSA-secp256k1",
|
|
69
|
+
"hashAlgorithm": "SHA-256",
|
|
70
|
+
"encoding": "raw",
|
|
71
|
+
"payloadHash": "b09ac5900c811654d3c31b43ad6c65512f9baa6585b121bdc88f43b40cbc55a0",
|
|
72
|
+
"publicKey": "02363ba0177d207ee13a23b63c9feb5c297e071c88c1d859312bf7cb46778b17f7",
|
|
73
|
+
"signature": "726113d4d8dafbe8f03b89377ffad4a4086ee30450c3e03ea62ae30d26c216091147dbfb36fa6c6f7e7e59eeae21c9b379e8fd012c7f8b87ac4ff416981dff11",
|
|
74
|
+
"createdAt": "2026-01-03T00:00:00.000Z",
|
|
75
|
+
"createdAtUnix": 1767398400,
|
|
76
|
+
"canonicalBytes": "0000000e4e6f74617279486173682f312e30010000000f45434453412d736563703235366b31000000075348412d32353600000020b09ac5900c811654d3c31b43ad6c65512f9baa6585b121bdc88f43b40cbc55a00000002102363ba0177d207ee13a23b63c9feb5c297e071c88c1d859312bf7cb46778b17f700000040726113d4d8dafbe8f03b89377ffad4a4086ee30450c3e03ea62ae30d26c216091147dbfb36fa6c6f7e7e59eeae21c9b379e8fd012c7f8b87ac4ff416981dff110000000069585c00",
|
|
77
|
+
"proofHash": "3c44828bea3ca01dfcd5305a839ce02cc1e855f5a7c7028bb4931d42dea3aa2b",
|
|
78
|
+
"leafHash": "9419bb538d2bb38e931ea45f2a6e83d38f99bf2679f6e31cd02145e68cda1d54",
|
|
79
|
+
"leafHashUnderRejectedReading": "b6beedf0fd93c2d32fe08db38242ec737e9f03605c457f0910ab42ff0f7c2eed",
|
|
80
|
+
"path": [
|
|
81
|
+
"341883196d41f5956f6b87238f71018be2bfc6ced6676ba64f5b1b0369b199a5",
|
|
82
|
+
"503a52c36f87e417987746db6964fbc21a177f034cc58639784e1e5b313cc7e4",
|
|
83
|
+
"8591a9b65f86529312b0eae212a95c15fd407f36cb8f4872a01bc0a64f13df83"
|
|
84
|
+
]
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"leafIndex": 3,
|
|
88
|
+
"keyPreimage": "BRC-220/batch-vector/key/3",
|
|
89
|
+
"payloadPreimage": "BRC-220/batch-vector/payload/3",
|
|
90
|
+
"algorithm": "ECDSA-secp256k1",
|
|
91
|
+
"hashAlgorithm": "SHA-256",
|
|
92
|
+
"encoding": "raw",
|
|
93
|
+
"payloadHash": "158d3edf327c1994d7154f9271dadc5d96418b54713aafbbf9ad6c534bf3dbe2",
|
|
94
|
+
"publicKey": "02927267de13d07285b06122293a72350376cc85060b00b8426c48e0cb2e39e2f9",
|
|
95
|
+
"signature": "8c1625d984577226d3f229d83aa1b3025821d1ef076b890f21667c62f49508640eaeb5ac1bfc2250a0b475653a598fa5f69f28b7e23aad18986a6f4a468d490b",
|
|
96
|
+
"createdAt": "2026-01-04T00:00:00.000Z",
|
|
97
|
+
"createdAtUnix": 1767484800,
|
|
98
|
+
"canonicalBytes": "0000000e4e6f74617279486173682f312e30010000000f45434453412d736563703235366b31000000075348412d32353600000020158d3edf327c1994d7154f9271dadc5d96418b54713aafbbf9ad6c534bf3dbe20000002102927267de13d07285b06122293a72350376cc85060b00b8426c48e0cb2e39e2f9000000408c1625d984577226d3f229d83aa1b3025821d1ef076b890f21667c62f49508640eaeb5ac1bfc2250a0b475653a598fa5f69f28b7e23aad18986a6f4a468d490b000000006959ad80",
|
|
99
|
+
"proofHash": "0692e22da9b68634e5384bb012324c140c676d2301e078a67f17e335661a9565",
|
|
100
|
+
"leafHash": "341883196d41f5956f6b87238f71018be2bfc6ced6676ba64f5b1b0369b199a5",
|
|
101
|
+
"leafHashUnderRejectedReading": "ca8d122b3f396533867bbe79cc0b878a3ece675ef636622cb321843cfc2b0a6c",
|
|
102
|
+
"path": [
|
|
103
|
+
"9419bb538d2bb38e931ea45f2a6e83d38f99bf2679f6e31cd02145e68cda1d54",
|
|
104
|
+
"503a52c36f87e417987746db6964fbc21a177f034cc58639784e1e5b313cc7e4",
|
|
105
|
+
"8591a9b65f86529312b0eae212a95c15fd407f36cb8f4872a01bc0a64f13df83"
|
|
106
|
+
]
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
"leafIndex": 4,
|
|
110
|
+
"keyPreimage": "BRC-220/batch-vector/key/4",
|
|
111
|
+
"payloadPreimage": "BRC-220/batch-vector/payload/4",
|
|
112
|
+
"algorithm": "ECDSA-secp256k1",
|
|
113
|
+
"hashAlgorithm": "SHA-256",
|
|
114
|
+
"encoding": "raw",
|
|
115
|
+
"payloadHash": "1c9be18eba3f6d45e49ba3cc651978d803c4a031e61e9c4ea0c5c4954d0fc7b8",
|
|
116
|
+
"publicKey": "02497aeb1118e5fe44af0aade81945dc23b8c727433a9d76e2ec37e914ce0467cf",
|
|
117
|
+
"signature": "c903ba5d61bdbd983168febeabba3997c8811a24cf4624f6952887f6dd50c9141d07a20abcb7e6822a1012f15c8b5df63d52d28b13cddf9efce451d2a020a953",
|
|
118
|
+
"createdAt": "2026-01-05T00:00:00.000Z",
|
|
119
|
+
"createdAtUnix": 1767571200,
|
|
120
|
+
"canonicalBytes": "0000000e4e6f74617279486173682f312e30010000000f45434453412d736563703235366b31000000075348412d323536000000201c9be18eba3f6d45e49ba3cc651978d803c4a031e61e9c4ea0c5c4954d0fc7b80000002102497aeb1118e5fe44af0aade81945dc23b8c727433a9d76e2ec37e914ce0467cf00000040c903ba5d61bdbd983168febeabba3997c8811a24cf4624f6952887f6dd50c9141d07a20abcb7e6822a1012f15c8b5df63d52d28b13cddf9efce451d2a020a95300000000695aff00",
|
|
121
|
+
"proofHash": "1a9c6bc1a6cf8319344ca8c30ca9e9eef8ab3df732748f6be2c824bb84ec0ca9",
|
|
122
|
+
"leafHash": "8591a9b65f86529312b0eae212a95c15fd407f36cb8f4872a01bc0a64f13df83",
|
|
123
|
+
"leafHashUnderRejectedReading": "40cfb9005011331c8cbb4524c27b04b3e62cbe525e07ec1dc443de25079b16d6",
|
|
124
|
+
"path": [
|
|
125
|
+
"060ca4e4bbcb647ab0162bb027cd8f08c1577aaa7069166dd629a3df7e57befd"
|
|
126
|
+
]
|
|
127
|
+
}
|
|
128
|
+
]
|
|
129
|
+
}
|