Skip to content
This repository has been archived by the owner on Oct 3, 2023. It is now read-only.

[draft] DLC-channels PoC #1

Draft
wants to merge 43 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
b56f6ae
[WIP] Implement add_custom_output protocol
luckysori Oct 25, 2022
e421968
fixup! [WIP] Implement add_custom_output protocol
luckysori Nov 2, 2022
e77dc83
fixup! fixup! [WIP] Implement add_custom_output protocol
luckysori Nov 2, 2022
604a668
fix: add missing function
bonomat Nov 2, 2022
b3ae2ea
fix: some formatting
bonomat Nov 2, 2022
8719a65
fix: Account for custom outputs when serde-ing Channel
luckysori Nov 2, 2022
af23fcb
feat: Define public API to add custom output
luckysori Nov 2, 2022
80a9c15
[WIP] fix: Find a route to custom output counterparty
luckysori Nov 3, 2022
eaa2a04
fixup! [WIP] fix: Find a route to custom output counterparty
luckysori Nov 3, 2022
52ea542
feat: update balance calc
bonomat Nov 3, 2022
228d822
fix: some formatting
bonomat Nov 3, 2022
6dd2329
fix: subtract fee from commit transaction for custom output
bonomat Nov 4, 2022
21e9902
add todo
bonomat Nov 4, 2022
afcec1d
fix: missing impl
bonomat Nov 4, 2022
4704774
fix: Ensure custom outputs are dual-funded
luckysori Nov 3, 2022
2625887
fixup! fix: Ensure custom outputs are dual-funded
luckysori Nov 4, 2022
2aa12da
fixup! fix: Ensure custom outputs are dual-funded
bonomat Nov 4, 2022
eb1c509
feat: show correct channel balances
bonomat Nov 4, 2022
7c02106
chore: remove commented code
bonomat Nov 6, 2022
c4eccdb
WIP: remove custom output
bonomat Nov 7, 2022
ae7488a
fixup! WIP: remove custom output
luckysori Nov 7, 2022
3995f12
[WIP] Make remove custom output integration test pass
luckysori Nov 7, 2022
e7857fd
fixup! [WIP] Make remove custom output integration test pass
bonomat Nov 8, 2022
28eb963
fixup! fixup! [WIP] Make remove custom output integration test pass
bonomat Nov 8, 2022
7896bc6
feat: remove custom output
bonomat Nov 8, 2022
462c5b1
fix: load channel manager from storage
bonomat Nov 8, 2022
c237a15
fixup! fix: load channel manager from storage
bonomat Nov 9, 2022
d1dc93d
fix: Add missing trait implementations in test code
luckysori Nov 9, 2022
d2bc70d
feat: Make custom output script configurable when adding
luckysori Nov 9, 2022
026e374
feat: Return CustomOutputDetails when adding custom output
luckysori Nov 10, 2022
eff64b4
WIP: adding new states for custom protocol
bonomat Nov 11, 2022
c186a18
fixup! WIP: adding new states for custom protocol
bonomat Nov 11, 2022
69b93a2
[WIP] Continue adding new states for custom protocol
luckysori Nov 13, 2022
efd7046
[WIP] Where is the RAA coming from???
luckysori Nov 14, 2022
51a39ae
fixup! [WIP] Where is the RAA coming from???
bonomat Nov 14, 2022
6d99a24
fixup! fixup! [WIP] Where is the RAA coming from???
luckysori Nov 14, 2022
321848d
fixup! fixup! fixup! [WIP] Where is the RAA coming from???
bonomat Nov 14, 2022
dd206f1
Include remote PK in RemoteSentCustomOutputCommitmentSignature event
luckysori Nov 15, 2022
2a0edd5
fix: forgot to serialize script
bonomat Nov 16, 2022
a4c1649
feat: Allow access to custom output ID list via ChannelManager
luckysori Nov 16, 2022
82ce436
feat: Simplify remove-custom-output APIs
luckysori Nov 22, 2022
86531aa
feat: Set ANTI_REORG_DELAY to 0
luckysori Dec 1, 2022
10b69c9
fix: Consider effect of removing custom outputs when closing channel
luckysori Dec 1, 2022
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
10 changes: 5 additions & 5 deletions fuzz/src/chanmon_consistency.rs
Original file line number Diff line number Diff line change
Expand Up @@ -600,7 +600,7 @@ pub fn do_test<Out: Output>(data: &[u8], underlying_out: Out) {
let expect_drop_id = if let Some(id) = expect_drop_node { Some(nodes[id].get_our_node_id()) } else { None };
for event in $excess_events {
let push_a = match event {
events::MessageSendEvent::UpdateHTLCs { ref node_id, .. } => {
events::MessageSendEvent::UpdateCommitmentOutputs { ref node_id, .. } => {
if Some(*node_id) == expect_drop_id { panic!("peer_disconnected should drop msgs bound for the disconnected peer"); }
*node_id == a_id
},
Expand Down Expand Up @@ -670,7 +670,7 @@ pub fn do_test<Out: Output>(data: &[u8], underlying_out: Out) {
for event in &mut events_iter {
had_events = true;
match event {
events::MessageSendEvent::UpdateHTLCs { node_id, updates: CommitmentUpdate { update_add_htlcs, update_fail_htlcs, update_fulfill_htlcs, update_fail_malformed_htlcs, update_fee, commitment_signed } } => {
events::MessageSendEvent::UpdateCommitmentOutputs { node_id, updates: CommitmentUpdate { update_add_htlcs, update_fail_htlcs, update_fulfill_htlcs, update_fail_malformed_htlcs, update_fee, commitment_signed } } => {
for (idx, dest) in nodes.iter().enumerate() {
if dest.get_our_node_id() == node_id {
for update_add in update_add_htlcs.iter() {
Expand Down Expand Up @@ -708,7 +708,7 @@ pub fn do_test<Out: Output>(data: &[u8], underlying_out: Out) {
!update_fail_htlcs.is_empty() || !update_fail_malformed_htlcs.is_empty();
if $limit_events != ProcessMessages::AllMessages && processed_change {
// If we only want to process some messages, don't deliver the CS until later.
extra_ev = Some(events::MessageSendEvent::UpdateHTLCs { node_id, updates: CommitmentUpdate {
extra_ev = Some(events::MessageSendEvent::UpdateCommitmentOutputs { node_id, updates: CommitmentUpdate {
update_add_htlcs: Vec::new(),
update_fail_htlcs: Vec::new(),
update_fulfill_htlcs: Vec::new(),
Expand Down Expand Up @@ -783,7 +783,7 @@ pub fn do_test<Out: Output>(data: &[u8], underlying_out: Out) {
if $counterparty_id == 0 {
for event in nodes[0].get_and_clear_pending_msg_events() {
match event {
events::MessageSendEvent::UpdateHTLCs { .. } => {},
events::MessageSendEvent::UpdateCommitmentOutputs { .. } => {},
events::MessageSendEvent::SendRevokeAndACK { .. } => {},
events::MessageSendEvent::SendChannelReestablish { .. } => {},
events::MessageSendEvent::SendChannelReady { .. } => {},
Expand All @@ -804,7 +804,7 @@ pub fn do_test<Out: Output>(data: &[u8], underlying_out: Out) {
} else {
for event in nodes[2].get_and_clear_pending_msg_events() {
match event {
events::MessageSendEvent::UpdateHTLCs { .. } => {},
events::MessageSendEvent::UpdateCommitmentOutputs { .. } => {},
events::MessageSendEvent::SendRevokeAndACK { .. } => {},
events::MessageSendEvent::SendChannelReestablish { .. } => {},
events::MessageSendEvent::SendChannelReady { .. } => {},
Expand Down
1 change: 1 addition & 0 deletions lightning-invoice/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ lightning = { version = "0.0.112", path = "../lightning", default-features = fal
secp256k1 = { version = "0.24.0", default-features = false, features = ["recovery", "alloc"] }
num-traits = { version = "0.2.8", default-features = false }
bitcoin_hashes = { version = "0.11", default-features = false }
bitcoin = { version = "0.29.0", default-features = false }
hashbrown = { version = "0.8", optional = true }
serde = { version = "1.0.118", optional = true }

Expand Down
155 changes: 150 additions & 5 deletions lightning-invoice/src/payment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@
//! # fn send_spontaneous_payment(
//! # &self, route: &Route, payment_preimage: PaymentPreimage
//! # ) -> Result<PaymentId, PaymentSendFailure> { unimplemented!() }
//!
//! # fn add_custom_output(&self, route: &Route) -> Result<(), String> {
//! # todo!()
//! # }
//! # fn retry_payment(
//! # &self, route: &Route, payment_id: PaymentId
//! # ) -> Result<(), PaymentSendFailure> { unimplemented!() }
Expand Down Expand Up @@ -107,7 +111,7 @@
//! match event {
//! Event::PaymentPathFailed { .. } => println!("payment failed after retries"),
//! Event::PaymentSent { .. } => println!("payment successful"),
//! _ => {},
//! _ => {}
//! }
//! };
//! # let payer = FakePayer {};
Expand Down Expand Up @@ -138,14 +142,15 @@ use crate::Invoice;

use bitcoin_hashes::Hash;
use bitcoin_hashes::sha256::Hash as Sha256;
use bitcoin::Script;

use crate::prelude::*;
use lightning::io;
use lightning::ln::{PaymentHash, PaymentPreimage, PaymentSecret};
use lightning::ln::channelmanager::{ChannelDetails, PaymentId, PaymentSendFailure};
use lightning::ln::msgs::LightningError;
use lightning::ln::channelmanager::{ChannelDetails, CustomOutputId, PaymentId, PaymentSendFailure, RemoveCustomOutputError, CustomOutputDetails};
use lightning::ln::msgs::{LightningError, ErrorAction};
use lightning::routing::gossip::NodeId;
use lightning::routing::router::{PaymentParameters, Route, RouteHop, RouteParameters};
use lightning::routing::router::{PaymentParameters, Route, RouteHop, RouteParameters, AddCustomOutputRouteDetails, RemoveCustomOutputDetails};
use lightning::util::errors::APIError;
use lightning::util::events::{Event, EventHandler};
use lightning::util::logger::Logger;
Expand Down Expand Up @@ -259,6 +264,16 @@ pub trait Payer {
&self, route: &Route, payment_preimage: PaymentPreimage
) -> Result<PaymentId, PaymentSendFailure>;

/// Adds a custom output over the Lightning Network using the given [`Route`].
fn add_custom_output(
&self, route_details: AddCustomOutputRouteDetails, script: Script
) -> Result<CustomOutputDetails, String>;

/// Removes a custom output with the provided values.
fn remove_custom_output(
&self, route_details: RemoveCustomOutputDetails,
) -> Result<(), RemoveCustomOutputError>;

/// Retries a failed payment path for the [`PaymentId`] using the given [`Route`].
fn retry_payment(&self, route: &Route, payment_id: PaymentId) -> Result<(), PaymentSendFailure>;

Expand All @@ -273,6 +288,15 @@ pub trait Router {
&self, payer: &PublicKey, route_params: &RouteParameters, payment_hash: &PaymentHash,
first_hops: Option<&[&ChannelDetails]>, inflight_htlcs: InFlightHtlcs
) -> Result<Route, LightningError>;
/// Gets custom output route details.
fn add_custom_output_route_details(
&self, local_pk: &PublicKey, local_amount_msats: u64, remote_amount_msats: u64, cltv_expiry: u32, channel_details: ChannelDetails,
) -> Result<AddCustomOutputRouteDetails, LightningError>;

/// Gets custom output route details to remove a custom output.
fn remove_custom_output_route_details(
&self, custom_output_id: CustomOutputId, local_amount_msats: u64, channel_details: ChannelDetails,
) -> Result<RemoveCustomOutputDetails, LightningError>;
/// Lets the router know that payment through a specific path has failed.
fn notify_payment_path_failed(&self, path: &[&RouteHop], short_channel_id: u64);
/// Lets the router know that payment through a specific path was successful.
Expand Down Expand Up @@ -320,6 +344,12 @@ pub enum PaymentError {
Routing(LightningError),
/// An error occurring when sending a payment.
Sending(PaymentSendFailure),
/// An error occurring when creating a custom output.
/// TODO(10101): Should remove this variant.
CreatingCustomOutput(String),
/// An error occurring when creating a custom output.
/// TODO(10101): Should remove this variant.
RemovingCustomOutput(RemoveCustomOutputError),
}

impl<P: Deref, R: Router, L: Deref, E: EventHandler, T: Time> InvoicePayerUsingTime<P, R, L, E, T>
Expand Down Expand Up @@ -433,6 +463,71 @@ where
.map_err(|e| { self.payment_cache.lock().unwrap().remove(&payment_hash); e })
}

/// TODO(10101): Docs
/// TODO(10101): Probably shouldn't be defined on the [`InvoicePayer`].
pub fn add_custom_output(
&self, pubkey: PublicKey, amount_local_msats: u64, amount_remote_msats: u64, final_cltv_expiry_delta: u32, script: Script
) -> Result<CustomOutputDetails, PaymentError> {
// TODO: We might have more than one channel with the peer identified by the
// `pubkey` argument. We will need to use a heuristic to select a channel among all
// the candidates
let channel_details = self.payer
.first_hops()
.iter()
.find(|details| details.counterparty.node_id == pubkey)
.ok_or_else(|| PaymentError::Routing(
LightningError {
err: "Cannot create custom output: No channel with peer {pubkey}".to_owned(),
action: ErrorAction::IgnoreError
}
))?
.clone();

let route_details = self.router.add_custom_output_route_details(
&self.payer.node_id(), // The node ID of the sender OK
amount_local_msats,
amount_remote_msats,
final_cltv_expiry_delta,
channel_details,
).map_err(|e| PaymentError::Routing(e))?;

let custom_output_details = self.payer.add_custom_output(route_details, script).map_err(PaymentError::CreatingCustomOutput)?;

Ok(custom_output_details)
}


/// TODO(10101): Docs
/// TODO(10101): Probably shouldn't be defined on the [`InvoicePayer`].
pub fn remove_custom_output(
&self, pubkey: PublicKey, custom_output_id: CustomOutputId, amount_local_msats: u64
) -> Result<(), PaymentError> {
// TODO: We might have more than one channel with the peer identified by the
// `pubkey` argument. We will need to use a heuristic to select a channel among all
// the candidates
let channel_details = self.payer
.first_hops()
.iter()
.find(|details| details.counterparty.node_id == pubkey)
.ok_or_else(|| PaymentError::Routing(
LightningError {
err: "Cannot create custom output: No channel with peer {pubkey}".to_owned(),
action: ErrorAction::IgnoreError
}
))?
.clone();

let route_details = self.router.remove_custom_output_route_details(
custom_output_id,
amount_local_msats,
channel_details,
).map_err(|e| PaymentError::Routing(e))?;

self.payer.remove_custom_output(route_details).map_err(PaymentError::RemovingCustomOutput)?;

Ok(())
}

fn pay_internal<F: FnOnce(&Route) -> Result<PaymentId, PaymentSendFailure> + Copy>(
&self, params: &RouteParameters, payment_hash: PaymentHash, send_payment: F,
) -> Result<PaymentId, PaymentError> {
Expand Down Expand Up @@ -1845,6 +1940,18 @@ mod tests {
})
}

fn add_custom_output_route_details(
&self, _dialer_pk: &PublicKey, _local_amount_msats: u64, _remote_amount_msats: u64, _cltv_expiry: u32, _channel_details: ChannelDetails,
) -> Result<AddCustomOutputRouteDetails, LightningError> {
todo!()
}

fn remove_custom_output_route_details(
&self, _custom_output_id: CustomOutputId, _local_amount_msats: u64, _channel_details: ChannelDetails,
) -> Result<RemoveCustomOutputDetails, LightningError> {
todo!()
}

fn notify_payment_path_failed(&self, path: &[&RouteHop], short_channel_id: u64) {
self.scorer.lock().payment_path_failed(path, short_channel_id);
}
Expand All @@ -1860,6 +1967,7 @@ mod tests {
fn notify_payment_probe_failed(&self, path: &[&RouteHop], short_channel_id: u64) {
self.scorer.lock().probe_failed(path, short_channel_id);
}

}

struct FailingRouter;
Expand All @@ -1872,13 +1980,25 @@ mod tests {
Err(LightningError { err: String::new(), action: ErrorAction::IgnoreError })
}

fn add_custom_output_route_details(
&self, _dialer_pk: &PublicKey, _local_amount_msats: u64, _remote_amount_msats: u64, _cltv_expiry: u32, _channel_details: ChannelDetails,
) -> Result<AddCustomOutputRouteDetails, LightningError> {
todo!()
}

fn remove_custom_output_route_details(
&self, _custom_output_id: CustomOutputId, _local_amount_msats: u64, _channel_details: ChannelDetails,
) -> Result<RemoveCustomOutputDetails, LightningError> {
todo!()
}

fn notify_payment_path_failed(&self, _path: &[&RouteHop], _short_channel_id: u64) {}

fn notify_payment_path_successful(&self, _path: &[&RouteHop]) {}

fn notify_payment_probe_successful(&self, _path: &[&RouteHop]) {}

fn notify_payment_probe_failed(&self, _path: &[&RouteHop], _short_channel_id: u64) {}
fn notify_payment_probe_failed(&self, _path: &[&RouteHop], _short_channel_id: u64) {}
}

struct TestScorer {
Expand Down Expand Up @@ -2113,6 +2233,18 @@ mod tests {
self.check_attempts()
}

fn add_custom_output(
&self, _route_details: AddCustomOutputRouteDetails, _script: Script
) -> Result<CustomOutputDetails, String> {
todo!()
}

fn remove_custom_output(
&self, _route_details: RemoveCustomOutputDetails,
) -> Result<(), RemoveCustomOutputError> {
todo!()
}

fn retry_payment(
&self, route: &Route, _payment_id: PaymentId
) -> Result<(), PaymentSendFailure> {
Expand All @@ -2121,6 +2253,7 @@ mod tests {
}

fn abandon_payment(&self, _payment_id: PaymentId) { }

}

// *** Full Featured Functional Tests with a Real ChannelManager ***
Expand All @@ -2134,6 +2267,18 @@ mod tests {
self.0.borrow_mut().pop_front().unwrap()
}

fn add_custom_output_route_details(
&self, _dialer_pk: &PublicKey, _local_amount_msats: u64, _remote_amount_msats: u64, _cltv_expiry_delta: u32, _channel_details: ChannelDetails,
) -> Result<AddCustomOutputRouteDetails, LightningError> {
todo!()
}

fn remove_custom_output_route_details(
&self, _custom_output_id: CustomOutputId, _local_amount_msats: u64, _channel_details: ChannelDetails,
) -> Result<RemoveCustomOutputDetails, LightningError> {
todo!()
}

fn notify_payment_path_failed(&self, _path: &[&RouteHop], _short_channel_id: u64) {}

fn notify_payment_path_successful(&self, _path: &[&RouteHop]) {}
Expand Down
Loading