Skip to content

Commit e93f564

Browse files
authored
Merge pull request #69 from tnull/2023-04-allow-manual-0conf
Allow for trusted inbound 0conf channels
2 parents 97d238c + 4c26c25 commit e93f564

File tree

5 files changed

+112
-9
lines changed

5 files changed

+112
-9
lines changed

bindings/ldk_node.udl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ dictionary Config {
1010
u64 wallet_sync_interval_secs;
1111
u64 fee_rate_cache_update_interval_secs;
1212
LogLevel log_level;
13+
sequence<PublicKey> trusted_peers_0conf;
1314
};
1415

1516
interface Builder {

src/event.rs

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ where
231231
payment_store: Arc<PaymentStore<K, L>>,
232232
runtime: Arc<RwLock<Option<tokio::runtime::Runtime>>>,
233233
logger: L,
234-
_config: Arc<Config>,
234+
config: Arc<Config>,
235235
}
236236

237237
impl<K: KVStore + Sync + Send + 'static, L: Deref> EventHandler<K, L>
@@ -242,7 +242,7 @@ where
242242
wallet: Arc<Wallet<bdk::database::SqliteDatabase>>, event_queue: Arc<EventQueue<K, L>>,
243243
channel_manager: Arc<ChannelManager<K>>, network_graph: Arc<NetworkGraph>,
244244
keys_manager: Arc<KeysManager>, payment_store: Arc<PaymentStore<K, L>>,
245-
runtime: Arc<RwLock<Option<tokio::runtime::Runtime>>>, logger: L, _config: Arc<Config>,
245+
runtime: Arc<RwLock<Option<tokio::runtime::Runtime>>>, logger: L, config: Arc<Config>,
246246
) -> Self {
247247
Self {
248248
event_queue,
@@ -253,7 +253,7 @@ where
253253
payment_store,
254254
logger,
255255
runtime,
256-
_config,
256+
config,
257257
}
258258
}
259259

@@ -545,7 +545,52 @@ where
545545
}
546546
}
547547
}
548-
LdkEvent::OpenChannelRequest { .. } => {}
548+
LdkEvent::OpenChannelRequest {
549+
temporary_channel_id,
550+
counterparty_node_id,
551+
funding_satoshis,
552+
channel_type: _,
553+
push_msat: _,
554+
} => {
555+
let user_channel_id: u128 = rand::thread_rng().gen::<u128>();
556+
let allow_0conf = self.config.trusted_peers_0conf.contains(&counterparty_node_id);
557+
let res = if allow_0conf {
558+
self.channel_manager.accept_inbound_channel_from_trusted_peer_0conf(
559+
&temporary_channel_id,
560+
&counterparty_node_id,
561+
user_channel_id,
562+
)
563+
} else {
564+
self.channel_manager.accept_inbound_channel(
565+
&temporary_channel_id,
566+
&counterparty_node_id,
567+
user_channel_id,
568+
)
569+
};
570+
571+
match res {
572+
Ok(()) => {
573+
log_info!(
574+
self.logger,
575+
"Accepting inbound{} channel of {}sats from{} peer {}",
576+
if allow_0conf { " 0conf" } else { "" },
577+
funding_satoshis,
578+
if allow_0conf { " trusted" } else { "" },
579+
counterparty_node_id,
580+
);
581+
}
582+
Err(e) => {
583+
log_error!(
584+
self.logger,
585+
"Error while accepting inbound{} channel from{} peer {}: {:?}",
586+
if allow_0conf { " 0conf" } else { "" },
587+
counterparty_node_id,
588+
if allow_0conf { " trusted" } else { "" },
589+
e,
590+
);
591+
}
592+
}
593+
}
549594
LdkEvent::PaymentForwarded {
550595
prev_channel_id,
551596
next_channel_id,

src/lib.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,7 @@ const WALLET_KEYS_SEED_LEN: usize = 64;
224224
/// | `onchain_wallet_sync_interval_secs` | 60 |
225225
/// | `wallet_sync_interval_secs` | 20 |
226226
/// | `fee_rate_cache_update_interval_secs` | 600 |
227+
/// | `trusted_peers_0conf` | [] |
227228
/// | `log_level` | `Debug` |
228229
///
229230
pub struct Config {
@@ -247,6 +248,12 @@ pub struct Config {
247248
///
248249
/// **Note:** A minimum of 10 seconds is always enforced.
249250
pub fee_rate_cache_update_interval_secs: u64,
251+
/// A list of peers that we allow to establish zero confirmation channels to us.
252+
///
253+
/// **Note:** Allowing payments via zero-confirmation channels is potentially insecure if the
254+
/// funding transaction ends up never being confirmed on-chain. Zero-confirmation channels
255+
/// should therefore only be accepted from trusted peers.
256+
pub trusted_peers_0conf: Vec<PublicKey>,
250257
/// The level at which we log messages.
251258
///
252259
/// Any messages below this level will be excluded from the logs.
@@ -263,6 +270,7 @@ impl Default for Config {
263270
onchain_wallet_sync_interval_secs: DEFAULT_BDK_WALLET_SYNC_INTERVAL_SECS,
264271
wallet_sync_interval_secs: DEFAULT_LDK_WALLET_SYNC_INTERVAL_SECS,
265272
fee_rate_cache_update_interval_secs: DEFAULT_FEE_RATE_CACHE_UPDATE_INTERVAL_SECS,
273+
trusted_peers_0conf: Vec::new(),
266274
log_level: DEFAULT_LOG_LEVEL,
267275
}
268276
}
@@ -573,6 +581,11 @@ impl Builder {
573581
// Initialize the ChannelManager
574582
let mut user_config = UserConfig::default();
575583
user_config.channel_handshake_limits.force_announced_channel_preference = false;
584+
if !config.trusted_peers_0conf.is_empty() {
585+
// Manually accept inbound channels if we expect 0conf channel requests, avoid
586+
// generating the events otherwise.
587+
user_config.manually_accept_inbound_channels = true;
588+
}
576589
let channel_manager = {
577590
if let Ok(mut reader) = kv_store
578591
.read(CHANNEL_MANAGER_PERSISTENCE_NAMESPACE, CHANNEL_MANAGER_PERSISTENCE_KEY)

src/peer_store.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ where
3232
pub(crate) fn add_peer(&self, peer_info: PeerInfo) -> Result<(), Error> {
3333
let mut locked_peers = self.peers.write().unwrap();
3434

35+
if locked_peers.contains_key(&peer_info.node_id) {
36+
return Ok(());
37+
}
38+
3539
locked_peers.insert(peer_info.node_id, peer_info);
3640
self.persist_peers(&*locked_peers)
3741
}

src/test/functional_tests.rs

Lines changed: 45 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
1+
use crate::io::KVStore;
12
use crate::test::utils::*;
23
use crate::test::utils::{expect_event, random_config};
3-
use crate::{Builder, Error, Event, PaymentDirection, PaymentStatus};
4+
use crate::{Builder, Error, Event, Node, PaymentDirection, PaymentStatus};
45

56
use bitcoin::Amount;
7+
use electrsd::bitcoind::BitcoinD;
8+
use electrsd::ElectrsD;
9+
10+
use std::sync::Arc;
611

712
#[test]
813
fn channel_full_cycle() {
@@ -14,14 +19,46 @@ fn channel_full_cycle() {
1419
builder_a.set_esplora_server(esplora_url.clone());
1520
let node_a = builder_a.build();
1621
node_a.start().unwrap();
17-
let addr_a = node_a.new_funding_address().unwrap();
1822

1923
println!("\n== Node B ==");
2024
let config_b = random_config();
2125
let builder_b = Builder::from_config(config_b);
2226
builder_b.set_esplora_server(esplora_url);
2327
let node_b = builder_b.build();
2428
node_b.start().unwrap();
29+
30+
do_channel_full_cycle(node_a, node_b, &bitcoind, &electrsd, false);
31+
}
32+
33+
#[test]
34+
fn channel_full_cycle_0conf() {
35+
let (bitcoind, electrsd) = setup_bitcoind_and_electrsd();
36+
println!("== Node A ==");
37+
let esplora_url = format!("http://{}", electrsd.esplora_url.as_ref().unwrap());
38+
let config_a = random_config();
39+
let builder_a = Builder::from_config(config_a);
40+
builder_a.set_esplora_server(esplora_url.clone());
41+
let node_a = builder_a.build();
42+
node_a.start().unwrap();
43+
44+
println!("\n== Node B ==");
45+
let mut config_b = random_config();
46+
config_b.trusted_peers_0conf.push(node_a.node_id());
47+
48+
let builder_b = Builder::from_config(config_b);
49+
builder_b.set_esplora_server(esplora_url.clone());
50+
let node_b = builder_b.build();
51+
52+
node_b.start().unwrap();
53+
54+
do_channel_full_cycle(node_a, node_b, &bitcoind, &electrsd, true)
55+
}
56+
57+
fn do_channel_full_cycle<K: KVStore + Sync + Send>(
58+
node_a: Arc<Node<K>>, node_b: Arc<Node<K>>, bitcoind: &BitcoinD, electrsd: &ElectrsD,
59+
allow_0conf: bool,
60+
) {
61+
let addr_a = node_a.new_funding_address().unwrap();
2562
let addr_b = node_b.new_funding_address().unwrap();
2663

2764
let premine_amount_sat = 100_000;
@@ -71,8 +108,11 @@ fn channel_full_cycle() {
71108

72109
wait_for_tx(&electrsd, funding_txo.txid);
73110

74-
println!("\n .. generating blocks, syncing wallets .. ");
75-
generate_blocks_and_wait(&bitcoind, &electrsd, 6);
111+
if !allow_0conf {
112+
println!("\n .. generating blocks ..");
113+
generate_blocks_and_wait(&bitcoind, &electrsd, 6);
114+
}
115+
76116
node_a.sync_wallets().unwrap();
77117
node_b.sync_wallets().unwrap();
78118

@@ -271,7 +311,7 @@ fn channel_open_fails_when_funds_insufficient() {
271311
node_b.listening_address().unwrap().into(),
272312
120000,
273313
None,
274-
true
314+
true,
275315
)
276316
);
277317
}

0 commit comments

Comments
 (0)