Bitcoin DSL

Make it easy to build and execute bitcoin transactions.

An Example Script

Here is the simplest script that mines a block to WPKH and makes the coinbase spendable by mining 101 blocks.

A bitcoin regtest node is automatically setup, started, stopped and cleaned up for you.

Setup Keys and Coinbases
@alice = key :new (2)
extend_chain to: @alice, num_blocks: 101 (3)
assert_height 101 (4)
1 A bitcoin regtest node is setup and started before running the script
2 Setup a key pair and assign it to variable @alice
3 Mine 101 blocks to WPKH for @alice
4 Assert block height
5 The bitcoin node is stopped and all data directories are deleted

Bitcoin DSL is NOT

  1. Not a language to write Bitcoin Script: Miniscript and Descriptors already do a great job of this. The DSL instead uses these innovations.

  2. Not dependent on a specific BIP: Bitcoin DSL is not meant to demonstrate any new bitcoin improvements opcodes or forks.

What is Bitcoin DSL?

Bitcoin DSL makes it easier to experiment with Bitcoin transactions and contracts by providing a highlevel language to build and execute transactions.

The DSL does so by providing a declarative syntax for the following.

  1. Building transactions

  2. Writing locking and unlocking scripts

  3. Executing multiple branches of contracts

  4. Interaction with bitcoin node

  5. Asserting system state

The DSL’s declarative syntax specifies what needs to be done, not how.

For example, we simply declare what a transaction should look like and don’t have to construct it one command at a time, as shown in the example next.

Example: Find and Spend a Coinbase

The following script, which can be executed by the DSL runtime, will do the following:

  • Start a bitcoin node

  • Mine new blocks with coinbase using a specified policy

  • Create new keys and transaction that spends the coinbase

  • broadcast and confirm the transaction

  • Clean up after itself by kill the bitcoin node and removing any data files

# When executing this script, the DSL runtime starts a new bitcoin node
@alice = key :new (1)
extend_chain to: @alice, num_blocks: 101 (2)
@alice_coinbase = get_coinbase_at 1 (3)

@alice_to_bob = transaction (4)
	      inputs: [
	        { tx: @alice_coinbase, vout: 0, script_sig: 'sig:wpkh(@alice)' } (5)
              outputs: [
	        { descriptor: 'wpkh(@bob)', amount: 49.99.sats } (6)

broadcast @alice_to_bob (6)
confirm @alice_to_bob (7)
assert_confirmations @alice_to_bob, confirmations: 1 (8)
# When the script ends, the DSL runtime stops the bitcoin node and removes all data files
1 Build a new key pair and assign it to variable @alice
2 Mine 101 blocks, making the first block spendable
3 Get the coinbase from the first block
4 Start building a new transaction and assign it to @alice_to_bob
5 Spend first output from @alice_coinbase. sig:wpkh(@alice) signs the transaction by using the correct witness program.
6 Broadcast the new transaction
7 Mine a new block to confirm the new transaction
8 Assert that @alice_to_bob transaction has one confirmation
The DSL uses sane defaults like using SegWit and defaulting to P2SWH.

Locking and Unlocking Scripts

Bitcoin DSL supports using miniscript, descriptors and Script to specify the locking script for an output. The example shows the policy for funding transaction of the ARK protocol - described using miniscript. See the details of the various options at Locking and unlocking script.

Example locking script using Policy
policy: 'or(99@thresh(2,pk(@alice),pk(@asp)),and(older(10),pk(@asp_timelock)))'
Example unlocking script using DSL extension
script_sig: 'sig:@asp_timelock @asp_timelock 0x01'

Contract Branch Executions

Bitcoin DSL makes it easy way to run various branches of a contract specification, by allowing composition of scripts.

We define state_transitions of the system and then run a series of state_transitions by using run_transitions.

# Define state transitions
state_transition :setup do

state_transition :exchange_signatures do

state_transition :cooperative_close do

state_transition :unilateral_close do

# Setup to cooperative close
run_transitions :setup, :exchange_signatures, :cooperate_close

# Setup to unilateral close
run_transitions :setup, :exchange_signatures, :unilateral_close

The Lightning Contracts is an excellent overview of how we use multiple scripts and compose the execution of the contract along various branches.

Interact With Bitcoin Node

All the Bitcoin JSON-RPC API commands are directly available from the DSL, so we don’t have to copy paste transactions around, and can query the bitcoin node to find transactions and then operate on them.

# Broadcast a transaction to local regtest node
broadcast @alice_tx

# Extend the local regest chain with a coinbase for pwkh(@alice)
extend_chain to: @alice

# Find a coinbase spendable by the keypair @alice
@alice_coinbase_utxo = spendable_coinbase_for @alice

Jump to Node Interaction.

Assert System State

Contract developers can verify the state of the transactions and the chain using high level commands.

# Confirm a transaction is confirmed
assert_confirmations @alice_tx, confirmations: 10

# Assert a transaction will be accepted by mempool
assert_mempool_accept @alice_tx

# Assert height of chain
assert_height 100

Jump to Assertions