@bsv/sdk 2.0.0 → 2.0.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bsv/sdk",
3
- "version": "2.0.0",
3
+ "version": "2.0.1",
4
4
  "type": "module",
5
5
  "description": "BSV Blockchain Software Development Kit",
6
6
  "main": "dist/cjs/mod.js",
@@ -355,11 +355,74 @@ export default class Script {
355
355
  */
356
356
  findAndDelete (script: Script): Script {
357
357
  this.invalidateSerializationCaches()
358
- const buf = script.toHex()
358
+ const targetBytes = script.toUint8Array()
359
+ const targetLen = targetBytes.length
360
+ if (targetLen === 0) return this
361
+
362
+ const targetOp = targetBytes[0] ?? 0
363
+
364
+ const matchesChunk = (chunk: ScriptChunk): boolean => {
365
+ if (chunk.op !== targetOp) return false
366
+ const dataArr = chunk.data ?? []
367
+ const dataLen = dataArr.length
368
+
369
+ if (dataLen === 0) {
370
+ return targetLen === 1
371
+ }
372
+
373
+ if (chunk.op === OP.OP_RETURN) {
374
+ if (targetLen !== 1 + dataLen) return false
375
+ for (let j = 0; j < dataLen; j++) {
376
+ if (targetBytes[1 + j] !== dataArr[j]) return false
377
+ }
378
+ return true
379
+ }
380
+
381
+ if (chunk.op < OP.OP_PUSHDATA1) {
382
+ if (targetLen !== 1 + dataLen) return false
383
+ for (let j = 0; j < dataLen; j++) {
384
+ if (targetBytes[1 + j] !== dataArr[j]) return false
385
+ }
386
+ return true
387
+ }
388
+
389
+ if (chunk.op === OP.OP_PUSHDATA1) {
390
+ if (targetLen !== 2 + dataLen) return false
391
+ if (targetBytes[1] !== (dataLen & 0xff)) return false
392
+ for (let j = 0; j < dataLen; j++) {
393
+ if (targetBytes[2 + j] !== dataArr[j]) return false
394
+ }
395
+ return true
396
+ }
397
+
398
+ if (chunk.op === OP.OP_PUSHDATA2) {
399
+ if (targetLen !== 3 + dataLen) return false
400
+ if (targetBytes[1] !== (dataLen & 0xff)) return false
401
+ if (targetBytes[2] !== ((dataLen >> 8) & 0xff)) return false
402
+ for (let j = 0; j < dataLen; j++) {
403
+ if (targetBytes[3 + j] !== dataArr[j]) return false
404
+ }
405
+ return true
406
+ }
407
+
408
+ if (chunk.op === OP.OP_PUSHDATA4) {
409
+ if (targetLen !== 5 + dataLen) return false
410
+ const size = dataLen >>> 0
411
+ if (targetBytes[1] !== (size & 0xff)) return false
412
+ if (targetBytes[2] !== ((size >> 8) & 0xff)) return false
413
+ if (targetBytes[3] !== ((size >> 16) & 0xff)) return false
414
+ if (targetBytes[4] !== ((size >> 24) & 0xff)) return false
415
+ for (let j = 0; j < dataLen; j++) {
416
+ if (targetBytes[5 + j] !== dataArr[j]) return false
417
+ }
418
+ return true
419
+ }
420
+
421
+ return false
422
+ }
423
+
359
424
  for (let i = 0; i < this.chunks.length;) {
360
- const script2 = new Script([this.chunks[i]])
361
- const buf2 = script2.toHex()
362
- if (buf === buf2) {
425
+ if (matchesChunk(this.chunks[i])) {
363
426
  this.chunks.splice(i, 1)
364
427
  } else {
365
428
  i++
@@ -354,12 +354,45 @@ describe('Script', () => {
354
354
  })
355
355
 
356
356
  describe('#findAndDelete', () => {
357
- it('should find and delete this buffer', () => {
358
- expect(
359
- Script.fromASM('OP_RETURN f0f0')
360
- .findAndDelete(Script.fromASM('f0f0'))
361
- .toASM()
362
- ).toEqual('OP_RETURN')
357
+ it('should delete all matching single-chunk scripts', () => {
358
+ const target = new Script().writeBin([0xf0, 0xf0])
359
+ const script = new Script()
360
+ .writeOpCode(OP.OP_RETURN)
361
+ .writeBin([0xf0, 0xf0])
362
+ .writeOpCode(OP.OP_1)
363
+ .writeBin([0xf0, 0xf0])
364
+
365
+ expect(script.findAndDelete(target).toASM()).toEqual('OP_RETURN OP_1')
366
+ })
367
+
368
+ it('should match OP_RETURN chunks with data', () => {
369
+ const target = new Script([{ op: OP.OP_RETURN, data: [0x01, 0x02, 0x03] }])
370
+ const script = new Script([
371
+ { op: OP.OP_RETURN, data: [0x01, 0x02, 0x03] },
372
+ { op: OP.OP_1 }
373
+ ])
374
+
375
+ expect(script.findAndDelete(target).toASM()).toEqual('OP_1')
376
+ })
377
+
378
+ it('should handle PUSHDATA2 payloads', () => {
379
+ const data = Array.from({ length: 300 }, (_, i) => i & 0xff)
380
+ const other = data.slice()
381
+ other[0] = (other[0] + 1) & 0xff
382
+
383
+ const target = new Script().writeBin(data)
384
+ const script = new Script().writeBin(other).writeBin(data).writeOpCode(OP.OP_1)
385
+
386
+ script.findAndDelete(target)
387
+ expect(script.chunks).toHaveLength(2)
388
+ expect(script.chunks[0].data).toEqual(other)
389
+ expect(script.chunks[1].op).toEqual(OP.OP_1)
390
+ })
391
+
392
+ it('should not delete when the target has multiple chunks', () => {
393
+ const script = Script.fromASM('OP_1')
394
+ const target = Script.fromASM('OP_1 OP_2')
395
+ expect(script.findAndDelete(target).toASM()).toEqual('OP_1')
363
396
  })
364
397
  })
365
398