Skip to content

Commit ab20284

Browse files
Merge pull request #1505 from tnull/2022-05-support-0conf-channeltype
Support `ZeroConf` channel type.
2 parents 9c50083 + efad02b commit ab20284

File tree

5 files changed

+194
-16
lines changed

5 files changed

+194
-16
lines changed

lightning/src/ln/channel.rs

+40-9
Original file line numberDiff line numberDiff line change
@@ -1081,16 +1081,22 @@ impl<Signer: Sign> Channel<Signer> {
10811081
if channel_type.supports_any_optional_bits() {
10821082
return Err(ChannelError::Close("Channel Type field contained optional bits - this is not allowed".to_owned()));
10831083
}
1084-
// We currently only allow two channel types, so write it all out here - we allow
1085-
// `only_static_remote_key` in all contexts, and further allow
1086-
// `static_remote_key|scid_privacy` if the channel is not publicly announced.
1087-
let mut allowed_type = ChannelTypeFeatures::only_static_remote_key();
1088-
if *channel_type != allowed_type {
1089-
allowed_type.set_scid_privacy_required();
1090-
if *channel_type != allowed_type {
1084+
1085+
if channel_type.requires_unknown_bits() {
1086+
return Err(ChannelError::Close("Channel Type field contains unknown bits".to_owned()));
1087+
}
1088+
1089+
// We currently only allow four channel types, so write it all out here - we allow
1090+
// `only_static_remote_key` or `static_remote_key | zero_conf` in all contexts, and
1091+
// further allow `static_remote_key | scid_privacy` or
1092+
// `static_remote_key | scid_privacy | zero_conf`, if the channel is not
1093+
// publicly announced.
1094+
if *channel_type != ChannelTypeFeatures::only_static_remote_key() {
1095+
if !channel_type.requires_scid_privacy() && !channel_type.requires_zero_conf() {
10911096
return Err(ChannelError::Close("Channel Type was not understood".to_owned()));
10921097
}
1093-
if announced_channel {
1098+
1099+
if channel_type.requires_scid_privacy() && announced_channel {
10941100
return Err(ChannelError::Close("SCID Alias/Privacy Channel Type cannot be set on a public channel".to_owned()));
10951101
}
10961102
}
@@ -6433,7 +6439,7 @@ mod tests {
64336439
use ln::channelmanager::{HTLCSource, PaymentId};
64346440
use ln::channel::{Channel, InboundHTLCOutput, OutboundHTLCOutput, InboundHTLCState, OutboundHTLCState, HTLCCandidate, HTLCInitiator};
64356441
use ln::channel::{MAX_FUNDING_SATOSHIS_NO_WUMBO, TOTAL_BITCOIN_SUPPLY_SATOSHIS};
6436-
use ln::features::InitFeatures;
6442+
use ln::features::{InitFeatures, ChannelTypeFeatures};
64376443
use ln::msgs::{ChannelUpdate, DataLossProtect, DecodeError, OptionalField, UnsignedChannelUpdate};
64386444
use ln::script::ShutdownScript;
64396445
use ln::chan_utils;
@@ -7748,4 +7754,29 @@ mod tests {
77487754
assert_eq!(chan_utils::derive_private_revocation_key(&secp_ctx, &per_commitment_secret, &base_secret).unwrap(),
77497755
SecretKey::from_slice(&hex::decode("d09ffff62ddb2297ab000cc85bcb4283fdeb6aa052affbc9dddcf33b61078110").unwrap()[..]).unwrap());
77507756
}
7757+
7758+
#[test]
7759+
fn test_zero_conf_channel_type_support() {
7760+
let feeest = TestFeeEstimator{fee_est: 15000};
7761+
let secp_ctx = Secp256k1::new();
7762+
let seed = [42; 32];
7763+
let network = Network::Testnet;
7764+
let keys_provider = test_utils::TestKeysInterface::new(&seed, network);
7765+
let logger = test_utils::TestLogger::new();
7766+
7767+
let node_b_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
7768+
let config = UserConfig::default();
7769+
let node_a_chan = Channel::<EnforcingSigner>::new_outbound(&&feeest, &&keys_provider,
7770+
node_b_node_id, &InitFeatures::known(), 10000000, 100000, 42, &config, 0, 42).unwrap();
7771+
7772+
let mut channel_type_features = ChannelTypeFeatures::only_static_remote_key();
7773+
channel_type_features.set_zero_conf_required();
7774+
7775+
let mut open_channel_msg = node_a_chan.get_open_channel(genesis_block(network).header.block_hash());
7776+
open_channel_msg.channel_type = Some(channel_type_features);
7777+
let node_b_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[7; 32]).unwrap());
7778+
let res = Channel::<EnforcingSigner>::new_from_req(&&feeest, &&keys_provider,
7779+
node_b_node_id, &InitFeatures::known(), &open_channel_msg, 7, &config, 0, &&logger, 42);
7780+
assert!(res.is_ok());
7781+
}
77517782
}

lightning/src/ln/channelmanager.rs

+21-1
Original file line numberDiff line numberDiff line change
@@ -4211,6 +4211,10 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
42114211
/// [`Event::ChannelClosed::user_channel_id`] to allow tracking of which events correspond
42124212
/// with which `accept_inbound_channel`/`accept_inbound_channel_from_trusted_peer_0conf` call.
42134213
///
4214+
/// Note that this method will return an error and reject the channel, if it requires support
4215+
/// for zero confirmations. Instead, `accept_inbound_channel_from_trusted_peer_0conf` must be
4216+
/// used to accept such channels.
4217+
///
42144218
/// [`Event::OpenChannelRequest`]: events::Event::OpenChannelRequest
42154219
/// [`Event::ChannelClosed::user_channel_id`]: events::Event::ChannelClosed::user_channel_id
42164220
pub fn accept_inbound_channel(&self, temporary_channel_id: &[u8; 32], counterparty_node_id: &PublicKey, user_channel_id: u64) -> Result<(), APIError> {
@@ -4252,7 +4256,20 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
42524256
if *counterparty_node_id != channel.get().get_counterparty_node_id() {
42534257
return Err(APIError::APIMisuseError { err: "The passed counterparty_node_id doesn't match the channel's counterparty node_id".to_owned() });
42544258
}
4255-
if accept_0conf { channel.get_mut().set_0conf(); }
4259+
if accept_0conf {
4260+
channel.get_mut().set_0conf();
4261+
} else if channel.get().get_channel_type().requires_zero_conf() {
4262+
let send_msg_err_event = events::MessageSendEvent::HandleError {
4263+
node_id: channel.get().get_counterparty_node_id(),
4264+
action: msgs::ErrorAction::SendErrorMessage{
4265+
msg: msgs::ErrorMessage { channel_id: temporary_channel_id.clone(), data: "No zero confirmation channels accepted".to_owned(), }
4266+
}
4267+
};
4268+
channel_state.pending_msg_events.push(send_msg_err_event);
4269+
let _ = remove_channel!(self, channel_state, channel);
4270+
return Err(APIError::APIMisuseError { err: "Please use accept_inbound_channel_from_trusted_peer_0conf to accept channels with zero confirmations.".to_owned() });
4271+
}
4272+
42564273
channel_state.pending_msg_events.push(events::MessageSendEvent::SendAcceptChannel {
42574274
node_id: channel.get().get_counterparty_node_id(),
42584275
msg: channel.get_mut().accept_inbound_channel(user_channel_id),
@@ -4294,6 +4311,9 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
42944311
},
42954312
hash_map::Entry::Vacant(entry) => {
42964313
if !self.default_configuration.manually_accept_inbound_channels {
4314+
if channel.get_channel_type().requires_zero_conf() {
4315+
return Err(MsgHandleErrInternal::send_err_msg_no_close("No zero confirmation channels accepted".to_owned(), msg.temporary_channel_id.clone()));
4316+
}
42974317
channel_state.pending_msg_events.push(events::MessageSendEvent::SendAcceptChannel {
42984318
node_id: counterparty_node_id.clone(),
42994319
msg: channel.accept_inbound_channel(0),

lightning/src/ln/features.rs

+24-3
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,8 @@ mod sealed {
130130
,
131131
// Byte 5
132132
,
133+
// Byte 6
134+
,
133135
],
134136
optional_features: [
135137
// Byte 0
@@ -144,6 +146,8 @@ mod sealed {
144146
,
145147
// Byte 5
146148
ChannelType | SCIDPrivacy,
149+
// Byte 6
150+
ZeroConf,
147151
],
148152
});
149153
define_context!(NodeContext {
@@ -177,7 +181,7 @@ mod sealed {
177181
// Byte 5
178182
ChannelType | SCIDPrivacy,
179183
// Byte 6
180-
Keysend,
184+
ZeroConf | Keysend,
181185
],
182186
});
183187
define_context!(ChannelContext {
@@ -218,6 +222,8 @@ mod sealed {
218222
,
219223
// Byte 5
220224
SCIDPrivacy,
225+
// Byte 6
226+
ZeroConf,
221227
],
222228
optional_features: [
223229
// Byte 0
@@ -232,6 +238,8 @@ mod sealed {
232238
,
233239
// Byte 5
234240
,
241+
// Byte 6
242+
,
235243
],
236244
});
237245

@@ -402,7 +410,9 @@ mod sealed {
402410
define_feature!(47, SCIDPrivacy, [InitContext, NodeContext, ChannelTypeContext],
403411
"Feature flags for only forwarding with SCID aliasing. Called `option_scid_alias` in the BOLTs",
404412
set_scid_privacy_optional, set_scid_privacy_required, supports_scid_privacy, requires_scid_privacy);
405-
413+
define_feature!(51, ZeroConf, [InitContext, NodeContext, ChannelTypeContext],
414+
"Feature flags for accepting channels with zero confirmations. Called `option_zeroconf` in the BOLTs",
415+
set_zero_conf_optional, set_zero_conf_required, supports_zero_conf, requires_zero_conf);
406416
define_feature!(55, Keysend, [NodeContext],
407417
"Feature flags for keysend payments.", set_keysend_optional, set_keysend_required,
408418
supports_keysend, requires_keysend);
@@ -852,14 +862,23 @@ mod tests {
852862

853863
assert!(InitFeatures::known().supports_scid_privacy());
854864
assert!(NodeFeatures::known().supports_scid_privacy());
865+
assert!(ChannelTypeFeatures::known().supports_scid_privacy());
855866
assert!(!InitFeatures::known().requires_scid_privacy());
856867
assert!(!NodeFeatures::known().requires_scid_privacy());
868+
assert!(ChannelTypeFeatures::known().requires_scid_privacy());
857869

858870
assert!(InitFeatures::known().supports_wumbo());
859871
assert!(NodeFeatures::known().supports_wumbo());
860872
assert!(!InitFeatures::known().requires_wumbo());
861873
assert!(!NodeFeatures::known().requires_wumbo());
862874

875+
assert!(InitFeatures::known().supports_zero_conf());
876+
assert!(!InitFeatures::known().requires_zero_conf());
877+
assert!(NodeFeatures::known().supports_zero_conf());
878+
assert!(!NodeFeatures::known().requires_zero_conf());
879+
assert!(ChannelTypeFeatures::known().supports_zero_conf());
880+
assert!(ChannelTypeFeatures::known().requires_zero_conf());
881+
863882
let mut init_features = InitFeatures::known();
864883
assert!(init_features.initial_routing_sync());
865884
init_features.clear_initial_routing_sync();
@@ -899,13 +918,15 @@ mod tests {
899918
// - opt_shutdown_anysegwit
900919
// -
901920
// - option_channel_type | option_scid_alias
902-
assert_eq!(node_features.flags.len(), 6);
921+
// - option_zeroconf
922+
assert_eq!(node_features.flags.len(), 7);
903923
assert_eq!(node_features.flags[0], 0b00000010);
904924
assert_eq!(node_features.flags[1], 0b01010001);
905925
assert_eq!(node_features.flags[2], 0b00001010);
906926
assert_eq!(node_features.flags[3], 0b00001000);
907927
assert_eq!(node_features.flags[4], 0b00000000);
908928
assert_eq!(node_features.flags[5], 0b10100000);
929+
assert_eq!(node_features.flags[6], 0b00001000);
909930
}
910931

911932
// Check that cleared flags are kept blank when converting back:

lightning/src/ln/priv_short_conf_tests.rs

+101-2
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ use chain::keysinterface::{Recipient, KeysInterface};
1717
use ln::channelmanager::{ChannelManager, ChannelManagerReadArgs, MIN_CLTV_EXPIRY_DELTA};
1818
use routing::network_graph::RoutingFees;
1919
use routing::router::{PaymentParameters, RouteHint, RouteHintHop};
20-
use ln::features::{InitFeatures, InvoiceFeatures};
20+
use ln::features::{InitFeatures, InvoiceFeatures, ChannelTypeFeatures};
2121
use ln::msgs;
22-
use ln::msgs::{ChannelMessageHandler, RoutingMessageHandler, OptionalField, ChannelUpdate};
22+
use ln::msgs::{ChannelMessageHandler, RoutingMessageHandler, OptionalField, ChannelUpdate, ErrorAction};
2323
use ln::wire::Encode;
2424
use util::enforcing_trait_impls::EnforcingSigner;
2525
use util::events::{ClosureReason, Event, MessageSendEvent, MessageSendEventsProvider};
@@ -922,3 +922,102 @@ fn test_0conf_channel_reorg() {
922922
});
923923
check_closed_broadcast!(nodes[1], true);
924924
}
925+
926+
#[test]
927+
fn test_zero_conf_accept_reject() {
928+
let mut channel_type_features = ChannelTypeFeatures::only_static_remote_key();
929+
channel_type_features.set_zero_conf_required();
930+
931+
// 1. Check we reject zero conf channels by default
932+
let chanmon_cfgs = create_chanmon_cfgs(2);
933+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
934+
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
935+
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
936+
937+
nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42, None).unwrap();
938+
let mut open_channel_msg = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
939+
940+
open_channel_msg.channel_type = Some(channel_type_features.clone());
941+
942+
nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), InitFeatures::known(), &open_channel_msg);
943+
944+
let msg_events = nodes[1].node.get_and_clear_pending_msg_events();
945+
match msg_events[0] {
946+
MessageSendEvent::HandleError { action: ErrorAction::SendErrorMessage { ref msg, .. }, .. } => {
947+
assert_eq!(msg.data, "No zero confirmation channels accepted".to_owned());
948+
},
949+
_ => panic!(),
950+
}
951+
952+
// 2. Check we can manually accept zero conf channels via the right method
953+
let mut manually_accept_conf = UserConfig::default();
954+
manually_accept_conf.manually_accept_inbound_channels = true;
955+
956+
let chanmon_cfgs = create_chanmon_cfgs(2);
957+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
958+
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs,
959+
&[None, Some(manually_accept_conf.clone())]);
960+
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
961+
962+
// 2.1 First try the non-0conf method to manually accept
963+
nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42,
964+
Some(manually_accept_conf)).unwrap();
965+
let mut open_channel_msg = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel,
966+
nodes[1].node.get_our_node_id());
967+
968+
open_channel_msg.channel_type = Some(channel_type_features.clone());
969+
970+
nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), InitFeatures::known(),
971+
&open_channel_msg);
972+
973+
// Assert that `nodes[1]` has no `MessageSendEvent::SendAcceptChannel` in the `msg_events`.
974+
assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty());
975+
976+
let events = nodes[1].node.get_and_clear_pending_events();
977+
978+
match events[0] {
979+
Event::OpenChannelRequest { temporary_channel_id, .. } => {
980+
// Assert we fail to accept via the non-0conf method
981+
assert!(nodes[1].node.accept_inbound_channel(&temporary_channel_id,
982+
&nodes[0].node.get_our_node_id(), 0).is_err());
983+
},
984+
_ => panic!(),
985+
}
986+
987+
let msg_events = nodes[1].node.get_and_clear_pending_msg_events();
988+
match msg_events[0] {
989+
MessageSendEvent::HandleError { action: ErrorAction::SendErrorMessage { ref msg, .. }, .. } => {
990+
assert_eq!(msg.data, "No zero confirmation channels accepted".to_owned());
991+
},
992+
_ => panic!(),
993+
}
994+
995+
// 2.2 Try again with the 0conf method to manually accept
996+
nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42,
997+
Some(manually_accept_conf)).unwrap();
998+
let mut open_channel_msg = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel,
999+
nodes[1].node.get_our_node_id());
1000+
1001+
open_channel_msg.channel_type = Some(channel_type_features);
1002+
1003+
nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), InitFeatures::known(),
1004+
&open_channel_msg);
1005+
1006+
let events = nodes[1].node.get_and_clear_pending_events();
1007+
1008+
match events[0] {
1009+
Event::OpenChannelRequest { temporary_channel_id, .. } => {
1010+
// Assert we can accept via the 0conf method
1011+
assert!(nodes[1].node.accept_inbound_channel_from_trusted_peer_0conf(
1012+
&temporary_channel_id, &nodes[0].node.get_our_node_id(), 0).is_ok());
1013+
},
1014+
_ => panic!(),
1015+
}
1016+
1017+
// Check we would send accept
1018+
let msg_events = nodes[1].node.get_and_clear_pending_msg_events();
1019+
match msg_events[0] {
1020+
MessageSendEvent::SendAcceptChannel { .. } => {},
1021+
_ => panic!(),
1022+
}
1023+
}

lightning/src/util/events.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,8 @@ pub enum Event {
430430
/// transaction.
431431
claim_from_onchain_tx: bool,
432432
},
433-
/// Used to indicate that a channel with the given `channel_id` is in the process of closure.
433+
/// Used to indicate that a previously opened channel with the given `channel_id` is in the
434+
/// process of closure.
434435
ChannelClosed {
435436
/// The channel_id of the channel which has been closed. Note that on-chain transactions
436437
/// resolving the channel are likely still awaiting confirmation.
@@ -499,6 +500,12 @@ pub enum Event {
499500
/// the resulting [`ChannelManager`] will not be readable by versions of LDK prior to
500501
/// 0.0.106.
501502
///
503+
/// Furthermore, note that if [`ChannelTypeFeatures::supports_zero_conf`] returns true on this type,
504+
/// the resulting [`ChannelManager`] will not be readable by versions of LDK prior to
505+
/// 0.0.107. Channels setting this type also need to get manually accepted via
506+
/// [`crate::ln::channelmanager::ChannelManager::accept_inbound_channel_from_trusted_peer_0conf`],
507+
/// or will be rejected otherwise.
508+
///
502509
/// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager
503510
channel_type: ChannelTypeFeatures,
504511
},

0 commit comments

Comments
 (0)