UNPKG

@vbyte/btc-dev

Version:

Batteries-included toolset for plebian bitcoin development

90 lines (89 loc) 3.36 kB
import { Buff } from '@vbyte/buff'; import { hash160, hash256 } from '@vbyte/micro-lib/hash'; import { Assert } from '@vbyte/micro-lib'; import { parse_txinput } from './util.js'; import { prefix_script_size, decode_script } from '../../lib/script/index.js'; import { encode_txin_vout, encode_tx_locktime, encode_txin_sequence, encode_txin_txid, encode_vout_value, encode_tx_version, parse_tx } from '../../lib/tx/index.js'; import * as CONST from '../../const.js'; export function hash_segwit_tx(txdata, options = {}) { const { sigflag = 0x01, txindex } = options; const tx = parse_tx(txdata); const is_anypay = (sigflag & 0x80) === 0x80; const flag = sigflag % 0x80; if (!CONST.SIGHASH_SEGWIT.includes(flag)) { throw new Error('Invalid hash type: ' + String(sigflag)); } const { version, vin, vout, locktime } = tx; const txinput = parse_txinput(tx, options); const { txid, vout: prevIdx, prevout, sequence } = txinput; const { value } = prevout ?? {}; if (value === undefined) { throw new Error('Prevout value is empty!'); } let { pubkey, script } = options; if (script === undefined && pubkey !== undefined) { const pkhash = hash160(pubkey).hex; script = `76a914${String(pkhash)}88ac`; } if (script === undefined) { throw new Error('No pubkey / script has been set!'); } if (decode_script(script).includes('OP_CODESEPARATOR')) { throw new Error('This library does not currently support the use of OP_CODESEPARATOR in segwit scripts.'); } const sighash = [ encode_tx_version(version), bip143_hash_prevouts(vin, is_anypay), bip143_hash_sequence(vin, flag, is_anypay), encode_txin_txid(txid), encode_txin_vout(prevIdx), prefix_script_size(script), encode_vout_value(value), encode_txin_sequence(sequence), bip143_hash_outputs(vout, flag, txindex), encode_tx_locktime(locktime), Buff.num(sigflag, 4).reverse() ]; return hash256(Buff.join(sighash)); } export function bip143_hash_prevouts(vin, isAnypay) { if (isAnypay === true) { return Buff.num(0, 32); } const stack = []; for (const { txid, vout } of vin) { stack.push(encode_txin_txid(txid)); stack.push(encode_txin_vout(vout)); } return hash256(Buff.join(stack)); } export function bip143_hash_sequence(vin, sigflag, isAnyPay) { if (isAnyPay || sigflag !== 0x01) { return Buff.num(0, 32); } const stack = []; for (const { sequence } of vin) { stack.push(encode_txin_sequence(sequence)); } return hash256(Buff.join(stack)); } export function bip143_hash_outputs(vout, sigflag, idx) { const stack = []; if (sigflag === 0x01) { for (const { value, script_pk } of vout) { stack.push(encode_vout_value(value)); stack.push(prefix_script_size(script_pk)); } return hash256(Buff.join(stack)); } if (sigflag === 0x03) { Assert.ok(idx !== undefined); if (idx < vout.length) { const { value, script_pk } = vout[idx]; stack.push(encode_vout_value(value)); stack.push(prefix_script_size(script_pk)); return hash256(Buff.join(stack)); } } return Buff.num(0, 32); }