@smartledger/bsv 9.14.0 → 9.16.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.
@@ -98,11 +98,34 @@ Interpreter.prototype._verifyCore = function (scriptSig, scriptPubkey, tx, nin,
98
98
  })
99
99
  var stackCopy
100
100
 
101
- if ((flags & Interpreter.SCRIPT_VERIFY_SIGPUSHONLY) !== 0 && !scriptSig.isPushOnly()) {
102
- this.errstr = 'SCRIPT_ERR_SIG_PUSHONLY'
101
+ // A UTXO cannot be post-Chronicle without being post-Genesis. The node refuses the
102
+ // combination outright (valid_flags, interpreter.cpp) rather than picking an era.
103
+ if ((flags & Interpreter.SCRIPT_UTXO_AFTER_CHRONICLE) !== 0 &&
104
+ (flags & Interpreter.SCRIPT_UTXO_AFTER_GENESIS) === 0) {
105
+ this.errstr = 'SCRIPT_ERR_INVALID_FLAGS'
103
106
  return false
104
107
  }
105
108
 
109
+ // SIGPUSHONLY is a rule of an era, not of the flag alone:
110
+ //
111
+ // if((IsGenesis(flags) && !IsChronicle(flags)) ||
112
+ // (IsChronicle(flags) && !IsMalleableTxnVersion(checker.Version())))
113
+ //
114
+ // Before Genesis this branch refused nothing — a non-push scriptSig was caught only where
115
+ // P2SH demanded it, below — and the node never sets the flag there anyway
116
+ // (InputScriptVerifyFlags adds it only once the block era is post-Genesis). Under
117
+ // Chronicle it survives as a non-malleability rule, so a malleable version is exempt,
118
+ // and that case DOES arise on today's mainnet flags.
119
+ if ((flags & Interpreter.SCRIPT_VERIFY_SIGPUSHONLY) !== 0) {
120
+ var chronicleBlock = (flags & Interpreter.SCRIPT_CHRONICLE) !== 0
121
+ var pushOnlyRequired = (((flags & Interpreter.SCRIPT_GENESIS) !== 0) && !chronicleBlock) ||
122
+ (chronicleBlock && enforcesNonMalleability(flags, tx))
123
+ if (pushOnlyRequired && !scriptSig.isPushOnly()) {
124
+ this.errstr = 'SCRIPT_ERR_SIG_PUSHONLY'
125
+ return false
126
+ }
127
+ }
128
+
106
129
  // evaluate scriptSig
107
130
  if (!this.evaluate()) {
108
131
  return false
@@ -197,18 +220,25 @@ Interpreter.prototype._verifyCore = function (scriptSig, scriptPubkey, tx, nin,
197
220
  // Disallow CLEANSTACK without P2SH, as otherwise a switch
198
221
  // CLEANSTACK->P2SH+CLEANSTACK would be possible, which is not a
199
222
  // softfork (and P2SH should be one).
200
- // Genesis removed P2SH, so post-Genesis the pairing no longer applies and
201
- // CLEANSTACK stands on its own.
202
- if ((flags & Interpreter.SCRIPT_VERIFY_P2SH) === 0 &&
203
- (flags & Interpreter.SCRIPT_UTXO_AFTER_GENESIS) === 0) {
204
- throw new Error('internal error - CLEANSTACK without P2SH')
223
+ // The flags come from a caller, so this is a bad request rather than a broken
224
+ // invariant. The node names it (SCRIPT_ERR_INVALID_FLAGS); throwing turned a verdict
225
+ // into a crash. It requires the P2SH flag in every era, including after Genesis removed
226
+ // P2SH, and its own corpus never reaches this branch because the harness adds the flag
227
+ // (`if(flags & SCRIPT_VERIFY_CLEANSTACK) flags |= SCRIPT_VERIFY_P2SH;` in DoTest,
228
+ // src/test/script_tests.cpp) — which is why this used to carry a post-Genesis carve-out
229
+ // that let the pair through. That was ours, not the node's.
230
+ if ((flags & Interpreter.SCRIPT_VERIFY_P2SH) === 0) {
231
+ this.errstr = 'SCRIPT_ERR_INVALID_FLAGS'
232
+ return false
205
233
  }
206
234
 
207
235
  // The final stack. After a P2SH evaluation that is stackCopy itself, since
208
236
  // the redeem script was evaluated over it, but reading stackCopy directly
209
237
  // is wrong once P2SH no longer applies: it is then either the stack as it
210
238
  // stood after the scriptSig, or never assigned at all.
211
- if (this.stack.length !== 1) {
239
+ // Clean stack was only ever a policy rule, never consensus, so Chronicle ties it to
240
+ // the transaction version rather than to the age of the output being spent.
241
+ if (this.enforceNonMalleability() && this.stack.length !== 1) {
212
242
  this.errstr = 'SCRIPT_ERR_CLEANSTACK'
213
243
  return false
214
244
  }
@@ -841,6 +871,37 @@ Interpreter.castToBool = function (buf) {
841
871
  /**
842
872
  * Translated from bitcoind's CheckSignatureEncoding
843
873
  */
874
+ /**
875
+ * Chronicle lets a transaction opt into malleability by using a version above 1, and the
876
+ * rules that exist only to stop a signed transaction being rewritten in flight then stop
877
+ * applying to it. The node's EnforceNonMalleability(flags, checker.Version()):
878
+ *
879
+ * return !(IsChronicle(flags) && IsMalleableTxnVersion(txnVersion)); // version > 1
880
+ *
881
+ * It gates LOW_S, MINIMALDATA, MINIMALIF, NULLFAIL, NULLDUMMY, SIGPUSHONLY and CLEANSTACK.
882
+ * Note which era flag it reads: SCRIPT_CHRONICLE, the era of the block being built, not
883
+ * SCRIPT_UTXO_AFTER_CHRONICLE, the era of the output being spent.
884
+ *
885
+ * Every version at or below 1 is non-malleable, so the rules apply; a missing transaction
886
+ * is treated the same way, which is the enforcing answer.
887
+ */
888
+ function enforcesNonMalleability (flags, tx) {
889
+ if ((flags & Interpreter.SCRIPT_CHRONICLE) === 0) {
890
+ return true
891
+ }
892
+ // int32, as CTransaction::nVersion is and as checker.Version() returns it. Comparing the
893
+ // JS number would read a version of 0xffffffff as 4294967295 and call the transaction
894
+ // malleable, where the node reads -1 and enforces. Such a version cannot arrive from the
895
+ // network — writeInt32LE refuses it and readInt32LE has already signed anything parsed —
896
+ // but a caller can set it in code, and the fail-open reading is the wrong one to have.
897
+ // With no transaction at all the rules apply: BaseSignatureChecker::Version() returns 0.
898
+ return !(tx && ((tx.version | 0) > 1))
899
+ }
900
+
901
+ Interpreter.prototype.enforceNonMalleability = function () {
902
+ return enforcesNonMalleability(this.flags, this.tx)
903
+ }
904
+
844
905
  Interpreter.prototype.checkSignatureEncoding = function (buf) {
845
906
  var sig
846
907
 
@@ -850,16 +911,26 @@ Interpreter.prototype.checkSignatureEncoding = function (buf) {
850
911
  return true
851
912
  }
852
913
 
914
+ // Three independent checks, as CheckSignatureEncoding has them. They used to be chained
915
+ // with else-if, so LOW_S — which mainnetFlags() and currentConsensusFlags() both set —
916
+ // returned early and the whole STRICTENC block below never ran. On the library's own
917
+ // default flags that silently accepted a signature with an undefined hash type, one
918
+ // without FORKID where FORKID is required, and one asking for the Chronicle digest
919
+ // outside Chronicle: three things the node refuses by name.
853
920
  if ((this.flags & (Interpreter.SCRIPT_VERIFY_DERSIG | Interpreter.SCRIPT_VERIFY_LOW_S | Interpreter.SCRIPT_VERIFY_STRICTENC)) !== 0 && !Signature.isTxDER(buf)) {
854
921
  this.errstr = 'SCRIPT_ERR_SIG_DER_INVALID_FORMAT'
855
922
  return false
856
- } else if ((this.flags & Interpreter.SCRIPT_VERIFY_LOW_S) !== 0) {
923
+ }
924
+
925
+ if ((this.flags & Interpreter.SCRIPT_VERIFY_LOW_S) !== 0) {
857
926
  sig = Signature.fromTxFormat(buf)
858
- if (!sig.hasLowS()) {
927
+ if (!sig.hasLowS() && this.enforceNonMalleability()) {
859
928
  this.errstr = 'SCRIPT_ERR_SIG_DER_HIGH_S'
860
929
  return false
861
930
  }
862
- } else if ((this.flags & Interpreter.SCRIPT_VERIFY_STRICTENC) !== 0) {
931
+ }
932
+
933
+ if ((this.flags & Interpreter.SCRIPT_VERIFY_STRICTENC) !== 0) {
863
934
  sig = Signature.fromTxFormat(buf)
864
935
  if (!sig.hasDefinedHashtype()) {
865
936
  this.errstr = 'SCRIPT_ERR_SIG_HASHTYPE'
@@ -1344,27 +1415,40 @@ Interpreter.prototype.step = function () {
1344
1415
  switch (opcode) {
1345
1416
  case Opcode.OP_2MUL:
1346
1417
  case Opcode.OP_2DIV:
1347
- // Chronicle restores both. Until it is enabled they stay disabled, and
1348
- // "disabled" is stronger than "unimplemented": a disabled opcode fails the
1349
- // script even in an UNEXECUTED branch, which is why this lives in
1350
- // isOpcodeDisabled rather than in the evaluation switch.
1418
+ // Chronicle restores both; until the UTXO is post-Chronicle they stay disabled.
1419
+ //
1420
+ // "Disabled" is stronger than "unimplemented", but only before Genesis. The node reads
1421
+ //
1422
+ // if(IsOpcodeDisabled(opcode, utxoEra) && (!utxo_after_genesis || fExec))
1423
+ // return SCRIPT_ERR_DISABLED_OPCODE;
1424
+ //
1425
+ // so a disabled opcode in an UNEXECUTED branch fails a pre-Genesis spend and is harmless
1426
+ // in a post-Genesis one. That is why this lives in isOpcodeDisabled, which the caller
1427
+ // consults before testing fExec — the era decides, not the branch alone. An earlier
1428
+ // version of this comment said it fails unexecuted in every era, which is half the rule.
1351
1429
  if (!self.isAfterChronicle()) {
1352
1430
  return true
1353
1431
  }
1354
1432
  break
1355
1433
 
1434
+ // Restored on BSV and never gated by the node. Monolith came back in May 2018 and
1435
+ // Magnetic in November 2018, and IsOpcodeDisabled (src/script/interpreter.cpp) disables
1436
+ // OP_2MUL and OP_2DIV and nothing else — so every opcode below executes in every era the
1437
+ // node can validate, with no flag to enable.
1438
+ //
1439
+ // The four Magnetic ones used to be refused here unless SCRIPT_ENABLE_MAGNETIC_OPCODES
1440
+ // was set, "for backwards compatibility". That refused 77 rows of the node's own corpus
1441
+ // as DISABLED_OPCODE. Fail-closed, so nothing was at risk of being accepted wrongly, but
1442
+ // they were spends the network accepts. The Monolith group beside them had already made
1443
+ // the opposite call on identical reasoning, so the two halves of one 2018 upgrade
1444
+ // disagreed with each other.
1445
+ //
1446
+ // SCRIPT_ENABLE_MAGNETIC_OPCODES and SCRIPT_ENABLE_MONOLITH_OPCODES remain exported and
1447
+ // accepted — they are public API — and setting either is now simply redundant.
1356
1448
  case Opcode.OP_INVERT:
1357
1449
  case Opcode.OP_MUL:
1358
1450
  case Opcode.OP_LSHIFT:
1359
1451
  case Opcode.OP_RSHIFT:
1360
- // Magnetic opcodes - still require flag for backwards compatibility
1361
- if ((self.flags & Interpreter.SCRIPT_ENABLE_MAGNETIC_OPCODES) === 0) {
1362
- return true
1363
- }
1364
- break
1365
-
1366
- // Monolith opcodes are now enabled by default in SmartLedger BSV
1367
- // These were activated in May 2018 and are part of standard BSV consensus
1368
1452
  case Opcode.OP_DIV:
1369
1453
  case Opcode.OP_MOD:
1370
1454
  case Opcode.OP_SPLIT:
@@ -1374,7 +1458,6 @@ Interpreter.prototype.step = function () {
1374
1458
  case Opcode.OP_XOR:
1375
1459
  case Opcode.OP_BIN2NUM:
1376
1460
  case Opcode.OP_NUM2BIN:
1377
- // These opcodes are now always enabled - no flag required
1378
1461
  return false
1379
1462
 
1380
1463
  default:
@@ -1384,7 +1467,8 @@ Interpreter.prototype.step = function () {
1384
1467
  return false
1385
1468
  }
1386
1469
 
1387
- var fRequireMinimal = (this.flags & Interpreter.SCRIPT_VERIFY_MINIMALDATA) !== 0
1470
+ var fRequireMinimal = (this.flags & Interpreter.SCRIPT_VERIFY_MINIMALDATA) !== 0 &&
1471
+ this.enforceNonMalleability()
1388
1472
 
1389
1473
  var buf, buf1, buf2, spliced, n, x1, x2, bn, bn1, bn2, bufSig, bufPubkey, subscript
1390
1474
  var sig, pubkey
@@ -1770,15 +1854,11 @@ Interpreter.prototype.step = function () {
1770
1854
  }
1771
1855
  buf = stacktop(-1)
1772
1856
 
1773
- if (this.flags & Interpreter.SCRIPT_VERIFY_MINIMALIF) {
1774
- if (buf.length > 1) {
1775
- this.errstr = 'SCRIPT_ERR_MINIMALIF'
1776
- return false
1777
- }
1778
- if (buf.length === 1 && buf[0] !== 1) {
1779
- this.errstr = 'SCRIPT_ERR_MINIMALIF'
1780
- return false
1781
- }
1857
+ if ((this.flags & Interpreter.SCRIPT_VERIFY_MINIMALIF) &&
1858
+ (buf.length > 1 || (buf.length === 1 && buf[0] !== 1)) &&
1859
+ this.enforceNonMalleability()) {
1860
+ this.errstr = 'SCRIPT_ERR_MINIMALIF'
1861
+ return false
1782
1862
  }
1783
1863
  fValue = Interpreter.castToBool(buf)
1784
1864
  if (opcodenum === Opcode.OP_NOTIF) {
@@ -2457,7 +2537,7 @@ Interpreter.prototype.step = function () {
2457
2537
  }
2458
2538
 
2459
2539
  if (!fSuccess && (this.flags & Interpreter.SCRIPT_VERIFY_NULLFAIL) &&
2460
- bufSig.length) {
2540
+ bufSig.length && this.enforceNonMalleability()) {
2461
2541
  this.errstr = 'SCRIPT_ERR_NULLFAIL'
2462
2542
  return false
2463
2543
  }
@@ -2487,7 +2567,17 @@ Interpreter.prototype.step = function () {
2487
2567
  return false
2488
2568
  }
2489
2569
 
2490
- var nKeysCount = BN.fromScriptNumBuffer(stacktop(-i), fRequireMinimal, this.maxScriptNumLength()).toNumber()
2570
+ // FOUR bytes, not the era's length. The node hardcodes it and says why:
2571
+ //
2572
+ // // initialize to max size of CScriptNum::MAXIMUM_ELEMENT_SIZE (4 bytes)
2573
+ // // because only 4 byte integers are supported by OP_CHECKMULTISIG / OP_CHECKMULTISIGVERIFY
2574
+ // nKeysCountSigned = CScriptNum(stack.stacktop(-i).GetElement(), requireMinimal,
2575
+ // CScriptNum::MAXIMUM_ELEMENT_SIZE).getint();
2576
+ //
2577
+ // So it is era-independent, unlike every other operand decode in this file. Passing
2578
+ // maxScriptNumLength() here accepted a 5-byte count that the node refuses as
2579
+ // SCRIPTNUM_OVERFLOW in every era — a false accept, the direction that costs money.
2580
+ var nKeysCount = BN.fromScriptNumBuffer(stacktop(-i), fRequireMinimal, 4).toNumber()
2491
2581
  // TODO: Keys and opcount are parameterized in client. No magic numbers!
2492
2582
  // Genesis raised this to UINT32_MAX rather than removing it.
2493
2583
  if (nKeysCount < 0 || nKeysCount > this.maxPubKeysPerMultisig()) {
@@ -2521,7 +2611,8 @@ Interpreter.prototype.step = function () {
2521
2611
  return false
2522
2612
  }
2523
2613
 
2524
- var nSigsCount = BN.fromScriptNumBuffer(stacktop(-i), fRequireMinimal, this.maxScriptNumLength()).toNumber()
2614
+ // Four bytes, for the same reason as nKeysCount above.
2615
+ var nSigsCount = BN.fromScriptNumBuffer(stacktop(-i), fRequireMinimal, 4).toNumber()
2525
2616
  if (nSigsCount < 0 || nSigsCount > nKeysCount) {
2526
2617
  this.errstr = 'SCRIPT_ERR_SIG_COUNT'
2527
2618
  return false
@@ -2583,7 +2674,7 @@ Interpreter.prototype.step = function () {
2583
2674
  // Clean up stack of actual arguments
2584
2675
  while (i-- > 1) {
2585
2676
  if (!fSuccess && (this.flags & Interpreter.SCRIPT_VERIFY_NULLFAIL) &&
2586
- !ikey2 && stacktop(-1).length) {
2677
+ !ikey2 && stacktop(-1).length && this.enforceNonMalleability()) {
2587
2678
  this.errstr = 'SCRIPT_ERR_NULLFAIL'
2588
2679
  return false
2589
2680
  }
@@ -2605,7 +2696,8 @@ Interpreter.prototype.step = function () {
2605
2696
  this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
2606
2697
  return false
2607
2698
  }
2608
- if ((this.flags & Interpreter.SCRIPT_VERIFY_NULLDUMMY) && stacktop(-1).length) {
2699
+ if ((this.flags & Interpreter.SCRIPT_VERIFY_NULLDUMMY) && stacktop(-1).length &&
2700
+ this.enforceNonMalleability()) {
2609
2701
  this.errstr = 'SCRIPT_ERR_SIG_NULLDUMMY'
2610
2702
  return false
2611
2703
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@smartledger/bsv",
3
- "version": "9.14.0",
3
+ "version": "9.16.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",
@@ -145,7 +145,8 @@
145
145
  "check:dts": "node scripts/check-dts-coverage.js",
146
146
  "check:audit-scope": "node scripts/check-audit-scope.js",
147
147
  "check:audit-scope:fix": "node scripts/check-audit-scope.js --fix",
148
- "check:dts:update": "node scripts/check-dts-coverage.js --update"
148
+ "check:dts:update": "node scripts/check-dts-coverage.js --update",
149
+ "vectors:sv-coverage": "node tools/sv-vector-coverage.js"
149
150
  },
150
151
  "unpkg": "bsv.min.js",
151
152
  "jsdelivr": "bsv.min.js",
@@ -243,13 +244,16 @@
243
244
  "vm-browserify": "^1.1.2"
244
245
  },
245
246
  "overrides": {
246
- "js-yaml@^3": "^3.15.1",
247
- "js-yaml@^4": "^4.3.1",
247
+ "js-yaml@^3": "^3.15.2",
248
+ "js-yaml@^4": "^4.3.2",
248
249
  "serialize-javascript": "^7.0.5",
249
250
  "tmp": "^0.2.7",
250
251
  "mocha": {
251
252
  "diff": "^8.0.3"
252
- }
253
+ },
254
+ "brace-expansion": "^2.0.2",
255
+ "browserslist": "^4.28.7",
256
+ "baseline-browser-mapping": "^2.11.0"
253
257
  },
254
258
  "license": "MIT",
255
259
  "standard": {