Script¶
The BSV::Script module handles Bitcoin script parsing, construction, and execution. Scripts define the spending conditions for transaction outputs.
Creating Scripts¶
From Serialised Data¶
# From hex
script = BSV::Script::Script.from_hex('76a914751e76e8199196d454941c45d1b3a323f1433bd688ac')
# From binary
script = BSV::Script::Script.from_binary(binary_data)
# From ASM (human-readable opcodes)
script = BSV::Script::Script.from_asm(
'OP_DUP OP_HASH160 751e76e8199196d454941c45d1b3a323f1433bd6 OP_EQUALVERIFY OP_CHECKSIG'
)
From Chunks¶
script = BSV::Script::Script.from_chunks([
BSV::Script::Chunk.new(opcode: BSV::Script::Opcodes::OP_DUP),
BSV::Script::Chunk.new(opcode: BSV::Script::Opcodes::OP_HASH160),
BSV::Script::Chunk.new(opcode: 0x14, data: pubkey_hash),
BSV::Script::Chunk.new(opcode: BSV::Script::Opcodes::OP_EQUALVERIFY),
BSV::Script::Chunk.new(opcode: BSV::Script::Opcodes::OP_CHECKSIG)
])
Script Templates¶
Templates provide convenient constructors for common script patterns.
P2PKH (Pay to Public Key Hash)¶
The most common script type. Locks funds to a public key hash (address).
pubkey_hash = private_key.public_key.hash160 # 20 bytes
# Locking script: OP_DUP OP_HASH160 <hash> OP_EQUALVERIFY OP_CHECKSIG
lock = BSV::Script::Script.p2pkh_lock(pubkey_hash)
# Unlocking script: <sig> <pubkey>
unlock = BSV::Script::Script.p2pkh_unlock(signature_bytes, pubkey_bytes)
P2PK (Pay to Public Key)¶
Locks funds directly to a public key (no hashing).
pubkey = private_key.public_key.compressed # 33 bytes
# Locking script: <pubkey> OP_CHECKSIG
lock = BSV::Script::Script.p2pk_lock(pubkey)
# Unlocking script: <sig>
unlock = BSV::Script::Script.p2pk_unlock(signature_bytes)
Multisig (m-of-n)¶
Requires m signatures from n public keys.
keys = [alice_pubkey, bob_pubkey, carol_pubkey] # compressed public key bytes
# Locking script: OP_2 <key1> <key2> <key3> OP_3 OP_CHECKMULTISIG
lock = BSV::Script::Script.p2ms_lock(2, keys) # 2-of-3
# Unlocking script: OP_0 <sig1> <sig2>
unlock = BSV::Script::Script.p2ms_unlock(sig1, sig2)
OP_RETURN (Data Carrier)¶
Store arbitrary data on-chain. The output carries zero satoshis.
# Single data item
script = BSV::Script::Script.op_return('hello world'.b)
# Multiple data items (push each separately)
script = BSV::Script::Script.op_return(
'app-prefix'.b,
'payload'.b,
[Time.now.to_i].pack('V')
)
Builder Pattern¶
For custom scripts, use the builder:
script = BSV::Script::Script.builder
.push_op(:OP_DUP)
.push_op(:OP_HASH160)
.push_data(pubkey_hash)
.push_op(:OP_EQUALVERIFY)
.push_op(:OP_CHECKSIG)
.build
Serialisation¶
script.to_hex # hex string
script.to_binary # raw bytes
script.to_asm # "OP_DUP OP_HASH160 751e76... OP_EQUALVERIFY OP_CHECKSIG"
script.length # byte length of the serialised script
Type Detection¶
Scripts can be classified by their pattern:
script.p2pkh? # Pay to Public Key Hash
script.p2pk? # Pay to Public Key
script.multisig? # m-of-n Multisig
script.op_return? # OP_RETURN (data carrier)
script.p2sh? # Pay to Script Hash (read-only detection)
# General classification
script.type
#=> 'pubkeyhash', 'pubkey', 'multisig', 'nulldata',
# 'scripthash', 'empty', or 'nonstandard'
P2SH Detection
P2SH scripts are detected for completeness (e.g. when parsing historical transactions), but BSV does not support P2SH execution. No P2SH constructors are provided.
Data Extraction¶
Extract structured data from known script types:
# P2PKH: extract the 20-byte public key hash
script.pubkey_hash #=> "\x75\x1e\x76..." or nil
# P2SH: extract the 20-byte script hash
script.script_hash #=> "\xa9\x14..." or nil
# OP_RETURN: extract data items
script.op_return_data #=> ["\x68\x65\x6c\x6c\x6f"] or nil
# Addresses (for P2PKH scripts)
script.addresses # mainnet
script.addresses(network: :testnet) # testnet
Working with Chunks¶
Scripts are composed of chunks — either opcodes or data pushes. Chunks are lazily parsed on first access.
chunks = script.chunks
chunks.each do |chunk|
if chunk.data
puts "DATA: #{chunk.data.unpack1('H*')} (#{chunk.data.bytesize} bytes)"
else
puts "OP: #{BSV::Script::Opcodes.name_for(chunk.opcode)}"
end
end
Script Interpreter¶
Verify that an unlocking script satisfies a locking script:
BSV::Script::Interpreter.verify(
tx: transaction,
input_index: 0,
unlock_script: input.unlocking_script,
lock_script: input.source_locking_script,
satoshis: input.source_satoshis
)
#=> true or false
The interpreter supports post-Genesis BSV opcodes and enforces FORKID sighash validation.