Skip to content
Open
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
3 changes: 3 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions smite-ir/src/generators/funding_created.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ impl Generator for FundingCreatedGenerator {
fn generate(&self, builder: &mut ProgramBuilder, rng: &mut impl Rng) {
// Funding and commitment transaction keys and parameters.
let opener_funding_privkey = builder.pick_variable(VariableType::PrivateKey, rng);
let opener_htlc_basepoint_privkey = builder.pick_variable(VariableType::PrivateKey, rng);
let opener_funding_pubkey =
builder.append(Operation::DerivePoint, &[opener_funding_privkey]);
let acceptor_funding_pubkey = builder.pick_variable(VariableType::Point, rng);
Expand All @@ -44,6 +45,7 @@ impl Generator for FundingCreatedGenerator {
&[
funding_transaction,
opener_funding_privkey,
opener_htlc_basepoint_privkey,
temporary_channel_id,
],
);
Expand Down
7 changes: 6 additions & 1 deletion smite-ir/src/generators/funding_flow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,12 @@ impl Generator for FundingFlowGenerator {
let funding_privkey = builder.generate_fresh(VariableType::PrivateKey, rng);
let funding_pubkey = builder.append(Operation::DerivePoint, &[funding_privkey]);

// Generate a fresh HTLC basepoint key pair for the commitment transaction.
let htlc_basepoint_privkey = builder.generate_fresh(VariableType::PrivateKey, rng);
let htlc_basepoint = builder.append(Operation::DerivePoint, &[htlc_basepoint_privkey]);

// Build and send open_channel.
let open_channel = append_open_channel(builder, rng, funding_pubkey);
let open_channel = append_open_channel(builder, rng, funding_pubkey, htlc_basepoint);

// Receive accept_channel.
let accept_channel = builder.append(
Expand Down Expand Up @@ -55,6 +59,7 @@ impl Generator for FundingFlowGenerator {
&[
funding_transaction,
funding_privkey,
htlc_basepoint_privkey,
open_channel.temporary_channel_id,
],
);
Expand Down
9 changes: 5 additions & 4 deletions smite-ir/src/generators/open_channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,14 +88,14 @@ pub fn append_open_channel(
builder: &mut ProgramBuilder,
rng: &mut impl Rng,
funding_pubkey: usize,
htlc_basepoint: usize,
) -> OpenChannelVars {
type Bounds = OpenChannelGenerator;

// Public keys are generated fresh to ensure they're distinct.
let revocation_basepoint = builder.generate_fresh(VariableType::Point, rng);
let payment_basepoint = builder.generate_fresh(VariableType::Point, rng);
let delayed_payment_basepoint = builder.generate_fresh(VariableType::Point, rng);
let htlc_basepoint = builder.generate_fresh(VariableType::Point, rng);
let first_per_commitment_point = builder.generate_fresh(VariableType::Point, rng);

// Bounds for the channel parameters, so generators are more likely to
Expand Down Expand Up @@ -193,12 +193,13 @@ pub fn append_open_channel(

impl Generator for OpenChannelGenerator {
fn generate(&self, builder: &mut ProgramBuilder, rng: &mut impl Rng) {
// The funding public key is generated fresh to ensure it's distinct
// from the basepoints.
// The funding public key and HTLC basepoint are generated fresh to
// ensure they are distinct from the other basepoints.
let funding_pubkey = builder.generate_fresh(VariableType::Point, rng);
let htlc_basepoint = builder.generate_fresh(VariableType::Point, rng);

// Build and send open_channel.
let open_channel = append_open_channel(builder, rng, funding_pubkey);
let open_channel = append_open_channel(builder, rng, funding_pubkey, htlc_basepoint);

// Receive accept_channel.
builder.append(
Expand Down
6 changes: 4 additions & 2 deletions smite-ir/src/operation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,10 +184,11 @@ pub enum Operation {
/// Build and send a `funding_created` message (BOLT 2, type 34).
/// Produces a `SentFundingCreated` variable.
///
/// Inputs (3):
/// Inputs (4):
/// 0: `funding_transaction` (`FundingTransaction`)
/// 1: `opener_funding_privkey` (`PrivateKey`)
/// 2: `temporary_channel_id` (`ChannelId`)
/// 2: `opener_htlc_basepoint_privkey` (`PrivateKey`)
/// 3: `temporary_channel_id` (`ChannelId`)
SendFundingCreated,
/// Build and send a `channel_ready` message (BOLT 2, type 36).
///
Expand Down Expand Up @@ -705,6 +706,7 @@ impl Operation {
Self::SendFundingCreated => vec![
VariableType::FundingTransaction, // funding_transaction
VariableType::PrivateKey, // opener_funding_privkey
VariableType::PrivateKey, // opener_htlc_basepoint_privkey
VariableType::ChannelId, // temporary_channel_id
],
Self::SendChannelReady { .. } => vec![
Expand Down
17 changes: 11 additions & 6 deletions smite-ir/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -667,7 +667,7 @@ fn postcard_roundtrip() {
},
Instruction {
operation: Operation::SendFundingCreated,
inputs: vec![11, 0, 3],
inputs: vec![11, 0, 8, 3],
},
],
};
Expand Down Expand Up @@ -829,19 +829,23 @@ fn displays_send_funding_created_recv_funding_signed_program() {
inputs: vec![1, 1, 2, 3],
},
// funding_created parameters.
Instruction {
operation: Operation::LoadPrivateKey(key(2)),
inputs: vec![],
},
Instruction {
operation: Operation::LoadChannelId([0xbb; 32]),
inputs: vec![],
},
// Build and send funding_created.
Instruction {
operation: Operation::SendFundingCreated,
inputs: vec![4, 0, 5],
inputs: vec![4, 0, 5, 6],
},
// receive funding_signed.
Instruction {
operation: Operation::RecvFundingSigned,
inputs: vec![6],
inputs: vec![7],
},
];

Expand All @@ -858,9 +862,10 @@ fn displays_send_funding_created_recv_funding_signed_program() {
"v2 = LoadAmount(10000000)".into(),
"v3 = LoadFeeratePerKw(15000)".into(),
"v4 = CreateFundingTransaction(v1, v1, v2, v3)".into(),
format!("v5 = LoadChannelId(0x{b32})"),
"v6 = SendFundingCreated(v4, v0, v5)".into(),
"v7 = RecvFundingSigned(v6)".into(),
format!("v5 = LoadPrivateKey(0x{z31}02)"),
format!("v6 = LoadChannelId(0x{b32})"),
"v7 = SendFundingCreated(v4, v0, v5, v6)".into(),
"v8 = RecvFundingSigned(v7)".into(),
];

assert_eq!(lines.len(), expected.len(), "line count mismatch");
Expand Down
14 changes: 11 additions & 3 deletions smite-scenarios/src/executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -797,7 +797,7 @@ fn build_open_channel(variables: &[Option<Variable>], inputs: &[usize]) -> OpenC
}
}

/// Builds a `funding_created` message from 3 input variables.
/// Builds a `funding_created` message from 4 input variables.
///
/// Channel parameters are read from the negotiated `open_channel` and
/// `accept_channel` messages recorded in `negotiations`, ensuring the
Expand All @@ -806,6 +806,7 @@ fn build_open_channel(variables: &[Option<Variable>], inputs: &[usize]) -> OpenC
///
/// If the negotiation for `temporary_channel_id` is incomplete, emits a
/// `funding_created` with the derived outpoint and an all-zero signature.
#[allow(clippy::too_many_lines)]
fn build_funding_created(
variables: &[Option<Variable>],
inputs: &[usize],
Expand All @@ -815,7 +816,8 @@ fn build_funding_created(
) -> Result<FundingCreated, ExecuteError> {
let funding_tx = resolve_funding_transaction(variables, inputs[0]);
let opener_funding_privkey_bytes = resolve_private_key(variables, inputs[1]);
let temporary_channel_id = resolve_channel_id(variables, inputs[2]);
let opener_htlc_basepoint_privkey_bytes = resolve_private_key(variables, inputs[2]);
let temporary_channel_id = resolve_channel_id(variables, inputs[3]);

let funding_outpoint = OutPoint {
txid: funding_tx.tx.compute_txid(),
Expand Down Expand Up @@ -849,12 +851,15 @@ fn build_funding_created(

let opener_funding_privkey =
SecretKey::from_slice(&opener_funding_privkey_bytes).expect("valid private key");
let opener_htlc_basepoint_privkey =
SecretKey::from_slice(&opener_htlc_basepoint_privkey_bytes).expect("valid private key");

let opener = ChannelPartyConfig {
funding_pubkey: open_channel.funding_pubkey,
payment_basepoint: open_channel.payment_basepoint,
revocation_basepoint: open_channel.revocation_basepoint,
delayed_payment_basepoint: open_channel.delayed_payment_basepoint,
htlc_basepoint: open_channel.htlc_basepoint,
dust_limit_satoshis: open_channel.dust_limit_satoshis,
to_self_delay: open_channel.to_self_delay,
};
Expand All @@ -863,6 +868,7 @@ fn build_funding_created(
payment_basepoint: accept_channel.payment_basepoint,
revocation_basepoint: accept_channel.revocation_basepoint,
delayed_payment_basepoint: accept_channel.delayed_payment_basepoint,
htlc_basepoint: accept_channel.htlc_basepoint,
dust_limit_satoshis: accept_channel.dust_limit_satoshis,
to_self_delay: accept_channel.to_self_delay,
};
Expand All @@ -884,8 +890,10 @@ fn build_funding_created(
let holder = HolderIdentity {
side: Side::Opener,
funding_privkey: opener_funding_privkey,
htlc_basepoint_privkey: opener_htlc_basepoint_privkey,
};
let signature = config.sign_counterparty_commitment(&commitments, &holder);
let (signature, htlc_signatures) = config.sign_counterparty_commitment(&commitments, &holder);
assert_eq!(htlc_signatures, Vec::<Signature>::new()); // There are no HTLCs in the initial commitment transaction.

// Only track a new channel when this negotiation has not built a
// `funding_created` yet. If it has, we are likely resending one for the
Expand Down
20 changes: 14 additions & 6 deletions smite-scenarios/src/executor/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -984,13 +984,15 @@ fn execute_send_funding_created_and_recv_funding_signed() {
let holder = HolderIdentity {
side: Side::Acceptor,
funding_privkey: acceptor_funding_sk(),
htlc_basepoint_privkey: acceptor_htlc_basepoint_sk(),
};

assert!(
state
.config
.verify_counterparty_signature(&state.commitments, &holder, &fc.signature)
);
assert!(state.config.verify_counterparty_signature(
&state.commitments,
&holder,
&fc.signature,
&[]
));

let pending = fx.negotiation(&TemporaryChannelId::new([0xbb; 32]));
assert!(pending.funding_built);
Expand Down Expand Up @@ -1058,6 +1060,7 @@ fn execute_send_funding_created_after_funding_built_does_not_track_channel() {
&[
second_tx,
funding.opener_privkey,
first.htlc_basepoint_privkey,
first.temporary_channel_id,
],
);
Expand Down Expand Up @@ -1503,7 +1506,12 @@ fn execute_recv_channel_ready_resend_with_new_alias() {
let second_temp_chan_id = b.append(Operation::LoadChannelId(second_id.0), &[]);
b.append(
Operation::SendFundingCreated,
&[tx.tx, tx.opener_privkey, second_temp_chan_id],
&[
tx.tx,
tx.opener_privkey,
tx.opener_privkey,
second_temp_chan_id,
],
);
b.append(Operation::MineBlocks(6), &[]);
b.append(Operation::RecvChannelReady, &[]);
Expand Down
12 changes: 12 additions & 0 deletions smite-scenarios/src/executor/tests/harness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,18 @@ pub fn acceptor_funding_sk() -> SecretKey {
.expect("valid secret key")
}

/// The opener's htlc basepoint key for the funding flow.
pub fn opener_htlc_basepoint_sk() -> SecretKey {
SecretKey::from_str("1111111111111111111111111111111111111111111111111111111111111111")
.expect("valid secret key")
}

/// The acceptor's htlc basepoint key for the funding flow.
pub fn acceptor_htlc_basepoint_sk() -> SecretKey {
SecretKey::from_str("4444444444444444444444444444444444444444444444444444444444444444")
.expect("valid secret key")
}

/// The outpoint of the funding transaction the funding-flow programs build.
pub fn funding_outpoint() -> OutPoint {
OutPoint {
Expand Down
18 changes: 16 additions & 2 deletions smite-scenarios/src/executor/tests/programs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@
//! `raw_program` is an exception and doesn't use [`ProgramBuilder`] since its
//! purpose is to create malformed program.

use super::harness::{PointSource, SampleOpenChannel, acceptor_funding_sk, opener_funding_sk};
use super::harness::{
PointSource, SampleOpenChannel, acceptor_funding_sk, opener_funding_sk,
opener_htlc_basepoint_sk,
};
use crate::executor::*;
use smite_ir::Instruction;
use smite_ir::builder::ProgramBuilder;
Expand Down Expand Up @@ -248,6 +251,7 @@ pub fn create_funding_tx_with(
#[derive(Clone, Copy)]
pub struct SentFundingCreated {
pub tx: FundingTxVars,
pub htlc_basepoint_privkey: usize,
pub temporary_channel_id: usize,
/// The `SendFundingCreated` result, an affine variable a single
/// `RecvFundingSigned` may consume.
Expand All @@ -274,14 +278,24 @@ pub fn send_funding_created_with(
tx: FundingTxVars,
signing_privkey: usize,
) -> SentFundingCreated {
let htlc_basepoint_privkey = b.append(
Operation::LoadPrivateKey(opener_htlc_basepoint_sk().secret_bytes()),
&[],
);
let temporary_channel_id = b.append(Operation::LoadChannelId([0xbb; 32]), &[]);
let sent = b.append(
Operation::SendFundingCreated,
&[tx.tx, signing_privkey, temporary_channel_id],
&[
tx.tx,
signing_privkey,
htlc_basepoint_privkey,
temporary_channel_id,
],
);

SentFundingCreated {
tx,
htlc_basepoint_privkey,
temporary_channel_id,
sent,
}
Expand Down
1 change: 1 addition & 0 deletions smite/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,4 @@ hex = "0.4"
[dev-dependencies]
tempfile = "3"
bitcoin = { workspace = true, features = ["serde"] }
hex = { version = "0.4", features = ["serde"] }
2 changes: 1 addition & 1 deletion smite/src/channel_tx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ mod funding;

pub use commitment::{
ChannelCommitments, ChannelConfig, ChannelPartyConfig, ChannelState, CommitmentCost,
CommitmentError, CommitmentState, HolderIdentity, Side,
CommitmentError, CommitmentState, HolderIdentity, Htlc, Side,
};
pub use funding::{FundingTransaction, InsufficientFunds, build_funding_transaction};
Loading
Loading