Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions lib/contracts/conditional.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# Copyright 2024 Kulpreet Singh
#
# This file is part of Bitcoin-DSL
#
# Bitcoin-DSL is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Bitcoin-DSL is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Bitcoin-DSL. If not, see <https://www.gnu.org/licenses/>.

# frozen_string_literal: false

@alice = key :new
@bob = key :new

extend_chain to: @alice, num_blocks: 101

@input_tx = spendable_coinbase_for @alice

@conditional_output_script = %(
OP_IF
@alice OP_CHECKSIGVERIFY 10 OP_CSV
OP_ELSE
@bob OP_CHECKSIGVERIFY 10 OP_CSV
OP_ENDIF
)

@generate_conditional_output = transaction inputs: [
{
tx: @input_tx,
vout: 0,
script_sig: 'sig:wpkh(@alice)'
}
],
outputs: [
{
script: @conditional_output_script,
amount: 49.999.sats
}
]
@spending_tx = transaction inputs: [
{
tx: @generate_conditional_output,
vout: 0,
script_sig: 'sig:@alice 0x01',
csv: 10
}
],
outputs: [
{
descriptor: 'wpkh(@alice)',
amount: 49.998.sats
}
]

broadcast @generate_conditional_output
confirm transaction: @generate_conditional_output, to: @bob

assert_not_mempool_accept @spending_tx
extend_chain num_blocks: 10
assert_mempool_accept @spending_tx
133 changes: 133 additions & 0 deletions lib/contracts/lightning/eltoo_onchain.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
# Copyright 2024 Kulpreet Singh
#
# This file is part of Bitcoin-DSL
#
# Bitcoin-DSL is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Bitcoin-DSL is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Bitcoin-DSL. If not, see <https://www.gnu.org/licenses/>.

# frozen_string_literal: false

@alice = key :new
@alice_settlement_key = key :new

@bob = key :new
@bob_settlement_key = key :new

@update_script = %(
OP_IF
2 @alice_settlement_key @bob_settlement_key 2 OP_CHECKMULTISIGVERIFY 10 OP_CSV
OP_ELSE
2 @alice @bob 2 OP_CHECKMULTISIG
OP_ENDIF
)

transition :setup do
extend_chain to: @alice, num_blocks: 101
@alice_input_tx = spendable_coinbase_for @alice

@setup_tx = transaction inputs: [{ tx: @alice_input_tx, vout: 0, script_sig: 'sig:_skip' }],
outputs: [{ script: @update_script, amount: 49.999.sats }]
assert_not_mempool_accept @setup_tx
end

transition :bob_creates_settlement do
@settlement_tx = transaction inputs: [{ tx: @setup_tx,
vout: 0,
script_sig: 'sig:multi(_empty,@bob_settlement_key) 0x01',
csv: 10 }],
outputs: [{ descriptor: 'wpkh(@alice)',
amount: 49.998.sats }]
end

transition :alice_broadcasts_setup_tx do
# Alice signs the funding transaction and broadcasts it
update_script_sig for_tx: @setup_tx, at_index: 0, with_script_sig: 'sig:wpkh(@alice)'
broadcast @setup_tx
confirm transaction: @setup_tx, to: @bob
end

transition :alice_signs_settlement do
update_script_sig for_tx: @settlement_tx, at_index: 0,
with_script_sig: 'sig:multi(@alice_settlement_key,@bob_settlement_key) 0x01'
extend_chain num_blocks: 10
assert_mempool_accept @settlement_tx
end

transition :alice_broadcasts_settlement do
broadcast @settlement_tx
confirm transaction: @settlement_tx
end

transition :create_new_update do
# new update transaction spending setup tx
@update_tx = transaction inputs: [{ tx: @setup_tx, vout: 0, script_sig: 'sig:multi(@alice,@bob) ""' }],
outputs: [{ script: @update_script, amount: 49.998.sats }]
assert_mempool_accept @update_tx
end

transition :broadcast_new_update do
broadcast @update_tx
confirm transaction: @update_tx
end

transition :create_new_settlement do
# new settlement transaction spending update tx
@new_settlement_tx = transaction inputs: [{ tx: @update_tx, vout: 0,
script_sig: 'sig:multi(_empty,@bob_settlement_key) 0x01', csv: 10 }],
outputs: [{ descriptor: 'wpkh(@alice)', amount: 48.997.sats },
{ descriptor: 'wpkh(@bob)', amount: 1.sats }]
assert_not_mempool_accept @new_settlement_tx
end

transition :broadcast_new_settlement do
update_script_sig for_tx: @new_settlement_tx, at_index: 0,
with_script_sig: 'sig:multi(@alice_settlement_key,@bob_settlement_key) 0x01'
extend_chain num_blocks: 10
broadcast @new_settlement_tx
confirm transaction: @new_settlement_tx
end

transition :broadcast_new_settlement_fails do
update_script_sig for_tx: @new_settlement_tx, at_index: 0,
with_script_sig: 'sig:multi(@alice_settlement_key,@bob_settlement_key) 0x01'
extend_chain num_blocks: 10
assert_not_mempool_accept @new_settlement_tx
end

# Simple case: settlement immediately spends from setup
run_transitions :setup,
:bob_creates_settlement,
:alice_broadcasts_setup_tx,
:alice_signs_settlement,
:alice_broadcasts_settlement

# Create an update and a new settlement, and finally spend the settlement.
# In this case, the setup is spent by an update which is spent by the settlement.
run_transitions :reset,
:setup,
:bob_creates_settlement,
:alice_broadcasts_setup_tx,
:create_new_update,
:create_new_settlement,
:broadcast_new_update,
:broadcast_new_settlement

# Capture the case where a settlement fails to be spent before the
# update has confirmed
run_transitions :reset,
:setup,
:bob_creates_settlement,
:alice_broadcasts_setup_tx,
:create_new_update,
:create_new_settlement,
:broadcast_new_settlement_fails
2 changes: 1 addition & 1 deletion lib/contracts/silent_payments.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
# tag::silent-payment[]
@sender_input_key = key :new # <1>
@sender = key :new
@receiver = key :new
@receiver = key even_y: true # Generate a key with even y

extend_chain to: @sender_input_key, num_blocks: 101

Expand Down
23 changes: 11 additions & 12 deletions lib/contracts/taproot/scriptpath_spend.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
# frozen_string_literal: false

# Generate new keys
Bitcoin::Node::Configuration.new(network: :regtest)
@alice = key wif: 'cNtZwU6mYnUXDJtPqfyEaRsZuNy6C5PCZHY16xbps85HvRSn9KqE'
@bob = key wif: 'cMyDpdQkC1qRfWYNQHXawUwzEmXyFjv7PYw2EqYFRnhXhBs4bXt9'
@carol = key wif: 'cRCuYhzDcPPCjfVZPzSiuRAsXUgivChpz5xEfeXPRAi2EDnuHymz'
Expand All @@ -33,17 +32,17 @@

# tag::taproot_tx[]
@taproot_output_tx = transaction inputs: [
{ tx: @coinbase_tx,
vout: 0,
script_sig: 'sig:wpkh(@alice)' }
],
outputs: [
{
taproot: { internal_key: @bob, # <1>
leaves: ['pk(@carol)', 'pk(@alice)'] }, # <2>
amount: 49.999.sats
}
]
{ tx: @coinbase_tx,
vout: 0,
script_sig: 'sig:wpkh(@alice)' }
],
outputs: [
{
taproot: { internal_key: @bob, # <1>
leaves: ['pk(@carol)', 'pk(@alice)'] }, # <2>
amount: 49.999.sats
}
]
# end::taproot_tx[]

broadcast @taproot_output_tx
Expand Down
26 changes: 21 additions & 5 deletions lib/dsl/key.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,34 @@
module Key
include GroupOperations

def self.included(_mod)
Bitcoin::Node::Configuration.new(network: :regtest)
end

def key(params = {})
if params.is_a?(Hash)
if params.include?(:wif)
Bitcoin::Key.from_wif params[:wif]
elsif params.include?(:from_point)
Bitcoin::Key.from_point params[:from_point]
end
from_params(params)
else
Bitcoin::Key.generate
end
end

def from_params(params)
if params.include?(:wif)
Bitcoin::Key.from_wif params[:wif]
elsif params.include?(:from_point)
Bitcoin::Key.from_point params[:from_point]
elsif params.include?(:even_y)
even_y
end
end

def even_y
generated = Bitcoin::Key.generate
generated = Bitcoin::Key.generate until generated.to_point.has_even_y?
generated
end

def point_from(key)
key.to_point
end
Expand Down
2 changes: 1 addition & 1 deletion spec/dsl/key_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
include Key

before(:context) do
@key = key wif: 'KztsFfy2uzazyo2zLgXneWH1U97Rv2dAiRQn74tR7qGMMYAjfGhD'
@key = key wif: 'cT3dEHwpi1EWbRxiUQaPYUYmeHTq2hSJRA4j81WoM5hiq3ZM33UK'
@message = Bitcoin.sha256('message')
end

Expand Down
5 changes: 5 additions & 0 deletions spec/runner_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@

describe 'Running contracts with CSV and CLTV' do
it_behaves_like 'script evaluation', './lib/contracts/csv.rb'
it_behaves_like 'script evaluation', './lib/contracts/conditional.rb'
it_behaves_like 'script evaluation', './lib/contracts/cltv.rb'
end

Expand All @@ -76,4 +77,8 @@
it_behaves_like 'script evaluation', './lib/contracts/taproot/keypath_spend.rb'
it_behaves_like 'script evaluation', './lib/contracts/taproot/scriptpath_spend.rb'
end

describe 'silent payment' do
it_behaves_like 'script evaluation', './lib/contracts/silent_payments.rb'
end
end