@smartledger/bsv 8.3.1 → 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 +91 -0
- package/README.md +74 -64
- 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 +82 -7
- 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/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 +1 -1
- package/test/build/esm_wrapper.js +32 -8
- package/test/data/brc220-batch-vector.json +129 -0
- package/test/notaryhash/batch_vector.js +282 -0
- 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
|
@@ -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",
|
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
/* global describe, it */
|
|
4
|
+
|
|
5
|
+
// The BRC-220 batch-mode golden vector.
|
|
6
|
+
//
|
|
7
|
+
// BRC-220 writes the batch leaf as `SHA256(0x00 ‖ d)` and never says what `d` is. Prose
|
|
8
|
+
// cannot reliably close that gap — two implementers read the same sentence and chose
|
|
9
|
+
// differently — so this file holds a concrete vector that any implementation can check
|
|
10
|
+
// itself against.
|
|
11
|
+
//
|
|
12
|
+
// What this vector is: a CONFORMANCE TARGET produced by this library. It is not external
|
|
13
|
+
// validation, and nothing here proves our reading is the one the spec intended. What makes
|
|
14
|
+
// it worth having is that the tree underneath it IS externally anchored — the RFC 6962
|
|
15
|
+
// construction is checked against the published Certificate Transparency roots in
|
|
16
|
+
// merkle.js. Given a tree that provably matches RFC 6962, this vector pins the one thing
|
|
17
|
+
// the spec leaves open.
|
|
18
|
+
//
|
|
19
|
+
// These tests rebuild every value from the recorded inputs rather than reading the
|
|
20
|
+
// recorded outputs back. A test that asserts `vector.root === vector.root` would pass
|
|
21
|
+
// forever while proving nothing, which is the failure mode this repository has fixed most
|
|
22
|
+
// often.
|
|
23
|
+
//
|
|
24
|
+
// See docs/BRC220_BATCH_LEAF_AMENDMENT.md and tools/gen-brc220-batch-vector.js.
|
|
25
|
+
|
|
26
|
+
require('chai').should()
|
|
27
|
+
var vector = require('../data/brc220-batch-vector.json')
|
|
28
|
+
var Hash = require('../../lib/crypto/hash')
|
|
29
|
+
var Encoding = require('../../lib/notaryhash/encoding')
|
|
30
|
+
var Merkle = require('../../lib/notaryhash/merkle')
|
|
31
|
+
var Suites = require('../../lib/notaryhash/suites')
|
|
32
|
+
var NotaryHash = require('../../lib/notaryhash')
|
|
33
|
+
var NotaryScript = require('../../lib/notaryhash/script')
|
|
34
|
+
var BN = require('../../lib/crypto/bn')
|
|
35
|
+
var PrivateKey = require('../../lib/privatekey')
|
|
36
|
+
// Deliberately a SECOND implementation: see the independent-verification test below.
|
|
37
|
+
var { secp256k1 } = require('@noble/curves/secp256k1.js')
|
|
38
|
+
|
|
39
|
+
function hex (s) { return Buffer.from(s, 'hex') }
|
|
40
|
+
|
|
41
|
+
describe('BRC-220 batch golden vector', function () {
|
|
42
|
+
describe('the vector describes the shape it claims', function () {
|
|
43
|
+
it('is five leaves, which is deliberate', function () {
|
|
44
|
+
// n=5 splits 4/1 under RFC 6962 (largest power of two BELOW n), where a midpoint
|
|
45
|
+
// split would give 2/3 and a different root. Odd n also exercises the rule that the
|
|
46
|
+
// last leaf is never duplicated. A power-of-two vector would catch neither.
|
|
47
|
+
vector.leafCount.should.equal(5)
|
|
48
|
+
vector.proofs.length.should.equal(5)
|
|
49
|
+
Merkle.largestPowerOfTwoBelow(5).should.equal(4)
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
it('names its tree and leaf datum explicitly', function () {
|
|
53
|
+
vector.tree.should.equal('RFC 6962')
|
|
54
|
+
vector.leafDatum.should.equal('proofHash')
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
// The 4/1 split shows up in the path lengths: the lone right-hand leaf needs one
|
|
58
|
+
// sibling, the four on the left need three. If a future change altered the split rule,
|
|
59
|
+
// this would move before any root did.
|
|
60
|
+
it('has path lengths matching a 4/1 split', function () {
|
|
61
|
+
vector.proofs.map(function (p) { return p.path.length })
|
|
62
|
+
.should.deep.equal([3, 3, 3, 3, 1])
|
|
63
|
+
})
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
describe('every input is derived, so the vector is reproducible', function () {
|
|
67
|
+
it('rebuilds each payloadHash from its recorded preimage', function () {
|
|
68
|
+
vector.proofs.forEach(function (p) {
|
|
69
|
+
Hash.sha256(Buffer.from(p.payloadPreimage, 'utf8')).toString('hex')
|
|
70
|
+
.should.equal(p.payloadHash, 'leaf ' + p.leafIndex)
|
|
71
|
+
})
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
it('records the preimage labels the generator actually uses', function () {
|
|
75
|
+
vector.proofs.forEach(function (p, i) {
|
|
76
|
+
p.keyPreimage.should.equal('BRC-220/batch-vector/key/' + i)
|
|
77
|
+
p.payloadPreimage.should.equal('BRC-220/batch-vector/payload/' + i)
|
|
78
|
+
})
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
it('uses raw encoding: 64-byte signatures and 33-byte compressed keys', function () {
|
|
82
|
+
vector.proofs.forEach(function (p) {
|
|
83
|
+
p.encoding.should.equal('raw')
|
|
84
|
+
hex(p.signature).length.should.equal(64, 'leaf ' + p.leafIndex + ' signature')
|
|
85
|
+
hex(p.publicKey).length.should.equal(33, 'leaf ' + p.leafIndex + ' publicKey')
|
|
86
|
+
})
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
it('rebuilds createdAtUnix from the recorded ISO timestamp', function () {
|
|
90
|
+
vector.proofs.forEach(function (p) {
|
|
91
|
+
Encoding.toUnixSeconds(p.createdAt).should.equal(p.createdAtUnix)
|
|
92
|
+
})
|
|
93
|
+
})
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
describe('every proof stands on its own', function () {
|
|
97
|
+
// Each signature must verify independently. Without this the vector could pin a tree
|
|
98
|
+
// built over five values that are not valid proofs at all.
|
|
99
|
+
it('verifies all five signatures under the named suite', function () {
|
|
100
|
+
vector.proofs.forEach(function (p) {
|
|
101
|
+
Suites.verify(p.algorithm, hex(p.payloadHash), hex(p.signature), hex(p.publicKey))
|
|
102
|
+
.should.equal(true, 'leaf ' + p.leafIndex + ' signature must verify')
|
|
103
|
+
})
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
// THE test this file most needs, and the one it originally lacked.
|
|
107
|
+
//
|
|
108
|
+
// The assertion above uses our own suite, and the generator uses our own signer, so
|
|
109
|
+
// the two agree by construction. The first version of this vector was generated with
|
|
110
|
+
// `endian: 'little'` — matching a verifier bug — and every signature in it was
|
|
111
|
+
// unverifiable by any other implementation. Both tests above still passed, because
|
|
112
|
+
// both sides of the comparison were wrong in the same direction.
|
|
113
|
+
//
|
|
114
|
+
// @noble/curves shares no signing or verification code with lib/crypto/ecdsa.js. If
|
|
115
|
+
// this vector is ever regenerated by a signer that disagrees with the rest of the
|
|
116
|
+
// world, this is the assertion that says so.
|
|
117
|
+
//
|
|
118
|
+
// { prehash: false } is REQUIRED: noble v2 hashes its input by default, so omitting
|
|
119
|
+
// it would compare our signature over `payloadHash` against noble's over
|
|
120
|
+
// `sha256(payloadHash)` — a mismatch that looks exactly like the bug this guards.
|
|
121
|
+
it('verifies all five signatures under an INDEPENDENT implementation', function () {
|
|
122
|
+
vector.proofs.forEach(function (p) {
|
|
123
|
+
secp256k1.verify(hex(p.signature), hex(p.payloadHash), hex(p.publicKey), { prehash: false })
|
|
124
|
+
.should.equal(true,
|
|
125
|
+
'leaf ' + p.leafIndex + ' signature must verify under @noble/curves, not just ours')
|
|
126
|
+
})
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
it('derives each public key from the recorded key preimage', function () {
|
|
130
|
+
// Ties the published public keys back to their labelled preimages, so a third party
|
|
131
|
+
// can reproduce the keys and not merely check the signatures against them.
|
|
132
|
+
vector.proofs.forEach(function (p) {
|
|
133
|
+
var priv = PrivateKey.fromObject({
|
|
134
|
+
bn: BN.fromBuffer(Hash.sha256(Buffer.from(p.keyPreimage, 'utf8'))),
|
|
135
|
+
compressed: true,
|
|
136
|
+
network: 'livenet'
|
|
137
|
+
})
|
|
138
|
+
priv.publicKey.toBuffer().toString('hex')
|
|
139
|
+
.should.equal(p.publicKey, 'leaf ' + p.leafIndex + ' public key must derive from its preimage')
|
|
140
|
+
})
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
it('rebuilds each canonicalBytes from the recorded fields', function () {
|
|
144
|
+
vector.proofs.forEach(function (p) {
|
|
145
|
+
Encoding.canonicalBytes({
|
|
146
|
+
algorithm: p.algorithm,
|
|
147
|
+
hashAlgorithm: p.hashAlgorithm,
|
|
148
|
+
payloadHash: hex(p.payloadHash),
|
|
149
|
+
publicKey: hex(p.publicKey),
|
|
150
|
+
signature: hex(p.signature),
|
|
151
|
+
createdAtUnix: p.createdAtUnix
|
|
152
|
+
}).toString('hex').should.equal(p.canonicalBytes, 'leaf ' + p.leafIndex)
|
|
153
|
+
})
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
it('rebuilds each proofHash as SHA-256 of those canonical bytes', function () {
|
|
157
|
+
vector.proofs.forEach(function (p) {
|
|
158
|
+
Hash.sha256(hex(p.canonicalBytes)).toString('hex')
|
|
159
|
+
.should.equal(p.proofHash, 'leaf ' + p.leafIndex)
|
|
160
|
+
})
|
|
161
|
+
})
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
describe('the leaf definition the spec leaves open', function () {
|
|
165
|
+
it('rebuilds each leaf as SHA-256(0x00 || proofHash)', function () {
|
|
166
|
+
vector.proofs.forEach(function (p) {
|
|
167
|
+
Merkle.hashLeaf(hex(p.proofHash)).toString('hex')
|
|
168
|
+
.should.equal(p.leafHash, 'leaf ' + p.leafIndex)
|
|
169
|
+
})
|
|
170
|
+
})
|
|
171
|
+
|
|
172
|
+
it('rebuilds the root from the five proofHash values', function () {
|
|
173
|
+
Merkle.root(vector.proofs.map(function (p) { return hex(p.proofHash) }))
|
|
174
|
+
.toString('hex').should.equal(vector.root)
|
|
175
|
+
})
|
|
176
|
+
|
|
177
|
+
it('rebuilds every inclusion path and folds each back to the root', function () {
|
|
178
|
+
var leaves = vector.proofs.map(function (p) { return hex(p.proofHash) })
|
|
179
|
+
vector.proofs.forEach(function (p, i) {
|
|
180
|
+
Merkle.path(leaves, i).map(function (n) { return n.toString('hex') })
|
|
181
|
+
.should.deep.equal(p.path, 'path for leaf ' + i)
|
|
182
|
+
Merkle.verifyInclusion(leaves[i], i, vector.leafCount,
|
|
183
|
+
p.path.map(hex), hex(vector.root)).should.equal(true, 'fold for leaf ' + i)
|
|
184
|
+
})
|
|
185
|
+
})
|
|
186
|
+
|
|
187
|
+
it('encodes leafCount as u32be for the on-chain record', function () {
|
|
188
|
+
var buf = Buffer.alloc(4)
|
|
189
|
+
buf.writeUInt32BE(vector.leafCount, 0)
|
|
190
|
+
buf.toString('hex').should.equal(vector.onChainRecordTail.leafCountU32be)
|
|
191
|
+
vector.onChainRecordTail.merkleRoot.should.equal(vector.root)
|
|
192
|
+
})
|
|
193
|
+
})
|
|
194
|
+
|
|
195
|
+
describe('the rejected reading is recorded and really does diverge', function () {
|
|
196
|
+
it('reproduces the canonicalBytes-leaf root the vector records', function () {
|
|
197
|
+
Merkle.root(vector.proofs.map(function (p) { return hex(p.canonicalBytes) }))
|
|
198
|
+
.toString('hex').should.equal(vector.rejectedReading.root)
|
|
199
|
+
})
|
|
200
|
+
|
|
201
|
+
// The whole reason the vector exists. Equal in strength, different root.
|
|
202
|
+
it('is a different root from the proofHash reading', function () {
|
|
203
|
+
vector.root.should.not.equal(vector.rejectedReading.root)
|
|
204
|
+
})
|
|
205
|
+
|
|
206
|
+
it('records each leaf hash under both readings, and they differ', function () {
|
|
207
|
+
vector.proofs.forEach(function (p) {
|
|
208
|
+
Merkle.hashLeaf(hex(p.canonicalBytes)).toString('hex')
|
|
209
|
+
.should.equal(p.leafHashUnderRejectedReading, 'leaf ' + p.leafIndex)
|
|
210
|
+
p.leafHash.should.not.equal(p.leafHashUnderRejectedReading)
|
|
211
|
+
})
|
|
212
|
+
})
|
|
213
|
+
})
|
|
214
|
+
|
|
215
|
+
// The amendment publishes these values as the text to put in the spec. A document that
|
|
216
|
+
// has drifted from the artifact it describes is worse than no document, and nothing
|
|
217
|
+
// else would notice: the doc is prose, the vector is JSON, and they are edited
|
|
218
|
+
// separately.
|
|
219
|
+
describe('the amendment document publishes the same values', function () {
|
|
220
|
+
var fs = require('fs')
|
|
221
|
+
var path = require('path')
|
|
222
|
+
var doc = fs.readFileSync(
|
|
223
|
+
path.join(__dirname, '..', '..', 'docs', 'BRC220_BATCH_LEAF_AMENDMENT.md'), 'utf8')
|
|
224
|
+
|
|
225
|
+
it('publishes the root', function () {
|
|
226
|
+
doc.indexOf(vector.root).should.be.above(-1, 'root missing from the amendment')
|
|
227
|
+
})
|
|
228
|
+
|
|
229
|
+
it('publishes the rejected reading root, so the divergence is diagnosable', function () {
|
|
230
|
+
doc.indexOf(vector.rejectedReading.root)
|
|
231
|
+
.should.be.above(-1, 'rejected reading root missing from the amendment')
|
|
232
|
+
})
|
|
233
|
+
|
|
234
|
+
it('publishes every proofHash', function () {
|
|
235
|
+
vector.proofs.forEach(function (p) {
|
|
236
|
+
doc.indexOf(p.proofHash).should.be.above(-1,
|
|
237
|
+
'proofHash for leaf ' + p.leafIndex + ' missing from the amendment')
|
|
238
|
+
})
|
|
239
|
+
})
|
|
240
|
+
|
|
241
|
+
it('publishes the leaf-4 audit path and the u32be leaf count', function () {
|
|
242
|
+
doc.indexOf(vector.proofs[4].path[0]).should.be.above(-1, 'leaf 4 path missing')
|
|
243
|
+
doc.indexOf(vector.onChainRecordTail.leafCountU32be).should.be.above(-1,
|
|
244
|
+
'u32be leaf count missing')
|
|
245
|
+
})
|
|
246
|
+
})
|
|
247
|
+
|
|
248
|
+
describe('the library verifies certificates built from this vector', function () {
|
|
249
|
+
it('accepts a batch certificate for every leaf', function () {
|
|
250
|
+
vector.proofs.forEach(function (p, i) {
|
|
251
|
+
var report = NotaryHash.verifyBatchInclusion({
|
|
252
|
+
mode: NotaryScript.MODE.BATCH,
|
|
253
|
+
proofHash: p.proofHash,
|
|
254
|
+
merkle: {
|
|
255
|
+
root: vector.root,
|
|
256
|
+
leafIndex: i,
|
|
257
|
+
leafCount: vector.leafCount,
|
|
258
|
+
path: p.path
|
|
259
|
+
}
|
|
260
|
+
})
|
|
261
|
+
report.valid.should.equal(true, 'leaf ' + i)
|
|
262
|
+
report.errors.should.deep.equal([])
|
|
263
|
+
})
|
|
264
|
+
})
|
|
265
|
+
|
|
266
|
+
// An implementation that chose the other reading produces exactly this, and this is
|
|
267
|
+
// what it looks like when it reaches our verifier.
|
|
268
|
+
it('rejects a certificate carrying the rejected reading root', function () {
|
|
269
|
+
var report = NotaryHash.verifyBatchInclusion({
|
|
270
|
+
mode: NotaryScript.MODE.BATCH,
|
|
271
|
+
proofHash: vector.proofs[0].proofHash,
|
|
272
|
+
merkle: {
|
|
273
|
+
root: vector.rejectedReading.root,
|
|
274
|
+
leafIndex: 0,
|
|
275
|
+
leafCount: vector.leafCount,
|
|
276
|
+
path: vector.proofs[0].path
|
|
277
|
+
}
|
|
278
|
+
})
|
|
279
|
+
report.valid.should.equal(false)
|
|
280
|
+
})
|
|
281
|
+
})
|
|
282
|
+
})
|
|
@@ -223,16 +223,19 @@ describe('Ordinals inscriptions', function () {
|
|
|
223
223
|
})
|
|
224
224
|
})
|
|
225
225
|
|
|
226
|
-
// The
|
|
227
|
-
//
|
|
228
|
-
// the
|
|
229
|
-
// hard-coded 10,000 bytes that useGenesisLimits() did not lift.
|
|
226
|
+
// Transferring a large inscription. The envelope is inert, so the spend is an
|
|
227
|
+
// ordinary P2PKH — but under pre-Genesis rules the interpreter could not even load
|
|
228
|
+
// the script, because total script size was capped at 10,000 bytes.
|
|
230
229
|
describe('transferring a large inscription', function () {
|
|
231
230
|
var I = bsv.Script.Interpreter
|
|
232
231
|
var Sighash = bsv.Transaction.Sighash
|
|
233
232
|
var BN = bsv.crypto.BN
|
|
234
233
|
var SIGHASH = bsv.crypto.Signature.SIGHASH_ALL | bsv.crypto.Signature.SIGHASH_FORKID
|
|
234
|
+
// Pre-Genesis: no era bit, so the 520-byte element cap and the 10,000-byte script
|
|
235
|
+
// cap both still apply. Kept deliberately, to show what they reject.
|
|
235
236
|
var FLAGS = I.SCRIPT_VERIFY_STRICTENC | I.SCRIPT_ENABLE_SIGHASH_FORKID
|
|
237
|
+
// Current mainnet, where Genesis lifted both.
|
|
238
|
+
var MAINNET = I.mainnetFlags()
|
|
236
239
|
var saved
|
|
237
240
|
|
|
238
241
|
beforeEach(function () { saved = I.getLimits() })
|
|
@@ -265,35 +268,43 @@ describe('Ordinals inscriptions', function () {
|
|
|
265
268
|
return { lock: lock, unlock: unlock, spend: spend, sig: sig, owner: owner }
|
|
266
269
|
}
|
|
267
270
|
|
|
268
|
-
|
|
271
|
+
// Both caps are derived from the ERA flags, not from the limit statics: see
|
|
272
|
+
// Interpreter#maxScriptElementSize and #maxScriptSize, each of which branches on
|
|
273
|
+
// isAfterGenesis(). Passing the era is therefore the whole fix — these tests used
|
|
274
|
+
// to call SmartContract.enableGenesis(), which raised process-wide statics instead
|
|
275
|
+
// and had to be undone in an afterEach or it changed the rules for every test that
|
|
276
|
+
// ran later.
|
|
277
|
+
function evaluate (t, flags) {
|
|
269
278
|
var interp = new I()
|
|
270
|
-
var ok = interp.verify(t.unlock, t.lock, t.spend, 0,
|
|
279
|
+
var ok = interp.verify(t.unlock, t.lock, t.spend, 0,
|
|
280
|
+
flags === undefined ? MAINNET : flags, new BN(1))
|
|
271
281
|
return { ok: ok, err: interp.errstr }
|
|
272
282
|
}
|
|
273
283
|
|
|
274
284
|
it('cannot be evaluated under pre-Genesis limits — two separate caps bite', function () {
|
|
285
|
+
// Explicitly pre-Genesis: FLAGS carries no era bit, so both caps still apply.
|
|
275
286
|
// Under 10 KB the script loads and the 520-byte push cap rejects the content...
|
|
276
|
-
var small = evaluate(transfer(3))
|
|
287
|
+
var small = evaluate(transfer(3), FLAGS)
|
|
277
288
|
small.ok.should.equal(false)
|
|
278
289
|
small.err.should.equal('SCRIPT_ERR_PUSH_SIZE')
|
|
279
290
|
// ...over 10 KB it never gets that far: evaluate() refuses the script outright.
|
|
280
|
-
|
|
281
|
-
var big = evaluate(transfer(50))
|
|
291
|
+
var big = evaluate(transfer(50), FLAGS)
|
|
282
292
|
big.ok.should.equal(false)
|
|
283
293
|
big.err.should.equal('SCRIPT_ERR_SCRIPT_SIZE')
|
|
284
294
|
})
|
|
285
295
|
|
|
286
|
-
it('evaluates
|
|
287
|
-
|
|
296
|
+
it('evaluates under mainnet consensus, with the limit statics untouched', function () {
|
|
297
|
+
var before = JSON.stringify(I.getLimits())
|
|
288
298
|
var t = transfer(50)
|
|
289
|
-
t.lock.toBuffer().length.should.be.above(10000) // past the
|
|
299
|
+
t.lock.toBuffer().length.should.be.above(10000) // past the pre-Genesis cap
|
|
290
300
|
evaluate(t).ok.should.equal(true)
|
|
301
|
+
// The point of the change: no process-wide mutation was needed to get here.
|
|
302
|
+
JSON.stringify(I.getLimits()).should.equal(before)
|
|
291
303
|
})
|
|
292
304
|
|
|
293
305
|
it('agrees with a direct signature check against the sighash', function () {
|
|
294
306
|
// The fallback used when the interpreter cannot run: verify the signature over
|
|
295
307
|
// the sighash directly. It must agree with the interpreter where both work.
|
|
296
|
-
bsv.SmartContract.enableGenesis()
|
|
297
308
|
var t = transfer(50)
|
|
298
309
|
var hash = Sighash.sighash(t.spend, SIGHASH, 0, t.lock, new BN(1), FLAGS)
|
|
299
310
|
var sigOk = bsv.crypto.ECDSA.verify(hash, t.sig, t.owner.toPublicKey(), 'little')
|
|
@@ -302,7 +313,6 @@ describe('Ordinals inscriptions', function () {
|
|
|
302
313
|
})
|
|
303
314
|
|
|
304
315
|
it('rejects a signature made over the base lock instead of the full script', function () {
|
|
305
|
-
bsv.SmartContract.enableGenesis()
|
|
306
316
|
var t = transfer(50)
|
|
307
317
|
var baseLock = bsv.Script.buildPublicKeyHashOut(t.owner.toAddress())
|
|
308
318
|
var wrong = Sighash.sign(t.spend, t.owner, SIGHASH, 0, baseLock, new BN(1), FLAGS)
|