@vbyte/btc-dev
Version:
Batteries-included toolset for plebian bitcoin development
86 lines (76 loc) • 1.88 kB
text/typescript
import { Buff, Bytes, Stream } from '@vbyte/buff'
import {
get_op_code,
get_op_type,
is_valid_op
} from './words.js'
import type { ScriptInfo } from '@/types/script.js'
export function parse_script (script: Bytes): ScriptInfo {
const bytes = Buff.bytes(script)
return {
asm: decode_script(bytes),
hex: bytes.hex
}
}
/**
* Decode a bitcoin script into asm instructions.
*/
export function decode_script (
script : Bytes
) : string[] {
const stream = new Stream(script)
const stack : string[] = []
const stack_size = stream.size
let word : number
let word_type : string
let word_size : number
let count = 0
while (count < stack_size) {
word = stream.read(1).num
word_type = get_op_type(word)
count++
switch (word_type) {
case 'varint':
stack.push(stream.read(word).hex)
count += word
break
case 'pushdata1':
word_size = stream.read(1).reverse().num
stack.push(stream.read(word_size).hex)
count += word_size + 1
break
case 'pushdata2':
word_size = stream.read(2).reverse().num
stack.push(stream.read(word_size).hex)
count += word_size + 2
break
case 'pushdata4':
word_size = stream.read(4).reverse().num
stack.push(stream.read(word_size).hex)
count += word_size + 4
break
case 'opcode':
if (!is_valid_op(word)) {
throw new Error(`Invalid OPCODE: ${word}`)
}
stack.push(get_op_code(word))
break
default:
throw new Error(`Word type undefined: ${word}`)
}
}
return stack
}
/**
* Check if a script is valid.
*/
export function is_valid_script (
script : string | Uint8Array
) : boolean {
try {
const stack = decode_script(script)
return stack.length > 0
} catch {
return false
}
}