@smartledger/bsv 9.13.0 → 9.15.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.
@@ -99,6 +99,50 @@ function targetLimit (powLimit) {
99
99
  return target
100
100
  }
101
101
 
102
+ /**
103
+ * A floor given in DIFFICULTY as the work it means: difficulty x 4,295,032,833, exactly.
104
+ *
105
+ * `minWork` counts hashes, and difficulty is the unit people actually quote — a real BSV
106
+ * header is "difficulty 2.6e10", not "1.1e20 hashes". Reading one as the other sets a floor
107
+ * 4.3 billion times too low and fails OPEN, which is why the unit is in the name. The
108
+ * multiplication is done on integers so a fractional difficulty keeps its digits instead of
109
+ * drifting through a float.
110
+ */
111
+ function workFromDifficulty (difficulty) {
112
+ var text = typeof difficulty === 'number' ? numberToDecimal(difficulty) : String(difficulty)
113
+ // `1e19` is how a floor this size is written, by hand and by JSON, so both a Number and a
114
+ // string may arrive in exponent form. Expanded by moving the point, never through a float.
115
+ if (/^[0-9]+(\.[0-9]+)?[eE][+]?[0-9]+$/.test(text)) text = expandExponent(text)
116
+ if (!/^[0-9]+(\.[0-9]+)?$/.test(text)) {
117
+ throw new Error('minDifficulty must be a non-negative decimal number, not ' +
118
+ JSON.stringify(difficulty))
119
+ }
120
+ var parts = text.split('.')
121
+ var frac = parts[1] || ''
122
+ var scaled = new BN(parts[0] + frac, 10).mul(workFromTarget(targetFromBits(POW_LIMIT_BITS)))
123
+ return frac.length ? scaled.div(new BN(10).pow(new BN(frac.length))) : scaled
124
+ }
125
+
126
+ /** `2.557e10` as `25570000000`, by moving the decimal point, with no float in the path. */
127
+ function expandExponent (text) {
128
+ var halves = text.split(/[eE]/)
129
+ var exp = parseInt(halves[1].replace('+', ''), 10)
130
+ var digits = halves[0].split('.')
131
+ var intPart = digits[0]
132
+ var frac = digits[1] || ''
133
+ if (exp >= frac.length) return intPart + frac + new Array(exp - frac.length + 1).join('0')
134
+ return intPart + frac.slice(0, exp) + '.' + frac.slice(exp)
135
+ }
136
+
137
+ /** A Number as plain decimal digits, so 2.6e10 does not reach the parser as "2.6e+10". */
138
+ function numberToDecimal (n) {
139
+ if (!Number.isFinite(n) || n < 0) {
140
+ throw new Error('minDifficulty must be a non-negative finite number, not ' + String(n))
141
+ }
142
+ if (!/e/i.test(String(n))) return String(n)
143
+ return n.toLocaleString('en-US', { useGrouping: false, maximumFractionDigits: 20 })
144
+ }
145
+
102
146
  /**
103
147
  * `minWork` as a BN, refusing anything bn.js would read loosely. It parses `1e21` as
104
148
  * 23521, `'4.3e9'` as 4 and `'abc'` as 1122, so a floor set from a Number near the
@@ -216,8 +260,10 @@ function verifyMerkleProof (proof) {
216
260
  * header: a bsv.BlockHeader, an 80-byte Buffer, or 80-byte hex.
217
261
  * powLimit: the easiest target a header may declare, as compact bits (number or hex
218
262
  * string) or a BN target. Default 0x1d00ffff. Regtest needs 0x207fffff.
219
- * minWork: minimum work the header must represent (number, decimal string or BN);
220
- * 2^256 / (target + 1). Difficulty 1 is about 4.295e9.
263
+ * minWork: minimum work the header must represent, in HASHES (number, decimal string or
264
+ * BN): 2^256 / (target + 1). Difficulty 1 is about 4.295e9.
265
+ * minDifficulty: the same floor in DIFFICULTY, which is the unit difficulty is quoted in
266
+ * (a real BSV header is about 2.6e10). Exactly one of the two, or neither.
221
267
  * With `requirePow: false` the work checks are not performed at all: `targetAllowed` and
222
268
  * `workSufficient` report true because nothing objected, and `powLimit`/`minWork` are not
223
269
  * even read.
@@ -240,8 +286,20 @@ function verifyTxInclusion (params) {
240
286
  // when the work checks are off.
241
287
  var targetAllowed = target !== null &&
242
288
  (!requirePow || target.cmp(targetLimit(params.powLimit)) <= 0)
243
- var workSufficient = !requirePow || params.minWork === undefined || params.minWork === null ||
244
- work.cmp(minWorkBN(params.minWork)) >= 0
289
+ var floor = null
290
+ if (requirePow) {
291
+ // One floor, named for its unit. Accepting both would leave the caller guessing which
292
+ // one bit, and the two are 4.3e9 apart.
293
+ if (params.minWork !== undefined && params.minWork !== null &&
294
+ params.minDifficulty !== undefined && params.minDifficulty !== null) {
295
+ throw new Error('pass minWork (hashes) or minDifficulty (difficulty), not both')
296
+ }
297
+ if (params.minWork !== undefined && params.minWork !== null) floor = minWorkBN(params.minWork)
298
+ else if (params.minDifficulty !== undefined && params.minDifficulty !== null) {
299
+ floor = workFromDifficulty(params.minDifficulty)
300
+ }
301
+ }
302
+ var workSufficient = floor === null || work.cmp(floor) >= 0
245
303
 
246
304
  return {
247
305
  valid: rootMatches && (!requirePow || (powValid && targetAllowed && workSufficient)),
@@ -262,6 +320,7 @@ module.exports = {
262
320
  targetFromBits: targetFromBits,
263
321
  targetLimit: targetLimit,
264
322
  workFromTarget: workFromTarget,
323
+ workFromDifficulty: workFromDifficulty,
265
324
  headerSnapshot: headerSnapshot,
266
325
  merkleRootFromBranch: merkleRootFromBranch,
267
326
  verifyMerkleProof: verifyMerkleProof,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@smartledger/bsv",
3
- "version": "9.13.0",
3
+ "version": "9.15.0",
4
4
  "description": "Bitcoin SV library with an interpreter-verified script engine: OP_PUSH_TX covenants, BIP-143 preimage tooling, and consensus flags that match what miners actually enforce. Also ships DID:web / W3C VC-JWT credentials and the Legal Token Protocol.",
5
5
  "author": "SmartLedger Technology <hello@smartledger.technology> (https://smartledger.technology)",
6
6
  "homepage": "https://github.com/codenlighten/smartledger-bsv#readme",
@@ -184,6 +184,17 @@ function classifyFlags (flagStr) {
184
184
  * only the spending transaction carries the version under test.
185
185
  */
186
186
  function evaluate (row, flags) {
187
+ // DoTest's one flag adjustment, which the rows themselves do not state:
188
+ //
189
+ // if(flags & SCRIPT_VERIFY_CLEANSTACK) flags |= SCRIPT_VERIFY_P2SH;
190
+ //
191
+ // Without it a row naming CLEANSTACK alone is verified under a flag set the node refuses
192
+ // outright, so it fails for the wrong reason and the row silently stops testing clean
193
+ // stacks at all.
194
+ if ((flags & Interpreter.SCRIPT_VERIFY_CLEANSTACK) !== 0) {
195
+ flags |= Interpreter.SCRIPT_VERIFY_P2SH
196
+ }
197
+
187
198
  const scriptSig = fromBitcoindString(row.scriptSig)
188
199
  const scriptPubKey = fromBitcoindString(row.scriptPubKey)
189
200
 
package/version.js CHANGED
@@ -1,3 +1,3 @@
1
1
  'use strict'
2
2
  // GENERATED by scripts/sync-version.js on `npm version` — do not edit.
3
- module.exports = '9.13.0'
3
+ module.exports = '9.15.0'