From 62e9565c3e7a400b8c62ea5a5dc8c17a3245f6f4 Mon Sep 17 00:00:00 2001 From: codenlighten Date: Thu, 17 Sep 2026 11:30:57 -0400 Subject: [PATCH] Write an unnamed opcode in ASM as its raw byte, 0xba @smartledger/bsv 9.11.1 writes an opcode with no name as 0xba and reads it back from ASM. exactAsm wrote OP_UNKNOWN186, which nothing reads, so it refused any script holding one. It now writes 0xba; the read-back check still refuses such scripts where an older @smartledger/bsv is installed. Tests run against 9.11.1. --- README.md | 3 ++- package-lock.json | 8 ++++---- package.json | 2 +- src/script.js | 7 +++++-- test/unit.test.js | 2 ++ 5 files changed, 14 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 6c54d49..40d6f33 100644 --- a/README.md +++ b/README.md @@ -171,7 +171,8 @@ under the rules before Chronicle as well as after it. - **ASM cannot hold every script.** It does not record how data was pushed, so `--asm -o` refuses a result with a non-minimal push (optimized code is minimal, but `OP_0 OP_IF` blocks and data after `OP_RETURN` are kept - verbatim), a truncated push, an unnamed opcode, or only data pushes, rather + verbatim), a truncated push, an unnamed opcode with `@smartledger/bsv` older + than 9.11.1, or only data pushes, rather than write a different script. Hex and `--binary` output are always exact. - **Signatures commit to the script.** `OP_CHECKSIG` signs the script code, so diff --git a/package-lock.json b/package-lock.json index 3fc8d40..cf822e0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "scriptmin": "bin/scriptmin.js" }, "devDependencies": { - "@smartledger/bsv": "^9.11.0" + "@smartledger/bsv": "^9.11.1" }, "engines": { "node": ">=20.19" @@ -64,9 +64,9 @@ } }, "node_modules/@smartledger/bsv": { - "version": "9.11.0", - "resolved": "https://registry.npmjs.org/@smartledger/bsv/-/bsv-9.11.0.tgz", - "integrity": "sha512-iUyHgEWAz8dHGHKMuUHjLN3fgO7Z+Od6DHq0m33j9CPlUmSQksT8+jmMVz2oM3lGLlk4CJwoxj9gySGrtf3NsQ==", + "version": "9.11.1", + "resolved": "https://registry.npmjs.org/@smartledger/bsv/-/bsv-9.11.1.tgz", + "integrity": "sha512-l7rB+UaHft9camYLqhMStL6ox9jeEPkSFyMNW16OIMjrm4BvDkskv9UrF9KhJXLM0XKbeO1H/ASYWUPGhEKWQA==", "dev": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 554ee43..105666a 100644 --- a/package.json +++ b/package.json @@ -44,6 +44,6 @@ "@smartledger/bsv": "^9.10.1" }, "devDependencies": { - "@smartledger/bsv": "^9.11.0" + "@smartledger/bsv": "^9.11.1" } } diff --git a/src/script.js b/src/script.js index 8eb880b..7c4aad1 100644 --- a/src/script.js +++ b/src/script.js @@ -181,6 +181,9 @@ function toAsm (ops, { maxData = 0, bare = false } = {}) { const shown = maxData && hex.length > maxData * 2 ? hex.slice(0, maxData * 2) + '…' : hex return op.code >= OP.OP_PUSHDATA1 && !bare ? `${opName(op.code)}:${shown}` : shown } + // An opcode with no name is written as its raw byte, as @smartledger/bsv + // writes it (and reads it back from 9.11.1). + if (bare && !NAMES[op.code]) return '0x' + op.code.toString(16).padStart(2, '0') return opName(op.code) }).join(' ') } @@ -229,8 +232,8 @@ function exactAsm (buf) { ? 'it contains a truncated push' : ops.some(o => isPush(o) && o.code !== TAIL && opSize(pushOp(pushValue(o))) !== opSize(o)) ? 'a push is not minimally encoded, and ASM cannot say how data was pushed' - : /OP_UNKNOWN|\bOP_INVALIDOPCODE\b/.test(asm) || ops.some(o => o.code >= 0 && !isPush(o) && !NAMES[o.code]) - ? 'it uses an opcode that has no name in ASM' + : ops.some(o => o.code >= 0 && !isPush(o) && !NAMES[o.code]) + ? 'it uses an opcode that has no name, which @smartledger/bsv reads back from ASM only from 9.11.1' : !/\bOP_/.test(asm) ? 'it is only data pushes, and ASM with no opcodes reads back as hex' : 'its ASM reads back as a different script' diff --git a/test/unit.test.js b/test/unit.test.js index 0d99899..3d132a5 100644 --- a/test/unit.test.js +++ b/test/unit.test.js @@ -199,6 +199,8 @@ test('ASM output reads back byte for byte, or is refused', () => { assert.ok(toBuffer(exactAsm(buf)).equals(buf), src) } assert.throws(() => exactAsm(Buffer.from('4c03aabbcc51', 'hex')), /not minimally encoded/) + // An unnamed opcode is written as its raw byte, 0xba. + assert.strictEqual(exactAsm(Buffer.from('51ba6a05aabbccddee', 'hex')), 'OP_1 0xba OP_RETURN aabbccddee') assert.throws(() => exactAsm(Buffer.from('516a05aabb', 'hex')), /truncated push/) assert.throws(() => exactAsm(Buffer.from('4c50' + 'ab'.repeat(80), 'hex')), /only data pushes/)