diff --git a/Cargo.toml b/Cargo.toml index 698f5112b9d..a384793cd79 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -67,4 +67,5 @@ check-cfg = [ "cfg(splicing)", "cfg(async_payments)", "cfg(dual_funding)", + "cfg(custom_tx)", ] diff --git a/ci/ci-tests.sh b/ci/ci-tests.sh index 8e3edfa43a8..e230b944354 100755 --- a/ci/ci-tests.sh +++ b/ci/ci-tests.sh @@ -135,4 +135,6 @@ RUSTFLAGS="--cfg=trampoline" cargo test --verbose --color always -p lightning [ "$CI_MINIMIZE_DISK_USAGE" != "" ] && cargo clean RUSTFLAGS="--cfg=async_payments" cargo test --verbose --color always -p lightning [ "$CI_MINIMIZE_DISK_USAGE" != "" ] && cargo clean +RUSTFLAGS="--cfg=custom_tx" cargo test --verbose --color always -p lightning +[ "$CI_MINIMIZE_DISK_USAGE" != "" ] && cargo clean RUSTFLAGS="--cfg=lsps1_service" cargo test --verbose --color always -p lightning-liquidity diff --git a/lightning/src/sign/mod.rs b/lightning/src/sign/mod.rs index 7aa41531ce2..c64628a902a 100644 --- a/lightning/src/sign/mod.rs +++ b/lightning/src/sign/mod.rs @@ -68,6 +68,8 @@ use crate::prelude::*; use crate::sign::ecdsa::EcdsaChannelSigner; #[cfg(taproot)] use crate::sign::taproot::TaprootChannelSigner; +#[cfg(custom_tx)] +use crate::sign::tx_builder::SpecTxBuilder; use crate::types::features::ChannelTypeFeatures; use crate::util::atomic_counter::AtomicCounter; use core::convert::TryInto; @@ -81,6 +83,8 @@ pub(crate) mod type_resolver; pub mod ecdsa; #[cfg(taproot)] pub mod taproot; +#[cfg(custom_tx)] +pub mod tx_builder; /// Information about a spendable output to a P2WSH script. /// @@ -816,6 +820,10 @@ pub trait ChannelSigner { /// /// channel_parameters.is_populated() MUST be true. fn provide_channel_parameters(&mut self, channel_parameters: &ChannelTransactionParameters); + + /// Derive a `TxBuilder` + #[cfg(custom_tx)] + fn derive_tx_builder(&self) -> SpecTxBuilder; } /// Specifies the recipient of an invoice. @@ -1400,6 +1408,11 @@ impl ChannelSigner for InMemorySigner { assert!(channel_parameters.is_populated(), "Channel parameters must be fully populated"); self.channel_parameters = Some(channel_parameters.clone()); } + + #[cfg(custom_tx)] + fn derive_tx_builder(&self) -> SpecTxBuilder { + SpecTxBuilder::default() + } } const MISSING_PARAMS_ERR: &'static str = diff --git a/lightning/src/sign/tx_builder.rs b/lightning/src/sign/tx_builder.rs new file mode 100644 index 00000000000..61e309ad0f1 --- /dev/null +++ b/lightning/src/sign/tx_builder.rs @@ -0,0 +1,81 @@ +//! Defines the `TxBuilder` trait, and the `SpecTxBuilder` type +#![allow(dead_code)] +#![allow(unused_variables)] + +use bitcoin::secp256k1::{self, PublicKey, Secp256k1}; +use bitcoin::{Amount, Transaction}; + +use crate::ln::chan_utils::{ChannelTransactionParameters, HTLCOutputInCommitment, TxCreationKeys}; +use crate::prelude::*; + +/// A trait for types that can build commitment transactions, both for the holder, and the counterparty. +pub trait TxBuilder { + /// Set the counterparty static channel data, including basepoints, + /// `counterparty_selected`/`holder_selected_contest_delay` and funding outpoint. + /// + /// This data is static, and will never change for a channel once set. + /// + /// channel_parameters.is_populated() MUST be true. + fn provide_channel_parameters(&mut self, channel_parameters: &ChannelTransactionParameters); + /// Build a commitment transaction, and populate the elements of `htlcs` with their output indices. + /// Do not sort `htlcs`; this will be done by the caller as needed. + /// This method will be called only after all the channel parameters have been provided via `provide_channel_parameters`. + fn build_commitment_transaction( + &self, is_holder_tx: bool, commitment_number: u64, per_commitment_point: &PublicKey, + to_broadcaster_value_sat: Amount, to_countersignatory_value_sat: Amount, + trimmed_value_sat: Amount, htlcs: Vec<&mut HTLCOutputInCommitment>, + secp_ctx: &Secp256k1, + ) -> Transaction; +} + +/// A type that builds commitment transactions according to the Lightning Specification. +#[derive(Clone, Debug, Default)] +pub struct SpecTxBuilder { + channel_parameters: Option, +} + +impl TxBuilder for SpecTxBuilder { + fn provide_channel_parameters(&mut self, channel_parameters: &ChannelTransactionParameters) { + assert!( + self.channel_parameters.is_none() + || self.channel_parameters.as_ref().unwrap() == channel_parameters + ); + if self.channel_parameters.is_some() { + // The channel parameters were already set and they match, return early. + return; + } + assert!(channel_parameters.is_populated(), "Channel parameters must be fully populated"); + self.channel_parameters = Some(channel_parameters.clone()); + } + fn build_commitment_transaction( + &self, is_holder_tx: bool, commitment_number: u64, per_commitment_point: &PublicKey, + to_broadcaster_value_sat: Amount, to_countersignatory_value_sat: Amount, + trimmed_value_sat: Amount, htlcs: Vec<&mut HTLCOutputInCommitment>, + secp_ctx: &Secp256k1, + ) -> Transaction { + let params = if is_holder_tx { + self.channel_parameters.as_ref().unwrap().as_holder_broadcastable() + } else { + self.channel_parameters.as_ref().unwrap().as_counterparty_broadcastable() + }; + let keys = TxCreationKeys::from_channel_static_keys( + per_commitment_point, + params.broadcaster_pubkeys(), + params.countersignatory_pubkeys(), + secp_ctx, + ); + /* + let (obscured_commitment_transaction_number, txins) = + internal_build_inputs(commitment_number, ¶ms); + let txouts = internal_build_outputs( + &keys, + to_broadcaster_value_sat, + to_countersignatory_value_sat, + htlcs, + ¶ms, + ); + make_transaction(obscured_commitment_transaction_number, txins, txouts) + */ + todo!(); + } +} diff --git a/lightning/src/util/test_channel_signer.rs b/lightning/src/util/test_channel_signer.rs index 3bc095d2ba7..e47ef24891f 100644 --- a/lightning/src/util/test_channel_signer.rs +++ b/lightning/src/util/test_channel_signer.rs @@ -15,6 +15,8 @@ use crate::ln::channel::{ANCHOR_OUTPUT_VALUE_SATOSHI, MIN_CHAN_DUST_LIMIT_SATOSH use crate::ln::channel_keys::HtlcKey; use crate::ln::msgs; use crate::sign::ecdsa::EcdsaChannelSigner; +#[cfg(custom_tx)] +use crate::sign::tx_builder::SpecTxBuilder; use crate::sign::{ChannelSigner, InMemorySigner}; use crate::types::payment::PaymentPreimage; @@ -227,6 +229,11 @@ impl ChannelSigner for TestChannelSigner { fn provide_channel_parameters(&mut self, channel_parameters: &ChannelTransactionParameters) { self.inner.provide_channel_parameters(channel_parameters) } + + #[cfg(custom_tx)] + fn derive_tx_builder(&self) -> SpecTxBuilder { + SpecTxBuilder::default() + } } impl EcdsaChannelSigner for TestChannelSigner {