@bsv/sdk 2.0.14 → 2.0.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/dist/cjs/package.json +14 -14
  2. package/dist/cjs/src/kvstore/GlobalKVStore.js +16 -3
  3. package/dist/cjs/src/kvstore/GlobalKVStore.js.map +1 -1
  4. package/dist/cjs/src/kvstore/types.js.map +1 -1
  5. package/dist/cjs/src/primitives/Hash.js +1 -1
  6. package/dist/cjs/src/primitives/Hash.js.map +1 -1
  7. package/dist/cjs/src/primitives/TransactionSignature.js +10 -3
  8. package/dist/cjs/src/primitives/TransactionSignature.js.map +1 -1
  9. package/dist/cjs/src/script/Script.js +60 -13
  10. package/dist/cjs/src/script/Script.js.map +1 -1
  11. package/dist/cjs/src/script/Spend.js +434 -59
  12. package/dist/cjs/src/script/Spend.js.map +1 -1
  13. package/dist/cjs/src/transaction/http/BinaryFetchClient.js +6 -2
  14. package/dist/cjs/src/transaction/http/BinaryFetchClient.js.map +1 -1
  15. package/dist/cjs/src/transaction/http/DefaultHttpClient.js +8 -4
  16. package/dist/cjs/src/transaction/http/DefaultHttpClient.js.map +1 -1
  17. package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
  18. package/dist/esm/src/kvstore/GlobalKVStore.js +16 -3
  19. package/dist/esm/src/kvstore/GlobalKVStore.js.map +1 -1
  20. package/dist/esm/src/kvstore/types.js.map +1 -1
  21. package/dist/esm/src/primitives/Hash.js +1 -1
  22. package/dist/esm/src/primitives/Hash.js.map +1 -1
  23. package/dist/esm/src/primitives/TransactionSignature.js +10 -3
  24. package/dist/esm/src/primitives/TransactionSignature.js.map +1 -1
  25. package/dist/esm/src/script/Script.js +60 -13
  26. package/dist/esm/src/script/Script.js.map +1 -1
  27. package/dist/esm/src/script/Spend.js +438 -59
  28. package/dist/esm/src/script/Spend.js.map +1 -1
  29. package/dist/esm/src/transaction/http/BinaryFetchClient.js +6 -2
  30. package/dist/esm/src/transaction/http/BinaryFetchClient.js.map +1 -1
  31. package/dist/esm/src/transaction/http/DefaultHttpClient.js +8 -4
  32. package/dist/esm/src/transaction/http/DefaultHttpClient.js.map +1 -1
  33. package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
  34. package/dist/types/src/kvstore/GlobalKVStore.d.ts +7 -0
  35. package/dist/types/src/kvstore/GlobalKVStore.d.ts.map +1 -1
  36. package/dist/types/src/kvstore/types.d.ts +2 -1
  37. package/dist/types/src/kvstore/types.d.ts.map +1 -1
  38. package/dist/types/src/primitives/TransactionSignature.d.ts +1 -0
  39. package/dist/types/src/primitives/TransactionSignature.d.ts.map +1 -1
  40. package/dist/types/src/script/Script.d.ts +1 -0
  41. package/dist/types/src/script/Script.d.ts.map +1 -1
  42. package/dist/types/src/script/ScriptChunk.d.ts +1 -0
  43. package/dist/types/src/script/ScriptChunk.d.ts.map +1 -1
  44. package/dist/types/src/script/Spend.d.ts +29 -0
  45. package/dist/types/src/script/Spend.d.ts.map +1 -1
  46. package/dist/types/src/transaction/http/BinaryFetchClient.d.ts.map +1 -1
  47. package/dist/types/src/transaction/http/DefaultHttpClient.d.ts +2 -2
  48. package/dist/types/src/transaction/http/DefaultHttpClient.d.ts.map +1 -1
  49. package/dist/types/tsconfig.types.tsbuildinfo +1 -1
  50. package/dist/umd/bundle.js +3 -4
  51. package/docs/reference/kvstore.md +2 -1
  52. package/docs/reference/primitives.md +1 -0
  53. package/docs/reference/script.md +7 -0
  54. package/docs/reference/transaction.md +2 -2
  55. package/package.json +14 -14
  56. package/src/kvstore/GlobalKVStore.ts +19 -3
  57. package/src/kvstore/__tests/GlobalKVStore.test.ts +24 -1
  58. package/src/kvstore/types.ts +2 -1
  59. package/src/primitives/Hash.ts +1 -1
  60. package/src/primitives/TransactionSignature.ts +11 -3
  61. package/src/script/Script.ts +59 -13
  62. package/src/script/ScriptChunk.ts +1 -0
  63. package/src/script/Spend.ts +483 -61
  64. package/src/script/__tests/NormativeVectors.test.ts +465 -0
  65. package/src/script/__tests/fixtures/SOURCES.md +25 -0
  66. package/src/script/__tests/fixtures/bitcoin-sv/script_tests.json +2591 -0
  67. package/src/script/__tests/fixtures/bitcoin-sv/sighash.json +1003 -0
  68. package/src/script/__tests/fixtures/bitcoin-sv/tx_invalid.json +285 -0
  69. package/src/script/__tests/fixtures/bitcoin-sv/tx_valid.json +367 -0
  70. package/src/script/__tests/fixtures/teranode/script_tests.json +2432 -0
  71. package/src/script/__tests/fixtures/teranode/sighash.json +1003 -0
  72. package/src/script/__tests/fixtures/teranode/tx_invalid.json +285 -0
  73. package/src/script/__tests/fixtures/teranode/tx_valid.json +367 -0
  74. package/src/transaction/broadcasters/__tests/ARC.test.ts +26 -4
  75. package/src/transaction/broadcasters/__tests/WhatsOnChainBroadcaster.test.ts +26 -4
  76. package/src/transaction/chaintrackers/__tests/WhatsOnChainChainTracker.test.ts +32 -10
  77. package/src/transaction/http/BinaryFetchClient.ts +5 -2
  78. package/src/transaction/http/DefaultHttpClient.ts +7 -4
  79. package/src/transaction/http/__tests/DefaultHttpClient.additional.test.ts +19 -1
  80. package/dist/cjs/src/auth/clients/__tests__/AuthFetch.additional.test.js +0 -827
  81. package/dist/cjs/src/auth/clients/__tests__/AuthFetch.additional.test.js.map +0 -1
  82. package/dist/cjs/src/auth/clients/__tests__/AuthFetch.test.js +0 -266
  83. package/dist/cjs/src/auth/clients/__tests__/AuthFetch.test.js.map +0 -1
  84. package/dist/cjs/src/auth/transports/__tests__/SimplifiedFetchTransport.additional.test.js +0 -654
  85. package/dist/cjs/src/auth/transports/__tests__/SimplifiedFetchTransport.additional.test.js.map +0 -1
  86. package/dist/cjs/src/auth/transports/__tests__/SimplifiedFetchTransport.test.js +0 -144
  87. package/dist/cjs/src/auth/transports/__tests__/SimplifiedFetchTransport.test.js.map +0 -1
  88. package/dist/esm/src/auth/clients/__tests__/AuthFetch.additional.test.js +0 -825
  89. package/dist/esm/src/auth/clients/__tests__/AuthFetch.additional.test.js.map +0 -1
  90. package/dist/esm/src/auth/clients/__tests__/AuthFetch.test.js +0 -264
  91. package/dist/esm/src/auth/clients/__tests__/AuthFetch.test.js.map +0 -1
  92. package/dist/esm/src/auth/transports/__tests__/SimplifiedFetchTransport.additional.test.js +0 -619
  93. package/dist/esm/src/auth/transports/__tests__/SimplifiedFetchTransport.additional.test.js.map +0 -1
  94. package/dist/esm/src/auth/transports/__tests__/SimplifiedFetchTransport.test.js +0 -109
  95. package/dist/esm/src/auth/transports/__tests__/SimplifiedFetchTransport.test.js.map +0 -1
  96. package/dist/types/src/auth/clients/__tests__/AuthFetch.additional.test.d.ts +0 -21
  97. package/dist/types/src/auth/clients/__tests__/AuthFetch.additional.test.d.ts.map +0 -1
  98. package/dist/types/src/auth/clients/__tests__/AuthFetch.test.d.ts +0 -2
  99. package/dist/types/src/auth/clients/__tests__/AuthFetch.test.d.ts.map +0 -1
  100. package/dist/types/src/auth/transports/__tests__/SimplifiedFetchTransport.additional.test.d.ts +0 -2
  101. package/dist/types/src/auth/transports/__tests__/SimplifiedFetchTransport.additional.test.d.ts.map +0 -1
  102. package/dist/types/src/auth/transports/__tests__/SimplifiedFetchTransport.test.d.ts +0 -2
  103. package/dist/types/src/auth/transports/__tests__/SimplifiedFetchTransport.test.d.ts.map +0 -1
  104. package/dist/umd/bundle.js.map +0 -1
@@ -249,7 +249,8 @@ Links: [API](#api), [Interfaces](#interfaces), [Classes](#classes), [Functions](
249
249
  ### Interface: KVStoreQuery
250
250
 
251
251
  Query parameters for KVStore lookups from overlay services.
252
- Used when searching for existing key-value pairs in the network.
252
+ Must include at least one selector: key, controller, protocolID, or non-empty tags.
253
+ Pagination and ordering fields only refine selector-based lookups.
253
254
 
254
255
  ```ts
255
256
  export interface KVStoreQuery {
@@ -4948,6 +4948,7 @@ export default class TransactionSignature extends Signature {
4948
4948
  static formatBip143(params: TransactionSignatureFormatParams): Uint8Array
4949
4949
  static format(params: TransactionSignatureFormatParams): number[]
4950
4950
  static formatBytes(params: TransactionSignatureFormatParams): Uint8Array
4951
+ static usesOtdaSingleBug(params: TransactionSignatureFormatParams): boolean
4951
4952
  static fromChecksigFormat(buf: number[]): TransactionSignature
4952
4953
  constructor(r: BigNumber, s: BigNumber, scope: number)
4953
4954
  public hasLowS(): boolean
@@ -45,6 +45,7 @@ A representation of a chunk of a script, which includes an opcode. For push oper
45
45
  export default interface ScriptChunk {
46
46
  op: number;
47
47
  data?: number[];
48
+ invalidLength?: boolean;
48
49
  }
49
50
  ```
50
51
 
@@ -804,10 +805,14 @@ export default class Spend {
804
805
  stack: number[][];
805
806
  altStack: number[][];
806
807
  ifStack: boolean[];
808
+ elseStack: boolean[];
807
809
  memoryLimit: number;
808
810
  stackMem: number;
809
811
  altStackMem: number;
810
812
  isRelaxedOverride: boolean;
813
+ verifyFlags?: Set<string>;
814
+ executedOpCount: number;
815
+ returningFromConditional: boolean;
811
816
  constructor(params: {
812
817
  sourceTXID: string;
813
818
  sourceOutputIndex: number;
@@ -822,6 +827,7 @@ export default class Spend {
822
827
  lockTime: number;
823
828
  memoryLimit?: number;
824
829
  isRelaxed?: boolean;
830
+ verifyFlags?: string | string[];
825
831
  })
826
832
  reset(): void
827
833
  step(): boolean
@@ -848,6 +854,7 @@ constructor(params: {
848
854
  lockTime: number;
849
855
  memoryLimit?: number;
850
856
  isRelaxed?: boolean;
857
+ verifyFlags?: string | string[];
851
858
  })
852
859
  ```
853
860
  See also: [LockingScript](./script.md#class-lockingscript), [TransactionInput](./transaction.md#interface-transactioninput), [TransactionOutput](./transaction.md#interface-transactionoutput), [UnlockingScript](./script.md#class-unlockingscript)
@@ -2455,8 +2455,8 @@ Links: [API](#api), [Interfaces](#interfaces), [Classes](#classes), [Functions](
2455
2455
  ### Function: defaultHttpClient
2456
2456
 
2457
2457
  Returns a default HttpClient implementation based on the environment that it is run on.
2458
- This method will attempt to use `window.fetch` if available (in browser environments).
2459
- If running in a Node environment, it falls back to using the Node `https` module
2458
+ This method will attempt to use `window.fetch` if available (in browser environments),
2459
+ then `globalThis.fetch` (service workers, Deno, Node 18+), then the Node `https` module.
2460
2460
 
2461
2461
  ```ts
2462
2462
  export function defaultHttpClient(): HttpClient
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bsv/sdk",
3
- "version": "2.0.14",
3
+ "version": "2.0.16",
4
4
  "type": "module",
5
5
  "description": "BSV Blockchain Software Development Kit",
6
6
  "main": "dist/cjs/mod.js",
@@ -251,23 +251,23 @@
251
251
  },
252
252
  "homepage": "https://github.com/bsv-blockchain/ts-sdk#readme",
253
253
  "devDependencies": {
254
- "@eslint/js": "^9.39.1",
255
- "@jest/globals": "^30.2.0",
256
- "@rspack/cli": "^1.6.1",
257
- "@rspack/core": "^1.6.1",
254
+ "@eslint/js": "^10.0.1",
255
+ "@jest/globals": "^30.3.0",
256
+ "@rspack/cli": "^2.0.0",
257
+ "@rspack/core": "^2.0.0",
258
258
  "@types/jest": "^30.0.0",
259
- "@types/node": "^24.10.1",
260
- "eslint": "^9.39.1",
261
- "globals": "^16.5.0",
262
- "jest": "^30.2.0",
263
- "jest-environment-jsdom": "^30.2.0",
264
- "ts-jest": "^29.4.5",
265
- "ts-loader": "^9.5.4",
259
+ "@types/node": "^25.6.0",
260
+ "eslint": "^10.2.1",
261
+ "globals": "^17.5.0",
262
+ "jest": "^30.3.0",
263
+ "jest-environment-jsdom": "^30.3.0",
264
+ "ts-jest": "^29.4.9",
265
+ "ts-loader": "^9.5.7",
266
266
  "ts-standard": "^12.0.2",
267
267
  "ts2md": "^0.2.8",
268
268
  "tsconfig-to-dual-package": "^1.2.0",
269
- "typescript": "^5.9.3",
270
- "typescript-eslint": "^8.46.4"
269
+ "typescript": "^6.0.3",
270
+ "typescript-eslint": "^8.59.0"
271
271
  },
272
272
  "ts-standard": {
273
273
  "project": "tsconfig.eslint.json",
@@ -106,9 +106,7 @@ export class GlobalKVStore {
106
106
  * @returns {Promise<KVStoreEntry | KVStoreEntry[] | undefined>} Single entry for key+controller queries, array for all other queries
107
107
  */
108
108
  async get (query: KVStoreQuery, options: KVStoreGetOptions = {}): Promise<KVStoreEntry | KVStoreEntry[] | undefined> {
109
- if (Object.keys(query).length === 0) {
110
- throw new Error('Must specify either key, controller, or protocolID')
111
- }
109
+ this.validateQuerySelectors(query)
112
110
  if (query.key != null && query.controller != null) {
113
111
  // Specific key+controller query - return single entry
114
112
  const entries = await this.queryOverlay(query, options)
@@ -117,6 +115,24 @@ export class GlobalKVStore {
117
115
  return await this.queryOverlay(query, options)
118
116
  }
119
117
 
118
+ /**
119
+ * Ensures lookup pagination and ordering options are only used with a real KV selector.
120
+ *
121
+ * @param {KVStoreQuery} query - Query parameters sent to overlay.
122
+ * @throws {Error} If the query does not include a valid selector.
123
+ */
124
+ private validateQuerySelectors (query: KVStoreQuery): void {
125
+ const hasSelector =
126
+ (typeof query.key === 'string' && query.key.length > 0) ||
127
+ (typeof query.controller === 'string' && query.controller.length > 0) ||
128
+ (Array.isArray(query.protocolID) && query.protocolID.length === 2) ||
129
+ (Array.isArray(query.tags) && query.tags.length > 0)
130
+
131
+ if (!hasSelector) {
132
+ throw new Error('Must specify at least one selector: key, controller, protocolID, or tags')
133
+ }
134
+ }
135
+
120
136
  /**
121
137
  * Sets a key-value pair. The current user (wallet identity) becomes the controller.
122
138
  *
@@ -577,7 +577,30 @@ describe('GlobalKVStore', () => {
577
577
 
578
578
  describe('sad paths', () => {
579
579
  it('rejects when no query parameters provided', async () => {
580
- await expect(kvStore.get({})).rejects.toThrow('Must specify either key, controller, or protocolID')
580
+ await expect(kvStore.get({})).rejects.toThrow(
581
+ 'Must specify at least one selector: key, controller, protocolID, or tags'
582
+ )
583
+ })
584
+
585
+ it('rejects pagination-only queries before resolving overlay hosts', async () => {
586
+ await expect(kvStore.get({ limit: 10 })).rejects.toThrow(
587
+ 'Must specify at least one selector: key, controller, protocolID, or tags'
588
+ )
589
+ expect(mockResolver.query).not.toHaveBeenCalled()
590
+ })
591
+
592
+ it('rejects ordering-only queries before resolving overlay hosts', async () => {
593
+ await expect(kvStore.get({ sortOrder: 'desc' })).rejects.toThrow(
594
+ 'Must specify at least one selector: key, controller, protocolID, or tags'
595
+ )
596
+ expect(mockResolver.query).not.toHaveBeenCalled()
597
+ })
598
+
599
+ it('rejects empty tag selector queries before resolving overlay hosts', async () => {
600
+ await expect(kvStore.get({ tags: [] })).rejects.toThrow(
601
+ 'Must specify at least one selector: key, controller, protocolID, or tags'
602
+ )
603
+ expect(mockResolver.query).not.toHaveBeenCalled()
581
604
  })
582
605
 
583
606
  it('propagates overlay errors', async () => {
@@ -37,7 +37,8 @@ export interface KVStoreConfig {
37
37
 
38
38
  /**
39
39
  * Query parameters for KVStore lookups from overlay services.
40
- * Used when searching for existing key-value pairs in the network.
40
+ * Must include at least one selector: key, controller, protocolID, or non-empty tags.
41
+ * Pagination and ordering fields only refine selector-based lookups.
41
42
  */
42
43
  export interface KVStoreQuery {
43
44
  key?: string
@@ -327,7 +327,7 @@ function zero8 (word: string): string {
327
327
 
328
328
  function bytesToHex (data: Uint8Array): string {
329
329
  let res = ''
330
- for (const b of data) res += (b.toString(16).padStart(2, '0') as string)
330
+ for (const b of data) res += (b.toString(16).padStart(2, '0'))
331
331
  return res
332
332
  }
333
333
 
@@ -3,7 +3,6 @@ import BigNumber from './BigNumber.js'
3
3
  import * as Hash from './Hash.js'
4
4
  import { toArray, Writer } from './utils.js'
5
5
  import Script from '../script/Script.js'
6
- import OP from '../script/OP.js'
7
6
  import TransactionInput from '../transaction/TransactionInput.js'
8
7
  import TransactionOutput from '../transaction/TransactionOutput.js'
9
8
 
@@ -56,8 +55,8 @@ export default class TransactionSignature extends Signature {
56
55
  const isNone = (params.scope & 31) === TransactionSignature.SIGHASH_NONE
57
56
  const isAll = (params.scope & 31) === TransactionSignature.SIGHASH_ALL || (!isSingle && !isNone)
58
57
 
59
- const subscript = new Script([...params.subscript.chunks])
60
- subscript.findAndDelete(new Script().writeOpCode(OP.OP_CODESEPARATOR))
58
+ const subscript = Script.fromBinary(params.subscript.toBinary())
59
+ subscript.removeCodeseparators()
61
60
 
62
61
  const currentInput = {
63
62
  sourceTXID: params.sourceTXID,
@@ -332,6 +331,15 @@ export default class TransactionSignature extends Signature {
332
331
  return new Uint8Array(0)
333
332
  }
334
333
 
334
+ static usesOtdaSingleBug (params: TransactionSignatureFormatParams): boolean {
335
+ const hasForkId = (params.scope & TransactionSignature.SIGHASH_FORKID) !== 0
336
+ const hasChronicle = params.ignoreChronicle !== true && (params.scope & TransactionSignature.SIGHASH_CHRONICLE) !== 0
337
+ const usesOtda = !hasForkId || (hasForkId && hasChronicle)
338
+ return usesOtda &&
339
+ (params.scope & 31) === TransactionSignature.SIGHASH_SINGLE &&
340
+ params.inputIndex >= params.outputs.length
341
+ }
342
+
335
343
  // The format used in a tx
336
344
  static fromChecksigFormat (buf: number[]): TransactionSignature {
337
345
  if (buf.length === 0) {
@@ -335,14 +335,11 @@ export default class Script {
335
335
  * @returns This script instance for chaining.
336
336
  */
337
337
  removeCodeseparators (): Script {
338
- this.invalidateSerializationCaches()
339
- const chunks: ScriptChunk[] = []
340
- for (let i = 0; i < this.chunks.length; i++) {
341
- if (this.chunks[i].op !== OP.OP_CODESEPARATOR) {
342
- chunks.push(this.chunks[i])
343
- }
344
- }
345
- this.chunks = chunks
338
+ const bytes = this.toUint8Array()
339
+ this.rawBytesCache = Uint8Array.from(Script.removeOpcodeBytes(bytes, OP.OP_CODESEPARATOR))
340
+ this.hexCache = undefined
341
+ this._chunks = []
342
+ this.parsed = false
346
343
  return this
347
344
  }
348
345
 
@@ -585,18 +582,22 @@ export default class Script {
585
582
  const end = Math.min(pos + len, length)
586
583
  chunks.push({
587
584
  data: Script.copyRange(bytes, pos, end),
588
- op
585
+ op,
586
+ invalidLength: end - pos !== len
589
587
  })
590
588
  pos = end
591
589
  } else if (op === OP.OP_PUSHDATA1) {
592
- const len = pos < length ? bytes[pos++] ?? 0 : 0
590
+ const hasLength = pos < length
591
+ const len = hasLength ? bytes[pos++] ?? 0 : 0
593
592
  const end = Math.min(pos + len, length)
594
593
  chunks.push({
595
594
  data: Script.copyRange(bytes, pos, end),
596
- op
595
+ op,
596
+ invalidLength: !hasLength || end - pos !== len
597
597
  })
598
598
  pos = end
599
599
  } else if (op === OP.OP_PUSHDATA2) {
600
+ const hasLength = pos + 1 < length
600
601
  const b0 = bytes[pos] ?? 0
601
602
  const b1 = bytes[pos + 1] ?? 0
602
603
  const len = b0 | (b1 << 8)
@@ -604,10 +605,12 @@ export default class Script {
604
605
  const end = Math.min(pos + len, length)
605
606
  chunks.push({
606
607
  data: Script.copyRange(bytes, pos, end),
607
- op
608
+ op,
609
+ invalidLength: !hasLength || end - pos !== len
608
610
  })
609
611
  pos = end
610
612
  } else if (op === OP.OP_PUSHDATA4) {
613
+ const hasLength = pos + 3 < length
611
614
  const len =
612
615
  ((bytes[pos] ?? 0) |
613
616
  ((bytes[pos + 1] ?? 0) << 8) |
@@ -618,7 +621,8 @@ export default class Script {
618
621
  const end = Math.min(pos + len, length)
619
622
  chunks.push({
620
623
  data: Script.copyRange(bytes, pos, end),
621
- op
624
+ op,
625
+ invalidLength: !hasLength || end - pos !== len
622
626
  })
623
627
  pos = end
624
628
  } else {
@@ -629,6 +633,48 @@ export default class Script {
629
633
  return chunks
630
634
  }
631
635
 
636
+ private static removeOpcodeBytes (bytes: ArrayLike<number>, opcode: number): number[] {
637
+ const out: number[] = []
638
+ const length = bytes.length
639
+ let pos = 0
640
+
641
+ while (pos < length) {
642
+ const start = pos
643
+ const op = bytes[pos++] ?? 0
644
+ let dataStart = pos
645
+ let dataLength = 0
646
+
647
+ if (op > 0 && op < OP.OP_PUSHDATA1) {
648
+ dataLength = op
649
+ } else if (op === OP.OP_PUSHDATA1) {
650
+ if (pos < length) dataLength = bytes[pos++] ?? 0
651
+ dataStart = pos
652
+ } else if (op === OP.OP_PUSHDATA2) {
653
+ if (pos + 1 < length) dataLength = (bytes[pos] ?? 0) | ((bytes[pos + 1] ?? 0) << 8)
654
+ pos = Math.min(pos + 2, length)
655
+ dataStart = pos
656
+ } else if (op === OP.OP_PUSHDATA4) {
657
+ if (pos + 3 < length) {
658
+ dataLength =
659
+ ((bytes[pos] ?? 0) |
660
+ ((bytes[pos + 1] ?? 0) << 8) |
661
+ ((bytes[pos + 2] ?? 0) << 16) |
662
+ ((bytes[pos + 3] ?? 0) << 24)) >>> 0
663
+ }
664
+ pos = Math.min(pos + 4, length)
665
+ dataStart = pos
666
+ }
667
+
668
+ const end = Math.min(dataStart + dataLength, length)
669
+ if (op !== opcode) {
670
+ for (let i = start; i < end; i++) out.push(bytes[i] ?? 0)
671
+ }
672
+ pos = end
673
+ }
674
+
675
+ return out
676
+ }
677
+
632
678
  private static copyRange (
633
679
  bytes: ArrayLike<number>,
634
680
  start: number,
@@ -4,4 +4,5 @@
4
4
  export default interface ScriptChunk {
5
5
  op: number
6
6
  data?: number[]
7
+ invalidLength?: boolean
7
8
  }